1. 程式人生 > >C++ 呼叫C#工程的 dll , 互相呼叫方法

C++ 呼叫C#工程的 dll , 互相呼叫方法

很多時候在專案中需要通過C++呼叫C#的dll,或者反過來條用。

首先明白一個前提:C#是託管型程式碼。C++是非託管型程式碼。

託管型程式碼的物件在託管堆上分配記憶體建立的物件由虛擬機器託管。(C# )

       非託管型程式碼物件有實際的記憶體地址,建立的物件必須自己來管理和釋放。(C++)

1、C#呼叫C++的dll.

在C#工程中的引用項中直接將要使用的C++dll引用進來即可。 然後建立物件或者呼叫介面。


2、C++呼叫C#的dll.

C++呼叫C#dll,目前我知道的有兩種方式

(1)com方式呼叫。

這種呼叫方式就是將dll轉換成類com元件的方式呼叫。

直接看方法:C++ 呼叫C#dll不是直接呼叫dll, 而是呼叫一個轉變後的檔案:.tlb檔案的支援

tlb檔案:com型別庫檔案,它包含介面相關資訊。在需要使用對應com類的模組裡,通過"#import xxx.tlb"來呼叫。

eg: 在C++程式碼中使用: #import "../../out/debug/TGPDFSignLib.tlb"

這個.tlb檔案會對應的生成tgpdfsignlib.tli 和 tgpdfsignlib.tlh兩個檔案。 

在VC下#import "TGPDFSignLib.tlb" no_namespace;編譯後產生TGPDFSignLib.tlh和TGPDFSignLib.tli兩個檔案,不生成namespace,如果沒有no_namespace,則生成的內容都在namespaceTGPDFSignLib

中。如果dll中含有tlb資源,則也可以使用#import "xxx.dll"來生成tlh和tli檔案。一般的c++ dll不能使用#import "xxx.dll"。

那麼tlh、tli檔案是什麼?

tlh、tli檔案是vc++編譯器解析tlb檔案生成的標準c++檔案。因為tlb並不是C++標準的東西,有必要把它們翻譯成標準的C++型別,使得C++開發者可以使用。tlh相當於型別申明(標頭檔案),tli相當於定義實現(CPP檔案,inline)。

當寫到這裡時所有的呼叫已經完成,你已經可以通過這種方法呼叫C#dll了。

但是有一個問題,我們需要通過.tlb檔案呼叫,那麼.tlb檔案從哪來的呢???

生成.tlb檔案一般有2種方法:

1)     在工程編譯時同步互操作註冊生成檔案。

在vs中C#專案,選擇專案屬性,開啟屬性配置頁,生成頁中選擇為com互操作註冊複選框,在編譯時會同時生成。

eg:vs2013

2)  在命令框中註冊dll生成。

直接將regasm.exe檔案拷貝到dll目錄方便。

開啟cmd,選擇管理員許可權執行。cd到dll所在目錄, 輸入命令:

regasmTGPDFSignLib.dll /tlb

執行,註冊成功,即可生成.tlb檔案。

注: 請注意版本的對應,也就是你不能用.net2.0的regasm.exe去註冊.ne t4.0的dll.如果這樣或報錯:RegAsm error: Failed to load 'XXXXX.dll' because it is not a valid.Net assembly。

每個版本都有一個對應的regasm.exe,2.0就用2.0的註冊,4.0用4.0的註冊。

(2)虛擬化方式呼叫(clr)

建立一個C#工程,得到一個dll.

eg:  這樣的一個簡單工程,

namespace MathDLL

{

   public class DDD

    {

       public int demoAdd(int x, int y)

       {

           int sum;

           sum = x + y;

           return sum;

       } 

}

}

那麼在C++工程中可以直接引用:

#include "stdafx.h"

#using "../MathDLL/bin/Debug/MathDLL.dll"   //引用dll

using namespace MathDLL;   //使用dll的名稱空間

int _tmain(intargc, _TCHAR* argv[])

{

    int sum, x, y;

    x = 10;

    y = 22;

    DDD ^a = gcnew DDD();  //建立物件

    sum = a->demoAdd(x, y);  //呼叫方法

    sum = x + y;

    printf("計算結果:%d", sum);

       return 0;

}

如此即可完成呼叫;這種方式不需要中間檔案。

該方法需要設定公共語言執行支援屬性,否則無法識別:


說明:以下幾點需要記住且明確

1、         使用#using引用C# DLL,而不是#include

2、         別忘了using namespace MathDLL

3、         使用C++/clr語法,採用正確的訪問託管物件,即:使用'^',而不是星號'*'

vs^顯示為:

4、         使用gcnew建立物件。

注:gcnew關鍵字

C++/CLI中使用gcnew關鍵字表示在託管堆上分配記憶體,並且為了與以前的指標區分,用^來替換*,就語義上來說他們的區別大致如下:
1.     gcnew返回的是一個控制代碼(Handle),而new返回的是實際的記憶體地址

2.     gcnew建立的物件由虛擬機器託管,而new建立的物件必須自己來管理和釋放.

從程式設計師的角度來說,管它是控制代碼還是什麼其他的東西,總跑不掉是對某塊記憶體地址的引用,實際上我們都可以理解成指標.

該方法:如果dll和應用程式不在同一目錄則呼叫失敗,執行報錯。

比如,ie瀏覽器呼叫C++控制元件,然後控制元件中呼叫C#dll, dll顯然和ie.exe不在同一目錄。

原因以及實現方法還在研究中…….

如果有人遇到過相同的問題,解決了的,歡迎留言一下分享一下解決方法,不勝感激。

如果有人遇到過相同的問題,解決了的,歡迎留言一下分享一下解決方法,不勝感激

如果有人遇到過相同的問題,解決了的,歡迎留言一下分享一下解決方法,不勝感激