概要
本文說(shuō)明什么是動(dòng)態(tài)鏈接庫(kù) (dll) 以及在使用 dll 時(shí)可能發(fā)生的各種問(wèn)題。
然后,本文說(shuō)明在開(kāi)發(fā)您自己的 dll 時(shí)應(yīng)該考慮的一些高級(jí)問(wèn)題。在說(shuō)明什么是 dll 的過(guò)程中,本文將說(shuō)明動(dòng)態(tài)鏈接方法、dll 依賴性、dll 入口點(diǎn)、導(dǎo)出 dll 函數(shù)以及 dll 故障排除工具。
本文最后將從較高的層次對(duì) dll 與 microsoft .net framework 程序集作一比較。
簡(jiǎn)介
對(duì)于“適用于”一節(jié)中列出的 microsoft windows 操作系統(tǒng),操作系統(tǒng)的大量功能是由動(dòng)態(tài)鏈接庫(kù) (dll) 提供的。另外,當(dāng)您在這些 windows 操作系統(tǒng)之一上運(yùn)行某一程序時(shí),該程序的很多功能可能是由 dll 提供的。例如,某些程序可能包含很多不同的模塊,而該程序的每個(gè)模塊都包含在 dll 中并從中分發(fā)。
使用 dll 有助于促進(jìn)代碼的模塊化、代碼重用、內(nèi)存的有效使用和減少所占用的磁盤空間。因此,操作系統(tǒng)和程序能夠更快地加載和運(yùn)行,并且在計(jì)算機(jī)中占用較少的磁盤空間。
當(dāng)程序使用 dll 時(shí),一個(gè)稱為依賴性的問(wèn)題可能導(dǎo)致該程序無(wú)法運(yùn)行。當(dāng)程序使用 dll 時(shí),就會(huì)創(chuàng)建一個(gè)依賴項(xiàng)。如果其他程序改寫和損壞了該依賴項(xiàng),原來(lái)的那個(gè)程序就可能無(wú)法成功運(yùn)行。
在引入 microsoft .net framework 之后,大多數(shù)依賴性問(wèn)題都已經(jīng)通過(guò)使用程序集消除了。
什么是 dll?
dll 是一個(gè)包含可由多個(gè)程序同時(shí)使用的代碼和數(shù)據(jù)的庫(kù)。例如,在 windows 操作系統(tǒng)中,comdlg32 dll 執(zhí)行與對(duì)話框有關(guān)的常見(jiàn)函數(shù)。因此,每個(gè)程序都可以使用該 dll 中包含的功能來(lái)實(shí)現(xiàn)“打開(kāi)”對(duì)話框。這有助于促進(jìn)代碼重用和內(nèi)存的有效使用。
通過(guò)使用 dll,程序可以實(shí)現(xiàn)模塊化,由相對(duì)獨(dú)立的組件組成。例如,一個(gè)計(jì)帳程序可以按模塊來(lái)銷售。可以在運(yùn)行時(shí)將各個(gè)模塊加載到主程序中(如果安裝了相應(yīng)模塊)。因?yàn)槟K是彼此獨(dú)立的,所以程序的加載速度更快,而且模塊只在相應(yīng)的功能被請(qǐng)求時(shí)才加載。
此外,可以更為容易地將更新應(yīng)用于各個(gè)模塊,而不會(huì)影響該程序的其他部分。例如,您可能具有一個(gè)工資計(jì)算程序,而稅率每年都會(huì)更改。當(dāng)這些更改被隔離到 dll 中以后,您無(wú)需重新生成或安裝整個(gè)程序就可以應(yīng)用更新。
下表說(shuō)明了 windows 操作系統(tǒng)中的一些作為 dll 實(shí)現(xiàn)的文件: •activex 控件 (.ocx) 文件
activex 控件的一個(gè)示例是日歷控件,它使您可以從日歷中選擇日期。
•控制面板 (.cpl) 文件
.cpl 文件的一個(gè)示例是位于控制面板中的項(xiàng)。每個(gè)項(xiàng)都是一個(gè)專用 dll。
•設(shè)備驅(qū)動(dòng)程序 (.drv) 文件
設(shè)備驅(qū)動(dòng)程序的一個(gè)示例是控制打印到打印機(jī)的打印機(jī)驅(qū)動(dòng)程序。
dll 的優(yōu)點(diǎn)
下表說(shuō)明了當(dāng)程序使用 dll 時(shí)提供的一些優(yōu)點(diǎn): •使用較少的資源
當(dāng)多個(gè)程序使用同一個(gè)函數(shù)庫(kù)時(shí),dll 可以減少在磁盤和物理內(nèi)存中加載的代碼的重復(fù)量。這不僅可以大大影響在前臺(tái)運(yùn)行的程序,而且可以大大影響其他在 windows 操作系統(tǒng)上運(yùn)行的程序。
•推廣模塊式體系結(jié)構(gòu)
dll 有助于促進(jìn)模塊式程序的開(kāi)發(fā)。這可以幫助您開(kāi)發(fā)要求提供多個(gè)語(yǔ)言版本的大型程序或要求具有模塊式體系結(jié)構(gòu)的程序。模塊式程序的一個(gè)示例是具有多個(gè)可以在運(yùn)行時(shí)動(dòng)態(tài)加載的模塊的計(jì)帳程序。
•簡(jiǎn)化部署和安裝
當(dāng) dll 中的函數(shù)需要更新或修復(fù)時(shí),部署和安裝 dll 不要求重新建立程序與該 dll 的鏈接。此外,如果多個(gè)程序使用同一個(gè) dll,那么多個(gè)程序都將從該更新或修復(fù)中獲益。當(dāng)您使用定期更新或修復(fù)的第三方 dll 時(shí),此問(wèn)題可能會(huì)更頻繁地出現(xiàn)。
dll 依賴項(xiàng)
當(dāng)某個(gè)程序或 dll 使用其他 dll 中的 dll 函數(shù)時(shí),就會(huì)創(chuàng)建依賴項(xiàng)。因此,該程序就不再是獨(dú)立的,并且如果該依賴項(xiàng)被損壞,該程序就可能遇到問(wèn)題。例如,如果發(fā)生下列操作之一,則該程序可能無(wú)法運(yùn)行: •依賴 dll 升級(jí)到新版本。
•修復(fù)了依賴 dll。
•依賴 dll 被其早期版本覆蓋。
•從計(jì)算機(jī)中刪除了依賴 dll。
這些操作通常稱為 dll 沖突。如果沒(méi)有強(qiáng)制實(shí)現(xiàn)向后兼容性,則該程序可能無(wú)法成功運(yùn)行。
下表說(shuō)明了為了幫助最大限度地減少依賴性問(wèn)題而在 microsoft windows 2000 和較高版本的 windows 操作系統(tǒng)中引入的更改: •windows 文件保護(hù)
在 windows 文件保護(hù)中,操作系統(tǒng)禁止未經(jīng)授權(quán)的代理更新或刪除系統(tǒng) dll。因此,當(dāng)程序安裝操作嘗試刪除或更新被定義為系統(tǒng) dll 的 dll 時(shí),windows 文件保護(hù)將尋找有效的數(shù)字簽名。
•專用 dll
通過(guò)專用 dll 可以使程序避免遭受對(duì)共享 dll 進(jìn)行的更改。專用 dll 使用版本特定信息或空 .local 文件來(lái)強(qiáng)制要求程序所使用的 dll 的版本。要使用專用 dll,請(qǐng)?jiān)诔绦蚋募A中查找 dll。然后,對(duì)于新程序,請(qǐng)向該 dll 中添加版本特定信息。對(duì)于舊程序,請(qǐng)使用空 .local 文件。每個(gè)方法都告訴操作系統(tǒng)使用位于程序根文件夾中的專用 dll。
dll 故障排除工具
可以使用多個(gè)工具來(lái)幫助您解決 dll 問(wèn)題。以下是其中的部分工具。
dependency walker
dependency walker 工具可以遞歸掃描以尋找程序所使用的所有依賴 dll。當(dāng)您在 dependency walker 中打開(kāi)程序時(shí),dependency walker 會(huì)執(zhí)行下列檢查: •dependency walker 檢查是否丟失 dll。
•dependency walker 檢查是否存在無(wú)效的程序文件或 dll。
•dependency walker 檢查導(dǎo)入函數(shù)和導(dǎo)出函數(shù)是否匹配。
•dependency walker 檢查是否存在循環(huán)依賴性錯(cuò)誤。
•dependency walker 檢查是否存在由于針對(duì)另一不同操作系統(tǒng)而無(wú)效的模塊。
通過(guò)使用 dependency walker,您可以記錄程序使用的所有 dll。這可能有助于避免和更正將來(lái)可能發(fā)生的 dll 問(wèn)題。當(dāng)您安裝 microsoft visual studio 6.0 時(shí),dependency walker 將位于以下目錄中:
drive/program files/microsoft visual studio/common/tools
dll universal problem solver
dll universal problem solver (dups) 工具用于審核、比較、記錄和顯示 dll 信息。下表說(shuō)明了組成 dups 工具的實(shí)用工具: •dlister.exe
該實(shí)用工具枚舉計(jì)算機(jī)中的所有 dll,并且將此信息記錄到一個(gè)文本文件或數(shù)據(jù)庫(kù)文件中。
•dcomp.exe
該實(shí)用工具比較在兩個(gè)文本文件中列出的 dll,并產(chǎn)生包含差異的第三個(gè)文本文件。
•dtxt2db.exe
該實(shí)用工具將通過(guò)使用 dlister.exe 實(shí)用工具和 dcomp.exe 實(shí)用工具創(chuàng)建的文本文件加載到 dllhell 數(shù)據(jù)庫(kù)中。
•dlgdtxt2db.exe
該實(shí)用工具提供 dtxt2db.exe 實(shí)用工具的圖形用戶界面 (gui) 版本。
有關(guān) dups 工具的更多信息,請(qǐng)單擊下面的文章編號(hào),以查看 microsoft 知識(shí)庫(kù)中相應(yīng)的文章:
247957 (http://support.microsoft.com/kb/247957/) 示例:使用 dups.exe 解決 dll 兼容性問(wèn)題
dll 幫助數(shù)據(jù)庫(kù)
dll 幫助數(shù)據(jù)庫(kù)幫助您查找由 microsoft 軟件產(chǎn)品安裝的特定版本的 dll。有關(guān) dll 幫助數(shù)據(jù)庫(kù)的更多信息,請(qǐng)?jiān)L問(wèn)下面的 microsoft 網(wǎng)站:
http://support.microsoft.com/dllhelp/ (http://support.microsoft.com/dllhelp/)
dll 開(kāi)發(fā)
本節(jié)介紹您在開(kāi)發(fā)自己的 dll 時(shí)應(yīng)該考慮的問(wèn)題和要求。
dll 的類型
當(dāng)您在應(yīng)用程序中加載 dll 時(shí),可以使用兩種鏈接方法來(lái)調(diào)用導(dǎo)出的 dll 函數(shù)。這兩種鏈接方法是加載時(shí)動(dòng)態(tài)鏈接和運(yùn)行時(shí)動(dòng)態(tài)鏈接。
加載時(shí)動(dòng)態(tài)鏈接
在加載時(shí)動(dòng)態(tài)鏈接中,應(yīng)用程序像調(diào)用本地函數(shù)一樣對(duì)導(dǎo)出的 dll 函數(shù)進(jìn)行顯式調(diào)用。要使用加載時(shí)動(dòng)態(tài)鏈接,請(qǐng)?jiān)诰幾g和鏈接應(yīng)用程序時(shí)提供頭文件 (.h) 和導(dǎo)入庫(kù)文件 (.lib)。當(dāng)您這樣做時(shí),鏈接器將向系統(tǒng)提供加載 dll 所需的信息,并在加載時(shí)解析導(dǎo)出的 dll 函數(shù)的位置。
運(yùn)行時(shí)動(dòng)態(tài)鏈接
在運(yùn)行時(shí)動(dòng)態(tài)鏈接中,應(yīng)用程序調(diào)用 loadlibrary 函數(shù)或 loadlibraryex 函數(shù)以在運(yùn)行時(shí)加載 dll。成功加載 dll 后,可以使用 getprocaddress 函數(shù)獲得要調(diào)用的導(dǎo)出的 dll 函數(shù)的地址。在使用運(yùn)行時(shí)動(dòng)態(tài)鏈接時(shí),無(wú)需使用導(dǎo)入庫(kù)文件。
下面的列表說(shuō)明了有關(guān)何時(shí)使用加載時(shí)動(dòng)態(tài)鏈接以及何時(shí)使用運(yùn)行時(shí)動(dòng)態(tài)鏈接的應(yīng)用程序條件: •啟動(dòng)性能
如果應(yīng)用程序的初始啟動(dòng)性能很重要,則應(yīng)使用運(yùn)行時(shí)動(dòng)態(tài)鏈接。
•易用性
在加載時(shí)動(dòng)態(tài)鏈接中,導(dǎo)出的 dll 函數(shù)類似于本地函數(shù)。這使您可以方便地調(diào)用這些函數(shù)。
•應(yīng)用程序邏輯
在運(yùn)行時(shí)動(dòng)態(tài)鏈接中,應(yīng)用程序可以分支,以便按照需要加載不同的模塊。在開(kāi)發(fā)多語(yǔ)言版本時(shí),這一點(diǎn)很重要。
dll 入口點(diǎn)
在創(chuàng)建 dll 時(shí),可以有選擇地指定入口點(diǎn)函數(shù)。當(dāng)進(jìn)程或線程將它們自身附加到 dll 或者將它們自身從 dll 分離時(shí),將調(diào)用入口點(diǎn)函數(shù)。您可以使用入口點(diǎn)函數(shù)根據(jù) dll 的需要來(lái)初始化數(shù)據(jù)結(jié)構(gòu)或者銷毀數(shù)據(jù)結(jié)構(gòu)。此外,如果應(yīng)用程序是多線程的,則可以在入口點(diǎn)函數(shù)中使用線程本地存儲(chǔ) (tls) 來(lái)分配各個(gè)線程專用的內(nèi)存。下面的代碼是一個(gè) dll 入口點(diǎn)函數(shù)的示例。
當(dāng)入口點(diǎn)函數(shù)返回 false 值時(shí),如果您使用的是加載時(shí)動(dòng)態(tài)鏈接,則應(yīng)用程序不啟動(dòng)。如果您使用的是運(yùn)行時(shí)動(dòng)態(tài)鏈接,則只有個(gè)別 dll 不會(huì)加載。
入口點(diǎn)函數(shù)只應(yīng)執(zhí)行簡(jiǎn)單的初始化任務(wù),不應(yīng)調(diào)用任何其他 dll 加載函數(shù)或終止函數(shù)。例如,在入口點(diǎn)函數(shù)中,不應(yīng)直接或間接調(diào)用 loadlibrary 函數(shù)或 loadlibraryex 函數(shù)。此外,不應(yīng)在進(jìn)程終止時(shí)調(diào)用 freelibrary 函數(shù)。
注意:在多線程應(yīng)用程序中,請(qǐng)確保將對(duì) dll 全局?jǐn)?shù)據(jù)的訪問(wèn)進(jìn)行同步(線程安全),以避免可能的數(shù)據(jù)損壞。為此,請(qǐng)使用 tls 為各個(gè)線程提供唯一的數(shù)據(jù)。
導(dǎo)出 dll 函數(shù)
要導(dǎo)出 dll 函數(shù),您可以向?qū)С龅?dll 函數(shù)中添加函數(shù)關(guān)鍵字,也可以創(chuàng)建模塊定義文件 (.def) 以列出導(dǎo)出的 dll 函數(shù)。
要使用函數(shù)關(guān)鍵字,您必須使用以下關(guān)鍵字來(lái)聲明要導(dǎo)出的各個(gè)函數(shù):
__declspec(dllexport)
要在應(yīng)用程序中使用導(dǎo)出的 dll 函數(shù),您必須使用以下關(guān)鍵字來(lái)聲明要導(dǎo)入的各個(gè)函數(shù):
__declspec(dllimport)
通常情況下,您最好使用一個(gè)包含 define 語(yǔ)句和 ifdef 語(yǔ)句的頭文件,以便分隔導(dǎo)出語(yǔ)句和導(dǎo)入語(yǔ)句。
您還可以使用模塊定義文件來(lái)聲明導(dǎo)出的 dll 函數(shù)。當(dāng)您使用模塊定義文件時(shí),您不必向?qū)С龅?dll 函數(shù)中添加函數(shù)關(guān)鍵字。在模塊定義文件中,您可以聲明 dll 的 library 語(yǔ)句和 exports 語(yǔ)句。下面的代碼是一個(gè)定義文件的示例。
// sampledll.def
//
下面的代碼是一個(gè)“win32 應(yīng)用程序”項(xiàng)目的示例,該示例調(diào)用 sampledll dll 中的導(dǎo)出 dll 函數(shù)。
// sampleapp.cpp
//
注意:在加載時(shí)動(dòng)態(tài)鏈接中,您必須鏈接在生成 sampledll 項(xiàng)目時(shí)創(chuàng)建的 sampledll.lib 導(dǎo)入庫(kù)。
在運(yùn)行時(shí)動(dòng)態(tài)鏈接中,您應(yīng)使用與以下代碼類似的代碼來(lái)調(diào)用 sampledll.dll 導(dǎo)出 dll 函數(shù)。
當(dāng)您編譯和鏈接 sampledll 應(yīng)用程序時(shí),windows 操作系統(tǒng)將按照以下順序在下列位置中搜索 sampledll dll: 1.應(yīng)用程序文件夾
2.當(dāng)前文件夾
3.windows 系統(tǒng)文件夾
注意:getsystemdirectory 函數(shù)返回 windows 系統(tǒng)文件夾的路徑。
4.windows 文件夾
注意:getwindowsdirectory 函數(shù)返回 windows 文件夾的路徑。
.net framework 程序集
在引入 microsoft .net 和 .net framework 以后,大多數(shù)與 dll 相關(guān)聯(lián)的問(wèn)題已經(jīng)通過(guò)使用程序集消除了。程序集是在 .net 公共語(yǔ)言運(yùn)行庫(kù) (clr) 控制之下運(yùn)行的邏輯功能單元。程序集實(shí)際上是作為 .dll 文件或 .exe 文件存在的。但是,在內(nèi)部,程序集與 microsoft win32 dll 大不相同。
程序集文件包含程序集清單、類型元數(shù)據(jù)、microsoft 中間語(yǔ)言 (msil) 代碼和其他資源。程序集清單包含程序集元數(shù)據(jù),以提供使程序集成為自描述程序集所需的全部信息。程序集清單中包含以下信息: •程序集名稱
•版本信息
•區(qū)域性信息
•強(qiáng)名稱信息
•程序集文件列表
•類型引用信息
•引用和依賴程序集信息
程序集中包含的 msil 代碼是無(wú)法直接執(zhí)行的,需要通過(guò) clr 來(lái)執(zhí)行。默認(rèn)情況下,當(dāng)您創(chuàng)建一個(gè)程序集時(shí),該程序集是應(yīng)用程序?qū)S械摹R獎(jiǎng)?chuàng)建共享程序集,需要為該程序集分配強(qiáng)名稱,然后在全局程序集緩存中發(fā)布該程序集。
下表說(shuō)明了程序集的一些功能,并將其與 win32 dll 的功能進(jìn)行了比較: •自描述
當(dāng)您創(chuàng)建程序集時(shí),clr 運(yùn)行該程序集所需的全部信息都包含在程序集清單中。程序集清單包含一個(gè)依賴程序集列表。因此,clr 可以維護(hù)一組在應(yīng)用程序中使用的一致的程序集。在 win32 dll 中,當(dāng)您使用共享 dll 時(shí),無(wú)法維護(hù)應(yīng)用程序中使用的一組 dll 之間的一致性。
•版本控制
在程序集清單中,版本信息由 clr 記錄和實(shí)施。另外,可以通過(guò)版本策略來(lái)實(shí)施版本特定用法。在 win32 dll 中,無(wú)法由操作系統(tǒng)實(shí)施版本控制。相反,您必須確保 dll 向后兼容。
•并行部署
程序集支持并行部署。一個(gè)應(yīng)用程序可以使用一個(gè)版本的程序集,而另一個(gè)應(yīng)用程序可以使用另一不同版本的程序集。從 windows 2000 開(kāi)始,通過(guò)將 dll 放置到應(yīng)用程序文件夾中支持并行部署。另外,windows 文件保護(hù)能夠防止系統(tǒng) dll 被未經(jīng)授權(quán)的代理改寫或替換。
•獨(dú)立和隔離
通過(guò)使用程序集開(kāi)發(fā)的應(yīng)用程序可以是獨(dú)立的,并且與計(jì)算機(jī)中正在運(yùn)行的其他應(yīng)用程序隔離。這一特性有助于創(chuàng)建零干擾安裝。
•執(zhí)行
程序集在程序集清單所提供的并且由 clr 控制的安全權(quán)限下運(yùn)行。
•語(yǔ)言無(wú)關(guān)性
可以通過(guò)使用任何一種受支持的 .net 語(yǔ)言來(lái)開(kāi)發(fā)程序集。例如,可以在 microsoft visual c# 中開(kāi)發(fā)程序集,然后在 microsoft visual basic .net 項(xiàng)目中使用該程序集。
參考
有關(guān) dll 和 .net framework 程序集的更多信息,請(qǐng)?jiān)L問(wèn)下面的 microsoft 網(wǎng)站:
dll 幫助數(shù)據(jù)庫(kù)
http://support.microsoft.com/dllhelp (http://support.microsoft.com/dllhelp)
dll 沖突 (dll conflicts)
http://msdn.microsoft.com/library/en-us/dnsetup/html/dlldanger1.asp (http://msdn.microsoft.com/library/en-us/dnsetup/html/dlldanger1.asp)
在應(yīng)用程序中實(shí)現(xiàn)并行組件共享 (implementing side-by-side component sharing in applications)
http://msdn.microsoft.com/library/en-us/dnsetup/html/sidebyside.asp (http://msdn.microsoft.com/library/en-us/dnsetup/html/sidebyside.asp)
如何生成和維護(hù)用于 windows xp 的獨(dú)立應(yīng)用程序和并行程序集 (how to build and service isolated applications and side-by-side assemblies for windows xp)
http://msdn.microsoft.com/library/en-us/dnwxp/html/sidexsidewinxp.asp (http://msdn.microsoft.com/library/en-us/dnwxp/html/sidexsidewinxp.asp)
使用 .net framework 簡(jiǎn)化部署和解決 dll 沖突 (simplifying deployment and solving dll conflicts with the .net framework)
http://msdn.microsoft.com/library/en-us/dndotnet/html/dplywithnet.asp (http://msdn.microsoft.com/library/en-us/dndotnet/html/dplywithnet.asp)
.net framework 開(kāi)發(fā)人員指南:程序集
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconassemblies.asp (http://msdn.microsoft.com/library/en-us/cpguide/html/cpconassemblies.asp)
創(chuàng)建 win32 dl (creating a win32 dll)
http://msdn.microsoft.com/library/en-us/vccore98/html/_core_overview.3a_.creating_a_win32_dll.asp (http://msdn.microsoft.com/library/en-us/vccore98/html/_core_overview.3a_.creating_a_win32_dll.asp)
運(yùn)行時(shí)動(dòng)態(tài)鏈接
http://msdn2.microsoft.com/en-us/library/ms685090.aspx (http://msdn2.microsoft.com/en-us/library/ms685090.aspx)
線程本地存儲(chǔ) (thread local storage)
http://msdn2.microsoft.com/en-us/library/ms686749.aspx
最大的網(wǎng)站源碼資源下載站,
新聞熱點(diǎn)
疑難解答
圖片精選