在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);
答案 0 :(得分:7)
您应该将返回的字符串封送为IntPtr
,否则CLR可能会使用错误的分配器释放内存,从而可能导致堆损坏和各种问题。
看到这个几乎(但不完全)重复的问题PInvoke for C function that returns char *。
理想情况下,当您希望释放字符串时,您的C dll还应该公开FreeText
函数供您使用。这样可以确保以正确的方式释放字符串(即使C dll发生更改)。
答案 1 :(得分:1)
添加另一个调用ReturnSomeText
的函数free
或再次释放内存所需的任何内容。
答案 2 :(得分:1)
如果返回使用本机malloc分配的.net内存,则还必须导出deallocator。我不认为这是一个理想的行动,而是宁愿将文本导出为BSTR
。这可以由C#运行时释放,因为它知道BSTR
是由COM分配器分配的。 C#编码变得简单得多。
唯一的问题是BSTR
使用Unicode字符,而您的C ++代码使用ANSI。我会像这样解决这个问题:
<强> C ++ 强>
#include <comutil.h>
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);