簡體   English   中英

在 c# 代碼中使用在 c++ dll 中定義的類

[英]using a class defined in a c++ dll in c# code

我有一個用 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; }

現在是將這些方法 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 來包裝原始 DLL 並提供一個小的 PInvoke 層。

元帥 C++ 類並使用 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; 

以下是如何從 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)依賴項確實會變得更加棘手,但您可能不會遇到這種情況。

myfile.i

%module learnaboutswig

class A

{

public:

    void boringfunction(char *charstr);
};

從swig.org下載swig

swig -c ++ -csharp myfile.i

查看輸出,看看它是否對您有用。

我同意 JaredPar。 在托管代碼中創建非托管類的實例應該是不可能的。

另一件事是 - 如果您可以在托管 C++ 中重新編譯 DLL 或從中制作一個 COM 組件,它會容易得多/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM