Ignacio Soler Garcia
Ignacio Soler Garcia

Reputation: 21855

How to PInvoke this C++ function?

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.

Upvotes: 0

Views: 693

Answers (2)

Hans Passant
Hans Passant

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

Ben Voigt
Ben Voigt

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

Related Questions