天天看點

12、動态連結庫,dll

動态連結庫通常都不能直接運作,也不能接收消息。它們是一些獨立的檔案,其中包含能被可執行程式或其它DLL調用來完成某項工作的函數。隻有在其它子產品調用動态連結庫中的函數時,它才發揮作用。

1、我們可以把完成某種功能的函數放在一個動态連結庫中,提供給其它函數調用。Windows API中所有的函數都包含在DLL中,其中三個最重要:

1)Kernal32.dll 包含那些用于記憶體管理,程序和線程的函數,如CreateThread函數。

2)User32.dll 包含執行使用者界面任務,如視窗的建立和消息的傳送的函數,如3)CreateWindow函數。

3)GDI32.dll 用于畫圖的顯示文本的函數。

2、靜态庫與動态庫:

靜态庫:

函數和資料被編譯進一個二進制檔案(通常擴充名為.LIB)。在使用靜态庫情況下,在編譯連結可執行檔案時,連結器從庫中複制這些函數和資料并把它們和應用程式的其它子產品組合起來建立最終的可執行檔案。産品釋出時不需要釋出被使用的靜态庫。

動态庫:

動态庫一般提供兩個檔案:一個引入庫(.lib),一個是DLL(.dll)檔案。.lib檔案中包含該DLL導出的函數和變量的符号名,而.dll檔案包含該DLL實際的函數和資料。在使用動态庫情況下,在編譯連結可執行檔案時,隻需要連結該DLL的引入庫檔案,該DLL中的函數代碼和資料并不複制到可執行檔案中,直到可執行程式運作時,才去加載所需的DLL,将該DLL映射到程序的位址空間中,然後通路DLL中導出的函數。釋出産品時要同時釋出 DLL。

12、動态連結庫,dll

圖示 P703 兩個程序通路同一個DLL時的情形

兩種加載dll檔案的方式,隐式加載和顯式加載。

3、Dumpbin指令

應用程式如果想要通路某個DLL中的函數,那麼該函數必須是已經被導出的函數。可以用Dumpbin檢視。在使用之前可能需要通過VCVARS32.bat來建立VC使用的環境變量。

dumpbin -exports name.dll

4、導出DLL中函數

加_declspec(dllexport)于函數前面。

1)隐式加載

(1)通過extern聲明外部函數。并在工程屬性的連結器的指令行中輸入lib符号名檔案。把dll檔案和lib檔案放入指定目錄中在工具選項的VC++目錄中包含。

(2)利用_declspec(dllimport)于外部函數聲明前。

為了友善dll的使用,通常都是提供一個.h檔案給客戶的;我們通常在頭檔案的函數聲明按如下形式處理:

而在函數定義的.cpp檔案中,如下形式定義:

這樣提供給客戶時不需要額外的改動代碼。

同樣,可以把上面定義的DLL1加在一個類前面,或類的成員函數前面來把類或類的成員函數導出。如下所示:

2)顯式加載

通過LoadLibrary來實作。LoadLibrary将指定的可執行子產品映射到調用程序的位址空間,and the return value is a handle to the module。再通過GetProcAddress 來獲得動态庫中導出函數的位址。

The MAKEINTRESOURCE macro converts an integer value to a resource type

compatible with the resource-management functions. This macro is used in place of a

string containing the name of the resource

The DllMain function is called when the driver DLL first starts up.

使用完後,通過FreeLibrary 來減少被加載的dll的引用計數,當減到0時,該DLL子產品從調用程序的位址空間解除安裝。

5、名字改編問題

不同的編譯器在編譯函數時,及采用不同的函數調用約定時,對函數的改編是不一樣的。

http://www.cnblogs.com/mydomain/archive/2010/09/27/1837179.html

由此,在函數調用時會産生一些問題,如用C++編譯器生成的函數通過C編譯器調用時會出錯。對于這種情況,可以在聲明中加上extern "C"

#define DLL1_API extern "C" _declspec(dllimport)

利用extern "C"可以解決C++,C間互相調用問題,但是有一個缺陷,就是不能用于導出一個類的成員函數。,隻能用于導出全局函數這種情況。

如果函數的調用約定發生了變化,如有的函數用_stdcall,有的用pascal,那麼即使使用了extern "C",名字改編仍會發生。

可以通過定義一個子產品定義檔案.def的方式來解決這個問題:

建立一個newname.def檔案,加入工程中:

Dll2與生成的動态連結庫名相同。

EXPORTS:下面定義的符号名如果與函數名一樣,則以符号名導出函數,如果不同,按下面規則導出函數:

entryname[=internalname] [@ordinal[NONAME]] [DATA] [PRIVATE]

There are three methods for exporting a definition, listed in recommended order of use:

1.The __declspec(dllexport) keyword in the source code

2.An EXPORTS statement in a .def file

3.An /EXPORT specification in a LINK command[1]

參考:

[1] http://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx

[2] VC++深入詳解

繼續閱讀