天行健,君子以自強(qiáng)不息; 地勢坤,君子以厚德載物
上文我簡單的介紹了如何建立一個(gè)簡單DLL,下面再我簡單的介紹一下如何使用一個(gè)DLL。當(dāng)一個(gè)DLL被生成后,它創(chuàng)建了一個(gè).dll文件和一個(gè).lib文件;這兩個(gè)都是你需要的。要使用DLL,就需要載入這個(gè)DLL。
隱式鏈接
這里有兩個(gè)方法來載入一個(gè)DLL;一個(gè)方法是捷徑另一個(gè)則相比要復(fù)雜些。捷徑是只鏈接到你.lib 文件并將.dll文件置入你的新項(xiàng)目的路徑中去。因此,創(chuàng)建一個(gè)新的空的Win32控制臺(tái)項(xiàng)目并添加一個(gè)源文件。將你做的DLL放入你的新項(xiàng)目相同的目錄下。
這就是載入一個(gè)DLL的簡單方法。
顯式鏈接
難點(diǎn)的加載DLL的方法稍微有點(diǎn)復(fù)雜。你將需要函數(shù)指針和一些Windows函數(shù)。但是,通過這種載入DLLs的方法,你不需要DLL的.lib或頭文件,而只需要DLL。
首先你會(huì)注意到:這里包括進(jìn)了文件“windows.h”同時(shí)移走了“DLLSample.h”。原因很簡單:因?yàn)閣indows.h包含了一些Windows函數(shù),當(dāng)然你現(xiàn)在將只需要其中幾個(gè)而已。它也包含了一些將會(huì)用到的Windows特定變量。你可以去掉DLL的頭文件(DLLSample.h)因?yàn)椋缥仪懊嫠f-當(dāng)你使用這個(gè)方法載入DLL時(shí)你并不需要它。
下面你會(huì)看到:下面的一句代碼:
typedef void (*DLLFunc)(int); 這是一個(gè)函數(shù)指針類型的定義。指向一個(gè)函數(shù)是一個(gè)int型的參數(shù),返回值為void類型。
一個(gè)HINSTANCE是一個(gè)Windows數(shù)據(jù)類型:是一個(gè)實(shí)例的句柄;在此情況下,這個(gè)實(shí)例將是這個(gè)DLL。你可以通過使用函數(shù)LoadLibrary()獲得DLL的實(shí)例,它獲得一個(gè)名稱作為參數(shù)。在調(diào)用LoadLibrary函數(shù)后,你必需查看一下函數(shù)返回是否成功。你可以通過檢查HINSTANCE是否等于NULL(在Windows.h中定義為0或Windows.h包含的一個(gè)頭文件)來查看其是否成功。如果其等于NULL,該句柄將是無效的,并且你必需釋放這個(gè)庫。換句話說,你必需釋放DLL獲得的內(nèi)存。如果函數(shù)返回成功,你的HINSTANCE就包含了指向DLL的句柄。
一旦你獲得了指向DLL的句柄,你現(xiàn)在可以從DLL中重新獲得函數(shù)。為了這樣作,你必須使用函數(shù)GetProcAddress(),它將DLL的句柄(你可以使用HINSTANCE)和函數(shù)的名稱作為參數(shù)。你可以讓函數(shù)指針獲得由GetProcAddress()返回的值,同時(shí)你必需將GetProcAddress()轉(zhuǎn)換為那個(gè)函數(shù)定義的函數(shù)指針。舉個(gè)例子,對于Add()函數(shù),你必需將GetProcAddress()轉(zhuǎn)換為AddFunc;這就是它知道參數(shù)及返回值的原因。現(xiàn)在,最好先確定函數(shù)指針是否等于NULL以及它們擁有DLL的函數(shù)。這只是一個(gè)簡單的if語句;如果其中一個(gè)等于NULL,你必需如前所述釋放庫。
一旦函數(shù)指針擁有DLL的函數(shù),你現(xiàn)在就可以使用它們了,但是這里有一個(gè)需要注意的地方:你不能使用函數(shù)的實(shí)際名稱;你必需使用函數(shù)指針來調(diào)用它們。在那以后,所有你需要做的是釋放庫如此而已。
模塊句柄
進(jìn)程中的每個(gè)DLL模塊被全局唯一的32字節(jié)的HINSTANCE句柄標(biāo)識(shí)。進(jìn)程自己還有一個(gè)HINSTANCE句柄。所有這些模塊句柄都只有在特定的進(jìn)程內(nèi)部有效,它們代表了DLL或EXE模塊在進(jìn)程虛擬空間中的起始地址。在Win32中,HINSTANCE和HMODULE的值是相同的,這個(gè)兩種類型可以替換使用。進(jìn)程模塊句柄幾乎總是等于0x400000,而DLL模塊的加載地址的缺省句柄是0x10000000。如果程序同時(shí)使用了幾個(gè)DLL模塊,每一個(gè)都會(huì)有不同的HINSTANCE值。這是因?yàn)樵趧?chuàng)建DLL文件時(shí)指定了不同的基地址,或者是因?yàn)榧虞d程序?qū)LL代碼進(jìn)行了重定位。模塊句柄對于加載資源特別重要。Win32 的FindResource函數(shù)中帶有一個(gè)HINSTANCE參數(shù)。EXE和DLL都有其自己的資源。如果應(yīng)用程序需要來自于DLL的資源,就將此參數(shù)指定為DLL的模塊句柄。如果需要EXE文件中包含的資源,就指定EXE的模塊句柄。但是在使用這些句柄之前存在一個(gè)問題,你怎樣得到它們呢?如果需要得到EXE模塊句柄,調(diào)用帶有Null參數(shù)的Win32函數(shù)GetModuleHandle;如果需要DLL模塊句柄,就調(diào)用以DLL文件名為參數(shù)的Win32函數(shù)GetModuleHandle。
應(yīng)用程序怎樣找到DLL文件
如果應(yīng)用程序使用LoadLibrary顯式鏈接,那么在這個(gè)函數(shù)的參數(shù)中可以指定DLL文件的完整路徑。如果不指定路徑,或是進(jìn)行隱式鏈接,Windows將遵循下面的搜索順序來定位DLL:1. 包含EXE文件的目錄,2. 進(jìn)程的當(dāng)前工作目錄,3. Windows系統(tǒng)目錄,4. Windows目錄,5. 列在Path環(huán)境變量中的一系列目錄。這里有一個(gè)很容易發(fā)生錯(cuò)誤的陷阱。如果你使用VC++進(jìn)行項(xiàng)目開發(fā),并且為DLL模塊專門創(chuàng)建了一個(gè)項(xiàng)目,然后將生成的DLL文件拷貝到系統(tǒng)目錄下,從應(yīng)用程序中調(diào)用DLL模塊。到目前為止,一切正常。接下來對DLL模塊做了一些修改后重新生成了新的DLL文件,但你忘記將新的DLL文件拷貝到系統(tǒng)目錄下。下一次當(dāng)你運(yùn)行應(yīng)用程序時(shí),它仍加載了老版本的DLL文件,這可要當(dāng)心!
調(diào)試DLL程序
Microsoft 的VC++是開發(fā)和測試DLL的有效工具,只需從DLL項(xiàng)目中運(yùn)行調(diào)試程序即可。當(dāng)你第一次這樣操作時(shí),調(diào)試程序會(huì)向你詢問EXE文件的路徑。此后每次在調(diào)試程序中運(yùn)行DLL時(shí),調(diào)試程序會(huì)自動(dòng)加載該EXE文件。然后該EXE文件用上面的搜索序列發(fā)現(xiàn)DLL文件,這意味著你必須設(shè)置Path環(huán)境變量讓其包含DLL文件的磁盤路徑,或者也可以將DLL文件拷貝到搜索序列中的目錄路徑下。或者當(dāng)你調(diào)試EXE程序時(shí),在Project Setting中,將Debug選項(xiàng)卡中的Category設(shè)置為Additional DLLs。就可以同時(shí)調(diào)試EXE和它調(diào)用的DLL(當(dāng)然,你需要有DLL的源代碼)了。
posted on 2009-07-20 14:27 Saga 閱讀(9699) 評論(1) 編輯 收藏 引用 所屬分類: Windows
學(xué)東西了??! 回復(fù) 更多評論