1。dll的建立
選擇win32的dll lib工程, 建立乙個cpp檔案,**如下:
_declspec(dllexport) int add(int a, int b)
注意前面的標識_declspec(dllexport),表示dll的輸出函式。每個輸出的函式都要用這個進行標識。
可以進行dll所在目錄用dumpbin -exports dll1.dll 檢視dll的輸出函式資訊。可以看到dll有輸出,但名字並不是add,
而是?add@@yahhh@z 這兒是因為c++編譯器對函式名字進行了改編。
2。dll的隱式呼叫(靜態呼叫)
隱式呼叫在引用dll檔案的lib檔案。(把dll1.dll ,dll1.lib兩個檔案複製到dlltest所在主目錄)
在工程setting屬性中,link標籤頁, 填入 dll1.lib
然後測試**如下:
extern add(int a, int b);
void ctestdll::onbtntest()
可以看到dll中的函式已經被執行了。
vs工具庫中depends工具可以選擇乙個執行檔案,檢視這個執行檔案所引用的dll檔案。
另外,對add函式的宣告是extern add(int a, int b); 這種不是專用的宣告方式,可以用下面的宣告
_declspec(dllimport) add(int a, int b);
從而指明函式是從dll中取出的,以增加程式的執行效率。
3。隱式引用,標頭檔案的使用
帶頭檔案的dll的編寫:
dll2.h:
_declspec(dllimport) add(int a, int b);
這裡是dllimport,是對呼叫檔案而言的。
dll2.cpp:
_declspec(dllexport) int add(int a, int b)
帶頭檔案的dll的呼叫:
同樣,dll2.lib要引入
呼叫檔案中,不用宣告dll2匯出的函式, 只在引用標頭檔案即可,如下:
#i nclude "../dll2/dll2.h"
呼叫函式不變。
4。隱式引用,標頭檔案的使用時,利用巨集簡化編寫
dll3.h:
#ifdef dll_api
#else
#define dll_api _declspec(dllimport)
#endif
dll_api add(int a, int b);
//說明:如果dll_api已經定義,不操作,否則,宣告為dll_api _declspec(dllimport),使用在標頭檔案。
//由於在cpp檔案中要引入dll3.h,在dll3.cpp中宣告了#define dll_api _declspec(dllexport), 使用dll_api
//可以在標頭檔案,原始檔中切換
dll3.cpp
#define dll_api _declspec(dllexport)
#i nclude "dll3.h"
int add(int a, int b)
5。類的輸出
dll3.h
#ifdef dll_api
#else
#define dll_api _declspec(dllimport)
#endif
dll_api int add(int a, int b);
class dll_api point
;dll3.cpp
#define dll_api _declspec(dllexport)
#i nclude "dll3.h"
#i nclude
#i nclude
#i nclude
int add(int a, int b)
void point::output(int a)
關鍵在於類的宣告:
class dll_api point
;注意在class後面加宣告標誌
6。輸出類中的部分函式
dll3.h
#ifdef dll_api
#else
#define dll_api _declspec(dllimport)
#endif
dll_api int add(int a, int b);
class /*dll_api*/ point
;只是在類宣告時,把對類的輸出去掉,然的在具體要輸出的函式的前面加上輸出宣告標誌,實現、呼叫都沒有變化。
7。防止函式名字改編
因為c++編譯器對dll匯出函式的名字進行了改編,c編譯器呼叫時就可能出錯。這裡提供乙個防止名字改編的方法。
這個解決方法解決c++, c互相呼叫的問題。
dll4.h
#ifdef dll_api
#else
#define dll_api extern "c" _declspec(dllimport)
#endif
dll_api int add(int a, int b);
dll4.cpp
#define dll_api extern "c" _declspec(dllexport)
#i nclude "dll4.h"
int add(int a, int b)
可以看到,只要在匯出函式的宣告和實現處加上 extern "c"
但是有個缺點,就是不能匯出類及類中的函式
注意這兒的"c" 為大寫
8。改變匯出函式的呼叫約定
dll4.h
#ifdef dll_api
#else
#define dll_api extern "c" _declspec(dllimport)
#endif
dll_api int _stdcall add(int a, int b);
dll4.cpp
#define dll_api extern "c" _declspec(dllexport)
#i nclude "dll4.h"
int _stdcall add(int a, int b)
可以看到在函式名的前面加上 _stdcall 即改變了函式的呼叫約定:標準呼叫
當vc寫的dll, 由dlephi呼叫時,就要加上_stdcall, 以符合object pascall 的約定。
這兒要注意,如果改變了呼叫約定,即使使用extern "c" 也會發生名字改編
9。利用模組定義檔案防止名字改編
新增乙個dll4.def檔案到原始檔, 內容如下:
library dll4
exports
add可以看到exports下面即為輸出的函式名。可以有下面的寫法:
library dll4
exports
export_add=add
export_add為要輸出的函式名,add為原始檔中的函式名
但是用模組定義檔案定義後,輸出的dll, 如果靜態呼叫則會找不到函式入口點。
此時應該如何靜態呼叫?
但至少可以動態呼叫
10。動態呼叫dll
dll檔案的編寫沒有變化。(有dll4.def檔案防止發生名字改編)
呼叫如下:
//動態呼叫
hinstance hist;
hist = loadlibrary("dll4.dll");
typedef int (_stdcall *addproc)(int a, int b);
addproc add = (addproc)getprocaddress(hist, "add");
if(!add)
int iret = add(5, 10);
cstring strmsg;
strmsg.format("%d", iret);
afxmessagebox(strmsg);
hist = loadlibrary("dll4.dll"); 是載入動態鏈結庫
typedef int (_stdcall *addproc)(int a, int b); 定義乙個和dll匯出函式一至的原型函式
addproc add = (addproc)getprocaddress(hist, "add"); 根據函式名,得到函式位址
注意:因為dll改變了呼叫約定,所以在宣告函式原型時,也加上了_stdcall ,否則應該如下:
typedef int (*addproc)(int a, int b);
注意:如果dll匯出函式發生了名字改編,再用dll中函式的名字則會出錯。要用dumpbin中看到的名字。或者用
addproc add = (addproc)getprocaddress(hist, makeintresource(1));
根據序號來取得函式位址,但這種方法不太好。
在不需要使用動態鏈結庫時,可以呼叫freelibrary(hist);來釋放動態鏈結庫
所以在以後dll的使用中可以:
a. 使用def檔案防止名字改編
b. 使用動態呼叫
dll開發及呼叫
這段時間用到了dll的呼叫,這裡總結下,也方便我以後使用。3 點選 finish 完成嚮導 4 新增檔案calltest1.cpp,新增如下 include bool apientry dllmain handle hmodule,dword ul reason for call,lpvoid lp...
DLL型別及呼叫
dll 型別判斷 1.mfc 規則dll 沒有介面要求 入口2.mfc 擴充套件dll 有介面匯出 dllmain 入口 3.win32dllapientry dllmain 入口dll分類 1。non mfc dll 非mfc動態庫 不採用mfc類庫結構,其匯出函式為標準的c介面,能被非mfc或m...
呼叫dll和編寫dll的幾種格式
一共兩種 extern c declspec dllexport dword sum int narg1,char nar 2 extern c 表示使用c的編譯方式編譯,c 格式 declspec dllexport 將乙個函式申明為匯出函式 就申明了乙個匯出函式 但是這中建立的dll的匯出函式序...