我正在使用Photvm,逆向PInvoke方案,如Thottam R. Sriram http://blogs.msdn.com/b/thottams/archive/2007/06/02/pinvoke-reverse-pinvoke-and-stdcall-cdecl.aspx
所述除了将字符串从C ++传递给C之外,一切似乎都运行良好。
(在Sriram中,字符串是用c#构造的,并且通过c ++不受影响,因此避免了这个问题。)
c#代码如下所示
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);
}
C ++代码如下所示
extern "C" dllapi void __stdcall gpscom_start(void (__stdcall *callback) (BSTR str))
{
BSTR bstr = SysAllocString(L"starting monitor");
(*callback)(bstr);
SysFreeString(bstr);
运行时,除回调字符串
外,一切看起来都不错Managed: m
它似乎是一个由ANSI例程打印出来的UNICODE字符串,但是c#字符串肯定是unicode吗?
TIA
答案 0 :(得分:4)
在P / Invoke边界编组字符串时,最好使用具有相应字符串类型的MarshalAs
属性。我认为在参数上加[MarshalAs(UnmanagedType.BStr)]
可以解决问题。
public delegate void callback([MarshalAs(UnmanagedType.BStr)]string str);
This article有一个类似的例子,有人在托管代码和非托管代码之间传递BSTR,但他在Marshal类上使用了IntPtr
和一些方法。 Marshal.PtrToStringBSTR
似乎在这里最有用。
答案 1 :(得分:1)
C#字符串是UTF-16。我建议C#可以期待LPWSTR或类似的东西,而不是BSTR。如果您查看发布的第一个示例,他会将调用类型设置为wchar_t *,而不是BSTR。