2010-04-14 52 views
10

我有一个非托管dll,里面有一个“MyClass”类。 现在有办法在C#代码中创建这个类的实例吗?调用它的构造函数?我尝试过,但视觉工作室报告错误,并提示此内存区域已损坏或出现错误。在C#中创建非托管C++对象#

在此先感谢

+0

你能发表你试过的吗? – SwDevMan81 2010-04-14 11:44:01

+0

和错误消息? – Asher 2010-04-14 11:46:01

+0

1) static void Main(string [] args) IntPtr p = new IntPtr(); Program.CreateObserv(ref p); } [的DllImport(@ “C:\ mm_2008 \ liba.dll”, 入口点= “?? 0CRls @ @@ FLD QAE @ @@ ABV01 Z”,SetLastError =真, CallingConvention = CallingConvention。ThisCall)] 内部静态extern void CreateObserv(ref IntPtr p); 此代码抛出AccessViolationException:accessviolationexception尝试读取或写入受保护的内存... – Evgeny007 2010-04-14 12:00:36

回答

19

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

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

  2. 为C++类编写C封装,可以由.NET客户端使用PInvoke。例如,过于简单化的C++类:

 

    class MyClass() 
    { 
    public: 
     MyClass(int n){data=n;} 
     ~MyClass(){} 
     int GetData(){return data;} 
    private: 
     int data; 
    }; 

该类C API的包装:

 

    void* CreateInstance() 
    { 
     MyClass* p = new MyClass(); 
     return p; 
    } 

    void ReleaseInstance(void* pInstance) 
    { 
     MyClass* p = (MyClass*)pInstance; 
     delete p; 
    } 

    int GetData(void* pInstance) 
    { 
     MyClass* p = (MyClass*)pInstance; 
     return p->GetData(); 
    } 

    // Write wrapper function for every MyClass public method. 
    // First parameter of every wrapper function should be class instance. 

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

+1

您在包装函数中错过了一个外部“C”。 – Danvil 2010-04-16 08:09:45

+0

丹维尔 - 这是我在问题笔记中写的。无论如何,谢谢,我现在感觉好多了。 – 2010-04-16 15:02:12

+0

@Alex如果在本机C++ dll中有一个类的层次结构...? – rsjethani 2012-05-07 19:19:38

2

您不能在C#中直接使用unmanged 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 
} 
+0

感谢大家,我讨厌承认它,但看起来除了编写包装外,没有别的办法。 – Evgeny007 2010-04-14 12:09:06

+0

其他选项是使用compiler/crl标志编写托管C++。然后,您可以在同一个DLL中混合使用非托管和托管代码,然后在您的C#代码中使用简单的调用托管方法。它会生成sam IL代码,就像在代码中包装本机方法一样。快速入门http://www.codeproject.com/Articles/19354/Quick-C-CLI-Learn-C-CLI-in-less-than-minutes – 2015-11-12 07:48:45

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。注意让lib找到这个dll。将dll和lib放在同一个目录下,并编译C++/CLI代码。在托管代码目录中放置原生dll和C++/CLI dll。在托管项目中放置了C++/CLI项目的参考。 Instanciate在C++/CLI类的恶意代码中是这样的:

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

这一切。