c# c#调用dll - 在c#代码中使用c++dll中定义的类




c#调用c++ dll类 (7)

Marshal C ++ Class并使用PInvoke

C ++代码,ClassName.h

class __declspec(dllexport) 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; 

我有一个用c ++编写的dll,我需要在我的c#代码中使用这个dll。 搜索后我发现使用P / Invoke可以访问我需要的函数,但这些函数是在类中定义的,并使用非静态私有成员变量。 所以我需要能够创建这个类的实例来正确使用这些函数。 如何才能访问此类以便创建实例? 我一直无法找到办法。

我想我应该注意c ++ dll不是我的代码。


我同意JaredPar。 不应该在托管代码中创建非托管类的实例。

另一件事是 - 如果您可以在托管C ++中重新编译DLL或从中创建一个COM组件,那将更容易/


无法在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。


myfile.i

%module learnaboutswig

class A

{

public:

    void boringfunction(char *charstr);
};

从swig.org下载swig

swig -c ++ -csharp myfile.i

查看输出,看看它是否适合您。


您可能需要编写一个中间DLL(可能是C ++),为您处理此问题并公开您需要的接口。 您的DLL将负责加载第三方DLL,创建此C ++对象的实例,并通过您设计的任何API根据需要公开其成员函数。 然后,您将使用P / Invoke来获取API并干净地操作对象。

注意:对于DLL的API,请尝试将数据类型限制为基元(long,int,char *等)以防止模块边界问题。


Here是一个如何从VB调用C ++类方法的示例 - 对于C#,您只需要在步骤4中重写示例程序。


与流行的观点相反,可能有一个NULL引用。

int * p = NULL;
int & r = *p;
r = 1;  // crash! (if you're lucky)

当然,使用参考文件要困难得多 - 但是如果你管理它,你会撕掉你的头发试图找到它。 在C ++中,引用本身并不安全!

从技术上讲,这是一个无效的引用 ,而不是空引用。 C ++不支持空引用作为您可能在其他语言中找到的概念。 还有其他类型的无效引用。 任何无效引用都会引发未定义行为的幽灵,就像使用无效指针一样。

在分配给引用之前,实际错误是在NULL指针的解引用中。 但是我不知道任何编译器会在这种情况下产生任何错误 - 错误会传播到代码中的某个点。 这就是让这个问题如此阴险的原因。 大多数情况下,如果你取消引用一个NULL指针,你就会在那个位置崩溃,并且不需要太多的调试就可以搞清楚。

我上面的例子简短而且做作。 这是一个更真实的例子。

class MyClass
{
    ...
    virtual void DoSomething(int,int,int,int,int);
};

void Foo(const MyClass & bar)
{
    ...
    bar.DoSomething(i1,i2,i3,i4,i5);  // crash occurs here due to memory access violation - obvious why?
}

MyClass * GetInstance()
{
    if (somecondition)
        return NULL;
    ...
}

MyClass * p = GetInstance();
Foo(*p);

我想重申,获取空引用的唯一方法是通过格式错误的代码,一旦你拥有它,你就会得到未定义的行为。 检查空引用是没有意义的; 例如,您可以尝试if(&bar==NULL)...但编译器可能会优化语句不存在! 有效的引用永远不能为NULL,因此从编译器的视图来看,比较总是为false,并且可以将if子句作为死代码消除 - 这是未定义行为的本质。

避免麻烦的正确方法是避免取消引用NULL指针来创建引用。 这是实现这一目标的自动化方法。

template<typename T>
T& deref(T* p)
{
    if (p == NULL)
        throw std::invalid_argument(std::string("NULL reference"));
    return *p;
}

MyClass * p = GetInstance();
Foo(deref(p));

对于那些具有更好写作技巧的人来看这个问题,请参阅Jim Hyslop和Herb Sutter的Null References

有关解除引用空指针的危险的另一个示例,请参阅Raymond Chen 尝试将代码移植到另一个平台时暴露未定义的行为







c# c++ dll pinvoke