【问题标题】:Create unmanaged c++ object in c#在 C# 中创建非托管 C++ 对象
【发布时间】:2011-02-07 21:08:14
【问题描述】:

我有一个包含类“MyClass”的非托管 dll。 现在有没有办法在 C# 代码中创建此类的实例?调用它的构造函数?我试过了,但 Visual Studio 报告错误,并显示此内存区域已损坏或其他什么的消息。

提前致谢

【问题讨论】:

  • 1) static void Main(string[] args) { IntPtr p = new IntPtr(); Program.CreateObserv(参考 p); } [DllImport(@"C:\mm_2008\liba.dll", EntryPoint = "??0CRls@fld@@QAE@ABV01@@Z", SetLastError = true, CallingConvention = CallingConvention.ThisCall)] 内部静态外部无效 CreateObserv (参考 IntPtr p);此代码引发 AccessViolationException:accessviolationexception 试图读取或写入受保护的内存...
  • 2) static void Main(string[] args) { IntPtr p = Program.CreateObserv(); } [DllImport(@"C:\mm_2008\liba.dll", EntryPoint = "??0CRls@fld@@QAE@ABV01@@Z", SetLastError = true, allingConvention = CallingConvention.ThisCall)] 内部静态 extern IntPtr CreateObserv (); - 此代码粉碎应用程序和应用程序主机
  • 为了避免像“??0CRls@fld@@QAE@ABV01@@Z”这样的入口点名称被破坏,请在非托管 Dll 中使用 extern "C"。声明为 extern "C" 的函数在没有名称修改的情况下导出。
  • @Evgeny007 不要将代码放入 cmets,删除您的 cmets 并将代码放入问题中。

标签: c# .net c++ unmanaged


【解决方案1】:

C# 无法创建从本机 Dll 导出的类实例。你有两个选择:

  1. 创建 C++/CLI 包装器。这是 .NET 类库,可以作为参考添加到任何其他 .NET 项目。在内部,C++/CLI 类与非托管类一起使用,通过标准 C++ 规则链接到本机 Dll。对于 .NET 客户端,这个 C++/CLI 类看起来像 .NET 类。

  2. 为 C++ 类编写 C 包装器,.NET 客户端可以通过 PInvoke 使用该包装器。例如,过度简化的 C++ 类:

类 MyClass() { 民众: MyClass(int n){数据=n;} ~MyClass(){} int GetData(){返回数据;} 私人的: 整数数据; };

此类的 C API 包装器:

无效* CreateInstance() { MyClass* p = new MyClass(); 返回 p; } 无效释放实例(无效* pInstance) { MyClass* p = (MyClass*)pInstance; 删除 p; } int GetData(void* pInstance) { MyClass* p = (MyClass*)pInstance; 返回 p->GetData(); } // 为每个 MyClass 公共方法编写包装函数。 // 每个包装函数的第一个参数应该是类实例。

CreateInstance、ReleaseInstance 和 GetData 可以在 C# 客户端使用 PInvoke 声明,并直接调用。 void* 参数应在 PInvoke 声明中声明为 IntPtr。

【讨论】:

  • 您在包装函数中遗漏了一个外部“C”。
  • Danvil - 这是我在问题说明中写的。无论如何,谢谢,我现在感觉好多了。
  • @Alex 如果本机 C++ dll 中存在类层次结构...??
  • 是什么让它成为“C”API? newdelete 不是 C++ 构造吗?似乎只是一个静态 C++ API
  • @Rotem:我的意思是,这个包装器可用于 C 客户端,以及任何使用 C 风格 API 的客户端:.NET PInvoke、Assembly、Delphi 等。包装器本身是用 C++ 实现的。
【解决方案2】:

解决方案是创建 C++/CLI 包装器,如:

#include "DllExportClass.h"

public ref class ManagedOperationHelper
{
    public:

    double Sum(double add1, double add2)
    {
        CDllExportClass obj;
        double ret=obj.Sum(add1, add2);
        return ret;
    }

    double Mult(double mult1, double mult2)
    {
        CDllExportClass obj;
        double ret=obj.Mult(mult1, mult2);
        return ret;
    }
};

其中 CDllExportClass 是从本机代码导出的类。以上是 C++/CLI 的 .h。注意让找到这个 dll 的库。将dll和lib放在同一个目录下,编译C++/CLI代码。在托管代码目录下放置native dll和C++/CLI dll。在托管项目中放置 C++/CLI 项目的引用。在 maged 代码中实例化 C++/CLI 类,如:

ManagedOperationHelper obj = new ManagedOperationHelper();
double ret=obj.Sum(10, 20);  

就是这样。

【讨论】:

    【解决方案3】:

    您不能直接在 C# 中使用未管理的 C++ 代码。可以使用 PInvoke 完成互操作性。有a lot of issues related to this topic,尤其是在调用以指针作为参数的函数时。

    基本流程如下:

    C#部分

    namespace MyNamespace {
      public class Test {
        [DllImport("TheNameOfThe.dll")]
        public static extern void CreateMyClassInstance();
    
        public void CallIt() {
            CreateMyClassInstance(); // calls the unmanged function via PInvoke
        }
      }
    }
    

    C++部分

    class MyClass {
      public: MyClass() { /** Constructor */ }
    };
    
    MyClass* staticObject;
    
    extern "C" void CreateMyObjectInstance() {
       staticObject = new MyClass(); // constructor is called
    } 
    

    【讨论】:

    • 感谢大家,我不想承认,但看起来除了写一个包装之外别无他法。
    • 其他选项是使用编译器 /crl 标志编写托管 c++。然后,您可以在同一个 dll 中混合非托管和托管代码,然后在 C# 代码中简单地调用托管方法。它将生成 sam IL 代码,就像您将本机方法包装在代码中一样。快速介绍codeproject.com/Articles/19354/…
    • 链接失效
    猜你喜欢
    • 2018-05-15
    • 1970-01-01
    • 2013-01-05
    • 2013-01-26
    • 2021-07-15
    • 1970-01-01
    • 2016-02-21
    • 2020-05-03
    • 1970-01-01
    相关资源
    最近更新 更多