在c#代码中使用c ++ dll中定义的类
我有一个用c ++编写的dll,我需要在我的c#代码中使用这个dll。 search后,我发现使用P / Invoke会给我访问我需要的函数,但是这些函数是在类中定义的,并使用非静态的私有成员variables。 所以我需要能够创build这个类的一个实例来正确使用这个函数。 我怎样才能访问这个类,以便我可以创build一个实例? 我一直无法find办法做到这一点。
我想我应该注意到,C + + DLL不是我的代码。
在C#代码中没有办法直接使用C ++类。 您可以间接使用PInvoke来访问您的types。
基本模式是,对于Foo类中的每个成员函数,创build一个调用成员函数的关联非成员函数。
class Foo { public: int Bar(); }; Foo* Foo_Create() { return new Foo(); } int Foo_Bar(Foo* pFoo) { return pFoo->Bar(); } void Foo_Delete(Foo* pFoo) { delete pFoo; }
现在将这些方法引入C#代码中
[DllImport("Foo.dll")] public static extern IntPtr Foo_Create(); [DllImport("Foo.dll")] public static extern int Foo_Bar(IntPtr value); [DllImport("Foo.dll")] public static extern void Foo_Delete(IntPtr value);
缺点是你会有一个尴尬的IntPtr传递,但是围绕这个指针创build一个C#包装类来创build一个更有用的模型是一件相当简单的事情。
即使你不拥有这个代码,你也可以创build另一个包装原始DLL的DLL,并提供一个小的PInvoke层。
统帅C ++类并使用PInvoke
C ++代码,ClassName.h
class __declspec(dllimport) CClassName { public: CClassName(); ~CClassName(); void function(); };
C ++代码,ClassName.cpp
CClassName::CClassName() { } CClassName::~CClassName() { } void CClassName::function() { std::cout << "Bla bla bla" << std::endl; }
C ++代码,调用者函数的ClassNameCaller.h文件
#include "ClassName.h" #ifdef __cplusplus extern "C" { #endif extern __declspec(dllexport) CClassName* CreateClassName(); extern __declspec(dllexport) void DisposeClassName(CClassName* a_pObject); extern __declspec(dllexport) void function(CClassName* a_pObject); #ifdef __cplusplus } #endif
C ++代码,调用者函数的ClassNameCaller.cpp文件
#include "ClassNameCaller.h" CClassName* CreateClassName() { return new CClassName(); } void DisposeClassName(CClassName* a_pObject) { if(a_pObject!= NULL) { delete a_pObject; a_pObject= NULL; } } void function(CClassName* a_pObject) { if(a_pObject!= NULL) { a_pObject->function(); } }
C#代码
[DllImport("ClassNameDll.dll")] static public extern IntPtr CreateClassName(); [DllImport("ClassNameDll.dll")] static public extern void DisposeClassName(IntPtr pClassNameObject); [DllImport("ClassNameDll.dll")] static public extern void CallFunction(IntPtr pClassNameObject); //use the functions IntPtr pClassName = CreateClassName(); CallFunction(pClassName); DisposeClassName(pClassName); pClassName = IntPtr.Zero;
这里是一个如何从VB调用C ++类方法的示例 – 对于C#,您只需在步骤4中重写示例程序。
myfile.i
%module learnaboutswig class A { public: void boringfunction(char *charstr); };
从swig.org下载swig
swig -c ++ -csharp myfile.i
看看输出,看看它是否会为你工作。
您可能需要编写一个中介DLL(可能是C ++)来处理这个DLL,并公开您所需要的接口。 你的DLL负责加载第三方DLL,创build这个C ++对象的一个实例,并根据需要通过你devise的任何API公开它的成员函数。 然后你可以使用P / Invoke来获取你的API并干净地操作这个对象。
注意:对于您的DLL的API,请尝试将数据types限制为基元(long,int,char *等)以防止模块边界问题。
我同意JaredPar。 在托pipe代码中创build非托pipe类的实例是不可能的。
另一件事是 – 如果你可以用托pipe的C ++重新编译这个DLL,或者让它成为一个COM组件,那么它会容易得多/
我这样做的方法是通过在我的非托pipeC ++ DLL周围创build一个精简的托pipeC ++包装器。 托pipe包装器包含“代理”类,这些类包装了暴露.NET应用程序所需接口的非托pipe代码。 这是一个双重的工作,但它允许在正常的环境中相当无缝的操作。 在某些情况下(比如ASP.NET),依赖关系会变得更复杂,但是您可能不会遇到这种情况。