如何 PInvoke 这个 C++功能?

发布于 2025-01-03 08:29:03 字数 578 浏览 0 评论 0原文

我有以下功能:

bool __declspec(dllexport) COMS_HL7QueryAnswer(char *szZone,char* szMessage, char** o_szAnswer)

我从 C# 中 PInvoking 它如下:

public static extern bool COMS_HL7QueryAnswer(string szZone,string szMessage, out StringBuilder szAnswer);

它在 Windows 2003 中工作,但我在 W2008 中遇到访问冲突异常,看起来它们发生在 PInvoke 的边界中。任何帮助都会很棒。

谢谢。

编辑: 看起来 AccessViolationException 发生在 PInvoke 边界中,因为:

  1. 除了 C# 函数之外,我没有调用堆栈。
  2. 当我使用调试器时,我可以按 F10 直到最后一个 C++ 函数,当我退出 } 时,我会转到 C# 异常处理程序。

I have the following function:

bool __declspec(dllexport) COMS_HL7QueryAnswer(char *szZone,char* szMessage, char** o_szAnswer)

And I'm PInvoking it from C# like this:

public static extern bool COMS_HL7QueryAnswer(string szZone,string szMessage, out StringBuilder szAnswer);

It's working in Windows 2003 but I'm getting access violation exceptions in W2008 and looks like they happen in the boundary of the PInvoke. Any help will be great.

Thanks.

EDIT: Looks like the AccessViolationException happens in the PInvoke boundary because:

  1. I don't have a callstack other than the C# function.
  2. When I go with the debugger I can F10 until the last C++ function and when I exit the } then I go to the C# exception handler.

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

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

发布评论

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

评论(2

寄离 2025-01-10 08:29:03

您需要使用

[DllImport(CallingConvention = CallingConvention.Cdecl)]
public static extern bool COMS_HL7QueryAnswer(string szZone,string szMessage, out IntPtr szAnswer);

因为 p/invoke 不知道如何正确释放 *o_szAnswer,所以您需要在检索数据后保留指针并将其传递给正确的释放函数。

如果您被允许更改 C++ 方面,您可以采取多种措施来使其更加 p/invoke 友好。或者您可以使用 C++/CLI 层。

You'll need to use

[DllImport(CallingConvention = CallingConvention.Cdecl)]
public static extern bool COMS_HL7QueryAnswer(string szZone,string szMessage, out IntPtr szAnswer);

Because p/invoke has no idea how to correctly free *o_szAnswer, you' need to keep the pointer and pass it to the correct deallocation function yourself, after retrieving the data.

If you are allowed to change the C++ side, there are a number of things you can do to make this more p/invoke-friendly. Or you can use a C++/CLI layer.

毁虫ゝ 2025-01-10 08:29:03

您的代码正在泄漏内存。是的,W2003 将默默地忽略 pinvoke 编组器释放字符串的尝试。 W2008 有更严格的内存管理器,无法忍受,它会触发 AccessViolation。如果没有 IntPtr 和 Marshal.PtrToStringAnsi(),您可能会继续泄漏内存。如果您可以修复 C 代码,则使用 CoTaskMemAlloc() 分配字符串缓冲区将解决问题,pinvoke 编组器使用 CoTaskMemFree()。

真正的修复方法是 char* 而不是 char**,以便调用者可以传递一个缓冲区来填充字符串。 StringBuilder 没有来自 C# 的 out。使用提供容量的额外参数,这样当字符串不适合时,您就不会意外损坏垃圾收集堆。

Your code is leaking memory. Yes, W2003 will silently ignore the pinvoke marshaller's attempt to release the string. W2008 has a much stricter memory manager and won't put up with it, it triggers an AccessViolation. You can keep leaking memory with out IntPtr and Marshal.PtrToStringAnsi(). If you can fix the C code then allocating the string buffer with CoTaskMemAlloc() will solve the problem, the pinvoke marshaller uses CoTaskMemFree().

A real fix is char* instead of char** so that the caller can pass a buffer to be filled with the string. StringBuilder without out from C#. With an extra argument that gives the Capacity so you won't corrupt the garbage collected heap by accident when the string doesn't fit.

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