【问题标题】:passing wstring, string and reference to enum variable from C# to C++(unmanaged DLL)将 wstring、字符串和对枚举变量的引用从 C# 传递到 C++(非托管 DLL)
【发布时间】:2012-06-29 05:39:50
【问题描述】:

我有一个 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);

status 是枚举类型...

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

【问题讨论】:

标签: c# c++ enums wstring


【解决方案1】:
    [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);
    }
}

【讨论】:

  • 谢谢老兄...我尝试了第一种方法,但它不适合我。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-18
    • 2017-02-09
    • 2014-04-03
    • 1970-01-01
    • 2013-01-07
    • 2018-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多