我有一个用c ++编写的dll,我需要在我的c#代码中使用这个dll。搜索后我发现使用P / Invoke可以访问我需要的函数,但这些函数是在类中定义的,并使用非静态私有成员变量。所以我需要能够创建这个类的实例来正确使用这些函数。如何才能访问此类以便创建实例?我一直无法找到办法。
我想我应该注意c ++ dll不是我的代码。
答案 0 :(得分:79)
无法在C#代码中直接使用C ++类。您可以间接方式使用PInvoke来访问您的类型。
基本模式是对于类Foo中的每个成员函数,创建一个调用成员函数的关联非成员函数。
class Foo {
public:
int Bar();
};
extern "C" Foo* Foo_Create() { return new Foo(); }
extern "C" int Foo_Bar(Foo* pFoo) { return pFoo->Bar(); }
extern "C" void Foo_Delete(Foo* pFoo) { delete pFoo; }
现在将这些方法PInvoking到您的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来传递,但是在这个指针周围创建一个C#包装类来创建一个更实用的模型是一件很简单的事情。
即使您不拥有此代码,也可以创建另一个包装原始DLL并提供小型PInvoke层的DLL。
答案 1 :(得分:16)
C ++ Code,ClassName.h
class __declspec(dllexport) CClassName
{
public:
CClassName();
~CClassName();
void function();
};
C ++ Code,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;
答案 2 :(得分:4)
Here是一个如何从VB调用C ++类方法的示例 - 对于C#,您只需要在步骤4中重写示例程序。
答案 3 :(得分:3)
myfile.i
%module learnaboutswig
class A
{
public:
void boringfunction(char *charstr);
};
从swig.org下载swig
swig -c ++ -csharp myfile.i
查看输出,看看它是否适合您。
答案 4 :(得分:2)
您可能需要编写一个中间DLL(可能是C ++),为您处理此问题并公开您需要的接口。您的DLL将负责加载第三方DLL,创建此C ++对象的实例,并通过您设计的任何API根据需要公开其成员函数。然后,您将使用P / Invoke来获取API并干净地操作对象。
注意:对于DLL的API,请尝试将数据类型限制为基元(long,int,char *等)以防止模块边界问题。
答案 5 :(得分:2)
我同意JaredPar。 不应该在托管代码中创建非托管类的实例。
另一件事是 - 如果您可以在托管C ++中重新编译DLL或从中创建一个COM组件,那将更容易/
答案 6 :(得分:2)
我这样做的方法是在我的非托管C ++ DLL周围创建一个瘦的托管C ++包装器。托管包装器包含“代理”类,它们包含暴露.NET应用程序所需接口的非托管代码。 这是一个双重工作,但它允许在正常环境中进行非常无缝的操作。在某些情况下(例如ASP.NET),依赖项会变得更加棘手,但您可能不会遇到这种情况。