PInvoke para la función C que devuelve char *

Intento escribir un código C # que invoque un método desde una DLL no administrada. El prototipo para la función en el dll es:

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

En C #, primero utilicé:

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

Parece que funciona en la superficie, pero estoy recibiendo errores de corrupción de memoria durante el tiempo de ejecución. Creo que estoy apuntando a la memoria que pasa a ser correcta, pero que ya ha sido liberada.

Intenté usar una utilidad de gen de código PInvoke llamada “P / Invoke Interop Assistant”. Me dio el resultado:

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

¿Es esto correcto? Si es así, ¿cómo convierto este IntPtr a una cadena en C #?

Debe devolver esto como IntPtr. La devolución de un tipo System.String desde una función PInvoke requiere gran cuidado. El CLR debe transferir la memoria de la representación nativa a la manejada. Esta es una operación fácil y predecible.

El problema viene con qué hacer con la memoria nativa devuelta por foo (). El CLR asume los siguientes dos elementos sobre una función PInvoke que devuelve directamente el tipo de cadena

  1. La memoria nativa necesita ser liberada
  2. La memoria nativa se asignó con CoTaskMemAlloc

Por lo tanto, alineará la cadena y luego llamará a CoTaskMemFree en el blob de memoria nativo. A menos que realmente haya asignado esta memoria con CoTaskMemAlloc, esto en el mejor de los casos causará un locking en su aplicación.

Para obtener la semántica correcta aquí, debe devolver un IntPtr directamente. Luego use Marshal.PtrToString * para obtener un valor de cadena administrado. Es posible que aún necesite liberar la memoria nativa, pero eso dependerá de la implementación de foo.

Puede usar el método Marshal.PtrToStringAuto.

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