PInvoke для функции C, которая возвращает char * - PullRequest
44 голосов
/ 16 декабря 2008

Я пытаюсь написать код на C #, который вызывает метод из неуправляемой DLL. Прототип для функции в dll:

extern "C" __declspec(dllexport) char *foo(void);

В C # я впервые использовал:

[DllImport(_dllLocation)]
public static extern string foo();

Кажется, это работает на поверхности, но я получаю ошибки повреждения памяти во время выполнения. Я думаю, что я указываю на память, которая оказывается правильной, но уже освобождена.

Я попытался использовать утилиту PInvoke code gen, которая называется «P / Invoke Interop Assistant». Это дало мне вывод:

[System.Runtime.InteropServices.DLLImportAttribute(_dllLocation, EntryPoint = "foo")]
public static extern System.IntPtr foo();

Это правильно? Если да, то как мне преобразовать этот IntPtr в строку в C #?

Ответы [ 2 ]

73 голосов
/ 16 декабря 2008

Вы должны вернуть это как IntPtr. Возвращение типа System.String из функции PInvoke требует большой осторожности. CLR должен перенести память из собственного представления в управляемое. Это простая и предсказуемая операция.

Проблема, однако, заключается в том, что делать с собственной памятью, которая была возвращена из foo (). CLR предполагает два следующих пункта о функции PInvoke, которая напрямую возвращает тип строки

  1. Собственная память должна быть освобождена
  2. Собственная память была выделена с помощью CoTaskMemAlloc

Поэтому он будет маршализовать строку и затем вызвать CoTaskMemFree для собственного большого двоичного объекта памяти. Если вы фактически не выделите эту память с помощью CoTaskMemAlloc, это в лучшем случае вызовет сбой в вашем приложении.

Чтобы получить правильную семантику здесь, вы должны вернуть IntPtr напрямую. Затем используйте Marshal.PtrToString *, чтобы получить управляемое значение String. Вам все еще может потребоваться освободить собственную память, но это будет зависеть от реализации foo.

23 голосов
/ 16 декабря 2008

Вы можете использовать метод Marshal.PtrToStringAuto.

IntPtr ptr = foo();
string str = Marshal.PtrToStringAuto(ptr);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...