Il marshaller P/Invoke assumerà che la memoria per il tipo restituito sia stata allocata con CoTaskMemAlloc() e chiamerà CoTaskMemFree() per rilasciarlo. Se ciò non è stato fatto, il programma fallirà con un'eccezione su Vista e Win7 ma silenziosamente perderà memoria su XP. È possibile utilizzare SysAllocString() per funzionare, ma è necessario annotare il tipo restituito nell'attributo [DllImport]. Non farlo causerà comunque una perdita, senza una diagnosi su Win7. Un BSTR è non un puntatore a un blocco di memoria allocato da CoTaskMemAlloc, ci sono 4 byte davanti all'indirizzo puntato che memorizza la dimensione della stringa.
Una delle seguenti combinazioni di funzionare correttamente:
extern "C" __declspec(dllexport)
BSTR __stdcall ReturnsAString() {
return SysAllocString(L"Hello world");
}
[DllImport(@"c:\projects\cpptemp1\debug\cpptemp1.dll")]
[return: MarshalAs(UnmanagedType.BStr)] // NOTE: required!
private static extern string ReturnsAString();
Oppure:
extern "C" __declspec(dllexport)
const wchar_t* __stdcall ReturnsAString() {
const wchar_t* str = L"Hello world";
wchar_t* retval = (wchar_t*)CoTaskMemAlloc((wcslen(str)+1) * sizeof(wchar_t));
wcscpy(retval, str);
return retval;
}
[DllImport(@"c:\projects\cpptemp1\debug\cpptemp1.dll", CharSet=CharSet.Auto)]
private static extern string ReturnsAString();
Si dovrebbe considerare che consente il codice del client di passare un buffer quindi non ci sono problemi di gestione della memoria. Questo dovrebbe essere simile a questo:
extern "C" __declspec(dllexport)
void __stdcall ReturnsAString(wchar_t* buffer, size_t buflen) {
wcscpy_s(buffer, buflen, L"Hello world");
}
[DllImport(@"c:\projects\cpptemp1\debug\cpptemp1.dll", CharSet=CharSet.Auto)]
private static extern void ReturnsAString(StringBuilder buffer, int buflen);
...
StringBuilder sb = new StringBuilder(256);
ReturnsAString(sb, sb.Capacity);
string s = sb.ToString();
fonte
2009-12-19 13:47:59
Grazie. Funziona bene. – Alex