我有一个用 c++ 编写的 dll,我需要在我的 c# 代码中使用这个 dll。搜索后我发现使用 P/Invoke 可以让我访问我需要的函数,但是这些函数是在一个类中定义的,并且使用非静态私有成员变量。所以我需要能够创建这个类的一个实例来正确使用这些函数。如何获得对此类的访问权限以便创建实例?我一直无法找到一种方法来做到这一点。
我想我应该注意 c++ dll 不是我的代码。
无法在 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; }
现在只需将这些方法调用到您的 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 来包装原始 DLL 并提供一个小的 PInvoke 层。
C++ 代码,类名.h
class __declspec(dllexport) CClassName
{
public:
CClassName();
~CClassName();
void function();
};
C++ 代码,类名.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 中重写示例程序。
您可能需要编写一个中间 DLL(也许用 C++)来为您处理这个问题并公开您需要的接口。您的 DLL 将负责加载第 3 方 DLL,创建此 C++ 对象的实例,并根据需要通过您设计的任何 API 公开其成员函数。然后,您将使用 P/Invoke 获取您的 API 并干净地操作该对象。
注意:对于您的 DLL 的 API,请尝试将数据类型限制为基元(long、int、char* 等)以防止模块边界问题。
我这样做的方法是在我的非托管 C++ DLL 周围创建一个瘦托管 C++ 包装器。托管包装器包含“代理”类,这些类包装非托管代码,公开 .NET 应用程序所需的接口。这是一项双重工作,但它允许在正常环境中进行非常无缝的操作。在某些情况下(例如 ASP.NET),依赖关系确实会变得更棘手,但您可能不会遇到这种情况。
我同意 JaredPar。在托管代码中创建非托管类的实例应该是不可能的。
另一件事是 - 如果您可以在托管 C++ 中重新编译 DLL 或用它制作 COM 组件,那会容易得多/