---------------------------------2016.09.10------------------------------------------
---------------------------------動態鏈接庫------------------------------------------
動態鏈接庫DLL(Dynamic-Link Library)
Kernel32.dll 包含用於管理內存,進程和線程的函數(CreateThread)。
User32.dll 包含用於執行用戶界面任務的函數(eg:CreateWindow)。
GDI32.dll 包含用於畫圖和顯示文本的函數。
靜態庫:函數與數據被編譯進一個二進制文件(.lib)
編譯鏈接可執行程序時,將lib中的內容複製,並把它們和應用程序的其他模塊結合起來創建最終的可執行文件.exe
發佈使勁發佈.exe文件即可。
動態庫:使用動態庫時,提供一個引入庫文件.lib(包含該DLL導出的函數和變量的符號名)和一個.dll文件(包含該DLL實際的函數和數據)
編譯鏈接時,只連接該DLL的引入庫文件,運行時加載所需的DLL,將其映射到進程的地址空間。
發佈時還需要發佈要調用的動態鏈接庫。
-----------------------------------------------------------------------------------------------------
dll的優勢:
可採用多種編程語言來編寫
增強產品功能
提供二次開發的平台
簡化項目管理
節省磁盤空間與內存
有助於資源共享
有助於實現應用程序本地化
-----------------------------------------------------------------------------------------------
動態鏈接庫加載有隱式加載和顯式加載兩種方式。
-------------------------------------------------------------------------------------------------
應用程序如果想要訪問某個DLL文件中的函數,那麼該函數必須是已經被導出的函數。
查看一個DLL中有哪些導出函數,可用Dunpbin實現。
為了讓DLL導出一些函數,有兩種方式:
1.在每一個將要被導出的函數前面加上標識符:_declspec(dllexport)
eg: _declspec(dllexport) int add(int a,int b)
{
return a+b;
}
_declspec(dllexport) int sustract(int a,int b)
{
return a-b;
}
2.一中採用模塊定義(.def)文件聲明,需要在庫工程中添加模塊文件,格式如下:
LIBRARY 庫工程名稱
EXPORTS 導出函數名
------------------------------------------------------------------------------
_declspec(dllimport)標識符來表明函數是從動態鏈接庫引入的。
-------------------------------------------------------------------------------
dumpbin 命令:
---------------
dumpbin -exports *.dll
信息列表中:
ordinal列列出的信息是導出函數的序號;
hint列列出的數字是提示碼;
RVA列列出的地址值時導出函數在DLL模塊中的位置,即通過該地址值,可以在DLL中找到它們。
name列列出的是導出函數的名稱(會出現名字改變現象)。
-------------------------------------------------------------------------------------------------
C++支持函數重載,對於重載的多個函數來說,其函數名都是一樣的,為了加以區分,在編譯鏈接時,C++會按照
自己的規則改變函數的名稱——名字改編、名字粉碎
解決的方法:
在定義導出函數時,加上限定符:external"C".字母C一定要大寫。
經過此操作的只能用於導出全局函數這種情況,不能導出類的成員函數。
標準調用約定:_stdcall;
在函數體與聲明前加上 _stdcall可以實現導出類的成員函數,但是又會出現名字改編問題;
模塊定義文件*.def
可以通過模塊定義文件的方式來解決名字改編問題。
------------------------------------------------------------------------------------
文件內部格式:
LIBRARY <動態鏈接庫內部名稱>
EXPORTS
//表明DLL將要導出的函數,以及為這些導出函數指定的符號名
<函數名>
---------------------------------------------------------
如果將要導出的符號名和原文件中定義的函數名不一樣,則可以按照 entryname = internalname 方法指定導出函數;
entryname :導出的符號名;
internalname :DLL中將要導出的函數的名字。
------------------------------------------------------------------------------------------------------
隱式鏈接方式加載DLL
--------------------
當應用程序需要調用某個動態鏈接庫時,在程序鏈接時只需要包含該動態鏈接庫提供的輸入文件庫即可。
當應用程序運行時,系統為其分配地址空間,然後加載模塊會分析該應用程序的輸入信息,從中找出該
程序要訪問的動態鏈接庫信息,然後在用戶機器上搜索這些動態鏈接庫,進而加載它們。
搜索的順序依次是:
》程序的執行目錄..\\Denug
》當前目錄“.”
》系統目錄 依次是:C:\WINNT\system32,C:\WINNT\system,C:\WINNT
》path環境變量中所列出的路徑
----------------------------------------------------------------------------
顯式鏈接方式加載DLL
--------------------
將生成的 *.dll 和 *.lib 文件複製到要調用動態鏈接庫的函數執行目錄中;
使用 LoadLibrary函數。將指定的可執行模塊映射到調用進程的地址空間。
HMODULE LoadLibrary(
LPCTSTR lpFileName//指定可執行模塊的名稱
)
該函數可以加載 *.dll 文件和 *.exe 文件。
返回值類型是 HMODULE.(HMODULE 類型和 HINSTAANCE 類型可以通用)
獲取到動態鏈接庫的句柄后,使用 GetProcAddress 函數獲得蓋動態鏈接庫中導出函數的地址,
函數原型:
FARPROC GetProcAddress(
HMODULE hModule,//指定動態鏈接庫模塊的句柄(LoadLibrary 的返回值)
LPCTSTR lpProcName//指定 DLL 導出的函數的名字或函數的序號
)
在獲取函數的返回值時,要進行強制轉換,轉換成 ADDPROC 類型。
應使用標準調用約定 _stdcall 在需要的地方。
即,當 DLL 中導出函數採用的是標準調用約定時,訪問該 DLL 的客戶端程序也應該採用約定類型來訪問相應的導出函數。
---------------------------------------------------------------------------------------------------------------
根據序號訪問 dll 中的導出函數
MAKEINTRESOURCE 宏:將指定的函數序號轉換為相應函數名字字符串。
----------------------------------------------------------------------------------
隱式鏈接方式與顯式連接方式的區別:
隱式鏈接方式:直接加載,隨時調用;
顯式連接方式:使用時加載;
-------------------------------------------------------------------------------
DllMain函數:Dll入口函數。類似於可執行模塊的 WinMain
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module,動態鏈接庫模塊的句柄
DWORD fdwReason, // reason for calling function,標記值,用來指示調用該 DLL 入口函數的原因。
LPVOID lpReserved ) // reserved,保留參數,若 DLL 被動態加載,則參數為 NULL;若被靜態加載,則為非 NULL.
----------------------------------------------------------------------------------------
FreeLibrary
-----------
BOOL FreeLibrary(HMODULE hModule);//參數指定將要釋放的那個 DLL 的模塊句柄。
若採用動態加載方式調用DLL時,在需要訪問時,調用 LoadLibrary 函數加載該 DLL;
當不再需要訪問該 DLL 時,調用 FreeLibrary 函數釋放對該 DLL 的引用。
--------------------------------未完----------------------------------------------