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