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

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

理想情况下,你的C dll也应该公开一个FreeText函数供你使用,当你希望释放字符串。这确保了字符串以正确的方式被释放(即使C dll发生了变化)。

添加另一个函数ReturnSomeText调用free或任何需要再次释放内存

如果您返回使用本机malloc分配的。net内存,那么您还必须导出释放程序。我不认为这是一个可取的行动,而是更喜欢导出文本作为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);

最新更新