動(dòng)態(tài)鏈接庫(kù)(dll)學(xué)習(xí)資料總結(jié)_第1頁(yè)
動(dòng)態(tài)鏈接庫(kù)(dll)學(xué)習(xí)資料總結(jié)_第2頁(yè)
動(dòng)態(tài)鏈接庫(kù)(dll)學(xué)習(xí)資料總結(jié)_第3頁(yè)
動(dòng)態(tài)鏈接庫(kù)(dll)學(xué)習(xí)資料總結(jié)_第4頁(yè)
動(dòng)態(tài)鏈接庫(kù)(dll)學(xué)習(xí)資料總結(jié)_第5頁(yè)
已閱讀5頁(yè),還剩90頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、1. 什么是lib文件,lib和dll的關(guān)系如何(1) lib 是編譯時(shí)需要的,dll是運(yùn)行時(shí)需要的。 如果要完成源代碼的編譯,有l(wèi)ib就夠了。如果也使動(dòng)態(tài)連接的程序運(yùn)行起來(lái),有 dll就夠了。在開(kāi)發(fā)和調(diào)試階段,當(dāng)然最好都有。(2) 一般的動(dòng)態(tài)庫(kù)程序有l(wèi)ib文件和dll文件。lib文件是必須在編 譯期就連接到應(yīng)用程序中的,而dll文件是運(yùn)行期才會(huì)被調(diào)用的。如 果有dll文件,那么對(duì)應(yīng)的lib文件一般是一些索引信息,具體的實(shí) 現(xiàn)在dll文件中。如果只有l(wèi)ib文件,那么這個(gè)lib文件是靜態(tài)編譯 出來(lái)的,索引和實(shí)現(xiàn)都在其中。靜態(tài)編譯的lib文件有好處:給用戶(hù) 安裝時(shí)就不需要再掛動(dòng)態(tài)庫(kù)了。但也有缺點(diǎn),

2、就是導(dǎo)致應(yīng)用程序比較 大,而且失去了動(dòng)態(tài)庫(kù)的靈活性,在版本升級(jí)時(shí),同時(shí)要發(fā)布新的應(yīng) 用程序才行。(3) 在動(dòng)態(tài)庫(kù)的情況下,有兩個(gè)文件,一個(gè)是引入庫(kù)(丄IB )文件,一個(gè)是DLL文件,引入庫(kù)文件包含被 DLL導(dǎo)出的函數(shù)的名稱(chēng)和位置, DLL包含實(shí)際的函數(shù)和數(shù)據(jù),應(yīng)用程序使用LIB文件鏈接到所需要使用的DLL文件,DLL庫(kù)中的函數(shù)和數(shù)據(jù)并不復(fù)制到可執(zhí)行文件中,因 此在應(yīng)用程序的可執(zhí)行文件中,存放的不是被調(diào)用的函數(shù)代碼,而是 DLL中所要調(diào)用的函數(shù)的內(nèi)存地址,這樣當(dāng)一個(gè)或多個(gè)應(yīng)用程序運(yùn)行 時(shí)再把程序代碼和被調(diào)用的函數(shù)代碼鏈接起來(lái),從而節(jié)省了內(nèi)存資源。從上面的說(shuō)明可以看出,DLL和丄IB文件必須隨應(yīng)用

3、程序一起發(fā)行, 否則應(yīng)用程序?qū)?huì)產(chǎn)生錯(cuò)誤。2、嚴(yán)重警告:(1)用 extern C _declspec(dllexport)只可以導(dǎo)出全局函數(shù),不能導(dǎo)出類(lèi)的成員函數(shù)(2)使用 extern C _declspec(dllexport)輸出的函數(shù)可以被c語(yǔ)言調(diào)用,否則則不可注意標(biāo)準(zhǔn)調(diào)用約定的問(wèn)題,輸出與調(diào)用的函數(shù)約定應(yīng)該 致,|如當(dāng)dll模塊的函數(shù)輸出采用標(biāo)準(zhǔn)調(diào)用約定_stdcall ,則調(diào)用程序的導(dǎo) 入函數(shù)說(shuō)明也要用標(biāo)準(zhǔn)約定(4) 用 extern C _declspec(dllexport)和 EXPOTR得出的函數(shù)不改變函數(shù)名,可以給C+或c編寫(xiě)的exe調(diào)用.假如沒(méi)有extern C,導(dǎo)出

4、的函數(shù)名將會(huì)改變,只能給c+編寫(xiě)的exe調(diào)用(5) 在動(dòng)態(tài)加載動(dòng)態(tài)鏈接庫(kù)函數(shù)時(shí)注意 GetProcAddress(hlnst,add) 中第二個(gè)參數(shù)是否為動(dòng)態(tài)鏈接庫(kù)導(dǎo)出的函數(shù)名,因?yàn)樵谏蓜?dòng)態(tài)庫(kù)時(shí) 可能會(huì)改變動(dòng)態(tài)庫(kù)導(dǎo)出函數(shù)的函數(shù)名,加上修飾符(6) dll初始化全局變量時(shí),全局變量要放在共享數(shù)據(jù)斷,并且初始化 每一個(gè)變量,在StartHook函數(shù)里初始化其值,記得一進(jìn)函數(shù)就初始 化 調(diào)試時(shí),編譯器會(huì)自動(dòng)查找其目錄下(不含 debug和release目 錄)的dll文件,所以dll文件應(yīng)該放在主文件目錄下,但生成的應(yīng) 用程序則只會(huì)在同一個(gè)目錄下找dll (不需要lib文件),所以單純的運(yùn)行exe

5、,不通過(guò)編譯器,那就要把dll文件放在與exe相同的目錄下(8) 用#pragma comment(lib,dllTest.lib)導(dǎo)入 lib 文件,不需要在設(shè)置里修改(9) dll里的指針變量不要用newDLL調(diào)用方式DLL動(dòng)態(tài)連接庫(kù)),可以分為動(dòng)態(tài)調(diào)用于靜態(tài)調(diào)用。下面我分別舉一個(gè)例子說(shuō)說(shuō)。1)動(dòng)態(tài)調(diào)用:首先:在 VC+6.0中創(chuàng)建 Win32 Dynamic-link library 工程創(chuàng)建一個(gè)動(dòng)態(tài)連接庫(kù)工程:在頭文件TestDll.h中寫(xiě)下代碼extern C i nt _declspec(dllexport) add(i nt numa, i nt numb);/聲明導(dǎo)出函數(shù)在源文

6、件TestDll.cpp中實(shí)現(xiàn)改函數(shù):int _declspec(dllexport) add(i nt nu ma, int nu mb)return numa + nu mb;然后,創(chuàng)建一個(gè)測(cè)試程序,TestDemo,創(chuàng)建一個(gè).cpp文件,然后放下代碼:HINSTANCE hin sta nee;typedef in t (*lpAdd)(i nt a, i nt b);lpAdd lpadd;int mai n()hi nsta nee = LoadLibrary(E:vcDLLTestDIIDebugTestDll.dll);lpadd = (I pAdd)GetProcAddress

7、(hi nsta nee, add);cout 2 + 3 = lpadd(2, 3) endl;FreeLibrary(hi nsta nee);return 0;下面我們來(lái)逐一分析。首先,語(yǔ)句typedef int ( * lpAddFun)(int,int)定義了一個(gè)與add函數(shù)接受參數(shù)類(lèi)型和返回值均相同的函數(shù)指針類(lèi)型。隨后,在main函數(shù)中定義了 IpAddFun的實(shí)例addFun;其次,在函數(shù) ma in中定義了一個(gè) DLL HINSTANCE句柄實(shí)例 hDll,通過(guò) Win 32 Api函數(shù)LoadLibrary 動(dòng)態(tài)加載了 DLL模塊并將DLL模塊句柄賦給了 hDlll;再次,在

8、函數(shù) main中通過(guò) Win32 Api函數(shù)GetProcAddress得到了所加載 DLL模塊中函數(shù)add的地址并賦給了 addFun。經(jīng)由函數(shù)指針 addFun進(jìn)行了對(duì)DLL中add函數(shù)的調(diào)用;最后,應(yīng)用工程使用完 DLL后,在函數(shù) main中通過(guò) Win32 Api函數(shù)FreeLibrary釋放了已經(jīng)加載的DLL模塊。通過(guò)這個(gè)簡(jiǎn)單的例子,我們獲知DLL定義和調(diào)用的一般概念:(1) DLL中需以某種特定的方式聲明導(dǎo)出函數(shù)(或變量、類(lèi));(2) 應(yīng)用工程需以某種特定的方式調(diào)用DLL的導(dǎo)出函數(shù)(或變量、類(lèi))。2)靜態(tài)連接:代碼如下:#in elude using n amespace std;

9、#pragma comme nt(lib,Testlib.lib)/.lib文件中僅僅是關(guān)于其對(duì)應(yīng)DLL文件中函數(shù)的重定位信息extern C _declspec(dllimport) add( int x,i nt y);聲明導(dǎo)入函數(shù)int mai n()int result = add(2,3);cout result ven dl;return 0;注意:(1卜在編寫(xiě)dll文件時(shí),必須以某種方式聲明導(dǎo)出函數(shù)(dll文件內(nèi)有導(dǎo)出函數(shù)和內(nèi)部函數(shù)兩種,內(nèi)部函數(shù)供 dll內(nèi)部調(diào)用),可以用自定義模塊文件(.def文件)來(lái)聲明導(dǎo)出函數(shù), 也可以使用_declspec(dllexport)前綴來(lái)聲明

10、導(dǎo)出函數(shù)。PS:.def文件除了聲明導(dǎo)出函數(shù)之外還可以消除函數(shù)修飾符的影響,并產(chǎn)生動(dòng)態(tài)鏈接庫(kù)導(dǎo)入庫(kù)(.lib文件)(2) 、在顯示調(diào)用dll時(shí),只需要.dll文件即可,而且只能通過(guò)函數(shù)指針來(lái)調(diào)用dll中的導(dǎo)出函數(shù)。在隱式調(diào)用dll時(shí),要將相應(yīng)的.lib文件加入到工程中,并且在調(diào)用dll的導(dǎo)出函數(shù)之前,必須對(duì)使用的函數(shù)進(jìn)行聲明(或者包含進(jìn)相應(yīng)的dll文件的頭文件也可)。(3) 、.def文件只在生成dll的過(guò)程中起作用,在應(yīng)用程序調(diào)用dll時(shí),不起作用。?DLL的調(diào)用方法1. 動(dòng)態(tài)鏈接庫(kù)(Dynamic Link Library),簡(jiǎn)稱(chēng) DLL。DLL 是一個(gè)包含可由多個(gè)程序同時(shí)使用的代碼和數(shù)據(jù)

11、的庫(kù)。它允許程序共享執(zhí)行特殊任務(wù)所必需的代碼和其他資源,一般來(lái)說(shuō),DLL是一種磁盤(pán)文件,以.dll 、.DRV、.FON、.SYS和許多以.EXE為擴(kuò)展名的系統(tǒng)文件都可在運(yùn)行時(shí)被系統(tǒng)加載到以是DLL。它由全局?jǐn)?shù)據(jù)、服務(wù)函數(shù)和資源組成,調(diào)用進(jìn)程的虛擬空間中,成為調(diào)用進(jìn)程的一部分。DLL的調(diào)用可以分為兩 種:一種是隱式調(diào)用,一種是顯示調(diào)用 這里簡(jiǎn)單分享DLL的兩種調(diào)用方 法。隱式的調(diào)用這種調(diào)用方式需要把產(chǎn)生動(dòng)態(tài)連接庫(kù)時(shí)產(chǎn)生的丄IB文件加入到應(yīng)用程序 的工程中,在使用DLL中的函數(shù)時(shí),只須聲明一下后就可以直接通過(guò)函 數(shù)名調(diào)用DLL的輸出函數(shù),調(diào)用方法和程序內(nèi)部其他的函數(shù)是一樣的。 隱式調(diào)用不需要調(diào)用

12、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ò)隱式調(diào)用方式編譯生成應(yīng)用程序時(shí),應(yīng)用程序中的調(diào)用函數(shù)與LIB文件中導(dǎo)出符號(hào)相匹配,這些符號(hào)或標(biāo)識(shí)號(hào)被寫(xiě)入到生成的 EXE文件中。LIB文件中也包含了對(duì)應(yīng)的DLL文件名(但不是完全的路 徑名),鏈接程序也將其存儲(chǔ)在 EXE文件內(nèi)部。當(dāng)應(yīng)用程序運(yùn)行過(guò)程中 需要加載DLL文件時(shí),Windows根據(jù)這些信息發(fā)現(xiàn)并

13、加載 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)存中。顯式調(diào)用這種調(diào)用方式是指在應(yīng)用程序中用 LoadLibrary 或MFC提供的AfxLoadLibrary顯式的將自己所做的動(dòng)態(tài)連接庫(kù)調(diào)進(jìn)來(lái),并指定 DLL的路徑作為參數(shù)。LoadLibary 返回HINSTANCE參數(shù),應(yīng)用程序在調(diào) 用GetProcAddress函數(shù)時(shí)使用這一參數(shù)。當(dāng)完成對(duì)動(dòng)態(tài)鏈接庫(kù)的導(dǎo)入以后,再使用GetProcAddress() 獲取想要引入的函數(shù),該函數(shù)將 符號(hào)名或標(biāo)識(shí)號(hào)轉(zhuǎn)換為DLL內(nèi)部的地址,之后就可以象使用 本應(yīng)用程序自

14、定義的函數(shù)一樣來(lái)調(diào)用此引入函數(shù)了。在應(yīng)用程序退出之前,應(yīng)該用FreeLibrary 或MFC提供的AfxFreeLibrary 釋放動(dòng)態(tài)連接 庫(kù)。DLL的優(yōu)點(diǎn)簡(jiǎn)單的說(shuō),dll有以下幾個(gè)優(yōu)點(diǎn):1)節(jié)省內(nèi)存。同一個(gè)軟件模塊,若是以源代碼的形式重用,則會(huì)被編譯到不同的可執(zhí)行程序中,同時(shí)運(yùn)行這些exe時(shí)這些模塊的二進(jìn)制碼會(huì)被重復(fù)加載到內(nèi)存中。女口果使用dll ,則只在內(nèi)存中加載一次,所有使用 該dll的進(jìn)程會(huì)共享此塊內(nèi)存(當(dāng)然,像 dll中的全局變量這種東西是 會(huì)被每個(gè)進(jìn)程復(fù)制一份的)。2)不需編譯的軟件系統(tǒng)升級(jí),若一個(gè)軟件系統(tǒng)使用了dll ,則該dll被改變(函數(shù)名不變)時(shí),系統(tǒng)升級(jí)只需要更換此dl

15、l即可,不需要重新編譯整個(gè)系統(tǒng)。事實(shí)上,很多軟件都是以這種方式升級(jí)的。例如我們經(jīng)常玩的星際、魔獸等游戲也是這樣進(jìn)行版本升級(jí)的3) Dll庫(kù)可以供多種編程語(yǔ)言使用,例如用 c編寫(xiě)的dll可以在vb中 調(diào)用。這一點(diǎn)上DLL還做得很不夠,因此在dll的基礎(chǔ)上發(fā)明了 COM技 術(shù),更好的解決了一系列問(wèn)題。顯示/隱式加載dll例子:首先生成dll文件項(xiàng)目屬性,配置屬性,常規(guī),配置類(lèi)型,動(dòng)態(tài)庫(kù)(dll)dll.hint add(i nt left, int right);dll.cpp#in cludedll.hint add(i nt left, int right)retur n left+right

16、;然后會(huì)在相應(yīng)工程目錄debug目錄下找到dll和lib 文件調(diào)用dll把dll.h XXX.dll XXX.lib文件拷貝到新工程目錄下加載dll.h 到工程里,下面開(kāi)始使用dllimport.cpp#in cludedll.h/顯示加載無(wú)需lib文件HINSTANCE hi nsta nee = LoadLibrary(XXX.dll);typedef int (*_add) (in t left, int right);_add addofdll = (_add)GetProAddress(hinstanee,add);/隱式加載需要lib 一起只用#prama comme nt(lib

17、, XXX.lib);F面可以正常使用add或者addofdll 兩個(gè)函數(shù)了當(dāng)函數(shù)功能比較小的時(shí)候,其實(shí)可以不用dll ,直接用靜態(tài)連接庫(kù)lib雖然它可以使得最后的exe文件變大項(xiàng)目屬性,配置屬性,常規(guī),配置類(lèi)型,靜態(tài)庫(kù)(lib)定義都和一樣,使用的時(shí)候直接根據(jù) XXX.h文件找到你想使用的函數(shù),然后 #prama comme nt(lib, XXX.lib);后便可使用。動(dòng)態(tài)庫(kù)的創(chuàng)建:1在VC里創(chuàng)建一個(gè) Win32項(xiàng)目,比如項(xiàng)目名稱(chēng)叫 MyTestDLL,選擇DLL和空項(xiàng)目,確定,一個(gè)空的 DLL工程便創(chuàng)建好;2添加頭文件和源文件以及def文件,之所以使用def文件,是因?yàn)閷?duì)于C+里面的函數(shù)

18、,編譯器會(huì)生成原函數(shù)名不同的名字,使用def文件可以直接避免這個(gè)問(wèn)題,也不需要定義 _declspec(dllexport)和declspec(dllimport)這些修飾符。定義要在DLL里包含的函數(shù),比如:int Add(i nt a, i nt b)return a + b;在def文件里,添加要導(dǎo)出的函數(shù)名,如下格式: 然后編譯工程,就會(huì)生成 MyTestDLL.dll 和MyTestDLL.lib 這兩個(gè)文件。對(duì)于動(dòng)態(tài)庫(kù)的顯示調(diào)用,在編譯時(shí),直接使用一個(gè)dll文件,然后在程序中LoadLibrary 即可。對(duì)于隱式調(diào)用,在編譯時(shí),需要同時(shí)有頭文件、dll文件和lib文件,并且也需要和

19、調(diào)用靜態(tài)庫(kù)一樣,使用預(yù)處理指令#pragma comme nt(lib, lib name)靜態(tài)庫(kù)的創(chuàng)建很簡(jiǎn)單,在調(diào)用工程中,編譯時(shí),只需要頭文件和lib文件,也需要上面的預(yù)處理指令,注意,“l(fā)ibname可以帶也可以不帶“.lib ” 后綴。對(duì)于動(dòng)態(tài)庫(kù),調(diào)用工程不管編譯時(shí)采用的是隱式還是顯示, 運(yùn)行時(shí)都需要dll文件;對(duì)于靜態(tài)庫(kù),調(diào)用工程則不需要在運(yùn)行期引用靜態(tài)庫(kù)文件動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)和運(yùn)行時(shí)庫(kù)和引入庫(kù)的區(qū)別1。運(yùn)行時(shí)庫(kù):Unix中一個(gè)典型的運(yùn)行時(shí)庫(kù)例子就是libc ,它包含標(biāo)準(zhǔn) 的C函數(shù),如,print() ,exit()等等,用戶(hù)能創(chuàng)建他們自己的運(yùn)行庫(kù)(在Windows中是DLL),而具體的

20、細(xì)節(jié)依賴(lài)編譯器和操作系統(tǒng)的。2。 靜態(tài)庫(kù):函數(shù)和數(shù)據(jù)被編譯進(jìn)一個(gè)二進(jìn)制文件(通常擴(kuò)展名為ib ), 靜態(tài)庫(kù)實(shí)際上是在鏈接時(shí)被鏈接到 EXE的,庫(kù)本身不需要與可執(zhí)行文件 一起發(fā)行。3。動(dòng)態(tài)庫(kù):用VC+創(chuàng)建的動(dòng)態(tài)庫(kù)包含兩個(gè)文件,一個(gè)lib 文件和一個(gè) dll文件,這個(gè)lib文件就是引入庫(kù),不是靜態(tài)庫(kù),引入庫(kù)有時(shí)也叫輸入庫(kù)或?qū)霂?kù)。注:windows操作系統(tǒng)下動(dòng)態(tài)庫(kù)和運(yùn)行時(shí)庫(kù)的擴(kuò)展名都是.dll ,COM組 件的擴(kuò)展名也是.dll ,動(dòng)態(tài)庫(kù)的引入庫(kù)和靜態(tài)庫(kù)的擴(kuò)展名都是.lib 。windows下調(diào)用動(dòng)態(tài)庫(kù)的方法:1。 隱式加載:即在程序中包含lib文件和.h文件|,隱式鏈接有時(shí)稱(chēng)為 靜態(tài)加載或加載時(shí)

21、動(dòng)態(tài)鏈接。例如:#in elude somedll.h#pragma comme nt( lib, somedll.lib)然后就可以直接調(diào)用此dll中的函數(shù),注意運(yùn)行時(shí)仍然需要 somedll.dll 。2。顯示加載:使用 loadlibrary , GetProcAddress,FreeLibrary,不需要.h文件和.lib文件,但是要知道函數(shù)的原型。顯式鏈接有時(shí)稱(chēng)為動(dòng)態(tài)加載或運(yùn)行時(shí)動(dòng)態(tài)鏈接。3。區(qū)別:如果在進(jìn)程啟動(dòng)時(shí)未找到 DLL,操作系統(tǒng)將終止使用隱式鏈接的進(jìn)程。同樣是在此情況下,使用顯式鏈接的進(jìn)程則不會(huì)被終止,并可以嘗試從錯(cuò)誤中恢復(fù)。有關(guān)Win32 DLL ,Unix共享庫(kù)及普通庫(kù)

22、的詳細(xì)庫(kù)結(jié)構(gòu)信息請(qǐng)參考鏈接器與加載器一書(shū)。MSDN1。確定要使用的鏈接方法:有兩種類(lèi)型的鏈接:隱式鏈接和顯式鏈接。隱式鏈接應(yīng)用程序的代碼調(diào)用導(dǎo)出 DLL函數(shù)時(shí)發(fā)生隱式鏈接。當(dāng)調(diào)用可執(zhí)行文件 的源代碼被編譯或被匯編時(shí),DLL函數(shù)調(diào)用在對(duì)象代碼中生成一個(gè)外部 函數(shù)引用。若要解析此外部引用,應(yīng)用程序必須與DLL的創(chuàng)建者所提供的導(dǎo)入庫(kù)(丄IB 文件)鏈接。導(dǎo)入庫(kù)僅包含加載DLL的代碼和實(shí)現(xiàn)DLL函數(shù)調(diào)用的代碼。在導(dǎo)入庫(kù) 中找到外部函數(shù)后,會(huì)通知鏈接器此函數(shù)的代碼在DLL中。要解析對(duì)DLL的外部引用,鏈接器只需向可執(zhí)行文件中添加信息,通知系統(tǒng)在進(jìn) 程啟動(dòng)時(shí)應(yīng)在何處查找DLL代碼。系統(tǒng)啟動(dòng)包含動(dòng)態(tài)鏈接引用

23、的程序時(shí),它使用程序的可執(zhí)行文件中的信息 定位所需的DLL。如果系統(tǒng)無(wú)法定位DLL,它將終止進(jìn)程并顯示一個(gè)對(duì) 話(huà)框來(lái)報(bào)告錯(cuò)誤。否則,系統(tǒng)將 DLL模塊映射到進(jìn)程的地址空間中。如果任何 DLL 具有(用于初始化代碼和終止代碼的)入口點(diǎn)函數(shù),操作 系統(tǒng)將調(diào)用此函數(shù)。 在傳遞到入口點(diǎn)函數(shù)的參數(shù)中, 有一個(gè)指定用以指示 DLL 正在附帶到進(jìn)程的代碼。如果入口點(diǎn)函數(shù)沒(méi)有返回 TRUE ,系統(tǒng)將 終止進(jìn)程并報(bào)告錯(cuò)誤。最后,系統(tǒng)修改進(jìn)程的可執(zhí)行代碼以提供 DLL 函數(shù)的起始地址。與程序代碼的其余部分一樣, DLL 代碼在進(jìn)程啟動(dòng)時(shí)映射到進(jìn)程的地址 空間中,且僅當(dāng)需要時(shí)才加載到內(nèi)存中。因此,由 .def 文件

24、用來(lái)在 Windows 的早期版本中控制加載的 PRELOAD 和 LOADONCALL 代碼 屬性不再具有任何意義。顯式鏈接大部分應(yīng)用程序使用隱式鏈接, 因?yàn)檫@是最易于使用的鏈接方法。 但是有 時(shí)也需要顯式鏈接。下面是一些使用顯式鏈接的常見(jiàn)原因:直到運(yùn)行時(shí),應(yīng)用程序才知道需要加載的 DLL 的名稱(chēng)。例如,應(yīng)用程序 可能需要從配置文件獲取 DLL 的名稱(chēng)和導(dǎo)出函數(shù)名。如果在進(jìn)程啟動(dòng)時(shí)未找到 DLL ,操作系統(tǒng)將終止使用隱式鏈接的進(jìn)程。 同樣是在此情況下, 使用顯式鏈接的進(jìn)程則不會(huì)被終止, 并可以嘗試從錯(cuò) 誤中恢復(fù)。例如,進(jìn)程可通知用戶(hù)所發(fā)生的錯(cuò)誤,并讓用戶(hù)指定 DLL 的 其他路徑。如果使用隱

25、式鏈接的進(jìn)程所鏈接到的 DLL 中有任何 DLL 具有失敗的DllMain 函數(shù),該進(jìn)程也會(huì)被終止。同樣是在此情況下,使用顯式鏈接 的進(jìn)程則不會(huì)被終止。因?yàn)?Windows 在應(yīng)用程序加載時(shí)加載所有的 DLL ,故隱式鏈接到許多 DLL 的應(yīng)用程序啟動(dòng)起來(lái)會(huì)比較慢。為提高啟動(dòng)性能,應(yīng)用程序可隱式 鏈接到那些加載后立即需要的 DLL ,并等到在需要時(shí)顯式鏈接到其他 DLL。顯式鏈接下不需將應(yīng)用程序與導(dǎo)入庫(kù)鏈接。 如果 DLL 中的更改導(dǎo)致導(dǎo)出 序號(hào)更改, 使用顯式鏈接的應(yīng)用程序不需重新鏈接 (假設(shè)它們是用函數(shù)名 而不是序號(hào)值調(diào)用 GetProcAddress ),而使用隱式鏈接的應(yīng)用程序必 須重

26、新鏈接到新的導(dǎo)入庫(kù)。下面是需要注意的顯式鏈接的兩個(gè)缺點(diǎn):如果 DLL 具有 DllMain 入口點(diǎn)函數(shù),則操作系統(tǒng)在調(diào)用LoadLibrary 的線(xiàn)程上下文中調(diào)用此函數(shù)。如果由于以前調(diào)用了LoadLibrary 但沒(méi)有相應(yīng)地調(diào)用 FreeLibrary 函數(shù)而導(dǎo)致 DLL 已 經(jīng)附加到進(jìn)程, 則不會(huì)調(diào)用此入口點(diǎn)函數(shù)。 如果 DLL 使用 DllMain 函 數(shù)為進(jìn)程的每個(gè)線(xiàn)程執(zhí)行初始化,顯式鏈接會(huì)造成問(wèn)題,因?yàn)檎{(diào)用 LoadLibrary (或 AfxLoadLibrary )時(shí)存在的線(xiàn)程將不會(huì)初始化。如果 DLL 將靜態(tài)作用域數(shù)據(jù)聲明為 _declspec(thread),則在顯式 鏈接時(shí)

27、DLL 會(huì)導(dǎo)致保護(hù)錯(cuò)誤。用 LoadLibrary 加載 DLL 后,每當(dāng)代碼引用此數(shù)據(jù)時(shí)DLL就會(huì)導(dǎo)致保護(hù)錯(cuò)誤。(靜態(tài)作用域數(shù)據(jù)既包括全局靜態(tài)項(xiàng),也包括局部靜態(tài)項(xiàng)。)因此,創(chuàng)建 DLL時(shí)應(yīng)避免使用線(xiàn)程本 地存儲(chǔ)區(qū),或者應(yīng)(在用戶(hù)嘗試動(dòng)態(tài)加載時(shí))告訴DLL用戶(hù)潛在的缺陷。2。隱式鏈接:為隱式鏈接到DLL,可執(zhí)行文件必須從DLL的提供程序獲取下列各項(xiàng):包含導(dǎo)出函數(shù)和/或C+類(lèi)的聲明的頭文件(.h文件)。類(lèi)、函數(shù)和數(shù),有關(guān)更多信息,請(qǐng)參見(jiàn)據(jù)均應(yīng)具有 declspec(dllimport)dllexport, dllimport要鏈接的導(dǎo)入庫(kù)(.LIB files )|。(生成DLL時(shí)鏈接器創(chuàng)建導(dǎo)入

28、庫(kù)。)實(shí)際的DLL ( .dll 文件)使用DLL的可執(zhí)行文件必須包括頭文件,此頭文件包含每個(gè)源文件中的 導(dǎo)出函數(shù)(或C+類(lèi)),而這些源文件包含對(duì)導(dǎo)出函數(shù)的調(diào)用。從編碼 的角度講,導(dǎo)出函數(shù)的函數(shù)調(diào)用與任何其他函數(shù)調(diào)用一樣。若要生成調(diào)用可執(zhí)行文件,必須與導(dǎo)入庫(kù)鏈接。如果使用的是外部生成文 件,請(qǐng)指定導(dǎo)入庫(kù)的文件名,此導(dǎo)入庫(kù)中列出了要鏈接到的其他對(duì)象(.obj)文件或庫(kù)。操作系統(tǒng)在加載調(diào)用可執(zhí)行文件時(shí),必須能夠定位DLL文件。3。顯式鏈接:DLL在顯式鏈接下,應(yīng)用程序必須進(jìn)行函數(shù)調(diào)用以在運(yùn)行時(shí)顯式加載為顯式鏈接到 DLL ,應(yīng)用程序必須:調(diào)用 LoadLibrary (或相似的函數(shù))以加載 DLL

29、 和獲取模塊句柄。調(diào)用 GetProcAddress ,以獲取指向應(yīng)用程序要調(diào)用的每個(gè)導(dǎo)出函數(shù)的 函數(shù)指針。由于應(yīng)用程序是通過(guò)指針調(diào)用 DLL 的函數(shù),編譯器不生成外 部引用,故無(wú)需與導(dǎo)入庫(kù)鏈接。使用完 DLL 后調(diào)用 FreeLibrary 。typedef UINT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT);HINSTANCE hDLL; / Handle to DLLLPFNDLLFUNC1 lpfnDllFunc1; / Function pointerDWORD dwParam1;UINT uParam2, uReturnVal;hDLL = Load

30、Library(MyDLL);if (hDLL != NULL)lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL,DLLFunc1);if (!lpfnDllFunc1)/ handle the errorFreeLibrary(hDLL);return SOME_ERROR_CODE;else/ call the functionuReturnVal = IpfnDlIFu nc1(dwParam1, uParam2); 4。將可執(zhí)行文件鏈接到DLL可執(zhí)行文件以下列兩種方式之一鏈接到(或加載)DLL:隱式鏈接顯式鏈接隱式鏈接有時(shí)稱(chēng)為靜態(tài)加載或加

31、載時(shí)動(dòng)態(tài)鏈接。顯式鏈接有時(shí)稱(chēng)為動(dòng)態(tài)加 載或運(yùn)行時(shí)動(dòng)態(tài)鏈接。在隱式鏈接下,使用DLL的可執(zhí)行文件鏈接到該DLL的創(chuàng)建者所提供 的導(dǎo)入庫(kù)(ib 文件)。使用DLL的可執(zhí)行文件加載時(shí),操作系統(tǒng)加 載此DLL??蛻?hù)端可執(zhí)行文件調(diào)用DLL的導(dǎo)出函數(shù),就好像這些函數(shù)包 含在可執(zhí)行文件內(nèi)一樣。在顯式鏈接下,使用DLL的可執(zhí)行文件必須進(jìn)行函數(shù)調(diào)用以顯式加載和 卸載該DLL,并訪(fǎng)問(wèn)該DLL的導(dǎo)出函數(shù)??蛻?hù)端可執(zhí)行文件必須通過(guò)函 數(shù)指針調(diào)用導(dǎo)出函數(shù)??蓤?zhí)行文件對(duì)兩種鏈接方法可以使用同一個(gè)DLL。另外,由于一個(gè)可執(zhí)行文件可隱式鏈接到某個(gè) DLL,而另一個(gè)可顯式附加到此 DLL,故這些 機(jī)制不是互斥的。vc調(diào)用dll

32、調(diào)用DLL,首先需要將DLL文件映像到用戶(hù)進(jìn)程的地址空間中,然后才能進(jìn)行函數(shù)調(diào)用,這個(gè)函數(shù)和進(jìn)程內(nèi)部一般函數(shù)的調(diào)用方法相同。Windows提供了兩種將DLL映像到進(jìn)程地址空間的方法:1.隱式的加載時(shí)鏈接這種方法需要DLL工程經(jīng)編譯產(chǎn)生的LIB文件,此文件中包含了 DLL允許應(yīng)用程序調(diào)用的所有函數(shù)的列表,當(dāng)鏈接器發(fā)現(xiàn)應(yīng)用程序調(diào)用了LIB文件列出的某個(gè)函數(shù),就會(huì)在應(yīng)用程序的可執(zhí)行文件的文件映像中加入一些信息,這些信息指出了包含這個(gè)函數(shù)的DLL文件的名字。當(dāng)這個(gè)應(yīng)用程序運(yùn)行時(shí),也就是它的可執(zhí)行文件被操作系統(tǒng)產(chǎn)生映像文件時(shí),系統(tǒng)會(huì)查看這個(gè)映像文件中關(guān)于 DLL的信息,然后將這個(gè) DLL文件映像到進(jìn)程的

33、地址空間。系統(tǒng)通過(guò)DLL文件的名稱(chēng),試圖加載這個(gè)文件到進(jìn)程地址空間時(shí),它尋找DLL文件的路徑按照先后順序如下:程序運(yùn)行時(shí)的目錄,即可執(zhí)行文件所在的目錄;當(dāng)前程序工作目錄系統(tǒng)目錄:對(duì)于Windows95/98 來(lái)說(shuō),可以調(diào)用 GetSystemDirectory函數(shù)來(lái)得到,對(duì)于WindowsNT/2000來(lái)說(shuō),指的是 32位 Windows的系統(tǒng)目錄,也可以調(diào)用 GetSystemDirectory 函數(shù)來(lái)得到,得到的值為SYSTEM32 Windows 目錄列在PATH環(huán)境變量中的所有目錄VC中加載DLL的LIB文件的方法有以下三種: LIB文件直接加入到工程文件列表中在VC中打開(kāi)File V

34、iew 一頁(yè),選中工程名,單擊鼠標(biāo)右鍵,然后選中“Add Files to Project ”菜單,在彈出的文件對(duì)話(huà)框中選中要加入DLL的LIB文件即可。 設(shè)置工程的 Project Sett in gs來(lái)加載 DLL的LIB文件打開(kāi)工程的 Project Settings菜單,選中Link,然后在 Object/library modules下的文本框中輸 入DLL的LIB文件。 通過(guò)程序代碼的方式加入預(yù)編譯指令#pragma comment (lib, ” *ib ,這種方法優(yōu)點(diǎn)是可以利用條件預(yù)編譯指令鏈接不同版本的LIB文件。因?yàn)?,在Debug方式下,產(chǎn)生的LIB文件是Debug版本,如

35、Regd.lib;在Release方式下,產(chǎn)生的 LIB文件是Release版本,如 Regr.lib。當(dāng)應(yīng)用程序?qū)?DLL的LIB文件加載后,還需要把DLL對(duì)應(yīng)的頭文件(*.h )包含到其中,在這個(gè)頭文件中給出了 DLL中定義的函數(shù)原型,然后聲明。2顯式的運(yùn)行時(shí)鏈接,(我用的是此方法)隱式鏈接雖然實(shí)現(xiàn)較簡(jiǎn)單,但除了必須的 *.dll文件外還需要 DLL的*.h文件和*.lib文件,在 那些只提供*.dll文件的場(chǎng)合就無(wú)法使用,而只能采用顯式鏈接的方式。這種方式通過(guò)調(diào)用API函數(shù)來(lái)完成對(duì)DLL的加載與卸載,其能更加有效地使用內(nèi)存,在編寫(xiě)大型應(yīng)用程序時(shí)往 往采用此方式。這種方法編程具體實(shí)現(xiàn)步驟如

36、下: 使用 Windows API函數(shù)Load Library或者 MFC提供的 AfxLoadLibrary將DLL模塊映像到進(jìn) 程的內(nèi)存空間,對(duì) DLL模塊進(jìn)行動(dòng)態(tài)加載。 使用GetProcAddress函數(shù)得到要調(diào)用 DLL中的函數(shù)的指針。 不用DLL時(shí),用Free Library函數(shù)或者AfxFreeLibrary函數(shù)從進(jìn)程的地址空間顯式卸載DLL。extern c與.def文件的作用首先,我們需要知道 C和C+編譯器對(duì)函數(shù)名字的處理方式是不一樣的;其次,就是同為C編譯器的兩個(gè)不同產(chǎn)品, 在編譯時(shí)對(duì)函數(shù)名字的處理方式也是有區(qū)別的,比如microsoft vc+與dev C+。所以,ex

37、tern C與.def文件正是為了解決這兩種情況而引入的處理方法。第一、extern C的作用比如一個(gè)C源程序A.c要使用C+編寫(xiě)的庫(kù)函數(shù), 在A.c中#include B.h,其中B.h中有 要使用的函數(shù)的原形聲明func。當(dāng)編譯鏈接源程序時(shí),卻發(fā)現(xiàn)了“鏈接錯(cuò)誤,未決的外部符號(hào)”的錯(cuò)誤,這是什么原因呢?原因就是,C編譯器編譯A.c時(shí),將func編譯為func,當(dāng)鏈接時(shí)鏈接器去 C+庫(kù)中尋找func, 但是C+的編譯器在編譯庫(kù)時(shí)將func編譯成_funcyyyrrr,自然鏈接器就找不著相應(yīng)的函數(shù)的信息了,所以就會(huì)報(bào)錯(cuò)!有什么辦法可以處理這種情況呢?一一可以在編寫(xiě)C+庫(kù)的時(shí)候,為每一個(gè)函數(shù)(或?qū)?/p>

38、出函數(shù))加上extern C,它的含義是告知 C+編譯器在編譯這些函數(shù)的時(shí)候,以C編譯器的方式處理函數(shù)名。這樣生成的庫(kù)中的函數(shù)名字就是func 了,當(dāng)C程序調(diào)用庫(kù)函數(shù),編譯鏈接時(shí),鏈接器就能找到期望的信息,則鏈接成功。 第二、.def文件的作用(僅與 VC+編程相關(guān))前面提到,不同廠商開(kāi)發(fā)的兩個(gè) C編譯器也會(huì)有一些差異,最突出的就是 microsoft的 C編譯器,它對(duì)函數(shù)名字的處理很特別(究竟是什么樣子,可以使用Dumpbin工具查看dll的導(dǎo)出函數(shù)),所以要在使用他方編寫(xiě)的庫(kù)時(shí),程序鏈接能成功,有兩種方法:1使用庫(kù)編寫(xiě)者使用的C編譯器(這里指VC+),顯然這種方法不合理;2庫(kù)的編寫(xiě)者在使用

39、 VC+編寫(xiě) 庫(kù)時(shí)使用.def文件。.def文件的作用即是,告知編譯器不要以microsoft編譯器的方式處理函數(shù)名,而以指定的某方式編譯導(dǎo)出函數(shù)(比如有函數(shù)func,讓編譯器處理后函數(shù)名仍為func)。這樣,就可以避免由于microsoft VC+編譯器的獨(dú)特處理方式而引起的鏈接錯(cuò)誤。用.def文件描述dll的輸出函數(shù),比如EXPORTSDllFu n1 1 NONAMEDllFu n2 2 NONAMEDllFu n3 3 NONAMEDllFu n4 4 NONAME后面是dll輸出函數(shù)的順序號(hào),順序號(hào)要求在1到max(函數(shù)個(gè)數(shù))之間。用.def聲明了輸出函數(shù)以后,不要在頭文件里再聲明A

40、FX EXT AP或者是dllexport之類(lèi)的聲明,而用extern C聲明了輸出函數(shù)以后,要引用原來(lái)輸出函數(shù)的頭文件。如果不是用externC聲明的(包括用.def聲明的),那么頭文件里無(wú)需用AFX_EXT_AP或者是dllexport之類(lèi)的聲明。.def文件的作用的。如果DLL是提供給VC+用戶(hù)使用的,你只需要把編譯DLL時(shí)產(chǎn)生的.lib提供給用戶(hù),它可以很輕松地調(diào)用你的DLL。但是如果你的DLL是供其他程序如 VB、delphi,以及.NET用戶(hù)使用的,那么會(huì)產(chǎn)生一個(gè)小麻煩。因?yàn)閂C+對(duì)于_declspec(dllexport)聲明的函數(shù)會(huì)進(jìn)行名稱(chēng)轉(zhuǎn)換,如下面的函數(shù):_declspec

41、(dllexport) int _stdcall IsWi nN T()會(huì)轉(zhuǎn)換為IsWinNT0,這樣你在 VB中必須這樣聲明:Declare Function IsWinNT Lib my.dll Alias IsWinNT0 () As Long的后面的數(shù)由于參數(shù)類(lèi)型不同而可能不同。這顯然不太方便。所以如果要想避免這種轉(zhuǎn)換,就要使用.def文件方式。EXPORTS面的數(shù)可以不給,系統(tǒng)會(huì)自動(dòng)分配一個(gè)數(shù)。對(duì)于VB、PB、Delphi用戶(hù),通常使用按名稱(chēng)進(jìn)行調(diào)用的方式,這個(gè)數(shù)關(guān)系不大,但是對(duì)于使用ib鏈接的VC程序來(lái)說(shuō),不是按名稱(chēng)進(jìn)行調(diào)用,而是按照這個(gè)數(shù)進(jìn)行調(diào)用的,所以最好給出。例子:我們用 V

42、C6.0制作一個(gè)dll,不使用.def文件,在頭文件中這樣寫(xiě)#ifndef LIB_H#defi ne LIB_Hexter n C int _declspec(dllexport)add(i nt x,i nt y);#en dif如果是.def文件,可以這樣LIBRARY xxx_dllEXPORTSadd PRIVAT動(dòng)態(tài)鏈接庫(kù)(Dynamic Link Library)學(xué)習(xí)筆記我對(duì)動(dòng)態(tài)鏈接和動(dòng)態(tài)鏈接庫(kù)的概念并不陌,但一直以來(lái)就停留在概念的層面上,沒(méi)有 更深入的了解。今天抽空看了一下有關(guān)動(dòng)態(tài)鏈接和動(dòng)態(tài)鏈接庫(kù)的文章,有了一些新的認(rèn)識(shí), 當(dāng)然不能忘了寫(xiě)在這里。那么現(xiàn)在就開(kāi)始 什么是動(dòng)態(tài)鏈接和

43、動(dòng)態(tài)鏈接庫(kù)動(dòng)態(tài)鏈接(Dynamic Linking)是相對(duì)于靜態(tài)鏈接(Static Linking)而言的。程序設(shè)計(jì)中, 為了能做到代碼和模塊的重用,程序設(shè)計(jì)者常常將常用的功能函數(shù)做成庫(kù),當(dāng)程序需要實(shí)現(xiàn)某種功能時(shí),就直接調(diào)用庫(kù)文件中的函數(shù),從而實(shí)現(xiàn)了代碼的重用。早期的程序設(shè)計(jì)中,可 重用的函數(shù)模塊以編譯好的二進(jìn)制代碼形式放于靜態(tài)庫(kù)文件中,在MS的操作系統(tǒng)中是 Lib為后綴的文件。程序編寫(xiě)時(shí),如果用戶(hù)程序調(diào)用到了靜態(tài)庫(kù)文件中的函數(shù),則在程序編譯時(shí),編譯器會(huì)自動(dòng)將相關(guān)函數(shù)的二進(jìn)制代碼從靜態(tài)庫(kù)文件中復(fù)制到用戶(hù)目標(biāo)程序,與目標(biāo)程序一編譯成可執(zhí)行文件。這樣做的確在編碼階段實(shí)現(xiàn)了代碼的重用,減輕了程序設(shè)計(jì)

44、者的負(fù)擔(dān),但并未在執(zhí)行期實(shí)現(xiàn)重用。如一個(gè)程序a.exe使用了靜態(tài)庫(kù)中的f()函數(shù),那么當(dāng)a.exe有多個(gè)實(shí)例運(yùn)行時(shí),內(nèi)存中實(shí)際上存在了多份f()的拷貝,造成了內(nèi)存的浪費(fèi)。隨著技術(shù)的進(jìn)步,出現(xiàn)了新的鏈接方式,即動(dòng)態(tài)鏈接,從根本上解決了靜態(tài)鏈接方式帶來(lái)的問(wèn)題。動(dòng)態(tài)鏈接的處理方式與靜態(tài)鏈接很相似,同樣是將可重用代碼放在一個(gè)單獨(dú)的庫(kù)文件中(在MS的操作系統(tǒng)中是以dll為后綴的文件,Linux下也有動(dòng)態(tài)鏈接庫(kù),被稱(chēng)為Shared Object的so文件),所不同的是編譯器在編譯調(diào)用了動(dòng)態(tài)鏈接庫(kù)的程序時(shí)并不將庫(kù)文件中的 函數(shù)執(zhí)行體復(fù)制到可執(zhí)行文件中,而是只在可執(zhí)行文件中保留一個(gè)函數(shù)調(diào)用的標(biāo)記。當(dāng)程序運(yùn)行時(shí)

45、,才由操作系統(tǒng)將動(dòng)態(tài)鏈接庫(kù)文件一并加載入內(nèi)存,并映射到程序的地址空間中,這樣就保證了程序能夠正常調(diào)用到庫(kù)文件中的函數(shù)。同時(shí)操作系統(tǒng)保證當(dāng)程序有多個(gè)實(shí)例運(yùn)行時(shí),動(dòng)態(tài)鏈接庫(kù)也只有一份拷貝在內(nèi)存中,也就是說(shuō)動(dòng)態(tài)鏈接庫(kù)是在運(yùn)行期共享的。使用動(dòng)態(tài)鏈接方式帶來(lái)了幾大好處:首先是動(dòng)態(tài)鏈接庫(kù)和用戶(hù)程序可以分開(kāi)編寫(xiě),這 里的分開(kāi)即可以指時(shí)間和空間的分開(kāi),也可以指開(kāi)發(fā)語(yǔ)言的分開(kāi),這樣就降低了程序的耦合度;其次由于動(dòng)態(tài)鏈接獨(dú)特的編譯方式和運(yùn)行方式,使得目標(biāo)程序本身體積比靜態(tài)鏈接時(shí)小,同時(shí)運(yùn)行期又是共享動(dòng)態(tài)鏈庫(kù),所以節(jié)省了磁盤(pán)存儲(chǔ)空間和運(yùn)行內(nèi)存空間;最后一個(gè)是增加了程序的靈活性,可以實(shí)現(xiàn)諸如插件機(jī)制等功能。用過(guò)win

46、 amp的人都知道,它的很多功能都是以插件的形式提供的,這些插件就是一些動(dòng)態(tài)鏈接庫(kù),主程序事先規(guī)定好了調(diào)用接口, 只要是按照規(guī)定的調(diào)用接口寫(xiě)的插件,都能被winamp調(diào)用。Window 95、98、NT系列等系統(tǒng)都提供了動(dòng)態(tài)鏈接庫(kù)的功能,并且這些操作系統(tǒng)的系 統(tǒng)調(diào)用大多都是通過(guò)動(dòng)態(tài)鏈接庫(kù)實(shí)現(xiàn)的,最常見(jiàn)的NT系列 OS中的 KENEL32.dll,USER32.dll,GDI32.dl等動(dòng)態(tài)鏈接庫(kù)文件就包含了大量的系統(tǒng)調(diào)用。在windows家族中,NT內(nèi)核的操作系統(tǒng)在動(dòng)態(tài)鏈接庫(kù)機(jī)制上較之前的95、98系統(tǒng)要更安全。95、98系統(tǒng)在程序調(diào)用動(dòng)態(tài)鏈接庫(kù)時(shí),將動(dòng)態(tài)鏈接庫(kù)加載到2G-3G之間的被稱(chēng)為進(jìn)程

47、共享空間的虛擬地址空間,并且所有進(jìn)程關(guān)于這1G的虛擬地址空間的頁(yè)表都是相同的,也就是說(shuō)對(duì)于所有的進(jìn)程,這片共享區(qū)的頁(yè)表都指向同一組物理頁(yè),這樣一來(lái),加載入內(nèi)存的的動(dòng)態(tài)鏈接庫(kù)對(duì)所有正在運(yùn)行的進(jìn)程都是可見(jiàn)的。如果一個(gè)動(dòng)態(tài)鏈接庫(kù)被其中一個(gè)進(jìn)程更改,或其自身崩潰,將影響到所有調(diào)用它的進(jìn)程,如果該動(dòng)態(tài)鏈接庫(kù)是系統(tǒng)的動(dòng)態(tài)鏈接庫(kù),那么將導(dǎo)致系統(tǒng)的崩潰。在Windows NT系統(tǒng)中,動(dòng)態(tài)鏈接庫(kù)被映射到進(jìn)程的用戶(hù)地址空間中,并用Copy OnWrite機(jī)制保證動(dòng)態(tài)鏈接庫(kù)的共享安全,Copy On Write可以理解為寫(xiě)時(shí)拷貝。一般情況下,多個(gè)運(yùn)行的進(jìn)程還是按原來(lái)的模式共享同一個(gè)動(dòng)態(tài)鏈接庫(kù),直到有進(jìn)程需要向動(dòng)態(tài)鏈

48、接庫(kù)的某個(gè)頁(yè)面寫(xiě)數(shù)據(jù)時(shí),系統(tǒng)將該頁(yè)做一個(gè)拷貝,并將新復(fù)制頁(yè)面的屬性置為可讀可寫(xiě),最后修改進(jìn)程的頁(yè)表使之指向新拷貝的物理頁(yè)。這樣無(wú)論該進(jìn)程怎么修改此頁(yè)的數(shù)據(jù),也不會(huì)影響到其他調(diào)用了此動(dòng)態(tài)鏈接庫(kù)的進(jìn)程了。Windows下動(dòng)態(tài)鏈接庫(kù)的編寫(xiě)因?yàn)楸救藢?duì)linux沒(méi)有太多研究,所以這里只介紹windwos環(huán)境下動(dòng)態(tài)鏈接庫(kù)的編寫(xiě)。在VC中新建一個(gè)空的 Win32動(dòng)態(tài)鏈接庫(kù)工程(Win32 Domanic Library),然后添加一個(gè) C+ Sourse File到工程,我這里的文件名取DIITest.cpp。然后在文件中添加如下內(nèi)容:/DIITest.cpp_declspec(dllexport) int

49、 add(i nt a,i nt b)return a+b;_declspec(dllexport) int subtract(i nt a,i nt b)return a-b;接下來(lái)編譯鏈接,就會(huì)在debug目錄下生成一個(gè)調(diào)試版本的動(dòng)態(tài)鏈接庫(kù),該鏈接庫(kù)包含了 add和subtract兩個(gè)可供外部調(diào)用的函數(shù)。我們注意到,在源文件中多了一個(gè)沒(méi)有見(jiàn)過(guò)的語(yǔ)句_declspec(dllexport),這個(gè)語(yǔ)句的作用就是向編譯器指出我需要在生成的動(dòng)態(tài)鏈接 庫(kù)中導(dǎo)出的函數(shù),沒(méi)有導(dǎo)出的函數(shù)是不能被其他程序調(diào)用的。要知道一個(gè)動(dòng)態(tài)鏈接庫(kù)導(dǎo)出了什么函數(shù),可以在命令提示行用命令dumpbin -exports Dl

50、lTest.dll來(lái)查看(也可以用 VC工具包中的depends使用程序來(lái)查看)。以下是用dumpbin命令查看DllTest.dll而生成的信息:Dump of file DIITest.dllFile Type: DLLSectio n contains the followi ng exports for DIITest.dll0 characteristics4420BEA4 time date stamp Wed Mar 22 11:04:04 20060.00 vers ion1 ordinal base2 nu mber of functions2 nu mber of n am

51、esordinal hint RVAn ame10 0000100A ?addYAHHHZ21 00001005 ?subtractYAHHHZSummary7000 .data1000 .idata3000 .rdata2000 .reloc2A000 .text可以看到,我們編寫(xiě)的動(dòng)態(tài)鏈接庫(kù)導(dǎo)出了兩個(gè)函數(shù),分別名為?addYAHHHZ和?subtractYAHHH乙為什么名字不是 add和subtract呢?這是因?yàn)镃+為了支持函數(shù)重載,會(huì)在編譯時(shí)將函數(shù)的參數(shù)類(lèi)型信息以及返回值類(lèi)型信息加入到函數(shù)名中,這樣代碼中名字一樣的重載函數(shù),在經(jīng)過(guò)編譯后就互相區(qū)分開(kāi)了,調(diào)用時(shí)函數(shù)名也經(jīng)過(guò)冋樣的處理,就

52、能找到對(duì)應(yīng)的函數(shù)了。 編譯器對(duì)函數(shù)的重命名規(guī)則是與調(diào)用方式相關(guān)的,在這里采用的是C+的默認(rèn)調(diào)用方式。以此對(duì)應(yīng)的還有 stdcall方式、cdecl方式、fastcall方式和thiscall方式,不冋調(diào)用方式的重命名規(guī)則不一樣。需要特別說(shuō)一下的是stdcall方式和cdecl方式:stdcall方式(標(biāo)準(zhǔn)調(diào)用方式)也即pascal調(diào)用方式,它的重命名規(guī)則是函數(shù)名自動(dòng)加前導(dǎo)的下劃線(xiàn),后面緊跟一個(gè)符號(hào),其后緊跟著參數(shù)所占字節(jié)數(shù),之所以要跟參數(shù)字節(jié)數(shù),是因?yàn)閟tdcall采用被調(diào)函數(shù)平衡堆棧方式,用函數(shù)名最后的數(shù)字告訴編譯器需要為函數(shù)平 衡的字節(jié)數(shù)。例如,如果我們的DllTest.dll采用stdc

53、all方式編譯的話(huà),導(dǎo)出的函數(shù)名將會(huì)是_add8和_subtract8,而函數(shù)編譯后的匯編代碼最后一句一定是ret8。cdecl方式即C語(yǔ)言調(diào)用方式,它的重命名規(guī)則僅僅是在函數(shù)名前加下劃線(xiàn)(奇怪的是 我用vc6編譯的c語(yǔ)言函數(shù),名字沒(méi)有任何改變),因?yàn)镃語(yǔ)言采用的是調(diào)用函數(shù)平衡堆棧 的方式,所以不需要在函數(shù)名中加入?yún)?shù)所占的字節(jié)數(shù),這樣的堆棧平衡方式也使 C語(yǔ)言可以編寫(xiě)出參數(shù)不固定的函數(shù);同時(shí)C語(yǔ)言不支持函數(shù)重載,因此不需要在函數(shù)名中加入?yún)?shù) 類(lèi)型信息和返回值類(lèi)型信息。更多關(guān)于調(diào)用方式的介紹請(qǐng)看我收藏的文章C語(yǔ)言函數(shù)調(diào)用約定。動(dòng)態(tài)鏈接庫(kù)已經(jīng)生成了,接下來(lái)就是調(diào)用的工作了。調(diào)用動(dòng)態(tài)鏈接庫(kù)有兩種方

54、式:隱式調(diào)用和顯式調(diào)用,下面我們分別來(lái)看兩種調(diào)用方式的具體過(guò)程: 動(dòng)態(tài)鏈接庫(kù)的隱式調(diào)用新建一個(gè)空的 Win32 Console Application,命名為DllCaller,向工程中添加名為DllCaller.cpp的C+ Sourse File在文件中寫(xiě)入如下代碼:#in clude using n amespace std;/exter n int add(i nt a,i nt b);_declspec(dllimport) int add(i nt a,i nt b);int mai n()cout3+5=add(3,5)Settings-Liink,在 Object/library Modules 中加入一項(xiàng)文件名:DllTest.lib,這里的DllTest.lib并不是靜態(tài)庫(kù)文件,而是DllTest.dll的導(dǎo)入庫(kù)文件,它包含了DllTest.dll動(dòng)態(tài)鏈接庫(kù)導(dǎo)出的函數(shù)信息,只有在工程鏈接設(shè)置里添加了該文件,才能夠使調(diào)了該動(dòng)態(tài)鏈接庫(kù)的工程正確鏈接。完成以上步驟后,我們?cè)倬幾g鏈接工程, 這次沒(méi)有任何錯(cuò)誤!程序可以順利調(diào)用動(dòng)態(tài)連接庫(kù)文件,正常運(yùn)行了 (為了能使程序找到并加載需要的動(dòng)態(tài)鏈接庫(kù),動(dòng)態(tài)鏈接庫(kù)文件必須與調(diào)用程序在同一個(gè)目錄下,或在path環(huán)境變量指定的目錄下)。這里需要說(shuō)明一點(diǎn),工程中的源

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論