動態(tài)鏈接庫DLL編程課件_第1頁
動態(tài)鏈接庫DLL編程課件_第2頁
動態(tài)鏈接庫DLL編程課件_第3頁
動態(tài)鏈接庫DLL編程課件_第4頁
動態(tài)鏈接庫DLL編程課件_第5頁
已閱讀5頁,還剩56頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、VC+動態(tài)鏈接庫(DLL)編程1.概論 先來闡述一下DLL(Dynamic Linkable Library)的概念,你可以簡單的把DLL看成一種倉庫,它提供給你一些可以直接拿來用的變量、函數(shù)或類。在倉庫的發(fā)展史上經歷了“無庫靜態(tài)鏈接庫動態(tài)鏈接庫”的時代。 對動態(tài)鏈接庫,需建立如下概念: (1)與具體的編程語言及編譯器無關 只要遵循約定的DLL接口規(guī)范和調用方式,用各種語言編寫的DLL都可以相互調用。譬如Windows提供的系統(tǒng)DLL(其中包括了Windows的API),在任何開發(fā)環(huán)境中都能被調用,不在乎其是Visual Basic、Visual C+還是Delphi。 (2)動態(tài)鏈接庫隨處可

2、見 在Windows目錄下的system32文件夾中會看到kernel32.dll、user32.dll和gdi32.dll,windows的大多數(shù)API都包含在這些DLL中。kernel32.dll中的函數(shù)主要處理內存管理和進程調度;user32.dll中的函數(shù)主要控制用戶界面(MessageBox函數(shù));gdi32.dll中的函數(shù)則負責圖形方面的操作。 #include #include .lib.h #pragma comment( lib, .debuglibTest.lib ) /指定與靜態(tài)庫一起連接 int main(int argc, char* argv) printf( 2

3、+ 3 = %d, add( 2, 3 ) ); 選擇tools、options、directories、library files菜單或選項,填入庫文件路徑 4.非MFC DLL 在建立的工程中添加lib.h及l(fā)ib.cpp文件,源代碼如下:/* 文件名:lib.h*/#ifndef LIB_H#define LIB_Hextern C int _declspec(dllexport)add(int x, int y);#endif/* 文件名:lib.cpp*/#include lib.hint add(int x, int y)return x + y;dllCall #include

4、#include typedef int(*lpAddFun)(int, int); /宏定義函數(shù)指針類型int main(int argc, char *argv) HINSTANCE hDll; /DLL句柄 lpAddFun addFun; /函數(shù)指針 hDll = LoadLibrary(.DebugdllTest.dll); if (hDll != NULL) addFun = (lpAddFun)GetProcAddress(hDll, add); if (addFun != NULL) int result = addFun(2, 3); printf(%d, result);

5、FreeLibrary(hDll); return 0;DLL的調用和靜態(tài)鏈接庫的調用有較大差異 首先,語句typedef int ( * lpAddFun)(int,int)定義了一個與add函數(shù)接受參數(shù)類型和返回值均相同的函數(shù)指針類型。隨后,在main函數(shù)中定義了lpAddFun的實例addFun;其次,在函數(shù)main中定義了一個DLL HINSTANCE句柄實例hDll,通過Win32 Api函數(shù)LoadLibrary動態(tài)加載了DLL模塊并將DLL模塊句柄賦給了hDll;再次,在函數(shù)main中通過Win32 Api函數(shù)GetProcAddress得到了所加載DLL模塊中函數(shù)add的地址并

6、賦給了addFun。經由函數(shù)指針addFun進行了對DLL中add函數(shù)的調用;最后,應用工程使用完DLL后,在函數(shù)main中通過Win32 Api函數(shù)FreeLibrary釋放了已經加載的DLL模塊。在DLL中想要export的函數(shù)和數(shù)據(jù)定義前添加_declspec(dllexport)關鍵字(對于函數(shù)和變量定義,加在最前面;對于class定義,加在class關鍵字后);_declspec(dllexport) void ShowDlg(void)class _declspec(dllexport) class_name /導出類 這樣該函數(shù)和數(shù)據(jù)就會被添加到ET中。使用這種方法函數(shù)將按名字e

7、xport。_declspec(dllexport)(.def) 文件聲明為DLL創(chuàng)建一個.DEF文件(模塊定義文件),并在build該DLL時使用這個.DEF文件。使用這種方法使你可以將函數(shù)按序號export。在LINK選項卡中假如: /def:lib.def將lib.def加入到工程中。庫的調試與查看 動態(tài)鏈接庫中的導出接口可以使用Visual C+的Depends工具進行查看,用Depends打開系統(tǒng)目錄中的MouseHook.dll .DLL的調用方式 隱式調用:將DLL工程生成的.lib文件和.dll文件拷入當前工程所在的目錄,并在*.cpp文件(的頂部添加:#pragma comm

8、ent(lib,RegularDll.lib) OR動態(tài)調用特點:是完全由編程者用 API 函數(shù)加載和卸載 DLL,程序員可以決定 DLL 文件何時加載或不加載,顯式鏈接在運行時決定加載哪個 DLL 文件。dllTest.dll 在建立的工程中添加lib.h及l(fā)ib.cpp文件,源代碼如下:/* 文件名:lib.h*/#ifndef LIB_H#define LIB_Hextern C int _declspec(dllexport)add(int x, int y);#endif/* 文件名:lib.cpp*/#include lib.hint add(int x, int y)return

9、 x + y;DLL的Export和Import DLL的export是指將DLL中的函數(shù)和數(shù)據(jù)輸出到其它程式中,以供其使用。DLL的import是指使用DLL的程式引入DLL中的函數(shù)和數(shù)據(jù)。DLL的export DLL中包含有一個表,稱為export table(以下簡稱ET),其中包含了DLL中可以被外部程式使用的所有函數(shù)和數(shù)據(jù)的名字。只有記錄在ET中的函數(shù)和數(shù)據(jù)才可以被外部程式所使用(如果沒有.DEF文件的話),其它所有沒有記錄在ET中的函數(shù)和數(shù)據(jù)都被視為是DLL私有的。DllMain函數(shù) Windows在加載DLL的時候,需要一個入口函數(shù),就如同控制臺或DOS程序需要main函數(shù)、WI

10、N32程序需要WinMain函數(shù)一樣。在前面的例子中,DLL并沒有提供DllMain函數(shù),應用工程也能成功引用DLL,這是因為Windows在找不到DllMain的時候,系統(tǒng)會從其它運行庫中引入一個不做任何操作的缺省DllMain函數(shù)版本,并不意味著DLL可以放棄DllMain函數(shù)。 DLL導出變量 /* 文件名:lib.h*/#ifndef LIB_H#define LIB_Hextern int dllGlobalVar;#endif/* 文件名:lib.cpp */#include lib.h#include int dllGlobalVar;BOOL APIENTRY DllMain(

11、HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) dllGlobalVar = 100; /在dll被加載時,賦全局變量為100 return TRUE;文件名:lib.def;在DLL中導出變量LIBRARY dllTestEXPORTSdllGlobalVar DATA 在主函數(shù)中引用DLL中定義的全局變量:#include #pragma comment(lib,dllTest.lib)extern int _declspec(dllimport) dllGlobalVar; /用_declspec(dllimpor

12、t)導入int main(int argc, char *argv)printf(%d , dllGlobalVar);dllGlobalVar = 1; printf(%d , dllGlobalVar);return 0;特別要注意用extern int dllGlobalVar聲明所導入的并不是DLL中全局變量本身,而是其地址,應用程序必須通過強制指針轉換來使用DLL中的全局變量。這一點,從*(int*)dllGlobalVar可以看出。因此在采用這種方式引用DLL全局變量時,千萬不要進行這樣的賦值操作:dllGlobalVar = 1;MFC規(guī)則DLL MFC規(guī)則DLL的概念體現(xiàn)在兩方

13、面:它是MFC的 “是MFC的”意味著可以在這種DLL的內部使用MFC;它是規(guī)則的 “是規(guī)則的”意味著它不同于MFC擴展DLL,在MFC規(guī)則DLL的內部雖然可以使用MFC,但是其與應用程序的接口不能是MFC。而MFC擴展DLL與應用程序的接口可以是MFC,可以從MFC擴展DLL中導出一個MFC類的派生類。Regular DLL能夠被所有支持DLL技術的語言所編寫的應用程序調用,當然也包括使用MFC的應用程序。 Regular DLL分為兩類:(1)靜態(tài)鏈接到MFC 的規(guī)則DLL靜態(tài)鏈接到MFC的規(guī)則DLL與MFC庫(包括MFC擴展 DLL)靜態(tài)鏈接,將MFC庫的代碼直接生成在.dll文件中。在

14、調用這種DLL的接口時,MFC使用DLL的資源。因此,在靜態(tài)鏈接到MFC 的規(guī)則DLL中不需要進行模塊狀態(tài)的切換。使用這種方法生成的規(guī)則DLL其程序較大,也可能包含重復的代碼。(2)動態(tài)鏈接到MFC 的規(guī)則DLL動態(tài)鏈接到MFC 的規(guī)則DLL 可以和使用它的可執(zhí)行文件同時動態(tài)鏈接到 MFC DLL 和任何MFC擴展 DLL。在使用了MFC共享庫的時候,默認情況下,MFC使用主應用程序的資源句柄來加載資源模板。這樣,當DLL和應用程序中存在相同ID的資源時(即所謂的資源重復問題),系統(tǒng)可能不能獲得正確的資源。因此,對于共享MFC DLL的規(guī)則DLL,必須進行模塊切換以使得MFC能夠找到正確的資源

15、模板。MFC規(guī)則DLL的創(chuàng)建 automation(自動化)技術 是否支持Windows Sockets 在MFC應用程序中CWinApp取代了SDK程序中WinMain的地位,SDK程序WinMain所完成的工作由CWinApp的三個函數(shù)完成:virtual BOOL InitApplication( );virtual BOOL InitInstance( );virtual BOOL Run( ); /傳說中MFC程序的“活水源頭”MFC規(guī)則DLL接口函數(shù)#include StdAfx.h #include DllDialog.h_declspec(dllexport) void Sho

16、wDlg(void)或extern C _declspec(dllexport) void ShowDlg(void) CDllDialog dllDialog; dllDialog.DoModal();分析:這個接口并不使用MFC,但是在其中卻可以調用MFC擴展類CdllDialog的函數(shù),這體現(xiàn)了“規(guī)則”的概類。與非MFC DLL完全相同,可以使用_declspec(dllexport)聲明或在.def中引出的方式導出MFC規(guī)則DLL中的接口。MFC規(guī)則DLL的調用 #pragma comment(lib,RegularDll.lib)_declspec(dllexport) void S

17、howDlg(void)void ShowDlg(void); 或extern C _declspec(dllexport) void ShowDlg(void)extern C void ShowDlg(void); void CRegularDllCallDlg:OnCalldllButton() ShowDlg();MFC擴展 DLL MFC擴展DLL與MFC規(guī)則DLL的相同點在于在兩種DLL的內部都可以使用MFC類庫,其不同點在于MFC擴展DLL與應用程序的接口可以是MFC的。MFC擴展DLL的含義在于它是MFC的擴展,其主要功能是實現(xiàn)從現(xiàn)有MFC庫類中派生出可重用的類。MFC擴展DL

18、L使用MFC 動態(tài)鏈接庫版本,因此只有用共享MFC 版本生成的MFC 可執(zhí)行文件(應用程序或規(guī)則DLL)才能使用MFC擴展DLL。一般使用MFC擴展DLL來包含一些MFC的增強功能,譬如擴展MFC的CStatic、CButton等類使之具備更強大的能力。三種DLL對DllMain入口函數(shù)的不同處理方式: DLL類型 入口函數(shù) 非 MFC DLL 編程者提供DllMain函數(shù) MFC規(guī)則 DLL CWinApp對象的InitInstance 和 ExitInstance MFC擴展 DLL MFC DLL向導生成DllMain 函數(shù) 宏宏為DLL和應用程序的編寫提供了方便。像AFX_EXT_CL

19、ASS、AFX_EXT_API、AFX_EXT_DATA在DLL和應用程序中將具有不同的定義,這取決于_AFXEXT宏是否被定義。這使得在DLL和應用程序中,使用統(tǒng)一的一個宏就可以表示出輸出和輸入的不同意思。在DLL中,表示輸出(因為_AFXEXT被定義,通常是在編譯器的標識參數(shù)中指定/D_AFXEXT);在應用程序中,則表示輸入(_AFXEXT沒有定義)。 AFX_CLASS_IMPORT _declspec(dllexport) AFX_API_IMPORT _declspec(dllexport) AFX_DATA_IMPORT _declspec(dllexport) AFX_CLAS

20、S_EXPORT _declspec(dllexport) AFX_API_EXPORT _declspec(dllexport) AFX_DATA_EXPORT _declspec(dllexport) AFX_EXT_CLASS #ifdef _AFXEXT AFX_CLASS_EXPORT #else AFX_CLASS_IMPORT AFX_EXT_API #ifdef _AFXEXT AFX_API_EXPORT #else AFX_API_IMPORT AFX_EXT_DATA #ifdef _AFXEXT AFX_DATA_EXPORT #else AFX_DATA_IMPORT

21、 class AFX_EXT_CLASS CExtDialog : public CDialog *#include .ExtDialog.h #pragma comment( lib, ExtDll.lib ) 而“調用DLL”按鈕的單擊事件的消息處理函數(shù)為: void CLoadExtDllDlg:OnDllcallButton() CExtDialogextDialog; extDialog.DoModal(); Win32系統(tǒng)鉤子技術APIHOOK技術應用廣泛,常用于屏幕取詞、網絡防火墻、病毒木馬、加殼軟件、串口紅外通信、游戲外掛、Internet通信等領域。HOOK的中文意思就是鉤子

22、,APIHOOK就是鉤住API,對API進行預處理,先執(zhí)行我們的函數(shù)。 APIHOOK技術鉤子的本質是一段用以處理系統(tǒng)消息的程序,通過系統(tǒng)調用,把它掛入系統(tǒng)。鉤子的種類很多,每種鉤子可以截獲并處理相應的消息,每當特定的消息發(fā)出,在到達目的窗口之前,鉤子程序先行截獲該消息、得到對此消息的控制權。此時鉤子函數(shù)可以對截獲的消息進行加工處理,甚至可以強制結束消息的傳遞。這有點類似與MFC中的PreTranslateMessage函數(shù),所不同的是該函數(shù)只能用于攔截本進程中的消息,而對系統(tǒng)消息則無能為力。 Win32系統(tǒng)鉤子的實現(xiàn) 每種類型的鉤子均由系統(tǒng)來維護一個鉤子鏈,最近安裝的鉤子位于鏈的開始,擁有最

23、高的優(yōu)先級,而最先安裝的鉤子則處在鏈的末尾。要實現(xiàn)Win32的系統(tǒng)鉤子,首先要調用SDK中的API函數(shù)SetWindowsHookEx來安裝這個鉤子函數(shù),其原型是: HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId); 其中:第一個參數(shù)是鉤子的類型,常用的有WH_MOUSE、WH_KEYBOARD、WH_GETMESSAGE等;第二個參數(shù)是鉤子函數(shù)的地址,當鉤子鉤到任何消息后便調用這個函數(shù);第三個參數(shù)是鉤子函數(shù)所在模塊的句柄;第四個參數(shù)是鉤子相關函數(shù)的ID用以指定想讓鉤子去鉤哪個

24、線程,為0時則攔截整個系統(tǒng)的消息此時為全局鉤子。如果指定確定的線程,即為線程專用鉤子。 全局鉤子函數(shù)必須包含在DLL(動態(tài)鏈接庫)中,而線程專用鉤子則可包含在可執(zhí)行文件中。得到控制權的鉤子函數(shù)在處理完消息后,可以調用另外一個SDK中的API函數(shù)CallNextHookEx來繼續(xù)傳遞該消息。也可以通過直接返回TRUE來丟棄該消息,阻止該消息的傳遞。使用全局鉤子函數(shù)時需要以DLL為載體,VC6中有三種形式的MFC DLL可供選擇,即標準靜態(tài)鏈接MFC DLL、標準動態(tài)鏈接MFC DLL以及擴展MFC DLL)。第一種DLL在編譯時把使用的MFC代碼鏈接到DLL中,執(zhí)行程序時不需要其他MFC動態(tài)鏈接

25、類庫的支持,但體積較大;第二種DLL在運行時動態(tài)鏈接到MFC類庫,因而體積較小,但卻依賴于MFC動態(tài)鏈接類庫的支持;這兩種DLL均可被MFC程序和Win32程序使用。第三種DLL的也是動態(tài)連接,但做為MFC類庫的擴展,只能被MFC程序使用。 Win32 DLL BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason, LPVOID lpvReserved);其中:第一個參數(shù)表示DLL的實例句柄;第三個參數(shù)系統(tǒng)保留;第二個參數(shù)指明了當前調用該動態(tài)連接庫的狀態(tài),它有四個可能的值:DLL_PROCESS_ATTACH(進程載入)、DLL_THRE

26、AD_ATTACH(線程載入)、DLL_THREAD_DETACH(線程卸載)、DLL_PROCESS_DETACH(進程卸載)。DLL的共享問題由于在Win32環(huán)境下,所有進程的空間都是相互獨立的,這減少了應用程序間的相互影響,但大大增加了編程的難度。當進程在動態(tài)加載DLL時,系統(tǒng)自動把DLL地址映射到該進程的私有空間;而且也復制該DLL的全局數(shù)據(jù)的一份拷貝到該進程空間,每個進程所擁有的相同的DLL的全局數(shù)據(jù)其值卻并不一定是相同的。當DLL內存被映射到進程空間中,每個進程都有自己的全局內存拷貝,加載DLL的每一個新的進程都重新初始化這一內存區(qū)域,也就是說進程不能再共享DLL。全局共享數(shù)據(jù)的實

27、現(xiàn) 在Win32環(huán)境下要想在多個進程中共享數(shù)據(jù),就必須進行必要的設置。一種方法便是把這些需要共享的數(shù)據(jù)單獨分離出來,放置在一個獨立的數(shù)據(jù)段里,并把該段的屬性設置為共享,建立一個內存共享的DLL。 #pragma data_seg用#pragma data_seg建立一個新的數(shù)據(jù)段并定義共享數(shù)據(jù),其具體格式為: #pragma data_seg (shareddata) HWND sharedwnd=NULL;/共享數(shù)據(jù) #pragma data_seg() 所有在data_seg pragmas語句之間聲明的變量都將在shareddata段中。僅定義一個數(shù)據(jù)段還不能達到共享數(shù)據(jù)的目的,還要告訴編譯器該段的屬性,有兩種方法可以實現(xiàn)該目的(其效果是相同的),一種方法是在.DEF文件中加入如下語句: SETCTIONS shareddata READ WRITE SHARED 另一種方法是在項目設

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論