標籤:style http color os 使用 io strong for 檔案
1. 動態連結之含義
在連結應用程式時常使用所謂“靜態連結”的方法,即將各個目標檔案(.obj)、運行時函數庫(.lib)以及已編譯的資源檔(.res)連結到一起,形成一個可執行檔(.exe)。使用靜態連結時,可執行檔需要使用的各種函數和資源都已包含到檔案中。這樣做的缺點是對於多個程式都使用的相同函數和資源要重複的連結到exe檔案中,使程式變大、佔用記憶體增加。 “動態連結”是將一些公用的函數或資源群組織成動態連結程式庫檔案(.dll),當某個需要使用dll中的函數或資源的程式啟動時(準確的說是初始化時),系統將該dll映射到調用進程的虛擬位址空間、增加該dll的引用計數值,然後當實際使用到該dll時作業系統就將該dll載入記憶體;如果使用該dll的所有程式都已結束,則系統將該庫從記憶體中移除。使用同一dll的各個進程在運行時共用dll的代碼,但是對於dll中的資料則各有一份拷貝(當然也有在dll中共用資料的方法)。 動態連結程式庫中可以定義兩種函數:輸出函數和內建函式。輸出函數可以被其他模組調用,內建函式只能被動態連結程式庫本身調用。動態連結程式庫也可以輸出資料,但這些資料通常只被它自己的函數所使用。
2. 動態連結的優點
→節約記憶體;
→使應用程式“變瘦”;
→可單獨修改動態連結程式庫而不必與應用程式重新連結;
→可方便實現多語言聯合編程(比如用VC++寫個dll,然後在VB中調用);
→可將資源打包;
→可在應用程式間共用記憶體
→......
3. 關於副檔名
動態連結程式庫的標準副檔名是dll,其他如exe,drv,fon也可作為副檔名,但只有副檔名為dll的動態連結程式庫才能被Windows自動載入。如果使用其它副檔名的動態連結程式庫,則調用動態連結程式庫的程式中必須使用LoadLibrary或LoadLibraryEx載入動態連結程式庫模組。
4. 用SDK建立一個簡單的dll檔案
在VC++中選擇建立一個Win32 Dynamic-Link Library。需要建立一個c/c++ head file和一個c/c++ source file並加入工程。標頭檔中內容為輸出函數的聲明,源檔案中內容為DllMain函數和輸出函數的定義。下面是一個最簡單的例子。
//dlldemo.h #ifdef __cplusplus #define EXPORT extern "C" __declspec(dllexport) #else #define EXPORT __declspec(dllexport) #endif
EXPORT void CALLBACK DllFoo(void) ;
//dlldemo.c #include #include "dlldemo.h"
int WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) { return TRUE ; }
EXPORT void CALLBACK DllFoo(void) { MessageBox(NULL,TEXT("This function is exported from a DLL"),TEXT("DllFoo"),MB_OK) ; return ; } |
標頭檔預先處理中的__declspec是微軟增加的“C擴充類儲存屬性”(C Extended Storage-Class Attributes),它指明一個給出的執行個體被儲存為一種微軟特定的類儲存屬性,可以為thread,naked,dllimport或dllexport. [MSDN原文:The extended attribute syntax for specifying storage-class information uses the __declspec keyword, which specifies that an instance of a given type is to be stored with a Microsoft-specific storage-class attribute (thread, naked, dllimport, or dllexport).] 輸出函數必須指明為CALLBACK。 DllMain是dll的進入點函數。也可以不寫它。DllMain必須返回TRUE,否則系統將終止程式並彈出一個“啟動程式時出錯”對話方塊。 編譯連結後,得到動態連結程式庫檔案dlldemo.dll和輸入庫檔案dlldemo.lib。
5.使用dll的兩種方式
方法一: load-time dynamic linking
在要調用dll的應用程式連結時,將dll的輸入庫檔案(import library,.lib檔案)包含進去。具體的做 法是在源檔案開頭加一句#include ,然後就可以在源檔案中調用dlldemo.dll中的輸出檔案了。
方法二: run-time dynamic linking
不必在連結時包含輸入庫檔案,而是在來源程式中使用LoadLibrary或LoadLibraryEx動態載入dll。
主要步驟為(以demodll.dll為例):
1) typedef函數原型和定義函數指標。 typedef void (CALLBACK* DllFooType)(void) ; DllFooType pfnDllFoo = NULL ; |
2) 使用LoadLibrary載入dll,並儲存dll執行個體控制代碼 HINSTANCE dllHandle = NULL ; ... dllHandle = LoadLibrary(TEXT("dlldemo.dll")); |
3) 使用GetProcAddress得到dll中函數的指標 pfnDllFoo = (DllFooType)GetProcAddress(dllHandle,TEXT("DllFoo")) ; 注意從GetProcAddress返回的指標必須轉型為特定類型的函數指標。 |
4)檢驗函數指標,如果不為空白則可調用該函數 if(pfnDllFoo!=NULL) DllFoo() ; |
5)使用FreeLibrary卸載dll FreeLibrary(dllHandle) ; |
使用run-time dynamic linking 比較麻煩,但有它的好處(下面討論)。MSDN中有一篇文章DLLs the Dynamic Way討論使用c的宏建立一個基類pDll完成以上複雜的操作,使用時只需定義一個類繼承自類pDll並 對類和函數使用宏。
以上兩種方法都要求應用程式能找到dll檔案,Windows按以下順序尋找dll檔案:
1)應用程式所在目錄。 |
2)目前的目錄。 |
3)Windows 9x : System目錄; Windows 2000/NT : System32 目錄 |
4)Windows 2000/NT的System目錄。 |
5)Windows所在目錄。 |
6)環境變數path中的路徑。 |
如果系統不能找到dll檔案,將結束調用dll的進程並彈出一個“啟動程式時出錯”對話方塊,告訴你“找 不到所需的dll檔案-XXX.dll”。
6 使用運行時的動態連結(Run-Time Dynamic Linking)有什麼好處?
如果使用載入時的動態連結(Load-Time Dynamic Linking),當dll檔案丟失時,調用此dll的程式將不能運行,你將會看到一個“啟動程式時出錯”對話方塊。而如果在運行時載入dll,你有機會處理這個錯誤,至少可以比較“溫柔”的結束程式。
如果dll改變了,使用load-time dynamic linking的程式可能會終止,而使用run-time dynamic linking 的程式只有當調用的函數在新的dll中不存在時才會出錯。
7 使用純資源dll
一般只在其c檔案中寫一個空的DllMain,然後向工程中插入資源,最後編譯為dll檔案。純資源dll沒有任何輸出函數,因此不會產生.lib檔案,所以必須在運行時用LoadLibrary載入。
8 在dll中使用共用資料(摘自programming windows)
// shared memory section (requires /SECTION:shared,RWS in link options) #pragma data_seg ("shared") int iTotal = 0 ; WCHAR szStrings [MAX_STRINGS][MAX_LENGTH + 1] = { ‘\0‘ } ; #pragma data_seg ()
#pragma comment(linker,"/SECTION:shared,RWS") |
第一個#pragma敘述建立資料段,這裡命名為shared。您可以將這段命名為任何一個您喜歡的名字。在這裡的#pragma敘述之後的所有初始化了的變數都放在shared資料段中。第二個#pragma敘述標示段的結束。對變數進行專門的初始化是很重要的,否則編譯器將把它們放在普通的未初始化資料段中而不是放在shared中。 連結器必須知道有一個「shared」共用資料段。在「Project Settings」對話方塊選擇「Link」頁面標籤。選中「STRLIB」時在「Project Options」欄位(在Release和Debug設定中均可),包含下面的連結敘述: /SECTION:shared,RWS 字母RWS表示段具有讀、寫和共用屬性。或者,您也可以直接用DLL原始碼指定連結選項,就像我們在STRLIB.C那樣: #pragma comment(linker,"/SECTION:shared,RWS")
the end
轉自:http://www.lihuasoft.net/article/show.php?id=759
SDK編程筆記 - DLL篇[轉]