3

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

2 Answers 2

4

When marshalling strings across a P/Invoke boundary, it is always good practice to use a MarshalAs attribute with the appropriate string type. I think putting a [MarshalAs(UnmanagedType.BStr)] on the parameter should take care of the problem.

public delegate void callback([MarshalAs(UnmanagedType.BStr)]string str);

This article has an similar example where someone was passing BSTRs between managed and unmanaged code, but he used IntPtr and some methods on the Marshal class. Marshal.PtrToStringBSTR seems most useful here.

Sign up to request clarification or add additional context in comments.

2 Comments

Can you please expand on this? My c# is not expert enough to know how to implement your answer.
@ravenspoint try changing the delegate to: public delegate void callback([MarshalAs(UnmanagedType.BStr)] string str); importing the System.Runtime.InteropServices namespace if needed. This tells the runtime that unmanaged code expects this to be a BSTR (or perhaps BSTR *, I am not an interop expert)
1

C# strings are UTF-16. I would suggest that C# could be expecting an LPWSTR or something similar rather than a BSTR. If you look at the first example posted, he puts the call type as a wchar_t*, not a BSTR.

3 Comments

Yes, and so are BSTRs I believe.
BSTRs are not plain wchar_t*s, they are a different binary format. That's why SysAllocString exists.
Yes. They are preceded by the string length. As I understand it, BSTR(c++) == string(c#)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.