PInvoke, передача данных туда и обратно - PullRequest
0 голосов
/ 21 октября 2011

Я пытаюсь использовать P / Invoke для вызова функции C ++ из C #.

[DllImport(PATH)]
public static extern int PQunescapeByteaWrapper(
    ref byte[] src,
    ref byte[] dst);

Соответствующая функция C ++ выглядит следующим образом:

extern DECLSPEC int PQunescapeByteaWrapper(unsigned char* src, unsigned char* dst)
{
size_t dst_len;
dst = PQunescapeBytea(src, &dst_len);
return ((int)dst_len);
}

И вызов C #:

PQfun.PQunescapeByteaWrapper(ref EscapedMessage, ref UnescapedMessage);

Отладка в C ++ Я вижу, что "src" передается правильно, а также "dst" вычисляется, но когда я возвращаюсь к C #, массив dst байтов [] не содержит "dst" значение без знака char * array , но оригинальное до C ++ P / Invoke !! Как я могу передать вычисленное значение?

С уважением, Стефан

Ответы [ 3 ]

1 голос
/ 21 октября 2011

Я думаю, что вместо этого вы должны написать это и выделить буфер dst снаружи в своем коде C #.

int PQunescapeByteaWrapper(unsigned char* src, unsigned char* dst, size_t maxlen)
{
   size_t dst_len = 0;
   unsgigned char* tmp = PQunescapeBytea( src, &dst_len );
   memcpy( dst, tmp, min( maxlen, dst_len ));
}
1 голос
/ 21 октября 2011

Вы подпись метода C ++, и реализация неверна. Вы назначаете новый адрес параметру. Вы должны использовать указатель на указатель, например

extern DECLSPEC int PQunescapeByteaWrapper(unsigned char* src, unsigned char** dst)
{
    size_t dst_len;
    *dst = PQunescapeBytea(src, &dst_len);
    return ((int)dst_len);
}

Кстати, у вас здесь нет утечки памяти? Вы намеревались перезаписать значения в существующем массиве, на который ссылается dst, или вы намеревались создать новый массив и присвоить его dst?

0 голосов
/ 21 октября 2011

Насколько я вижу, есть несколько проблем.

1) C # использует __stdcall для вызова функций C. Поэтому вы должны добавить атрибут [DllImport (PATH, CallingConvention = CallingConvention.Cdecl)] или указать атрибут __stdcall для вашей функции C.

2) Если вам нужно передать массив, вам не нужно ключевое слово "ref".

[DllImport(PATH)]
public static extern int MyFunction(byte[] src);

extern DECLSPEC int __stdcall MyFunction(unsigned char* src);

3) Вы не можете использовать в C # массив, выделенный из C ++. Вам необходимо скопировать его в управляемую память (массив C #). Для этого вы можете сделать две функции, например. Тот, который подсчитывает, сколько символов вам нужно для вашего нового массива. Еще один, который выполняет преобразование в массиве назначения.

Так что вы можете сделать что-то вроде этого:

public static byte[] MyConvert(byte[] myArray)
{
    // Function defined in your C/C++ dll that compute how much space you need.
    int count = CountRequiredChars(myArray);

    byte[] myNewArray = new byte[count];

    // Function defined in your C/C++ dll that writes into myNewArray the output.
    PerformMyConversion(myArray, myNewArray);

    return myNewArray;
}

PerformMyConversion не должен возвращать новый массив, он должен копировать содержимое преобразования в выходной параметр.

...