I am interfacing with code that takes a char**
(that is, a pointer to a string):
int DoSomething(Whatever* handle, char** error);
You should just be able to use a ref string
and have the runtime default marshaller take care of this conversion for you. You can hint the char width on the parameter with [MarshalAs(UnmanagedType.LPStr)]
to make sure that you are using 8-bit characters.
Since you have a special deallocation method to call, you'll need to keep the pointer, like you've already shown in your question's example.
Here's how I'd write it:
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
private static unsafe extern int DoSomething(
MySafeHandle handle, void** error); // byte** should work, too, I'm just lazy
Then you can get a string:
var errorMsg = Marshal.PtrToStringAnsi(new IntPtr(*error));
And cleanup:
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int FreeMyMemory(IntPtr h);
// ...
FreeMyMemory(new IntPtr(error));
And now we have the marshalled error, so just return it.
return errorMsg;
Also note the MySafeHandle
type, which would inherit from System.Runtime.InteropServices.SafeHandle
. While not strictly needed (you can use IntPtr), it gives you a better handle management when interoping with native code. Read about it here: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.aspx.