劉大鵬
摘要:介紹了Windows下動(dòng)態(tài)鏈接庫(kù)的創(chuàng)建和使用方法。
關(guān)鍵詞:動(dòng)態(tài)鏈接庫(kù)導(dǎo)出函數(shù)隱式鏈接顯式鏈接
中圖分類號(hào)TF311.52文獻(xiàn)標(biāo)識(shí)碼B文章編號(hào):1002-2422(2007)03--0048-02
1動(dòng)態(tài)鏈接庫(kù)的創(chuàng)建
在VC++6.0開(kāi)發(fā)系統(tǒng)的菜單“File”中單擊“New”,在彈出窗口中選擇Project選項(xiàng)卡,可以看到有Win32 Dy-name-Link Library和MFC AppWizard兩種方式創(chuàng)建動(dòng)態(tài)鏈接庫(kù)。前者用來(lái)創(chuàng)建不與MFC(微軟基礎(chǔ)類庫(kù))鏈接的動(dòng)態(tài)鏈接庫(kù),稱為非MFC動(dòng)態(tài)庫(kù),后者創(chuàng)建與MFC鏈接的動(dòng)態(tài)鏈接庫(kù),稱為MFC動(dòng)態(tài)庫(kù)。
1.1創(chuàng)建非MFC動(dòng)態(tài)庫(kù)
選擇Win32 Dynamic-Link Library,在Project name編輯框輸入工程名:MyDLL,創(chuàng)建一個(gè)空的非MFC工程。
要使DLL中包含的某些函數(shù)和數(shù)據(jù)能夠被外部應(yīng)用程序調(diào)用,就應(yīng)該在創(chuàng)建DLL時(shí),指出這些函數(shù)(數(shù)據(jù))是可導(dǎo)出的,稱為導(dǎo)出函數(shù)(數(shù)據(jù))。導(dǎo)出函數(shù)有兩種方法,一種是在聲明函數(shù)原型語(yǔ)句中的函數(shù)類型關(guān)鍵字左邊添加導(dǎo)出關(guān)鍵字_declspec(dlhxport);另一種是使用模塊定義文件.def。
(1)使用導(dǎo)出關(guān)鍵字declapee(duexport)導(dǎo)出函數(shù)
在前面創(chuàng)建的空工程中加入MyDLL.h、MyDL、cpp兩個(gè)文件,
頭文件MyDLL.h.代碼如下:_declspec(dllexport)int Add(int x,int y);
實(shí)現(xiàn)文件MyDLL.cpp代碼如下:#include
#include“MyDLL.h”
int Add(int x,int y)
{return(x+y);}
在工程中有一個(gè)被導(dǎo)出函數(shù)(輸出函數(shù))Add(),用來(lái)進(jìn)行加法運(yùn)算。
編譯、連接工程MyDLL,成功后,可以看到debug目錄下生成了動(dòng)態(tài)庫(kù)MyDLL.d11和引入庫(kù)MyDLL.Iib這兩個(gè)文件。引入庫(kù)文件中存有對(duì)應(yīng)DLL的文件名和輸出函數(shù)名等(MyDLL、Add等),動(dòng)態(tài)庫(kù)文件中存有實(shí)際的函數(shù)和數(shù)據(jù)。
(2)使用模塊定義文件.def導(dǎo)出函數(shù)
對(duì)方法(1)中建立的工程,刪除文件MyDLL.h,保留文件MyDLL.cpp,再加入文本文件MyDLL.def作為模塊定義文件。在MyDLL.def中輸入代碼如下:
;MyDLL.def
LIBRARY MyDLL
EXPORTS
Add
一個(gè)模塊定義文件至少要有兩條語(yǔ)句,一條是LI-BRARY語(yǔ)句,用它指出DLL的名字,該語(yǔ)句必須位于除注釋語(yǔ)句外的其它語(yǔ)句之前;另一條是EXPORTS語(yǔ)句,在它之下列出輸出函數(shù)的名字。
1.2創(chuàng)建MFC動(dòng)態(tài)庫(kù)
選擇MFC AppWizard,在Project name編輯框輸入工程名:MyDLL,單擊OK,可創(chuàng)建三種類型的MFC動(dòng)態(tài)庫(kù):第一種是與MFC靜態(tài)鏈接的常規(guī)DLL(Regular DLLWith MFG Statically Linked);第二種是與MFC動(dòng)態(tài)鏈接的常規(guī)DLL(Regular DLL using shared MFC DLL)。常規(guī)DLL既可以被MFC應(yīng)用程序使用,也可以被非MFC應(yīng)用程序使用(BC,VB等)。第三種是MFC擴(kuò)展型DLL(MFCExtension DLL),這種DLL與MFC動(dòng)態(tài)鏈接,其特點(diǎn)是可導(dǎo)出MFC派生類,但MFC擴(kuò)展型DLL只能被那些動(dòng)態(tài)鏈接到MFC的應(yīng)用程序使用。
MFC動(dòng)態(tài)庫(kù)導(dǎo)出函數(shù)(或變量)的方法與非MFC動(dòng)態(tài)庫(kù)的導(dǎo)出方法相同。
MFC擴(kuò)展DLL導(dǎo)出類的常用方法是在類的聲明前加一個(gè)宏“AFX_EXT_CLASS”,例如:class AFX_EXT_CLASSCMyClass;
特別要注意的是,對(duì)于動(dòng)態(tài)鏈接到MFC的DLL,其輸出函數(shù)若要調(diào)用MFC,則在該輸出函數(shù)的定義體內(nèi)第一條語(yǔ)句必須是下面的宏語(yǔ)句:
AEX_MANAGE_STATE(AfxCetStaticModuleStme());
此語(yǔ)句保證在其后輸出函數(shù)中的語(yǔ)句能夠調(diào)用MFC。
新創(chuàng)建的動(dòng)態(tài)鏈接庫(kù)提供給其它程序使用時(shí)(或發(fā)布)要提供三個(gè)文件:動(dòng)態(tài)庫(kù)文件(MyDLLdll)、引入庫(kù)文件(MyDLL.lib)和頭文件(MyDLL.h)。發(fā)布與MFC動(dòng)態(tài)鏈接的動(dòng)態(tài)庫(kù)時(shí)還要附上VC++開(kāi)發(fā)系統(tǒng)內(nèi)的MFC#O.dll(文件名中#是MFC的版本號(hào)碼)和MSVCRT.dll這兩個(gè)動(dòng)態(tài)庫(kù)。
2動(dòng)態(tài)鏈接庫(kù)的使用
應(yīng)用程序使用動(dòng)態(tài)庫(kù)時(shí)可以采用兩種鏈接方式:隱式鏈接和顯式鏈接。
2.1隱式鏈接
應(yīng)用程序使用引入庫(kù)(.lib)文件隱式鏈接到DLL,DLL中的函數(shù)和數(shù)據(jù)并不復(fù)制到可執(zhí)行文件中,在可執(zhí)行文件中,存放的不是被調(diào)用的函數(shù)代碼,而是DLL中所要調(diào)用的函數(shù)的內(nèi)存地址。隱式鏈接方式下,操作系統(tǒng)加載應(yīng)用程序時(shí)就加載DLL文件。
實(shí)現(xiàn)隱式鏈接需要?jiǎng)?chuàng)建動(dòng)態(tài)庫(kù)時(shí)產(chǎn)生的三個(gè)文件:動(dòng)態(tài)庫(kù)文件(.dll)、引入庫(kù)文件(.lib)和頭文件(.h)。隱式鏈接的三個(gè)要點(diǎn)如下:
(1)把動(dòng)態(tài)庫(kù)的頭文件(.h)拷貝到應(yīng)用程序工程目錄下,對(duì)其拷貝作如下修改:把所有的導(dǎo)出關(guān)鍵字declspec(dllexport)換成導(dǎo)入關(guān)鍵字_declspec(dllimport),在文件開(kāi)始處加入語(yǔ)句:#pragma comment(lib,“引入庫(kù)名”),告訴Link要連接引入庫(kù),在應(yīng)用程序的各個(gè)使用DDL的.cpp文件中用語(yǔ)句#include包含這個(gè)頭文件(.h)。
(2)將引入庫(kù)(.lib)拷貝到應(yīng)用程序工程目錄下,以便VC++的Link鏈接時(shí)使用。
(3)將動(dòng)態(tài)庫(kù)(.dll)復(fù)制到應(yīng)用程序工程目錄下,便于Windows查找。
下面是一個(gè)制臺(tái)應(yīng)用程序DLLTestA隱式鏈接到前面創(chuàng)建的動(dòng)態(tài)庫(kù)的例子。
頭文件DLLTestA.h代碼如下:
#pragma comment(lib,“MyDLL.lib”)
_declspec(dllimport)int Add(int x,int y);
實(shí)現(xiàn)文件DLLTestA.cpp代碼如下:
#1nchde
#include“DLLTestA.h”
void main()
{int a;
a=Add(20,10);
printf(“20+10=%d”,a);
}
DLLTextA.h文件中的關(guān)鍵字pmgam comment通知Link程序要鏈接MyDLL.lib。導(dǎo)入關(guān)鍵字_declspec(dl-Hmpoa)用來(lái)說(shuō)明其后的函數(shù)是從動(dòng)態(tài)庫(kù)中引入的。按Ctrl+F5鍵就可以編譯執(zhí)行該程序。
2.2顯式鏈接
使用顯式鏈接時(shí),應(yīng)用程序不需要使用相應(yīng)的.lib和.h文件,只需將.dll拷貝到當(dāng)前工作目錄下即可。顯式鏈接方式下,應(yīng)用程序運(yùn)行時(shí)可以隨時(shí)加載和卸載DLL。
顯式鏈接的幾個(gè)要點(diǎn)如下:
(1)調(diào)用GetModuleHandle()函數(shù)檢查DLL是否已經(jīng)被映射到進(jìn)程的地址空間中:
(2)調(diào)用LoadLibrary函數(shù)加載DLL并得到其模塊句柄:
(3)調(diào)用GetProcAddress函數(shù)獲得DLL中輸出函數(shù)的地址:
(4)使用DLL結(jié)束后,調(diào)用FreeLibrary函數(shù)卸載DLL。
下面是在MFC對(duì)話框工程DLLTestB中實(shí)現(xiàn)顯式鏈接的部分代碼:
void CDLLTestBDlg::OnAdd()
{
HMODULE hlnst=GetModuleHandle(“MyDLL.dll”);
if(hlnst==NULL)
{hlnst=LoadLibrary(“MyDLL.dll”);}
typcda int(*AddProe)(int m,int n);
AddProc addp=(AddProc)GetProcAddress(hlnst“Add”);
if(!addp){“MessageBox(“獲取函數(shù)地址失敗!”);return;”}
CString str;
str.Format(“10+20=%d”,addp(10,20));
MessageBox(str);
FreeLibrary(hlnst);
}
上面代碼中使用類型定義關(guān)鍵字typedef定義與DLL中相同類型的函數(shù)指針,用來(lái)存函數(shù)的地址。
3結(jié)束語(yǔ)
DLL封裝了共享資源和代碼,在開(kāi)發(fā)以Windows為平臺(tái)的應(yīng)用程序時(shí),使用DLL技術(shù)開(kāi)發(fā)項(xiàng)目,可簡(jiǎn)化項(xiàng)目管理,提高開(kāi)發(fā)速度。因此,掌握DLL技術(shù)很有必要。