ravenspoint
ravenspoint

Reputation: 20616

Passing string from C++ to C#

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

Upvotes: 3

Views: 5102

Answers (2)

Gideon Engelberth
Gideon Engelberth

Reputation: 6155

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.

Upvotes: 4

Puppy
Puppy

Reputation: 147036

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.

Upvotes: 1

Related Questions