1. 程式人生 > >Dll 模組間(dll, exe)使用匯出變數、靜態變數和外部變數的試驗與結論

Dll 模組間(dll, exe)使用匯出變數、靜態變數和外部變數的試驗與結論

DLL檔案(Dynamic Linkable Library 即動態連結庫檔案),是一種不能單獨執行的檔案,它允許程式共享執行特殊任務所必需的程式碼和其他資源
比較大的應用程式都由很多模組組成,這些模組分別完成相對獨立的功能,它們彼此協作來完成整個軟體系統的工作。可能存在一些模組的功能較為通用,在構造其它軟體系統時仍會被使用。在構造軟體系統時,如果將所有模組的原始碼都靜態編譯到整個應用程式 EXE 檔案中,會產生一些問題:一個缺點是增加了應用程式的大小,它會佔用更多的磁碟空間,程式執行時也會消耗較大的記憶體空間,造成系統資源的浪費;另一個缺點是,在編寫大的 EXE 程式時,在每次修改重建時都必須調整編譯所有原始碼,增加了編譯過程的複雜性,也不利於階段性的單元測試。
Windows 系統平臺上提供了一種完全不同的較有效的程式設計和執行環境,你可以將獨立的程式模組建立為較小的 DLL 檔案,並可對它們單獨編譯和測試。在執行時,只有當 EXE 程式確實要呼叫這些 DLL 模組的情況下,系統才會將它們裝載到記憶體空間中。這種方式不僅減少了 EXE 檔案的大小和對記憶體空間的需求,而且使這些 DLL 模組可以同時被多個應用程式使用。Windows 自己就將一些主要的系統功能以 DLL 模組的形式實現。
一般來說,DLL 是一種磁碟檔案,以.dll、.DRV、.FON、.SYS 和許多以 .EXE 為副檔名的系統檔案都可以是 DLL。它由全域性資料、服務函式和資源組成,在執行時被系統載入到呼叫程序的虛擬空間中,成為呼叫程序的一部分。如果與其它 DLL 之間沒有衝突,該檔案通常對映到程序虛擬空間的同一地址上。DLL 模組中包含各種匯出函式,用於向外界提供服務。DLL 可以有自己的資料段,但沒有自己的堆疊,使用與呼叫它的應用程式相同的堆疊模式;一個 DLL 在記憶體中只有一個例項;DLL 實現了程式碼封裝性;DLL 的編制與具體的程式語言及編譯器無關。
在 Win32 環境中,每個程序都複製了自己的讀/寫全域性變數。如果想要與其它程序共享記憶體,必須使用記憶體對映檔案或者宣告一個共享資料段。DLL 模組需要的堆疊記憶體都是從執行程序的堆疊中分配出來的。Windows 在載入 DLL 模組時將程序函式呼叫與 DLL 檔案的匯出函式相匹配。Windows 作業系統對 DLL 的操作僅僅是把 DLL 對映到需要它的程序的虛擬地址空間裡去。DLL 函式中的程式碼所建立的任何物件(包括變數)都歸呼叫它的執行緒或程序所有。
呼叫方式:
1、靜態呼叫方式:由編譯系統完成對 DLL 的載入和應用程式結束時 DLL 解除安裝的編碼(如還有其它程式使用該 DLL,則 Windows 對 DLL 的應用記錄減1,直到所有相關程式都結束對該 DLL 的使用時才釋放它,簡單實用,但不夠靈活,只能滿足一般要求。
隱式的呼叫:需要把產生動態連線庫時產生的 .LIB 檔案加入到應用程式的工程中,想使用 DLL 中的函式時,只須說明一下。隱式呼叫不需要呼叫 LoadLibrary() 和 FreeLibrary()。程式設計師在建立一個 DLL 檔案時,連結程式會自動生成一個與之對應的 LIB 匯入檔案。該檔案包含了每一個 DLL 匯出函式的符號名和可選的標識號,但是並不含有實際的程式碼。LIB 檔案作為 DLL 的替代檔案被編譯到應用程式專案中。
當程式設計師通過靜態連結方式編譯生成應用程式時,應用程式中的呼叫函式與 LIB 檔案中匯出符號相匹配,這些符號或標識號進入到生成的 EXE 檔案中。LIB 檔案中也包含了對應的 DL L檔名(但不是完全的路徑名),連結程式將其儲存在 EXE 檔案內部。
當應用程式執行過程中需要載入 DLL 檔案時,Windows 根據這些資訊發現並載入 DLL,然後通過符號名或標識號實現對 DLL 函式的動態連結。所有被應用程式呼叫的 DLL 檔案都會在應用程式 EXE 檔案載入時被載入在到記憶體中。可執行程式連結到一個包含 DLL 輸出函式資訊的輸入庫檔案(.LIB檔案)。作業系統在載入使用可執行程式時載入 DLL。可執行程式直接通過函式名呼叫 DLL 的輸出函式,呼叫方法和程式內部其 它的函式是一樣的。
2、動態呼叫方式:是由程式設計者用 API 函式載入和解除安裝 DLL 來達到呼叫 DLL 的目的,使用上較複雜,但能更加有效地使用記憶體,是編制大型應用程式時的重要方式。
顯式的呼叫:
是指在應用程式中用 LoadLibrary 或 MFC 提供的 AfxLoadLibrary 顯式的將自己所做的動態連線庫調進來,動態連線庫的檔名即是上面兩個函式的引數,再用 GetProcAddress() 獲取想要引入的函式。自此,你就可以象使用如同本應用程式自定義的函式一樣來呼叫此引入函數了。在應用程式退出之前,應該用 FreeLibrary 或 MFC 提供的 AfxFreeLibrary 釋放動態連線庫。直接呼叫 Win32 的 LoadLibary 函式,並指定 DLL 的路徑作為引數。LoadLibary 返回 HINSTANCE 引數,應用程式在呼叫 GetProcAddress 函式時使用這一引數。GetProcAddress 函式將符號名或標識號轉換為 DLL 內部的地址。程式設計師可以決定 DLL 檔案何時載入或不載入,顯式連結在執行時決定載入哪個 DLL 檔案。使用 DLL 的程式在使用之前必須載入(LoadLibrary)載入DLL從而得到一個DLL模組的控制代碼,然後呼叫 GetProcAddress 函式得到輸出函式的指標,在退出之前必須解除安裝DLL(FreeLibrary)。
正因為DLL 有佔用記憶體小,好編輯等的特點有很多電腦病毒都是DLL格式檔案。但不能單獨執行。
動態連結庫通常都不能直接執行,也不能接收訊息。它們是一些獨立的檔案,其中包含能被可執行程式或其它DLL呼叫來完成某項工作的函式。只有在其它模組呼叫動態連結庫中的函式時,它才發揮作用。