PInvoke para function C que retorna char *

Eu estou tentando escrever algum código c # que chama um método de uma DLL não gerenciada. O protótipo para a function na dll é:

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

Em C #, usei pela primeira vez:

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

Parece funcionar na superfície, mas estou recebendo erros de corrupção de memory durante o tempo de execução. Acho que estou apontando para a memory que está correta, mas que já foi liberada.

Eu tentei usar um utilitário PInvoke code gen chamado “P / Invoke Interop Assistant”. Isso me deu a saída:

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

Isso está correto? Em caso afirmativo, como converter este IntPtr para uma seqüência de caracteres em c #?

Você deve retornar isso como um IntPtr. Retornar um tipo System.String de uma function PInvoke requer muito cuidado. O CLR deve transferir a memory da representação nativa para a gerenciada. Esta é uma operação fácil e previsível.

O problema, no entanto, vem com o que fazer com a memory nativa retornada de foo (). O CLR assume os dois itens a seguir sobre uma function PInvoke que retorna diretamente o tipo de string

  1. A memory nativa precisa ser liberada
  2. A memory nativa foi alocada com CoTaskMemAlloc

Portanto, ele irá empacotar a seqüência de caracteres e, em seguida, chamar CoTaskMemFree no blob de memory nativa. A menos que você realmente alocou essa memory com CoTaskMemAlloc isso na melhor das hipóteses causará uma falha em seu aplicativo.

Para obter a semântica correta aqui, você deve retornar um IntPtr diretamente. Em seguida, use Marshal.PtrToString * para obter um valor de String gerenciado. Você ainda pode precisar liberar a memory nativa, mas isso dependerá da implementação do foo.

Você pode usar o método Marshal.PtrToStringAuto.

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