【问题标题】:Marshal C++ "string" class in C# P/InvokeC# P/Invoke 中的 Marshal C++“字符串”类
【发布时间】:2010-09-14 14:10:11
【问题描述】:

我在原生 DLL 中有一个函数,定义如下:

#include <string>
void SetPath(string path);

我试图将它放在 Microsoft 的 P/Invoke Interop Assistant 中,但它在“字符串”类(我认为它来自 MFC?)上卡住了。

我尝试将其编组为各种不同的类型(C# String、char[]、byte[]),但每次我得到 NotSupportedException 或 Native Assembly Exception(取决于我尝试的编组)。

任何人都做过使用原生字符串类的原生/托管互操作?有什么办法可以对此进行元帅吗?我是否必须编写自己的 Marshaler?

【问题讨论】:

  • 好问题;我很惊讶它不会自动工作。 msdn.microsoft.com/en-us/library/1b4az623.aspx
  • 我也很惊讶...没有主要原因它不应该...但似乎 STL 无法使用它...另外...我只想更改使用 WCHAR 的函数,但它不是我可以更改的 DLL。

标签: .net c++ string interop marshalling


【解决方案1】:

是的。你可以。实际上,不只是 std::stringstd::wstring,任何标准 C++ 类或您自己的类都可以从 C#/.NET 进行编组或实例化和调用。

从 .NET 世界中实例化 C++ 对象的基本思想是从 .NET 中分配 C++ 对象的确切大小,然后调用从 C++ DLL 导出的构造函数来初始化对象,然后您就可以调用任何函数来访问该 C++ 对象,如果任何方法涉及其他 C++ 类,您还需要将它们包装在 C# 类中,对于具有原始类型的方法,您可以简单地 P/Invoke 它们。如果你只有几个方法可以调用,那会很简单,手动编码不会花很长时间。完成 C++ 对象后,调用 C++ 对象的析构函数方法,这也是一个导出函数。如果它没有,那么你只需要从 .NET 中释放你的内存。

这是一个例子。

public class SampleClass : IDisposable
{    
    [DllImport("YourDll.dll", EntryPoint="ConstructorOfYourClass", CharSet=CharSet.Ansi,          CallingConvention=CallingConvention.ThisCall)]
    public extern static void SampleClassConstructor(IntPtr thisObject);

    [DllImport("YourDll.dll", EntryPoint="DoSomething", CharSet=CharSet.Ansi,      CallingConvention=CallingConvention.ThisCall)]
    public extern static void DoSomething(IntPtr thisObject);

    [DllImport("YourDll.dll", EntryPoint="DoSomethingElse", CharSet=CharSet.Ansi,      CallingConvention=CallingConvention.ThisCall)]
    public extern static void DoSomething(IntPtr thisObject, int x);

    IntPtr ptr;

    public SampleClass(int sizeOfYourCppClass)
    {
        this.ptr = Marshal.AllocHGlobal(sizeOfYourCppClass);
        SampleClassConstructor(this.ptr);  
    }

    public void DoSomething()
    {
        DoSomething(this.ptr);
    }

    public void DoSomethingElse(int x)
    {
        DoSomethingElse(this.ptr, x);
    }

    public void Dispose()
    {
        Marshal.FreeHGlobal(this.ptr);
    }
}

详情请看以下链接,

C#/.NET PInvoke Interop SDK

(我是SDK工具的作者)

一旦为 C++ 类准备好 C# 包装类,就很容易实现 ICustomMarshaler,以便您可以从 .NET 编组 C++ 对象。

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.icustommarshaler.aspx

【讨论】:

    【解决方案2】:

    PInvoke 互操作助手仅支持 C 而不是 C++。不幸的是,MFC String 类(我相信是 CString?)是 C++,不能通过助手工作。而是尝试使用以下

    void SetPath(__in const WCHAR* path);
    

    【讨论】:

      【解决方案3】:

      看起来您正在尝试使用 C++ 标准库字符串类。我怀疑这将是容易的元帅。最好坚持使用 char * 和 Marshal 作为 StringBuilder。这就是我通常做的。您必须添加一个为您生成 C++ 字符串的包装器。

      【讨论】:

      • 我害怕那个...数字
      猜你喜欢
      • 1970-01-01
      • 2020-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      相关资源
      最近更新 更多