關於動態庫 - LIB和DLL的區別與使用
1. 共有兩種庫
一種是LIB包含了函式所在的DLL檔案和檔案中函式位置的資訊(入口),程式碼由執行時載入在程序空間中的DLL提供,稱為動態連結庫dynamic link library。
一種是LIB包含函式程式碼本身,在編譯時直接將程式碼加入程式當中,稱為靜態連結庫static link library。
2. 共有兩種連結方式
動態連結使用動態連結庫,允許可執行模組(.dll檔案或.exe檔案)僅包含在執行時定位DLL函式的可執行程式碼所需的資訊。
靜態連結使用靜態連結庫,連結器從靜態連結庫LIB獲取所有被引用函式,並將庫同程式碼一起放到可執行檔案中。
3. 關於lib和dll的區別如下
(1)lib是編譯時用到的,dll是執行時用到的。如果要完成原始碼的編譯,只需要lib;如果要使動態連結的程式執行起來,只需要dll。
(2)如果有dll檔案,那麼lib一般是一些索引資訊,記錄了dll中函式的入口和位置,dll中是函式的具體內容;如果只有lib檔案,那麼這個lib檔案是靜態編譯出來的,索引和實現都在其中。使用靜態編譯的lib檔案,在執行程式時不需要再掛動態庫,缺點是導致應用程式比較大,而且失去了動態庫的靈活性,釋出新版本時要釋出新的應用程式才行。
(3)動態連結的情況下,有兩個檔案:一個是LIB檔案,一個是DLL檔案。LIB包含被DLL匯出的函式名稱和位置,DLL包含實際的函式和資料,應用程式使用LIB檔案連結到DLL檔案。在應用程式的可執行檔案中,存放的不是被呼叫的函式程式碼,而是DLL中相應函式程式碼的地址,從而節省了記憶體資源。DLL和LIB檔案必須隨應用程式一起發行,否則應用程式會產生錯誤。如果不想用lib檔案或者沒有lib檔案,可以用WIN32 API函式LoadLibrary、GetProcAddress裝載。
4. 使用lib需注意兩個檔案
(1).h標頭檔案,包含lib中說明輸出的類或符號原型或資料結構。應用程式呼叫lib時,需要將該檔案包含入應用程式的原始檔中。
(2).LIB檔案,略。
5. 使用dll需注意三個檔案
(1).h標頭檔案,包含dll中說明輸出的類或符號原型或資料結構的.h檔案。應用程式呼叫dll時,需要將該檔案包含入應用程式的原始檔中。
(2).LIB檔案,是dll在編譯、連結成功之後生成的檔案,作用是當其他應用程式呼叫dll時,需要將該檔案引入應用程式,否則產生錯誤。如果不想用lib檔案或者沒有lib檔案,可以用WIN32 API函式LoadLibrary、GetProcAddress裝載。
(3).dll檔案,真正的可執行檔案,開發成功後的應用程式在釋出時,只需要有.exe檔案和.dll檔案,並不需要.lib檔案和.h標頭檔案。
6. 使用lib的方法
靜態lib中,一個lib檔案實際上是任意個obj檔案的集合,obj檔案是cpp檔案編譯生成的。在編譯這種靜態庫工程時,根本不會遇到連結錯誤;即使有錯,也只會在使用這個lib的EXT檔案或者DLL工程裡暴露出來。
在VC中新建一個static library型別的工程Lib,加入test.cpp檔案和test.h檔案(標頭檔案內包括函式宣告),然後編譯,就生成了Lib.lib檔案。
7. 別的工程要使用這個lib有兩種方式
(1)在project->link->Object/Library Module中加入Lib.lib檔案(先查詢工程目錄,再查詢系統Lib目錄);或者在原始碼中加入指令#pragma comment(lib, “Lib.lib”)。
(2)將Lib.lib拷入工程所在目錄,或者執行檔案生成的目錄,或者系統Lib目錄中。
(3)加入相應的標頭檔案test.h。
8. 使用DLL的方法
使用動態連結中的lib,不是obj檔案的集合,即裡面不會有實際的實現,它只是提供動態連結到DLL所需要的資訊,這種lib可以在編譯一個DLL工程時由編譯器生成。建立DLL工程的方法(略)。
(1)隱式連結
第一種方法是:通過project->link->Object/Library Module中加入.lib檔案(或者在原始碼中加入指令#pragma comment(lib, “Lib.lib”)),並將.dll檔案置入工程所在目錄,然後新增對應的.h標頭檔案。
#include "stdafx.h"
#include "DLLSample.h"
#pragma comment(lib, "DLLSample.lib") //你也可以在專案屬性中設定庫的連結
int main()
{
TestDLL(123); //dll中的函式,在DllSample.h中宣告
return(1);
}
(2)顯式連結
需要函式指標和WIN32 API函式LoadLibrary、GetProcAddress裝載,使用這種載入方法,不需要.lib檔案和.h標頭檔案,只需要.dll檔案即可(將.dll檔案置入工程目錄中)。
#include <iostream>
#include <windows.h> //使用函式和某些特殊變數
typedef void (*DLLFunc)(int);
int main()
{
DLLFunc dllFunc;
HINSTANCE hInstLibrary = LoadLibrary("DLLSample.dll");
if (hInstLibrary == NULL)
{
FreeLibrary(hInstLibrary);
}
dllFunc = (DLLFunc)GetProcAddress(hInstLibrary, "TestDLL");
if (dllFunc == NULL)
{
FreeLibrary(hInstLibrary);
}
dllFunc(123);
std::cin.get();
FreeLibrary(hInstLibrary);
return(1);
}
LoadLibrary函式利用一個名稱作為引數,獲得DLL的例項(HINSTANCE型別是例項的控制代碼),通常呼叫該函式後需要檢視一下函式返回是否成功,如果不成功則返回NULL(控制代碼無效),此時呼叫函式FreeLibrary釋放DLL獲得的記憶體。
GetProcAddress函式利用DLL的控制代碼和函式的名稱作為引數,返回相應的函式指標,同時必須使用強轉;判斷函式指標是否為NULL,如果是則呼叫函式FreeLibrary釋放DLL獲得的記憶體。此後,可以使用函式指標來呼叫實際的函式。
最後要記得使用FreeLibrary函式釋放記憶體。
9. 注意:應用程式如何找到DLL檔案?
使用LoadLibrary顯式連結,那麼在函式的引數中可以指定DLL檔案的完整路徑;如果不指定路徑,或者進行隱式連結,Windows將遵循下面的搜尋順序來定位DLL:
(1)包含EXE檔案的目錄
(2)工程目錄
(3)Windows系統目錄
(4)Windows目錄
(5)列在Path環境變數中的一系列目錄