如何 PInvoke 这个 C++功能?
我有以下功能:
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 边界中,因为:
- 除了 C# 函数之外,我没有调用堆栈。
- 当我使用调试器时,我可以按 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:
- I don't have a callstack other than the C# function.
- 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要使用
因为 p/invoke 不知道如何正确释放
*o_szAnswer
,所以您需要在检索数据后保留指针并将其传递给正确的释放函数。如果您被允许更改 C++ 方面,您可以采取多种措施来使其更加 p/invoke 友好。或者您可以使用 C++/CLI 层。
You'll need to use
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.
您的代码正在泄漏内存。是的,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.