关于c#:pinvoke:如何释放malloc字符串?

 2021-04-09 

pinvoke: How to free a malloc'd string?

在C dll中,我具有这样的功能:

1
2
3
4
5
6
7
8
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#调用它。

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

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

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

编辑:
像这样

1
2
3
4
5
6
7
8
9
[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,否则CLR可能会使用错误的分配器释放内存,从而可能导致堆损坏和各种问题。

请参见此几乎(但不是完全)重复的问题PInvoke for返回char *的C函数。

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


如果返回使用本机malloc分配的.net内存,则还必须导出解除分配器。我不认为这是理想的操作,而是希望将文本导出为BSTR。 C#运行时可以释放它,因为它知道BSTR是由COM分配器分配的。 C#编码变得更加简单。

唯一的麻烦是BSTR使用Unicode字符,而您的C代码使用ANSI。我会这样解决:

C

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#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#

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


添加另一个调用free的功能ReturnSomeText或再次释放内存所需的任何功能。