最近一段時間,經常遇到這些問題,前一陣子研究了一下,沒有記下來,沒想到最近研究又有些不記得了,今天把它寫下來以備忘。
一般我們提供給其他語言呼叫的dll,都是用c或者c++編寫,然後封裝。我這邊也是採用的c++。
首先有幾個注意點:
1、如果功能很簡單,或者不使用第三方庫(如mfc自帶的庫),建立乙個win32的控制台程式就可以了,然後把專案生成改為dll。值得一提的是,**生成裡面
執行時庫分四種:
(1)多執行緒mtd(靜態庫,編譯之後,你的lib帶有除錯功能)——> debug時用
(2)多執行緒mt(靜態庫,沒有除錯功能) ——> release時用
(3)多執行緒dll mtd(動態庫,帶有除錯功能) ——> debug時用
(4)多執行緒dll mt(動態庫,沒有有除錯功能)。 ——> release時用s
既然封裝dll,那除錯的時候用(3),發布的時候用(4)。
2、設定為匯出函式,並採用c風格。函式前加extern "c" __declspec(dllexport)。定義函式在退出前自己清空堆疊,在函式前加__stdcall。
如extern "c" __declspec(dllexport) int __stdcall add(int x,int y);
具備上述條件時,生成的dll就含有匯出函式的功能了,不過此時dll中的函式名稱不是規則的,使用編譯器自定義的,可能是這樣乙個名字_add@20,具體的可以用vs的depends工具檢視一下。
3、把匯出函式名稱變為標準名稱,需加模組定義檔案,就是.def檔案。
內容如下:(需要注釋,前面加分號就可以了,注釋需要單獨行)
library "test"
exports
;add函式
adds
library 庫名稱
exports 需要匯出的各個函式名稱
重新編譯之後,再用depends工具看一下,函式已經變成標準add,而不是_add@20。這個在動態載入時很有用,特別是在getprocaddress函式尋找入庫函式的時候。
4、c#呼叫c++ dll,介紹兩種方法
(1)靜態載入
[dllimport("test.dll", entrypoint = "add")]
public int add(int x,int y);//與dll中一致
注意如果需要返回字串可以這樣
c++中
int getstring(const char* source,char* dest);
c#中int getstring(string source,stringbuilder sbr);
切記呼叫的時候給stringbuilder 分配空間,否則會報錯。
如dest 長度為10,可以這樣。
stringbuilder sbr=new stringbuilder(10);
getstring("hello",sbr);
如果你希望c++的dll還能被vb等語言呼叫,建議將字串寫成com的形式 如
c++中
int getstring(bstr source,bstr dest);//bstr就是乙個com形式的字元陣列,相當於字串
c#中int getstring(string source,stringbuilder sbr);
vb中declare function getstring lib "test.dll" (byval source as string, byval dest as string) as integer;
(2)動態載入
[dllimport("kernel32.dll")]
private extern static intptr loadlibrary(string path);//path 就是dll路徑 返回結果為0表示失敗。
[dllimport("kernel32.dll")]
private extern static intptr getprocaddress(intptr lib, string funcname);//lib是loadlibrary返回的控制代碼,funcname 是函式名稱 返回結果為0標識失敗。
[dllimport("kernel32.dll")]
private extern static bool freelibrary(intptr lib);
//宣告委託
delegate int add(int x,int y);
//使用動態載入
intptr hlib = loadlibrary(dllpath);//載入函式
intptr apifunction = getprocaddress(hlib, apiname);//獲取函式位址
int i = marshal.getlastwin32error();
if (apifunction.toint32() == 0)//0表示函式沒找到
return null;
//獲取函式介面,相當於函式指標
add add = (delegate)marshal.getdelegateforfunctionpointer(apifunction, typeof(add)) as add;
//呼叫函式
add(1,2);
//釋放控制代碼
freelibrary(hlib );
最後,1)c++在返回字串時,切記最後新增/0,不然在c#等中呼叫,會顯示部分亂碼。
2)c++動態申請的記憶體,需在出函式之前就必須釋放,否則會報意想不到的錯誤。比如記憶體寫入錯誤等等。
C 呼叫C DLL的方式
動態鏈結庫 dll 是乙個包含可由多個程式同時使用的 和資料的庫,dll不是可執行檔案。可以說在windows作業系統中隨處可見,開啟主分割槽盤下的system32。在一些專案中,如果有大量運算或者涉及大量演算法時通常使用c或c 語言封裝成乙個dll,開放一些介面供其他程式呼叫。下面是寫的乙個簡單的...
c 呼叫C dll 的方法
c 呼叫c dll 的方法 1.新增 using system.runtime.interopservices 2.將dll 放到執行程式的根目錄下 3.c 中可識別的字元為 utf8,在傳輸字元的時候,需要先轉換為utf8,然後再傳輸,要不然中文會識別不了,同樣在返回資料的時候,也需要將utf8轉...
C 呼叫C Dll例程
form1.cs內容 using system using system.windows.forms using system.runtime.interopservices using system.text 申明dll中函式 dllimport kb dll.dll entrypoint inp...