1. 程式人生 > >靜態連結庫(LIB)和動態連結庫(DLL),DLL的靜態載入和動態載入,兩種LIB檔案。

靜態連結庫(LIB)和動態連結庫(DLL),DLL的靜態載入和動態載入,兩種LIB檔案。

靜態連結庫(LIB)和動態連結庫(DLL),DLL的靜態載入和動態載入,兩種LIB檔案。


一、 靜態連結庫(LIB,也簡稱“靜態庫”)與動態連結庫(DLL,也簡稱“動態庫”)的區別

靜態連結庫與動態連結庫都是共享程式碼的方式,如果採用靜態連結庫,則無論你願不願意,lib 中的指令都全部被直接包含在最終生成的 EXE 檔案中了。但是若使用 DLL,該 DLL 不必被包含在最終 EXE 檔案中,EXE 檔案執行時可以“動態”地引用和解除安裝這個與 EXE 獨立的 DLL 檔案。靜態連結庫和動態連結庫的另外一個區別在於靜態連結庫中不能再包含其他的動態連結庫或者靜態庫,而在動態連結庫中還可以再包含其他的動態或靜態連結庫。 動態庫就是在需要呼叫其中的函式時,根據函式對映表找到該函式然後調入堆疊執行。如果在當前工程中有多處對dll檔案中同一個函式的呼叫,那麼執行時,這個函式只會留下一份拷貝。但是如果有多處對lib檔案中同一個函式的呼叫,那麼執行時,該函式將在當前程式的執行空間裡留下多份拷貝,而且是一處呼叫就產生一份拷貝。


1. 靜態連結庫(LIB)
首先,靜態連結庫的使用需要庫的開發者提供生成庫的.h標頭檔案和.lib檔案。生成庫的.h標頭檔案中的宣告格式如下:
extern "C" 函式返回型別 函式名(引數表);
在呼叫程式的.cpp原始碼檔案中如下:
#include "..\lib.h"
#pragma comment(lib,"..\\debug\\libTest.lib") // 指定與靜態庫一起連結(或者在IDE的lib欄中填入lib檔案的路徑,在IDE的lib目錄欄填入lib所在資料夾目錄)
其次因為靜態連結庫是將全部指令都包含入呼叫程式生成的EXE檔案中。因此如果用的是靜態連結庫,那麼也就不存在“匯出某個函式提供給使用者使用”的情況,要想用就得全要,要不就都別要。

個人理解:其實可以認為靜態連結看做與直接將要鏈入的lib工程的原始碼引入編譯等效,因為實際結果來看也應該是等效的,最終都只是一個exe檔案,功能會是完全一樣的,只是多了一些編譯連結的過程.


2. 動態連結庫(DLL)
動態連結庫的使用需要庫的開發者提供生成的.lib檔案和.dll檔案。或者只提供dll檔案。
首先我們必須先注意到DLL內的函式分為兩種:
(1)匯出函式,可供應用程式呼叫;
(2) DLL內部函式,只能在 DLL 程式使用,應用程式無法呼叫它們。
因此呼叫程式若想呼叫DLL中的某個函式就要以某種形式或方式指明它到底想呼叫哪一個函式。
對於DLL的匯出/匯入,可以採用如下方法:
#ifdef WLL_EXPORTS
#define WLL_API __declspec(dllexport) // 宣告一個匯出函式,用於dll中。
#else
#define WLL_API __declspec(dllimport) // 宣告一個匯入函式,用於使用某個dll的exe中。
#endif
這是匯出/匯入類的巨集定義,將匯出/匯入類必須加上該巨集,才能被匯出/匯入。
此處的WLL_EXPORTS會出現在 project setting C++ PreProcessor的PreProcessor definition中,這個MACRO表明其要定義一個匯出巨集。當前庫編譯時,加了WLL_API的類將被匯出,而包含該標頭檔案的其他呼叫DLL或EXE,由於沒有定義WLL_API巨集,將申明為匯入該類。


DLL有兩種載入方式:靜態載入和動態載入。

靜態載入的步驟:

(1) 包含DLL中匯出的標頭檔案。

(2) 採用#pragma comment(lib,"..\\debug\\libTest.lib")匯入動態庫生成的*.lib標頭檔案。或在 projectàsettingsàLinkeràInput的Additional Dependencies中加入lib檔案。

(3) 將動態庫生成的*.dll檔案放到EXE或DLL的同一目錄下。


動態載入的步驟:

Another.dll有一個int Add(int x,int y) 函式。則完整的呼叫過程如下:

typedef int (* FunPtr)(int,int); //定義函式指標

FunPtr funPtr;

Handle handle =LoadLibrary("Another.dll");

funPtr =(FunPtr)GetProcAddress(handle ,"Add");

funPtr(2,3); // 2+3;

FreeLibrary(handle); // 釋放載入的動態庫

二、 兩種LIB檔案

目前以lib字尾的庫有兩種,一種為靜態連結庫,另一種為動態連線庫的匯入庫 (Import Libary,簡稱“匯入庫”)。

靜態庫是一個或者多個obj檔案的打包,所以有人乾脆把從obj檔案生成lib的過程稱為Archive,即合併到一起。比如你連結一個靜態庫,如果其中有錯,它會準確的找到是哪個obj有錯,即靜態lib只是殼子。

動態庫一般會有對應的匯入庫,方便程式靜態載入動態連結庫,否則你可能就需要自己LoadLibary調入DLL檔案,然後再手工GetProcAddress獲得對應函數了。有了匯入庫,你只需要連結匯入庫後按照標頭檔案函式介面的宣告呼叫函式就可以了。

匯入庫和靜態庫的區別很大,他們實質是不一樣的東西。靜態庫本身就包含了實際執行程式碼、符號表等等,而對於匯入庫而言,其實際的執行程式碼位於動態庫中,匯入庫只包含了地址符號表等,確保程式找到對應函式的一些基本地址資訊。

這也是實際上很多開原始碼釋出的慣用方式:

1. 預編譯的開發包:包含一些.dll檔案和一些.lib檔案。其中這裡的.lib就是匯入庫,而不要錯以為是靜態庫。但是引入方式和靜態庫一樣,要在連結路徑上新增找到這些.lib的路徑。 而.dll則最好放到最後產生的應用程式exe執行檔案相同的目錄。這樣執行時,就會自動調入動態連結庫。

2. 使用者自己編譯:下載的是原始碼,按照readme自己編譯。生成很可能也是.dll + .lib(匯入庫)的庫檔案

3. 如果你只有dll,並且你知道dll中函式的函式原型,那麼你可以直接在自己程式中使用LoadLibary調入DLL檔案,GetProcAddress獲取函式地址,然後呼叫。

三、 DLL檔案

動態連結庫 (DLL) 是作為共享函式庫的可執行檔案。動態連結提供了一種方法,使程序可以呼叫不屬於其可執行程式碼的函式。函式的可執行程式碼位於一個 DLL 中,該 DLL 包含一個或多個已被編譯、連結並與使用它們的程序分開儲存的函式。DLL 還有助於共享資料和資源。多個應用程式可同時訪問記憶體中單個 DLL 副本的內容。

動態連結與靜態連結的不同之處在於它允許可執行模組(.dll 檔案或 .exe 檔案)僅包含在執行時定位 DLL 函式的可執行程式碼所需的資訊。在靜態連結中,連結器從靜態連結庫獲取所有被引用的函式,並將庫同程式碼一起放到可執行檔案中。

使用動態連結代替靜態連結有若干優點。DLL 節省記憶體,減少交換操作,節省磁碟空間,更易於升級,提供售後支援,提供擴充套件 MFC 庫類的機制,支援多語言程式,並使國際版本的建立輕鬆完成。

API 就是應用程式程式設計介面。它是能用來操作元件、應用程式或者作業系統的一組函式。典型的情況下,API 由一個或多個提供某種特殊功能的 DLL 組成。

DLL 是一個檔案,其中包含了在 Microsoft Windows下執行的任何應用程式都可呼叫的函式。執行時,DLL 中的函式動態地連結到呼叫它的應用程式中。無論有多少應用程式呼叫 DLL 中的某個函式,在磁碟上只有一個檔案包含該函式,且只在它調入記憶體時才建立該 DLL。 您聽到最多的 API 可能是 Windows API,它包括構成 Windows 作業系統的各種 DLL。每個 Windows 應用程式都直接或間接地與 Windows API 互動。Windows API 保證 Windows 下執行的所有應用程式的行為方式一致。

隨著 Windows 作業系統的發展,現已釋出了幾個版本的 Windows API。Windows 3.1 使用 Win16 API。Microsoft Windows NT、Windows 95 和 Windows 98 平臺使用 Microsoft Win32 API。除 Windows API 外,其他一些 API 也已釋出。例如,郵件應用程式程式設計介面 (MAPI) 是一組可用於編寫電子郵件應用程式的 DLL。API 傳統上是為開發 Windows 應用程式的 C 和 C++ 程式設計師編寫的,但其他的程式語言(包括VBA)也可以呼叫 DLL 中的函式。因為大部分 DLL 主要是為 C 和 C++ 程式設計師編寫和整理說明的,所以呼叫 DLL 函式的方法與呼叫 VBA 函式會有所不同。在使用 API 時必須瞭解如何給 DLL 函式傳遞引數。

警告:呼叫 Windows API 和 其他 DLL 函式可能會給您的應用程式帶來不良影響。從自己的程式碼中直接呼叫 DLL 函式時,您繞過了 VBA 通常提供的一些安全機制。如果在定義或呼叫 DLL 函式時出現錯誤(所有程式設計師都不可避免),可能會在應用程式中引起應用程式錯誤(也稱為通用性保護錯誤,或GPF)。最好的解決辦法是在執行程式碼以前儲存該專案,並確保瞭解 DLL 函式呼叫的原理。

轉自:http://blog.csdn.net/iw1210/article/details/29615569