Allocating and freeing memory in unmanaged code using the Invoke platform (C #)

I want to allocate and free memory in unmanaged code (C ++), and we will call them functions from managed code (C #). I'm not sure if the following code is good without memory leaks or not?

C # code:

[DllImport("SampleDLL.dll")] public extern void getString([MarshalAs(UnmanagedType.LPStr)] out String strbuilder); [DllImport("SampleDLL.dll")] public extern void freeMemory([MarshalAs(UnmanagedType.LPStr)] out String strBuilder); .... //call to unmanaged code getString(out str); Console.WriteLine(str); freeMemory(out str); 

C ++ Code:

 extern void _cdecl getString(char **str) { *str = new char[20]; std::string temp = "Hello world"; strncpy(*str,temp.c_str(),temp.length()+1); } extern void _cdecl freeMemory(char **str) { if(*str) delete []*str; *str=NULL; } 
+6
source share
2 answers

No, that will not work. The pinvoke router will attempt to free memory for the string using CoTaskMemFree (). Otherwise, it is not known that you have a release function. This will not work well, you have not allocated a line with CoTaskMemAlloc. This will be a quiet memory leak in XP, a crash in Vista and higher.

You must stop the marshaller from trying to do the right thing:

 [DllImport("SampleDLL.dll")] public extern void getString(out IntPtr strptr); [DllImport("SampleDLL.dll")] public extern void freeMemory(IntPtr strptr); 

Which then requires Marshal.PtrToStringAnsi () in your C # code to infer a string from the returned pointer.

+4
source

Personally, I think this is easiest to do with BSTR and thus avoid the need to export deallocator.

C ++

 BSTR ANSItoBSTR(const char* input) { BSTR result = NULL; int lenA = lstrlenA(input); int lenW = ::MultiByteToWideChar(CP_ACP, 0, input, lenA, NULL, 0); if (lenW > 0) { result = ::SysAllocStringLen(0, lenW); ::MultiByteToWideChar(CP_ACP, 0, input, lenA, result, lenW); } return result; } BSTR __stdcall getString() { return ANSItoBSTR("Hello world"); } 

Of course, if you work with Unicode strings, this is even easier.

 BSTR __stdcall getString() { return ::SysAllocString(L"Hello world"); } 

FROM#

 [DllImport(@"test.dll")] [return: MarshalAs(UnmanagedType.BStr)] private static extern string getString(); 

And on the C # side it is. You just call getString() , and it returns a .net string , and you don't need to march or call a deactivator.

0
source

Source: https://habr.com/ru/post/896553/


All Articles