Chap 19 動態鏈結庫

2021-05-10 13:57:07 字數 3332 閱讀 6956

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 ...