将wstring,string和enum变量从C#传递给C ++(非托管DLL)

时间:2012-06-29 05:39:50

标签: c# c++ enums wstring

我有一个C ++ DLL,其中导出了以下函数。

double getDouble(std::wstring filename, std::string ID, status &stCode);

int getInt(std::wstring filename, std::string ID, status &stCode);

float getFloat(std::wstring filename, std::string ID, status &stCode);

string getString(std::wstring filename, std::string ID, status &stCode);

int* getIntArray(std::wstring filename, std::string ID, status &stCode);

float* getFloatArray(std::wstring filename, std::string ID, status &stCode);

string* getStringArray(std::wstring filename, std::string ID, status &stCode);

其中状态为枚举类型...

现在我想在我的C#.NET应用程序中使用这个DLL ...任何人都可以告诉我如何在C#中声明受尊重的方法并且可以调用这些方法....提前感谢...

2 个答案:

答案 0 :(得分:0)

    [DllImport("external.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
    public static extern MbStatus queue_accept(
        int reader,
        [MarshalAs(UnmanagedType.LPStr)] string status);

查找DllImport属性的参数。根据您的DLL,可能需要调整它们!

旁注:我通常将外部dll包装在一个接口和一个代码层中,以便将其解耦以进行测试,并使用依赖注入加载它。我也不改变命名约定。

public interface IExternalDllInterop
{
    MB_STATUS queue_accept(int reader, string status);
}

public class AmbInterop : IAmbInterop
{
    public MbStatus queue_accept(int reader, string status)
    {
        return StaticAmbInterop.mb_queue_accept(reader, message, status);
    }
}

答案 1 :(得分:0)

是。您可以。实际上,不是std::stringstd::wstring,任何标准C ++类或您自己的类都可以被编组或实例化并从C#/ .NET调用。您需要为每个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