Reputation: 21855
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:
Upvotes: 0
Views: 693
Reputation: 941545
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.
Upvotes: 1
Reputation: 283684
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.
Upvotes: 3