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
那麼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不在同一目錄。
原因以及實現方法還在研究中…….
如果有人遇到過相同的問題,解決了的,歡迎留言一下分享一下解決方法,不勝感激。
如果有人遇到過相同的問題,解決了的,歡迎留言一下分享一下解決方法,不勝感激。
如果有人遇到過相同的問題,解決了的,歡迎留言一下分享一下解決方法,不勝感激。