Подтвердить что ты не робот

Функция PInvoke для C, которая возвращает char *

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

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

В С# я сначала использовал:

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

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

Я попытался использовать служебную программу кода PInvoke, называемую "P/Invoke Interop Assistant". Это дало мне результат:

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

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

4b9b3361

Ответ 1

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

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

  • Необходимо освободить встроенную память.
  • Собственная память была выделена CoTaskMemAlloc

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

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

Ответ 2

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

IntPtr ptr = foo();
string str = Marshal.PtrToStringAuto(ptr);