動態鏈結庫的總結

2021-08-25 10:06:44 字數 4503 閱讀 8903

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. 使用動態呼叫

靜態鏈結庫與動態鏈結庫總結

1 在生成lib檔案的時候並不發生連線的過程,編譯器僅僅把obj檔案裝載為乙個lib檔案。例如 static1 int add int a,int b int sub int a,int b static2 int myadd int a,int b int mysub int a,int b 這個...

動態鏈結庫使用 靜 動態鏈結庫使用總結

一 靜態庫編寫 1.首先當然是開vs然後建立乙個靜態庫工程啦 2.格式.一般有標頭檔案.h和原檔案.cpp,當然你也可以寫一在乙個cpp裡.mydll.h extends c mydll.cpp include mylib.h int sum int num1,int num2 int mult i...

動態鏈結庫 靜態鏈結庫

包含標頭檔案和庫 idir 指定編譯查詢標頭檔案的目錄,常用於查詢第三方的庫的標頭檔案,例 gcc test.c i.inc o test。ldir 指定鏈結時查詢lib的目錄,常用於查詢第三方庫。llibrary 指定額外鏈結的lib庫 巨集定義 dmacro 以字串 1 預設值 定義 macro...