C Dll Import создает исключение директивы Маршалла в C#

У меня проблема с включением DLL (написанной на C) в мой проект на C#, и я надеюсь, что вы мне поможете. В своем исследовании я нашел DLLImport, но я не уверен, какие типы переменных C преобразуются в...

Метод C из DLL, которую я хочу импортировать, выглядит следующим образом:

int lou_translateString (
     const char * tableList,
     const widechar * inbuf,
     int *inlen,
     widechar *outbuf,
     int *outlen,
     char *typeform,
     char *spacing,
     int mode);

Это DLLImport, который я пробовал:

[DllImport("liblouis-2.dll", EntryPoint = "lou_translateString", CharSet = CharSet.Ansi, ExactSpelling = true)]
    [return: MarshalAs(UnmanagedType.LPStr)]
    public static extern int translate([MarshalAs(UnmanagedType.LPStr)]
        String tableList,
        String inbuf,
        int inlen,
        String outbuf,
        int outlen,
        String typeform,
        String spacing,
        int mode);

Но когда я пытаюсь вызвать метод, я получаю:

MarshallDirectiveException Не удалось маршалировать 'возвращаемое значение': недопустимая комбинация управляемого / неуправляемого типа (Int32/UInt32 должен быть связан с I4 или U4)

Может кто-нибудь помочь с исключением? Я почти уверен, что это связано с типами параметров в методе, но я не знаю, как правильно их объявить. Любая помощь будет оценена!

Заранее спасибо Алекс

Добавлена ​​закороченная документация для уточнения

Эта функция принимает строку из 16-битных символов Unicode в inbuf и переводит ее в строку из 16-битных символов в outbuf.

Параметр tableList указывает на список таблиц перевода, разделенных запятыми.

Обратите внимание, что оба параметра *inlen и *outlen являются указателями на целые числа. Когда функция вызывается, эти целые числа содержат максимальную длину входа и выхода соответственно. Когда он возвращается, они устанавливаются на фактические используемые длины.

Параметр typeform используется для указания типа курсива, полужирного шрифта, компьютерного шрифта Брайля и т. Д. Это строка символов той же длины, что и входной буфер, на который указывает *inbuf. Однако он используется для передачи посимвольных результатов, поэтому необходимо выделить достаточно места для соответствия параметру *outlen. Каждый символ указывает форму типа соответствующего символа во входном буфере. Значения следующие: 0 обычный текст; 1 курсив; 2 жирным шрифтом; 4 подчеркивание; 8 компьютерный шрифт Брайля. Эти значения могут быть добавлены для множественного выделения. Если этот параметр НЕДЕЙСТВИТЕЛЕН, никакая проверка для форм типа не сделана. Кроме того, если этот параметр не равен NULL, при возврате устанавливается значение 8 в каждой позиции, соответствующей символу в outbuf, который был определен как имеющий представление точки, содержащее точку 7, точку 8 или оба, и 0 в противном случае.

Параметр spacing используется для указания различий между входной строкой и переведенной выходной строкой. Он также имеет ту же длину, что и строка, на которую указывает *inbuf. Если этот параметр равен NULL, информация о расстоянии не вычисляется.

Параметр mode указывает, как должен выполняться перевод.

Функция возвращает 1, если ошибок не обнаружено, и 0, если полный перевод не может быть выполнен.

Вот что я написал для проверки функции в Main:

        StringBuilder outbuf = new StringBuilder("Test", 30);
        int inlength = 100;
        int louint = 0;
        int outlength = 100;
        String inbuf = "test";


        louint = lou_translateString("de-de-g1.ctb", inbuf, inlen: ref inlength, outbuf: outbuf, outlen: ref outlength, typeform: null, spacing: null, mode: 8);

Но в итоге исходный outbuf вообще не меняется. Вы бы сказали, что параметры верны? Нужно ли каким-либо образом изменять параметр outbuf, так как это StringBuilder, а не просто String ( outbuf.Replace())?

1 ответ

Решение

Возвращаемое значение MarshalAs было просто неправильно. Возвращаемое значение int а не строка. Это объясняет ошибку, но это еще не все. В остальной части вашей декларации pinvoke есть ошибки. Я бы сделал это так:

[DllImport("liblouis-2.dll", CharSet = CharSet.Unicode)]
public static extern int lou_translateString(
    [MarshalAs(UnmanagedType.LPStr)]
    string tableList,
    string inbuf,
    ref int inlen,
    StringBuilder outbuf,
    ref int outlen,
    [MarshalAs(UnmanagedType.LPStr)]
    StringBuilder typeform,
    [MarshalAs(UnmanagedType.LPStr)]
    StringBuilder spacing,
    int mode
);

Текстовые буферы, которые выделяются из функции, должны быть объявлены как StringBuilder, И у тебя были другие ошибки. Переведите int* как ref int,

Для вызова функции необходимо создать новый экземпляр StringBuilder пройти как outbuf параметр. Вы должны решить, насколько большим должен быть буфер. Я предполагаю, что документация для функции говорит вам, как это сделать. По крайней мере, для первоначального тестирования вы можете пройти null за typeform а также spacing,

Другие вопросы по тегам