C#P / Invoke中的Marshal C ++“string”类

时间:2008-10-01 16:58:02

标签: .net c++ string interop marshalling

我在本机DLL中有一个函数,定义如下:

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

我试着将它放在微软的P / Invoke Interop助手中,但它在“字符串”类(我认为是来自MFC?)上窒息。

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

有没有人使用本机字符串类的Native / Managed Interop?有没有办法让这个元帅?我是否必须自己编写Marshaler?

3 个答案:

答案 0 :(得分:6)

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

答案 1 :(得分:2)

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

void SetPath(__in const WCHAR* path);

答案 2 :(得分:0)

是。您可以。实际上,不仅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