如何PInvoke此C++函数

本文关键字:函数 C++ PInvoke 如何 | 更新日期: 2023-09-27 18:23:45

我有以下功能:

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

我是这样从C#中检索的:

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#异常处理程序

如何PInvoke此C++函数

您需要使用

[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层。

您的代码正在泄漏内存。是的,W2003将默默地忽略pinvoke-mashaller释放字符串的尝试。W2008有一个更严格的内存管理器,它不会容忍它,它会触发AccessViolation。你可以用out IntPtr和Marshal.PtrToStringAnsi()来保持内存泄漏。如果你能修复C代码,那么用CoTaskMemAlloc()分配字符串缓冲区就能解决问题,pinvoke marshaller使用CoTaskMemFree()。

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