将字符串从 C++ 传递到 C#

Posted

技术标签:

【中文标题】将字符串从 C++ 传递到 C#【英文标题】:Passing string from C++ to C# 【发布时间】:2010-12-15 21:42:35 【问题描述】:

我正在使用 Thottam R. Sriram http://blogs.msdn.com/b/thottams/archive/2007/06/02/pinvoke-reverse-pinvoke-and-stdcall-cdecl.aspx 所描述的 PInvoke,反向 PInvoke 方案

除了将字符串从 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

【问题讨论】:

【参考方案1】:

跨 P/Invoke 边界编组字符串时,最好使用具有适当字符串类型的 MarshalAs 属性。我认为在参数上加上[MarshalAs(UnmanagedType.BStr)] 应该可以解决这个问题。

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

This article 有一个类似的例子,有人在托管和非托管代码之间传递 BSTR,但他使用了 IntPtr 和 Marshal 类上的一些方法。 Marshal.PtrToStringBSTR 似乎在这里最有用。

【讨论】:

您能详细说明一下吗?我的 c# 不够专业,不知道如何实现您的答案。 @ravenspoint 尝试将委托更改为:public delegate void callback([MarshalAs(UnmanagedType.BStr)] string str);,如果需要,导入 System.Runtime.InteropServices 命名空间。这告诉运行时非托管代码期望这是一个 BSTR(或者可能是 BSTR *,我不是互操作专家) 做到了!非常感谢。【参考方案2】:

C# 字符串是 UTF-16。我建议 C# 可能期待 LPWSTR 或类似的东西,而不是 BSTR。如果您查看发布的第一个示例,他将调用类型设置为 wchar_t*,而不是 BSTR。

【讨论】:

是的,我相信 BSTR 也是如此。 BSTR 不是普通的 wchar_t*s,它们是不同的二进制格式。这就是 SysAllocString 存在的原因。 是的。它们前面是字符串长度。据我了解,BSTR(c++) == string(c#)

以上是关于将字符串从 C++ 传递到 C#的主要内容,如果未能解决你的问题,请参考以下文章

将字符串从 C++ 传递到 C#

通过互操作将字符串数组从 C# 传递到 C++

使用 void 指针将字符串从 C++ 传递到 C#

如何将字符串从 C++ 原生传递到 C# Unity?

如何安全地将字符串引用从 c# 传递到 c++?

使用 Dllimport 将一个非常大的字符串作为字节数组从 C++ 传递到 C#