pinvoke:如何释放 malloc 字符串?

发布于 2024-12-03 08:21:26 字数 1022 浏览 1 评论 0原文

在 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);

In a C dll, I have a function like this:

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;
}

I would like to call it from C# using P/invoke.

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

How do I properly release the allocated memory?

I am writing cross-platform code targeting both Windows and Linux.

Edit:
Like this

[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);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

滿滿的愛 2024-12-10 08:21:26

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

看到这个几乎(但不完全)重复的问题 PInvoke for C function that returns char *

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

You should marshal returned strings as IntPtr otherwise the CLR may free the memory using the wrong allocator, potentially causing heap corruption and all sorts of problems.

See this almost (but not quite) duplicate question PInvoke for C function that returns char *.

Ideally your C dll should also expose a FreeText function for you to use when you wish to free the string. This ensures that the string is deallocated in the correct way (even if the C dll changes).

海的爱人是光 2024-12-10 08:21:26

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

Add another function ReturnSomeText that calls free or whatever is needed to release the memory again.

偏爱自由 2024-12-10 08:21:26

如果您返回使用本机 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);

If you return to .net memory allocated with your native malloc, then you also have to export the deallocator. I don't regard that to be a desirable action and instead prefer to export the text as a BSTR. This can be freed by the C# runtime because it knows that the BSTR was allocated by the COM allocator. The C# coding becomes a lot simpler.

The only wrinkle is that a BSTR uses Unicode characters and your C++ code uses ANSI. I would work around that like so:

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文