2008-12-15 10 views
41

Sto provando a scrivere un codice C# che chiama un metodo da una DLL non gestita. Il prototipo per la funzione nella DLL è:PInvoke per la funzione C che restituisce char *

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

In C#, ho usato:

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

Sembra funzionare in superficie, ma sto ricevendo errori di corruzione della memoria durante l'esecuzione. Penso che sto indicando la memoria che sembra essere corretta, ma è già stata liberata.

Ho provato a utilizzare un'utilità di codice PInvoke chiamata "P/Invoke Interop Assistant". Mi ha dato l'output:

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

È corretto? In tal caso, come posso convertire questo IntPtr in una stringa in C#?

risposta

67

È necessario restituirlo come IntPtr. Restituire un tipo System.String da una funzione PInvoke richiede molta attenzione. Il CLR deve trasferire la memoria dalla rappresentazione nativa a quella gestita. Questa è un'operazione facile e prevedibile.

Il problema però viene fornito con cosa fare con la memoria nativa restituita da foo(). CLR assume i seguenti due elementi in una funzione PInvoke che restituisce direttamente il tipo stringa

  1. la memoria nativa deve essere liberata
  2. la memoria nativo è stato allocato con CoTaskMemAlloc

Pertanto mobiliterà la stringa e quindi chiamare CoTaskMemFree sul BLOB di memoria nativo. A meno che non abbiate allocato questa memoria con CoTaskMemAlloc, ciò causerà al meglio un crash nella vostra applicazione.

Per ottenere la semantica corretta qui è necessario restituire un IntPtr direttamente. Quindi utilizzare Marshal.PtrToString * per ottenere un valore String gestito. Potrebbe essere ancora necessario liberare la memoria nativa, ma ciò dipenderà dall'implementazione di foo.

19

È possibile utilizzare il metodo Marshal.PtrToStringAuto.

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

Questo ha funzionato per me. L'unico cambiamento che ho dovuto fare è stato 'PtrToStringAuto' in' PtrToStringAnsi', altrimenti ho ottenuto alcuni caratteri cinesi – 3vts

Problemi correlati