dll的背景知識
靜態鏈結和動態鏈結
鏈結程式搜尋乙個或者多個庫檔案(標準庫.lib),直到在某個庫中找到了含有所引用函式的物件模組,然後鏈結程式把這個物件模組拷貝到結果可執行檔案(.exe)中。鏈結程式維護對該函式的所有引用,使它們指向該程式中現在含有該函式拷貝的地方。
鏈結程式也是搜尋乙個或者多個庫檔案(輸入庫.lib),當在某個庫中找到了所引用函式的輸入記錄時,便把輸入記錄拷貝到結果可執行檔案中,產生一次對該函式的動態鏈結。這裡,輸入記錄不包含函式的**或者資料,而是指定乙個包含該函式**以及該函式的順序號或函式名的動態鏈結庫。
當程式執行時,windows裝入程式,並尋找檔案中出現的任意動態鏈結。對於每個動態鏈結,windows裝入指定的dll並且把它對映到呼叫程序的虛擬位址空間(如果沒有對映的話)。因此,呼叫和目標函式之間的實際鏈結不是在鏈結應用程式時一次完成的(靜態),相反,是執行該程式時由windows完成的(動態)。
這種動態鏈結稱為載入時動態鏈結。還有一種動態鏈結方式下面會談到。
動態鏈結的方法
如上所述。windows搜尋要裝入的dll時,按以下順序:
應用程式所在目錄→當前目錄→windows system目錄→windows目錄→path環境變數指定的路徑。
程式設計師使用loadlibrary把dll裝入記憶體並且對映dll到呼叫程序的虛擬位址空間(如果已經作了對映,則增加dll的引用計數)。首先,loadlibrary搜尋dll,搜尋順序如同載入時動態鏈結一樣。然後,使用getprocessaddress得到dll中輸出函式的位址,並呼叫它。最後,使用freelibrary減少dll的引用計數,當引用計數為0時,把dll模組從當前程序的虛擬空間移走。
輸入庫(.lib): 輸入庫以.lib為副檔名,格式是coff(common object file format)。coff標準庫(靜態鏈結庫)的副檔名也是.lib。coff格式的檔案可以用dumpbin來檢視。
輸入庫包含了dll中的輸出函式或者輸出資料的動態鏈結資訊。當使用mfc建立dll程式時,會生成輸入庫(.lib)和動態鏈結庫(.dll)。
輸出檔案(.exp) 輸出檔案以.exp為副檔名,包含了輸出的函式和資料的資訊,鏈結程式使用它來建立dll動態鏈結庫。
映像檔案(.map) 映像檔案以.map為副檔名,包含了如下資訊:
模組名、時間戳、組列表(每一組包含了形式如section::offset的起始位址,長度、組名、類名)、公共符號列表(形式如section::offset的位址,符號名,虛擬位址flat address,定義符號的.obj檔案)、入口點如section::offset、fixup列表。
lib.exe工具 它可以用來建立輸入庫和輸出檔案。通常,不用使用lib.exe,如果工程目標是建立dll程式,鏈結程式會完成輸入庫的建立。
更詳細的資訊可以參見mfc使用手冊和文件。
鏈結規範(linkage specification ) 這是指鏈結採用不同程式語言寫的函式(function)或者過程(procedure)的鏈結協議。mfc所支援的鏈結規範是「c」和「c++」,預設的是「c++」規範,如果要宣告乙個「c」鏈結的函式或者變數,則一般採用如下語法:
#if defined(__cplusplus)
extern "c"
#endif
所有的c標準標頭檔案都是用如上語法宣告的,這樣它們在c++環境下可以使用。
修飾名(decoration name)
「c」或者「c++」函式在內部(編譯和鏈結)通過修飾名識別。修飾名是編譯器在編譯函式定義或者原型時生成的字串。有些情況下使用函式的修飾名是必要的,如在模組定義檔案裡頭指定輸出「c++」過載函式、建構函式、析構函式,又如在彙編**裡呼叫「c」」或「c++」函式等。
修飾名由函式名、類名、呼叫約定、返回型別、引數等共同決定。
呼叫約定
呼叫約定(calling convention)決定以下內容:函式引數的壓棧順序,由呼叫者還是被呼叫者把引數彈出棧,以及產生函式修飾名的方法。mfc支援以下呼叫約定:
_cdecl 按從右至左的順序壓引數入棧,由呼叫者把引數彈出棧。對於「c」函式或者變數,修飾名是在函式名前加下劃線。對於「c++」函式,有所不同。
如函式void test(void)的修飾名是_test;對於不屬於乙個類的「c++」全域性函式,修飾名是?test@@zaxxz。
這是mfc預設呼叫約定。由於是呼叫者負責把引數彈出棧,所以可以給函式定義個數不定的引數,如printf函式。
_stdcall 按從右至左的順序壓引數入棧,由被呼叫者把引數彈出棧。對於「c」函式或者變數,修飾名以下劃線為字首,然後是函式名,然後是符號「@」及引數的位元組數,如函式int func(int a, double b)的修飾名是_func@12。對於「c++」函式,則有所不同。
所有的win32 api函式都遵循該約定。
_fastcall 頭兩個dword型別或者佔更少位元組的引數被放入ecx和edx暫存器,其他剩下的引數按從右到左的順序壓入棧。由被呼叫者把引數彈出棧,對於「c」函式或者變數,修飾名以「@」為字首,然後是函式名,接著是符號「@」及引數的位元組數,如函式int func(int a, double b)的修飾名是@func@12。對於「c++」函式,有所不同。
未來的編譯器可能使用不同的暫存器來存放引數。
naked call 採用1-4的呼叫約定時,如果必要的話,進入函式時編譯器會產生**來儲存esi,edi,ebx,ebp暫存器,退出函式時則產生**恢復這些暫存器的內容。naked call不產生這樣的**。
naked call不是型別修飾符,故必須和_declspec共同使用,如下:
__declspec( naked ) int func( formal_parameters )
過時的呼叫約定
原來的一些呼叫約定可以不再使用。它們被定義成呼叫約定_stdcall或者_cdecl。例如:
#define callback __stdcall
#define winapi __stdcall
#define winapiv __cdecl
#define apientry winapi
#define apiprivate __stdcall
#define pascal __stdcall
表7-1顯示了乙個函式在幾種呼叫約定下的修飾名(表中的「c++」函式指的是「c++」全域性函式,不是成員函式),函式原型是void calltype test(void),calltype可以是_cdecl、_fastcall、_stdcall。
表7-1 不同呼叫約定下的修飾名
呼叫約定
extern 「c」或.c檔案
.cpp, .cxx或/tp編譯開關
_cdecl
_test
?test@@zaxxz
_fastcall
@test@0
?test@@yixxz
_stdcall
_test@0
?test@@ygxxz
MFC DLL的一些知識
雖然能用dll實現的東西都可以用com來實現,但dll的優點確實不少,它更容易建立。本文將討論如何利用mfc來建立不同型別的dll,以及如何使用他們。一 dll的不同型別 使用mfc可以生成兩種型別的dll mfc擴充套件dll和常規dll。常規dll有可以分為動態連線和靜態連線。visual c ...
const 的一些知識
收集了別人關於 const 的一些論述。const 的用法很多很靈活,稍不注意,就會有些莫名其妙的問題出現。甲 用於定義乙個不能被更改的變數的時候 const int i 10 i 的值不能被改變,否則報錯 void fun const int i 在函式中,i 的值不能被改變,即使他是個區域性變數...
SYBASE的一些知識
1。建立server時要注意頁大小 2k 4k。因為如果要重新恢復時需保證備份的與當前的一致,否則提示檔案頭不是4096或 2048byte一類的錯誤 2。建立adapter時主裝置大小一般不需要改。預設的即可,改太大時有可能裝不上。按預設大小建立即可。空間不夠可通過建立裝置來擴充套件。3。建立ad...