dll文件介紹
比較大的應(yīng)用程序都由很多模塊組成,這些模塊分別完成相對(duì)獨(dú)立的功能,它們彼此協(xié)作來(lái)完成整個(gè)軟件系統(tǒng)的工作??赡艽嬖谝恍┠K的功能較為通用,在構(gòu)造其它軟件系統(tǒng)時(shí)仍會(huì)被使用。在構(gòu)造軟件系統(tǒng)時(shí),如果將所有模塊的源代碼都靜態(tài)編譯到整個(gè)應(yīng)用程序 EXE 文件中,會(huì)產(chǎn)生一些問(wèn)題:一個(gè)缺點(diǎn)是增加了應(yīng)用程序的大小,它會(huì)占用更多的磁盤空間,程序運(yùn)行時(shí)也會(huì)消耗較大的內(nèi)存空間,造成系統(tǒng)資源的浪費(fèi);另一個(gè)缺點(diǎn)是,在編寫大的 EXE 程序時(shí),在每次修改重建時(shí)都必須調(diào)整編譯所有源代碼,增加了編譯過(guò)程的復(fù)雜性,也不利于階段性的單元測(cè)試。
Windows 系統(tǒng)平臺(tái)上提供了一種完全不同的較有效的編程和運(yùn)行環(huán)境,你可以將獨(dú)立的程序模塊創(chuàng)建為較小的 DLL (Dynamic Linkable Library) 文件,并可對(duì)它們單獨(dú)編譯和測(cè)試。在運(yùn)行時(shí),只有當(dāng) EXE 程序確實(shí)要調(diào)用這些 DLL 模塊的情況下,系統(tǒng)才會(huì)將它們裝載到內(nèi)存空間中。這種方式不僅減少了 EXE 文件的大小和對(duì)內(nèi)存空間的需求,而且使這些 DLL 模塊可以同時(shí)被多個(gè)應(yīng)用程序使用。Windows 自己就將一些主要的系統(tǒng)功能以 DLL 模塊的形式實(shí)現(xiàn)。
一般來(lái)說(shuō),DLL 是一種磁盤文件,以.dll、.DRV、.FON、.SYS 和許多以 .EXE 為擴(kuò)展名的系統(tǒng)文件都可以是 DLL。它由全局?jǐn)?shù)據(jù)、服務(wù)函數(shù)和資源組成,在運(yùn)行時(shí)被系統(tǒng)加載到調(diào)用進(jìn)程的虛擬空間中,成為調(diào)用進(jìn)程的一部分。如果與其它 DLL 之間沒(méi)有沖突,該文件通常映射到進(jìn)程虛擬空間的同一地址上。DLL 模塊中包含各種導(dǎo)出函數(shù),用于向外界提供服務(wù)。DLL 可以有自己的數(shù)據(jù)段,但沒(méi)有自己的堆棧,使用與調(diào)用它的應(yīng)用程序相同的堆棧模式;一個(gè) DLL 在內(nèi)存中只有一個(gè)實(shí)例;DLL 實(shí)現(xiàn)了代碼封裝性;DLL 的編制與具體的編程語(yǔ)言及編譯器無(wú)關(guān)。
在 Win32 環(huán)境中,每個(gè)進(jìn)程都復(fù)制了自己的讀/寫全局變量。如果想要與其它進(jìn)程共享內(nèi)存,必須使用內(nèi)存映射文件或者聲明一個(gè)共享數(shù)據(jù)段。DLL 模塊需要的堆棧內(nèi)存都是從運(yùn)行進(jìn)程的堆棧中分配出來(lái)的。Windows 在加載 DLL 模塊時(shí)將進(jìn)程函數(shù)調(diào)用與 DLL 文件的導(dǎo)出函數(shù)相匹配。Windows 操作系統(tǒng)對(duì) DLL 的操作僅僅是把 DLL 映射到需要它的進(jìn)程的虛擬地址空間里去。DLL 函數(shù)中的代碼所創(chuàng)建的任何對(duì)象(包括變量)都?xì)w調(diào)用它的線程或進(jìn)程所有。
調(diào)用方式
1、靜態(tài)調(diào)用方式:由編譯系統(tǒng)完成對(duì) DLL 的加載和應(yīng)用程序結(jié)束時(shí) DLL 卸載的編碼(如還有其它程序使用該 DLL,則 Windows 對(duì) DLL 的應(yīng)用記錄減1,直到所有相關(guān)程序都結(jié)束對(duì)該 DLL 的使用時(shí)才釋放它,簡(jiǎn)單實(shí)用,但不夠靈活,只能滿足一般要求。
隱式的調(diào)用:需要把產(chǎn)生動(dòng)態(tài)連接庫(kù)時(shí)產(chǎn)生的 .LIB 文件加入到應(yīng)用程序的工程中,想使用 DLL 中的函數(shù)時(shí),只須說(shuō)明一下。隱式調(diào)用不需要調(diào)用 LoadLibrary() 和 FreeLibrary()。程序員在建立一個(gè) DLL 文件時(shí),鏈接程序會(huì)自動(dòng)生成一個(gè)與之對(duì)應(yīng)的 LIB 導(dǎo)入文件。該文件包含了每一個(gè) DLL 導(dǎo)出函數(shù)的符號(hào)名和可選的標(biāo)識(shí)號(hào),但是并不含有實(shí)際的代碼。LIB 文件作為 DLL 的替代文件被編譯到應(yīng)用程序項(xiàng)目中。
當(dāng)程序員通過(guò)靜態(tài)鏈接方式編譯生成應(yīng)用程序時(shí),應(yīng)用程序中的調(diào)用函數(shù)與 LIB 文件中導(dǎo)出符號(hào)相匹配,這些符號(hào)或標(biāo)識(shí)號(hào)進(jìn)入到生成的 EXE 文件中。LIB 文件中也包含了對(duì)應(yīng)的 DL L文件名(但不是完全的路徑名),鏈接程序?qū)⑵浯鎯?chǔ)在 EXE 文件內(nèi)部。
當(dāng)應(yīng)用程序運(yùn)行過(guò)程中需要加載 DLL 文件時(shí),Windows 根據(jù)這些信息發(fā)現(xiàn)并加載 DLL,然后通過(guò)符號(hào)名或標(biāo)識(shí)號(hào)實(shí)現(xiàn)對(duì) DLL 函數(shù)的動(dòng)態(tài)鏈接。所有被應(yīng)用程序調(diào)用的 DLL 文件都會(huì)在應(yīng)用程序 EXE 文件加載時(shí)被加載在到內(nèi)存中??蓤?zhí)行程序鏈接到一個(gè)包含 DLL 輸出函數(shù)信息的輸入庫(kù)文件(.LIB文件)。操作系統(tǒng)在加載使用可執(zhí)行程序時(shí)加載 DLL??蓤?zhí)行程序直接通過(guò)函數(shù)名調(diào)用 DLL 的輸出函數(shù),調(diào)用方法和程序內(nèi)部其 它的函數(shù)是一樣的。
2、動(dòng)態(tài)調(diào)用方式:是由編程者用 API 函數(shù)加載和卸載 DLL 來(lái)達(dá)到調(diào)用 DLL 的目的,使用上較復(fù)雜,但能更加有效地使用內(nèi)存,是編制大型應(yīng)用程序時(shí)的重要方式。
顯式的調(diào)用:是指在應(yīng)用程序中用 LoadLibrary 或 MFC 提供的 AfxLoadLibrary 顯式的將自己所做的動(dòng)態(tài)連接庫(kù)調(diào)進(jìn)來(lái),動(dòng)態(tài)連接庫(kù)的文件名即是上面兩個(gè)函數(shù)的參數(shù),再用 GetProcAddress() 獲取想要引入的函數(shù)。自此,你就可以象使用如同本應(yīng)用程序自定義的函數(shù)一樣來(lái)調(diào)用此引入函數(shù)了。在應(yīng)用程序退出之前,應(yīng)該用 FreeLibrary 或 MFC 提供的 AfxFreeLibrary 釋放動(dòng)態(tài)連接庫(kù)。直接調(diào)用 Win32 的 LoadLibary 函數(shù),并指定 DLL 的路徑作為參數(shù)。LoadLibary 返回 HINSTANCE 參數(shù),應(yīng)用程序在調(diào)用 GetProcAddress 函數(shù)時(shí)使用這一參數(shù)。GetProcAddress 函數(shù)將符號(hào)名或標(biāo)識(shí)號(hào)轉(zhuǎn)換為 DLL 內(nèi)部的地址。程序員可以決定 DLL 文件何時(shí)加載或不加載,顯式鏈接在運(yùn)行時(shí)決定加載哪個(gè) DLL 文件。使用 DLL 的程序在使用之前必須加載(LoadLibrary)加載DLL從而得到一個(gè)DLL模塊的句柄,然后調(diào)用 GetProcAddress 函數(shù)得到輸出函數(shù)的指針,在退出之前必須卸載DLL(FreeLibrary)。
Windows將遵循下面的搜索順序來(lái)定位 DLL:
- 包含EXE文件的目錄
- 進(jìn)程的當(dāng)前工作目錄
- Windows系統(tǒng)目錄
- Windows目錄
- 列在 Path 環(huán)境變量中的一系列目錄
MFC中的DLL
- Non-MFC DLL:指的是不用 MFC 的類庫(kù)結(jié)構(gòu),直接用 C 語(yǔ)言寫的 DLL,其輸出的函數(shù)一般用的是標(biāo)準(zhǔn) C 接口,并能被 非 MFC 或 MFC 編寫的應(yīng)用程序所調(diào)用。
- Regular DLL:和下述的 Extension DLLs 一樣,是用 MFC 類庫(kù)編寫的。明顯的特點(diǎn)是在源文件里有一個(gè)繼承 CWinApp 的類。其又可細(xì)分成靜態(tài)連接到 MFC 和動(dòng)態(tài)連接到 MFC 上的。
靜態(tài)連接到 MFC 的動(dòng)態(tài)連接庫(kù)只被 VC 的專業(yè) 版和企業(yè)版所支持。該類 DLL 應(yīng)用程序里頭的輸出函數(shù)可以被任意 Win32 程序使用,包括使用 MFC 的應(yīng)用程序。輸入函數(shù)有如下形式:
extern "C" EXPORT YourExportedFunction();
如果沒(méi)有 extern "C" 修飾,輸出函數(shù)僅僅能從 C++ 代碼中調(diào)用。
DLL 應(yīng)用程序從 CWinApp 派生,但沒(méi)有消息循環(huán)。
動(dòng)態(tài)鏈接到 MFC 的 規(guī)則 DLL 應(yīng)用程序里頭的輸出函數(shù)可以被任意 Win32 程序使用,包括使用 MFC 的應(yīng)用程序。但是,所有從 DLL 輸出的函數(shù)應(yīng)該以如下語(yǔ)句開(kāi)始:
AFX_MANAGE_STATE(AfxGetStaticModuleState( ))
此語(yǔ)句用來(lái)正確地切換 MFC 模塊狀態(tài)。
Regular DLL能夠被所有支持 DLL 技術(shù)的語(yǔ)言所編寫的應(yīng)用程序所調(diào)用。在這種動(dòng)態(tài)連接庫(kù)中,它必須有一個(gè)從 CWinApp 繼承下來(lái)的類,DLLMain 函數(shù)被 MFC 所提供,不用自己顯式的寫出來(lái)。
-
Extension DLL:用來(lái)實(shí)現(xiàn)從 MFC 所繼承下來(lái)的類的重新利用,也就是說(shuō),用這種類型的動(dòng)態(tài)連接庫(kù),可以用來(lái)輸出一個(gè)從 MFC 所繼承下來(lái)的類。它輸出的函數(shù)僅可以被使用 MFC 且動(dòng)態(tài)鏈接到 MFC 的應(yīng)用程序使用。可以從 MFC 繼承你所想要的、更適于你自己用的類,并把它提供給你的應(yīng)用程序。你也可隨意的給你的應(yīng)用程序提供 MFC 或 MFC 繼承類的對(duì)象指針。Extension DLL使用 MFC 的動(dòng)態(tài)連接版本所創(chuàng)建的,并且它只被用 MFC 類庫(kù)所編寫的應(yīng)用程序所調(diào)用。Extension DLLs 和 Regular DLLs 不一樣,它沒(méi)有從 CWinApp 繼承而來(lái)的類的對(duì)象,所以,你必須為自己 DLLMain 函數(shù)添加初始化代碼和結(jié)束代碼。
和規(guī)則 DLL 相比,有以下不同:
1、它沒(méi)有從 CWinApp 派生的對(duì)象;
2、它必須有一個(gè) DLLMain 函數(shù);
3、DLLMain 調(diào)用 AfxInitExtensionModule 函數(shù),必須檢查該函數(shù)的返回值,如果返回0,DLLMmain 也返回 0;
-
4、如果它希望輸出 CRuntimeClass 類型的對(duì)象或者資源,則需要提供一個(gè)初始化函數(shù)來(lái)創(chuàng)建一個(gè) CDynLinkLibrary 對(duì)象。并且,有必要把初始化函數(shù)輸出;
5、使用擴(kuò)展 DLL 的 MFC 應(yīng)用程序必須有一個(gè)從 CWinApp 派生的類,而且,一般在InitInstance 里調(diào)用擴(kuò)展 DLL 的初始化函數(shù)。
DLL入口函數(shù)
1、每一個(gè) DLL 必須有一個(gè)入口點(diǎn),DLLMain 是一個(gè)缺省的入口函數(shù)。DLLMain 負(fù)責(zé)初始化和結(jié)束工作,每當(dāng)一個(gè)新的進(jìn)程或者該進(jìn)程的新的線程訪問(wèn) DLL 時(shí),或者訪問(wèn) DLL 的每一個(gè)進(jìn)程或者線程不再使用DLL或者結(jié)束時(shí),都會(huì)調(diào)用 DLLMain。但是,使用 TerminateProcess 或 TerminateThread 結(jié)束進(jìn)程或者線程,不會(huì)調(diào)用 DLLMain。
DLLMain的函數(shù)原型:
BOOL APIENTRY DLLMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID
lpReserved)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
.......
case DLL_THREAD_ATTACH:
.......
case DLL_THREAD_DETACH:
.......
case DLL_PROCESS_DETACH:
.......
return TRUE;
}
}參數(shù):
hMoudle:是動(dòng)態(tài)庫(kù)被調(diào)用時(shí)所傳遞來(lái)的一個(gè)指向自己的句柄(實(shí)際上,它是指向_DGROUP段的一個(gè)選擇符);
ul_reason_for_call:是一個(gè)說(shuō)明動(dòng)態(tài)庫(kù)被調(diào)原因的標(biāo)志。當(dāng)進(jìn)程或線程裝入或卸載動(dòng)態(tài)連接庫(kù)的時(shí)
關(guān)鍵詞:dll,dll文件
閱讀本文后您有什么感想? 已有 人給出評(píng)價(jià)!
- 0
- 0
- 0
- 0
- 0
- 0