chap 19
動態鏈結庫
一.只有在其他模組呼叫動態鏈結庫中的函式時,它才發揮作用。win32 api 中所有的函式都在dll 中,其中最重要的三個dll : 1.
kernel32.dll:
所有與記憶體操作,執行緒,程序相關的操作。
2. user32.dll:
所有與執行使用者介面相關的操作。
3. gdi32.dll:
所有用於畫圖和顯示文字的操作。
二.動態鏈結庫分為隱式呼叫和顯式呼叫:
(1)隱式呼叫
a. 用
def的方法製作
dll,則不需要加
dllexport
於dllimport
來宣告匯出函式,而是在
def檔案中指明匯出函式
library 「dll」
exports
addsub
這裡指明的匯出函式的名字要和程式裡的函式名一致,或者不一致時,可以用
exportedname = infuncname
來匯出不同於程式中函式名的函式名。
這個方法比較簡單,而且不會進行名字改編。 b.
用dllexport
和dllimport
的方法製作
dll 在
dll.h
檔案中:
#ifdef dll_exports
#define dll_api extern 「c」
_declspec
(dllexport )
#else
#define dll_api extern 「c
」_declspec (dllimport)
#endif
dll_api int add(int a,int b)
在製作dll的工程中加上預處理器
dll_exports
,這樣在製作
dll的工程時,會把
add函式匯出,在使用
dll的工程中由於沒有定義
dll_exports
,會把add
函式當成是匯入函式,告訴編譯器這個函式是從其他的
dll中匯入的。其實不加
dllimport
也可以編譯通過並成功執行,但是加了可以使執行效率更高。
(2)顯式呼叫
這種方式呼叫
dll時,那麼只有在程式需要載入
dll的時候才會將
dll加入記憶體,而不會
像第一種方法,在程式開始的時候就載入
dll到記憶體中,這樣,可以節省記憶體,提高效率。呼叫方法:
hinstance hinst;
hinst = loadlibrary (「dll.dll」);
typedef int (*addproc)(int a,int b); //
定義函式指標,獲取函式位址
addproc add = (addproc)getprocaddress (hinst, 「add」); //
注意add
為函式的名稱,如果不是使用
def方式得到的
dll,那麼函式名字發生了改編,前後加了些符號,這樣就不能得到
add函式的位址了。
add(1,2);
freelibaray (hinst);
當乙個dll使用
_stdcall
的呼叫約定時,呼叫它的時候也要使用
_stdcall
的呼叫約定,這樣就可以將上述一行改為:
typedef int (_stdcall *addporc)(int a,int b);
三.程式載入
dll時搜尋
dll的路徑順序: 1.
程式的執行目錄
(exe
所在目錄)
2.當前目錄(
vcproj
所在目錄)
3. 系統目錄:
c:/windows/system32,c:windows/system,c:/windows
4. 環境變數
path
中所列出的路徑
四.名字改編和呼叫約定: 1.
c++和c
c++和
c語言在編譯時編譯器會做不同的處理:由於
c++有函式過載的機制,所以在
c++語言中
void f1(int a)
在編譯完後進行名字改編為
f1_int, 而c
語言中同樣的函式在編譯完後就是
f1,即不進行名字改編,所以當
c++呼叫
c語言生成的函式或函式庫時鏈結器會無法正確的鏈結相應的函式,同樣,c呼叫
c++生成的函式庫時鏈結器也無法解析相應的函式。為了解決這個問題,
c++提供了限定符
extern 「c」
來解決這個問題: 假設
cfile.h(
內含f1
函式),cfile.c是c
檔案,那麼在
cplusplus.cpp
中引用cfile.h
時,應該:
extern 「c」
int main()
} 這樣,編譯器在編譯
cplusplus.cpp
的時候,知道按照
c的方式去處理
f1函式,及不進行名字改編,那麼就能夠識別
c語言的
f1函式。 2.
呼叫約定
vc++
中預設的呼叫約定是
c呼叫約定
_cdecl
,而標準呼叫約定是
_stdcall
。在呼叫約定
改變時,名字改編也不一致。例如,對於c 語言的
add(int,int)
函式,如果用
_cdecl
編譯時不進行名字改編,但是用
_stdcall
時,會改變成
_add@8
,這樣,別的用
_stdcall
呼叫約定的編譯器就無法呼叫
add函式,
def檔案能夠解決這個問題,用
def檔案匯出的
dll,函式名字不進行改編,也就是說,用
def製作的
dll,不管是什麼呼叫約定,都不發生名字改編。但是,函式用什麼呼叫約定編譯的,呼叫者就應該使用什麼呼叫方式來呼叫函式,否則即使函式名字不發生改編,也無法正確呼叫。也就是說,名字改編與否和呼叫約定一致與否,這兩個條件一起決定了函式能否被其他模組正確呼叫。
另外,main
函式只能用
_cdecl
呼叫約定,這個不可更改。
第19講 動態鏈結庫
declspec dllexport 識別符號宣告的函式效率更高,相對於用extern 3,可以用dependency walker檢視動態鏈結庫中匯出的函式 4,如果動態鏈結庫專案中源程式自己要使用動態鏈結庫函式,則在動態鏈結庫標頭檔案中使用預編譯巨集 ifdef dll1 api else de...
動態鏈結庫 靜態鏈結庫
包含標頭檔案和庫 idir 指定編譯查詢標頭檔案的目錄,常用於查詢第三方的庫的標頭檔案,例 gcc test.c i.inc o test。ldir 指定鏈結時查詢lib的目錄,常用於查詢第三方庫。llibrary 指定額外鏈結的lib庫 巨集定義 dmacro 以字串 1 預設值 定義 macro...
靜態鏈結庫 動態鏈結庫
庫是寫好的現有的,成熟的,可以復用的 現實中每個程式都要依賴很多基礎的底層庫,不可能每個人的 都從零開始,因此庫的存在意義非同尋常。本質上來說庫是一種可執行 的二進位制形式,可以被作業系統載入記憶體執行。庫有兩種 靜態庫 a lib 和動態庫 so dll windows上對應的是.lib dll ...