pinvoke:如何释放malloc’d字符串?

在C dll中,我有这样的函数:

char* GetSomeText(char* szInputText) { char* ptrReturnValue = (char*) malloc(strlen(szInputText) * 1000); // Actually done after parsemarkup with the proper length init_parser(); // Allocates an internal processing buffer for ParseMarkup result, which I need to copy sprintf(ptrReturnValue, "%s", ParseMarkup(szInputText) ); terminate_parser(); // Frees the internal processing buffer return ptrReturnValue; } 

我想使用P / invoke从C#中调用它。

 [DllImport("MyDll.dll")] private static extern string GetSomeText(string strInput); 

如何正确释放分配的内存?

我正在编写针对Windows和Linux的跨平台代码。

编辑:像这样

 [DllImport("MyDll.dll")] private static extern System.IntPtr GetSomeText(string strInput); [DllImport("MyDll.dll")] private static extern void FreePointer(System.IntPtr ptrInput); IntPtr ptr = GetSomeText("SomeText"); string result = Marshal.PtrToStringAuto(ptr); FreePointer(ptr); 

您应该将返回的字符串IntPtr送为IntPtr否则CLR可能会使用错误的分配器释放内存,从而可能导致堆损坏和各种问题。

看到几乎(但不完全)重复的问题PInvoke for C函数返回char * 。

理想情况下,当您希望释放字符串时,您的C dll还应该公开FreeText函数供您使用。 这可确保以正确的方式释放字符串(即使C dll更改)。

添加另一个函数ReturnSomeText ,它可以调用free或者再次释放内存所需的任何内容。

如果返回使用本机malloc分配的.net内存,则还必须导出deallocator。 我不认为这是一个理想的行动,而是宁愿将文本导出为BSTR 。 这可以由C#运行时释放,因为它知道BSTR是由COM分配器分配的。 C#编码变得简单得多。

唯一的缺点是BSTR使用Unicode字符,而您的C ++代码使用ANSI。 我会像这样解决这个问题:

C ++

 #include  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 GetSomeText(char* szInputText) { return ANSItoBSTR(szInputText); } 

C#

 [DllImport("MyDll.dll", CallingConvention=CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.BStr)] private static extern string GetSomeText(string strInput);