El Marshaller P/Invoke asumirá que la memoria para el tipo de devolución se asignó con CoTaskMemAlloc() y llamará a CoTaskMemFree() para liberarlo. Si esto no se hizo, el programa fallará con una excepción en Vista y Win7 pero silenciosamente perderá memoria en XP. Se puede hacer que SysAllocString() funcione, pero debe anotar el tipo de devolución en el atributo [DllImport]. No hacerlo todavía causará una fuga, sin un diagnóstico en Win7. Un BSTR es no un puntero a un bloque de memoria asignado por CoTaskMemAlloc, hay 4 bytes delante de la dirección apuntada que almacena el tamaño de cadena.
Cualquiera de las siguientes combinaciones funcionará correctamente:
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();
O:
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();
usted debe considerar lo que permite el código de cliente para pasar un buffer para que no haya problemas de gestión de memoria. Eso debería parecerse a esto:
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();
Gracias. Funciona bien. – Alex