#c# #c #pinvoke #bytearray #dllimport
#c# #c #pinvoke #bytearray #dllimport
Вопрос:
Я пытаюсь использовать 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, amp;dst_len);
return ((int)dst_len);
}
И вызов C#:
PQfun.PQunescapeByteaWrapper(ref EscapedMessage, ref UnescapedMessage);
Отладка в C Я вижу, что «src» передается правильно, а также вычисляется «летнее время», но когда я возвращаюсь к C #, массив байтов [] «dst» содержит не значение массива символов без знака «dst», а исходное значение перед C P/ Вызвать!!
Как я могу передать вычисленное значение?
С уважением, Стефан
Ответ №1:
Вы используете сигнатуру метода C , и реализация неверна. Вы присваиваете параметру новый адрес. Вы должны использовать указатель на указатель, например
extern DECLSPEC int PQunescapeByteaWrapper(unsigned char* src, unsigned char** dst)
{
size_t dst_len;
*dst = PQunescapeBytea(src, amp;dst_len);
return ((int)dst_len);
}
Кстати, у вас здесь нет утечки памяти? вы намеревались перезаписать значения в существующем массиве, на который ссылается dst, или вы намеревались создать новый массив и назначить его dst?
Комментарии:
1. Я намеревался перезаписать существующий массив. Он
ref byte[] dst
уже выделен в моем коде на C #. Как вы думаете, где утечка памяти?2. @luckymanStefanc — Вот почему я задал свой вопрос 😉 возможно, вы хотели выделить летнее время в своем методе C и вернуть его в C #, поскольку именно это делает реализация вашего метода C . Если вы хотите скопировать результат PUnescapeByteA в ваш предварительно выделенный буфер dst, вы должны это сделать. Смотрите Пример другого ответа для этого. Если вы хотите выделить новый массив на c и вернуть его на C #, см. Мой ответ
Ответ №2:
Я думаю, вам следует написать это так и выделить dst
буфер снаружи в вашем коде на C #.
int PQunescapeByteaWrapper(unsigned char* src, unsigned char* dst, size_t maxlen)
{
size_t dst_len = 0;
unsgigned char* tmp = PQunescapeBytea( src, amp;dst_len );
memcpy( dst, tmp, min( maxlen, dst_len ));
}
Комментарии:
1. Спасибо, теперь это работает. Чтобы понять, в чем разница, если я использую временный массив, как вы предложили?
Ответ №3:
Насколько я вижу, есть несколько проблем.
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 не должен возвращать новый массив, он должен копировать содержимое преобразования в выходной параметр.