- 什么是DLL:
自從微軟推出16位的Windows操作系統起,此后每種版本的Windows操作系統都非常依賴於動態鏈接庫(DLL)中的函數和數據,實際上 Windows操作系統中幾乎所有的內容都由DLL以一種或另外一種形式代表着,例如顯示的字體和圖標存儲在GDI DLL中、顯示Windows桌面和處理用戶的輸入所需要的代碼被存儲在一個User DLL中、Windows編程所需要的大量的API函數也被包含在Kernel DLL中。
DLL是建立在客戶/服務器通信的概念上,包含若干函數、類或資源的庫文件,函數和數據被存儲在一個DLL(服務器)上並由一個或多個客戶導出而使用,這些客戶可以是應用程序或者是其它的DLL。DLL庫不同於靜態庫,在靜態庫情況下,函數和數據被編譯進一個二進制文件(通常擴展名為*.LIB), Visual C++的編譯器在處理程序代碼時將從靜態庫中恢復這些函數和數據並把他們和應用程序中的其他模塊組合在一起生成可執行文件。這個過程稱為"靜態鏈接",此時因為應用程序所需的全部內容都是從庫中復制了出來,所以靜態庫本身並不需要與可執行文件一起發行。
在動態庫的情況下,有兩個文件,一個是引入庫(.LIB)文件,一個是DLL文件,引入庫文件包含被DLL導出的函數的名稱和位置,DLL包含實際的函數和數據,應用程序使用LIB文件鏈接到所需要使用的DLL文件,庫中的函數和數據並不復制到可執行文件中,因此在應用程序的可執行文件中,存放的不是被調用的函數代碼,而是DLL中所要調用的函數的內存地址,這樣當一個或多個應用程序運行是再把程序代碼和被調用的函數代碼鏈接起來,從而節省了內存資源。從上面的說明可以看出,DLL和.LIB文件必須隨應用程序一起發行,否則應用程序將會產生錯誤。
微軟的Visual C++支持三種DLL,它們分別是Non-MFC Dll(非MFC動態庫)、Regular Dll(常規DLL)、Extension Dll(擴展DLL)。Non-MFC DLL指的是不用MFC的類庫結構,直接用C語言寫的DLL,其導出的函數是標准的C接口,能被非MFC或MFC編寫的應用程序所調用。Regular DLL:和下述的Extension Dlls一樣,是用MFC類庫編寫的,它的一個明顯的特點是在源文件里有一個繼承CWinApp的類(注意:此類DLL雖然從CWinApp派生,但沒有消息循環),被導出的函數是C函數、C++類或者C++成員函數(注意不要把術語C++類與MFC的微軟基礎C++類相混淆),調用常規DLL的應用程序不必是MFC應用程序,只要是能調用類C函數的應用程序就可以,它們可以是在Visual C++、Dephi、Visual Basic、Borland C等編譯環境下利用DLL開發應用程序。
- DLL的創建:
打開VS2013,選擇Win32:
選擇DLL:
里邊會自動為你添加好幾個文件:
以及一個dllmain的格式,這里面是,當加載一個DLL(ATTACH)或者釋放一個DLL(DETACH)等不同狀態發生時,所要執行的代碼(只不過下面的代碼是當四個狀態發生時什么都不執行):
參數中,hMoudle是動態庫被調用時所傳遞來的一個指向自己的句柄(實際上,它是指向_DGROUP段的一個選擇符); ul_reason_for_call是一個說明動態庫被調原因的標志,當進程或線程裝入或卸載動態鏈接庫的時候,操作系統調用入口函數,並說明動態鏈接庫被調用的原因,它所有的可能值為:DLL_PROCESS_ATTACH: 進程被調用、DLL_THREAD_ATTACH: 線程被調用、DLL_PROCESS_DETACH: 進程被停止、DLL_THREAD_DETACH: 線程被停止;lpReserved為保留參數。
我們直接在testDLL.cpp中添加代碼,這里保存的是DLL的導出函數:
extern "C" __declspec(dllexport) int add(int a, int b) { return (a + b); } extern "C" __declspec(dllexport) int sub(int a, int b) { return (a - b); }
編譯生成一個testDLL.dll.下面進行測試:
隱式連接:
#include <iostream> #include <windows.h> #pragma comment(lib,"testDLL.lib") extern "C"_declspec(dllimport) int add(int a, int b); extern "C"_declspec(dllimport) int sub(int a, int b); int main() { int nParam1 = 9; int nParam2 = 3; int nAdd = add(nParam1, nParam2); int nSub = sub(nParam1, nParam2); std::cout << nAdd << ":" << nSub << std::endl; system("pause"); return 0; }
顯示鏈接:
#include <iostream> #include <windows.h> int main() { typedef int (*_pAdd)(int a, int b); typedef int (*_pSub)(int a, int b); HINSTANCE hDll = LoadLibrary("testDLL.dll"); int nParam1 = 9; int nParam2 = 3; _pAdd pAdd = (_pAdd)GetProcAddress(hDll, "add"); _pSub pSub = (_pSub)GetProcAddress(hDll, "sub"); int nAdd = pAdd(nParam1, nParam2); int nSub = pSub(nParam1, nParam2); std::cout << nAdd << ":" << nSub << std::endl;
FreeLibrary(hDll); system("pause"); return 0; }
正確輸出結果:
參考:
http://www.cnblogs.com/daocaoren/archive/2012/05/30/2526495.html