I am using the PInvoke, reverse PInvoke scheme as described by Thottam R. Sriram http://blogs.msdn.com/b/thottams/archive/2007/06/02/pinvoke-reverse-pinvoke-and-stdcall-cdecl.aspx
Everything seems to work well, except for passing a string from C++ to C.
( In Sriram the string is constructed in c# and passed untouched through c++, so the issue is avoided. )
The c# code looks like this
class Program
{
public delegate void callback(string str);
public static void callee(string str)
{
System.Console.WriteLine("Managed: " + str);
}
static void Main(string[] args)
{
gpscom_start(new callback(Program.callee));
Console.WriteLine("NMEA COM Monitor is running");
System.Threading.Thread.Sleep(50000);
}
[DllImport("gpscomdll.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void gpscom_start(callback call);
}
The C++ code looks like this
extern "C" dllapi void __stdcall gpscom_start(void (__stdcall *callback) (BSTR str))
{
BSTR bstr = SysAllocString(L"starting monitor");
(*callback)(bstr);
SysFreeString(bstr);
When run, everything looks good except the callback string
Managed: m
It looks like a UNICODE string being printed out by an ANSI routine, but surely c# strings are unicode?
TIA
When marshalling strings across a P/Invoke boundary, it is always good practice to use a
MarshalAsattribute with the appropriate string type. I think putting a[MarshalAs(UnmanagedType.BStr)]on the parameter should take care of the problem.This article has an similar example where someone was passing BSTRs between managed and unmanaged code, but he used
IntPtrand some methods on the Marshal class.Marshal.PtrToStringBSTRseems most useful here.