畢業論文-VC++環境下的動態鏈接庫的開發與應用_第1頁
畢業論文-VC++環境下的動態鏈接庫的開發與應用_第2頁
畢業論文-VC++環境下的動態鏈接庫的開發與應用_第3頁
畢業論文-VC++環境下的動態鏈接庫的開發與應用_第4頁
畢業論文-VC++環境下的動態鏈接庫的開發與應用_第5頁
已閱讀5頁,還剩19頁未讀 繼續免費閱讀

下載本文檔

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

文檔簡介

.PAGE.1目錄TOC\o"1-3"\h\u10536目錄111610中文摘要25598Abstract2438一、概論3327571.1.研究背景3271611.2.動態鏈接庫的定義3159921.3.動態鏈接庫與靜態鏈接庫411931.3.1.靜態鏈接庫4135941.3.2.動態鏈接庫與靜態鏈接庫的區別4296721.4.動態鏈接庫的優點4316241.5.在以下這些情況下,必須使用動態鏈接庫: 5151661.6.VisualC++支持的動態鏈接庫的類型520557二、非MFC動態鏈接庫6196472.1.Non-MFCDLL動態鏈接庫的創建6153542.1.1.創建一個Non-MFCDll工程"MyDll"6149152.1.2.代碼分析8118872.2.聲明導出函數 9194582.3.DLL的調用方式 10285312.4.DllMain函數 114437三、MFC規則動態鏈接庫的創建13176603.1.概述13256823.2.MFC規則DLL分為兩類: 1312433.3.MFC規則DLL的創建 14244033.4.MFC規則DLL的調用 18134783.5.隱式調用2231657四、MFC擴展動態鏈接庫的創建24128254.1.概述2428344.3.MFC擴展DLL的加載3028477五、動態鏈接庫的典型應用3124705.4.DLL木馬3626909六、參考文獻3729778七、致謝38中文摘要動態鏈接庫英文為DynamicLinkLibrary,英文縮寫為DLL,是程序運行時由該程序動態鏈接調用的函數庫,是一些函數、數據和類集合成的可執行模塊,程序員可以將動態鏈接庫動態地集成到自己的程序中以使用庫中的函數、數據和類。開發和應用動態鏈接庫,有助于數據和資源的共享,簡化了軟件項目的管理。本文主要介紹動態鏈接庫創建、調用方法,及其典型應用。關鍵詞:動態鏈接庫〔DLL,非MFCDLL,MFC規則DLL,MFC擴展DLLAbstractDynamicLinkLibrary<DLL>encapsulatesthesharedresourceandcode.InexploringtheapplicationbasedonWindows,theuseofDLLtechnologycangreatlysavethememory.UsingDLLdevelopingprojectcansimplifytheprojectmanagementandspeeduptheexploration.Thispaper,introducingtheimplicitandexplicitlinkingofDLLwithinstances,providestechnicalsupporttotechniciansinexploringandusingDLL.Keywords:DynamicLinkLibrary<DLL>,Non-MFCDLL,MFCRegularDLL,MFCExtensionDLL一、概論1.1.研究背景自從微軟推出16位的Windows操作系統起,此后每種版本的Windows操作系統都非常依賴于動態鏈接庫<DLL>中的函數和數據,實際上Windows操作系統中幾乎所有的內容都由DLL以一種或另外一種形式代表著,例如顯示的字體和圖標存儲在GDIDLL中、顯示Windows桌面和處理用戶的輸入所需要的代碼被存儲在一個UserDLL中、Windows編程所需要的大量的API函數也被包含在KernelDLL中。在Windows操作系統中使用DLL有很多優點,最主要的一點是多個應用程序、甚至是不同語言編寫的應用程序可以共享一個DLL文件,真正實現了資源"共享",大大縮小了應用程序的執行代碼,更加有效的利用了內存;使用DLL的另一個優點是DLL文件作為一個單獨的程序模塊,封裝性、獨立性好,在軟件需要升級的時候,開發人員只需要修改相應的DLL文件就可以了,而且,當DLL中的函數改變后,只要不是參數的改變,程序代碼并不需要重新編譯。這在編程時十分有用,大大提高了軟件開發和維護的效率。既然DLL那么重要,所以搞清楚什么是DLL、如何在Windows操作系統中開發使用DLL是程序開發人員不得不解決的一個問題。本文針對這些問題,通過一個簡單的例子,全面地解析了在VisualC++編譯環境下編程實現DLL的過程。1.2.動態鏈接庫的定義動態鏈接庫英文為DynamicLinkLibrary,英文縮寫為DLL,是程序運行時由該程序動態鏈接調用的函數庫,是一些函數、數據和類集合成的可執行模塊,程序員可以將動態鏈接庫動態地集成到自己的程序中以使用庫中的函數、數據和類。動態鏈接提供了一種方法,使進程可以調用不屬于其可執行代碼的函數。函數的可執行代碼位于一個DLL中,該DLL包含一個或多個已被編譯、鏈接并與使用它們的進程分開存儲的函數。多個應用程序可同時訪問內存中單個DLL副本的內容。1.3.動態鏈接庫與靜態鏈接庫1.3.1.靜態鏈接庫靜態鏈接庫就是你使用的.lib文件,庫中的代碼最后需要連接到你的可執行文件中去。靜態鏈接庫不同于動態鏈接庫〔*.dll,在靜態庫情況下,函數和數據被編譯進一個二進制文件〔通常擴展名為*.LIB,VisualC++的編譯器在鏈接過程中將從靜態庫中恢復這些函數和數據并把他們和應用程序中的其他模塊組合在一起生成可執行文件。這個過程稱為"靜態鏈接",此時因為應用程序所需的全部內容都是從庫中復制了出來,所以靜態庫本身并不需要與可執行文件一起發行。用戶在交付最終靜態鏈接庫時,只需要提供.lib文件和相應的頭文件,不需要再提供庫的源代碼。在需要使用靜態庫的工程中,包含相應的頭文件,并把.lib文件加入工程中就可以了。1.3.2.動態鏈接庫與靜態鏈接庫的區別動態鏈接發生在程序運行時,動態鏈接的函數代碼不出現在程序的EXE文件中,它僅僅包含了應用程序運行過程中所調用的DLL函數的一些最基本信息〔例如DLL文件位置、函數名等;而靜態鏈接發生在編譯時,靜態鏈接的函數代碼實際被插入到程序的EXE文件中。1.4.動態鏈接庫的優點動態鏈接庫隨處可見,無論大型系統還是小規模軟件,都應用了動態鏈接庫,有效地實現了資源共享。在軟件開發中,應用動態鏈接庫具有以下優點:〔1擴展了應用程序的特性;〔2可以用許多種編程語言來編寫;〔3簡化了軟件項目的管理;〔4有助于節省內存;〔5有助于資源共享;〔6有助于應用程序的本地化;〔7有助于解決平臺差異。1.5.在以下這些情況下,必須使用動態鏈接庫:〔1多個應用程序共享代碼和數據〔2在各子程序過濾系統消息時必須使用動態鏈接庫〔3設備驅動程序必須是動態鏈接庫〔4在對話框編輯器中使用自己定義的控件,也必須使用動態鏈接庫〔5為了實現應用程序的國際化,往往需要使用動態鏈接庫1.6.VisualC++支持的動態鏈接庫的類型VisualC++支持三種DLL,它們分別是Non-MFCDLL〔非MFC動態庫、MFCRegularDLL〔MFC規則DLL、MFCExtensionDLL〔MFC擴展DLL。〔1非MFC動態庫指不使用MFC類庫創建的DLL。Win32DLL中的導出函數通常使用標準的C接口,這些函數可以被MFC或非MFC應用程序調用。〔2MFC規則DLLMFC規則DLL可以使用MFC來創建,可以導出C風格的函數,但不能導出C++類、成員函數或重載函數。它們可以被MFC或非MFC應用程序調用。但這種類型的DLL不能向應用程序傳遞MFC對象指針,必須使用MFC擴展DLL。MFC常規DLL按照與MFC的鏈接方式又分動態鏈接和靜態鏈接兩種。〔3MFC擴展DLL表面上更像應用程序而不像一組函數的集合,因為它可以創建MFC派生類。只能以動態方式與MFC鏈接,而且只能是使用MFC的動態鏈接版本的應用程序才可以使用這種DLL。在MFC擴展DLL中,可以由現有的MFC類導出自己的類,然后給應用程序一個擴展的MFC版本。支持C++接口,也就是說,該DLL可以導出整個類,客戶可以構造這些類的對象或從這些類進行派生。還可以用于在應用程序和DLL之間傳遞MFC導出對象。對象的成員函數位于創建對象的模塊中,應用程序和它加載的擴展DLL之間可以自如地傳遞MFC或MFC導出對象的指針。接下來,我們一起來具體討論一下以上三種動態鏈接庫的創建方法與調用方法。二、非MFC動態鏈接庫2.1.Non-MFCDLL動態鏈接庫的創建在VisualC++6.0開發環境下,打開File/New/Project選項,可以選擇Win32Dynamic-LinkLibrary或MFCAppWizard[dll]來以不同的方式來創建Non-MFCDll、RegularDll、ExtensionDll等不同種類的動態鏈接庫。下面演示以Win32Dynamic-LinkLibrary方式創建一個簡單Non-MFCDll工程"MyDll"。2.1.1.創建一個Non-MFCDll工程"MyDll"在VisualC++6.0開發環境下,打開File/New/Project選項,選擇Win32Dynamic-LinkLibrary創建一個簡單DLL工程,并命名為"MyDll"。圖2-1-1創建Non-MFCDll工程"MyDll"在建立的工程中添加lib.h及lib.cpp文件,源代碼如下:/*文件名:lib.h*/#ifndefLIB_H#defineLIB_Hextern"C"int__declspec<dllexport>multi<intx,inty>;#endif

/*文件名:lib.cpp*/

#include"lib.h"intmulti<intx,inty>{returnx*y;}顯然,以上建立的是一個返回兩個數的乘積的動態鏈接庫。〔3建立一個與MyDll工程處于同一工作區的應用工程DllCall。圖2-1-2創建應用工程"DllCall"在工程"DllCall"創建源代碼文件"DllCall.cpp",它調用DLL中的函數multi,其源代碼如下:#include<stdio.h>#include<windows.h>typedefint<*lpmultiFunc><int,int>;//宏定義函數指針類型intmain<>{ HINSTANCEhDll;//DLL句柄 lpmultiFuncmultiFunc;//函數指針 hDll=LoadLibrary<"..\\Debug\\MyDll.dll">; if<hDll!=NULL>{ multiFunc=<lpmultiFunc>GetProcAddress<hDll,"multi">; if<multiFunc!=NULL>{ intresult=multiFunc<3,5>;//計算3與5的乘積printf<"%d\n",result>;} FreeLibrary<hDll>;} return0;}編譯,運行結果如下:圖2-1-3運行結果如上圖所示,成功返回3*5的結果,表明此NON-MFCDLL創建成功。2.1.2.代碼分析分析上述代碼,Mydll工程中的lib.h對函數multi的聲明前面添加了__declspec<dllexport>語句。這個語句的含義是聲明函數multi為DLL的導出函數。DLL內的函數分為兩種:<1>DLL導出函數,可供應用程序調用;<2>DLL內部函數,只能在DLL程序使用,應用程序無法調用它們。現在分析應用工程dllCall對DLL的調用是如何實現的:首先,語句typedefint<*lpmultiFun><int,int>定義了一個與multi函數接受參數類型和返回值均相同的函數指針類型。隨后,在main函數中定義了lpmultiFunc的實例multiFunc;其次,在函數main中定義了一個DLLHINSTANCE句柄實例hDll,通過Win32Api函數LoadLibrary動態加載了DLL模塊并將DLL模塊句柄賦給了hDll;再次,在函數main中通過Win32Api函數GetProcAddress得到了所加載DLL模塊中函數multi的地址并賦給了multiFunc。經由函數指針multiFunc進行了對DLL中add函數的調用;最后,應用工程使用完DLL后,在函數main中通過Win32Api函數FreeLibrary釋放了已經加載的DLL模塊。從而完成了對dll的調用。通過以上例子分析可得出以下結論:<1>DLL中需以某種特定的方式聲明導出函數〔或變量、類;<2>應用工程需以某種特定的方式調用DLL的導出函數〔或變量、類。2.2.聲明導出函數DLL中導出函數的聲明有兩種方式:一是像上述例子一樣,在定義函數時使用導出關鍵字_declspec<dllexport>;另外一種方法是在創建DLL文件時使用模塊定義文件.def。如以下例子:下面的代碼演示了怎樣在.def文件中將函數multi聲明為DLL導出函數〔需在MyDll工程中添加lib.def文件:LIBRARYMydllEXPORTSmulti1def文件的規則為:<1>LIBRARY語句說明.def文件相應的DLL;<2>EXPORTS語句后列出要導出函數的名稱。可以在.def文件中的導出函數名后加n,表示要導出函數的序號為n〔在進行函數調用時,這個序號將發揮其作用;<3>.def文件中的注釋由每個注釋行開始處的分號<;>指定,且注釋不能與語句共享一行。由此可以看出,例子中lib.def文件的含義為生成名為"MyDll"的動態鏈接庫,導出其中的multi函數,并指定multi函數的序號為1。2.3.DLL的調用方式DLL有兩種調用方式:〔1動態調用在上述的例子中我們看到了由"LoadLibrary-GetProcAddress-FreeLibrary"系統Api提供的三位一體"DLL加載-DLL函數地址獲取-DLL釋放"方式,這種調用方式稱為DLL的動態調用。

動態調用方式的特點是完全由編程者用API函數加載和卸載DLL,程序員可以決定DLL文件何時加載或不加載,顯式鏈接在運行時決定加載哪個DLL文件。〔2靜態調用靜態調用方式的特點是由編譯系統完成對DLL的加載和應用程序結束時DLL的卸載。當調用某DLL的應用程序結束時,若系統中還有其它程序使用該DLL,則Windows對DLL的應用記錄減1,直到所有使用該DLL的程序都結束時才釋放它。靜態調用方式簡單實用,但不如動態調用方式靈活。如以下例子所示:將編譯MyDll工程所生成的.lib和.dll文件拷入dllCall工程所在的路徑,圖2-3-1添加MyDll.lib和MyDll.dll文件在dllCall源文件下執行下列代碼:#include<stdio.h>#pragmacomment<lib,"MyDll.lib">//.lib文件中僅僅是關于其對應DLL文件中函數的重定位信息extern"C"__declspec<dllimport>multi<intx,inty>;intmain<intargc,char*argv[]>

{intresult=multi<3,5>;printf<"靜態調用結果:%d\n",result>;return0;}編譯運行,運行結果如下:圖2-3-2運行結果由上述代碼可以看出,靜態調用方式的順利進行需要完成兩個動作:告訴編譯器與DLL相對應的.lib文件所在的路徑及文件名,#pragmacomment<lib,"MyDll.lib">就是起這個作用。程序員在建立一個DLL文件時,連接器會自動為其生成一個對應的.lib文件,該文件包含了DLL導出函數的符號名及序號〔并不含有實際的代碼。在應用程序里,.lib文件將作為DLL的替代文件參與編譯。〔2聲明導入函數,extern"C"__declspec<dllimport>multi<intx,inty>語句中的__declspec<dllimport>發揮這個作用。靜態調用方式不再需要使用系統API來加載、卸載DLL以及獲取DLL中導出函數的地址。這是因為,當程序員通過靜態鏈接方式編譯生成應用程序時,應用程序中調用的與.lib文件中導出符號相匹配的函數符號將進入到生成的EXE文件中,.lib文件中所包含的與之對應的DLL文件的文件名也被編譯器存儲在EXE文件內部。當應用程序運行過程中需要加載DLL文件時,Windows將根據這些信息發現并加載DLL,然后通過符號名實現對DLL函數的動態鏈接。這樣,EXE將能直接通過函數名調用DLL的輸出函數,就象調用程序內部的其他函數一樣。2.4.DllMain函數Windows在加載DLL的時候,需要一個入口函數,就如同控制臺或DOS程序需要main函數、WIN32程序需要WinMain函數一樣。在前面的例子中,DLL并沒有提供DllMain函數,應用工程也能成功引用DLL,這是因為Windows在找不到DllMain的時候,系統會從其它運行庫中引入一個不做任何操作的缺省DllMain函數版本,并不意味著DLL可以放棄DllMain函數。根據編寫規范,Windows必須查找并執行DLL里的DllMain函數作為加載DLL的依據,它使得DLL得以保留在內存里。這個函數并不屬于導出函數,而是DLL的內部函數。這意味著不能直接在應用工程中引用DllMain函數,DllMain是自動被調用的。以下是一個DllMain函數的例子BOOLAPIENTRYDllMain<HANDLEhModule,DWORDul_reason_for_call,LPVOIDlpReserved>

{

switch<ul_reason_for_call>

{

caseDLL_PROCESS_ATTACH:

printf<"\nprocessattachofdll">;

break;

caseDLL_THREAD_ATTACH:

printf<"\nthreadattachofdll">;

break;

caseDLL_THREAD_DETACH:

printf<"\nthreaddetachofdll">;

break;

caseDLL_PROCESS_DETACH:

printf<"\nprocessdetachofdll">;

break;

}

returnTRUE;

}DllMain函數在DLL被加載和卸載時被調用,在單個線程啟動和終止時,DLLMain函數也被調用,ul_reason_for_call指明了被調用的原因。原因共有4種,即PROCESS_ATTACH、PROCESS_DETACH、THREAD_ATTACH和THREAD_DETACH,以switch語句列出。分析DllMain的函數頭BOOLAPIENTRYDllMain<HANDLEhModule,WORDul_reason_for_call,LPVOIDlpReserved>APIENTRY被定義為__stdcall,它意味著這個函數以標準Pascal的方式進行調用,也就是WINAPI方式;進程中的每個DLL模塊被全局唯一的32字節的HINSTANCE句柄標識,只有在特定的進程內部有效,句柄代表了DLL模塊在進程虛擬空間中的起始地址。在Win32中,HINSTANCE和HMODULE的值是相同的,這兩種類型可以替換使用,這就是函數參數hModule的來歷。三、MFC規則動態鏈接庫的創建3.1.概述〔1MFC規則DLL,顧名思義,可以在這種DLL的內部使用MFC;〔2它是規則的,意味著它不同于MFC擴展DLL,在MFC規則DLL的內部雖然可以使用MFC,但是其與應用程序的接口不能是MFC。而MFC擴展DLL與應用程序的接口可以是MFC,可以從MFC擴展DLL中導出一個MFC類的派生類。MFC規則DLL能夠被所有支持DLL技術的語言所編寫的應用程序調用,當然也包括使用MFC的應用程序。在這種動態連接庫中,包含一個從CWinApp繼承下來的類,DllMain函數則由MFC自動提供。3.2.MFC規則DLL分為兩類:〔1靜態鏈接到MFC的規則DLL靜態鏈接到MFC的規則DLL與MFC庫〔包括MFC擴展DLL靜態鏈接,將MFC庫的代碼直接生成在.dll文件中。在調用這種DLL的接口時,MFC使用DLL的資源。因此,在靜態鏈接到MFC的規則DLL中不需要進行模塊狀態的切換。使用這種方法生成的規則DLL其程序較大,也可能包含重復的代碼。〔2動態鏈接到MFC的規則DLL動態鏈接到MFC的規則DLL可以和使用它的可執行文件同時動態鏈接到MFCDLL和任何MFC擴展DLL。在使用了MFC共享庫的時候,默認情況下,MFC使用主應用程序的資源句柄來加載資源模板。這樣,當DLL和應用程序中存在相同ID的資源時〔即所謂的資源重復問題,系統可能不能獲得正確的資源。因此,對于共享MFCDLL的規則DLL,我們必須進行模塊切換以使得MFC能夠找到正確的資源模板。我們可以在VisualC++中設置MFC規則DLL是靜態鏈接到MFCDLL還是動態鏈接到MFCDLL。如下圖,依次選擇VisualC++的project->Settings->General菜單或選項,在MicrosoftFoundationClasses中進行設置。圖3-2-1設置動態/靜態鏈接MFCDLL3.3.MFC規則DLL的創建下面一步步講述使用MFC向導創建一個簡單的MFC規則DLL的過程。〔1首先在VisualC++6.0開發環境下,打開File/New/Project選項,選擇MFCAppWizard<dll>創建一個簡單DLL工程,并命名為"regularDll"。圖3-3-1創建MFC規則DLL點擊"確定"進入如下圖所示的對話框,選擇"動態鏈接庫和MFC靜態鏈接"圖3-3-2創建MFC規則DLL點擊"完成"按鈕完成向導。〔2在工程中添加一個對話框,并設計該對話框。圖3-3-3創建對話框為該對話框新建一個類CDllDialog,圖3-3-4新建類CDllDialog為對話框上的按鈕"MFCRegualrDll"添加消息響應函數,圖3-3-5添加消息響應函數并添加以下代碼:voidCDllDialog::OnButton1<>{ //TODO:Addyourcontrolnotificationhandlercodehere MessageBox<"MFCRegularDLL">;}在RegularDll.cpp的最后,添加MFC規則DLL接口函數。extern"C"__declspec<dllexport>voidShowDlg<void>{ AFX_MANAGE_STATE<AfxGetStaticModuleState<>> ; CDllDialogdllDialog; dllDialog.DoModal<>;}圖3-3-6添加MFC規則DLL接口函數在RegularDll.cpp的前面,添加#include"DllDialog.h"圖3-3-7添加MFC規則DLL接口函數完成上述步驟后,就可以編譯并生成Dll文件了。圖3-3-8添加MFC規則DLL接口函數3.4.MFC規則DLL的調用〔1首先,創建一個基于MFC的單文檔應用程序"CallRegDll"。圖3-4-1創建MFC的單文檔應用程序CallRegDll〔2添加一個菜單項"CallRegDll"。圖3-4-2添加一個菜單項〔3在視類對該菜單項添加消息響應函數,函數代碼如下:voidCCallRegDllView::OnRegdll<>{ //TODO:Addyourcommandhandlercodehere typedefvoid<*lpFun><void>; HINSTANCEhDll=NULL;//DLL句柄 hDll=LoadLibrary<"RegularDll.dll">;if<hDll!=NULL> {lpFunpShowDlg=<lpFun>GetProcAddress<hDll,"ShowDlg">;if<pShowDlg!=NULL>{ pShowDlg<>;}else{MessageBox<"DLL中函數尋找失敗">;}} else { MessageBox<"沒有找到相應的dll">; }}〔4編譯并運行程序。點擊菜單項,會彈出如下界面:圖3-4-3運行結果〔5將RegularDll.dll和復制到RegularDll.lib復制到CallRegDll工程的debug目錄下。圖3-4-4復制RegularDll.lib和RegularDll.dll再次編譯,運行程序,結果如下:圖3-4-5運行結果3.5.隱式調用上述例子中給出的是顯式調用的方式,我們也可以在EXE程序中隱式調用MFC規則DLL。將DLL工程生成的.lib文件和.dll文件拷入當前工程所在的目錄。圖3-4-6添加.lib文件和.dll文件并在CCallRegDllView.cpp文件的頂部添加以下代碼:#pragmacomment<lib,"RegularDll.lib">//extern"C"__declspec<dllimport>voidShowDlg<void>;//把消息響應函數CCallRegDllView::OnRegDll<>修改為以下:voidCCallRegDllView::OnRegDll<>{ //TODO:Addyourcommandhandlercodehere ShowDlg<>;}編譯運行程序,同樣能得到正確的結果。圖3-4-7運行結果四、MFC擴展動態鏈接庫的創建4.1.概述MFC擴展DLL與MFC規則DLL的相同點在于在兩種DLL的內部都可以使用MFC類庫,其不同點在于MFC擴展DLL與應用程序的接口可以是MFC的。MFC擴展DLL的含義在于它是MFC的擴展,其主要功能是實現從現有MFC庫類中派生出可重用的類。MFC擴展DLL使用MFC動態鏈接庫版本,因此只有用共享MFC版本生成的MFC可執行文件〔應用程序或規則DLL才能使用MFC擴展DLL。MFC規則DLL被MFC向導自動添加了一個CWinApp的對象,而MFC擴展DLL則不包含該對象,它只是被自動添加了DllMain函數。對于MFC擴展DLL,開發人員必須在DLL的DllMain函數中添加初始化和結束代碼。

總結三種DLL對DllMain入口函數的不同處理方式,可得出下表:

DLL類型入口函數非MFCDLL編程者提供DllMain函數MFC規則DLLCWinApp對象的InitInstance和ExitInstanceMFC擴展DLLMFCDLL向導生成DllMain函數對于MFC擴展DLL,系統會自動在工程中添加如下表所示的宏,這些宏為DLL和應用程序的編寫提供了方便。像AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA這樣的宏,在DLL和應用程序中將具有不同的定義,這取決于_AFXEXT宏是否被定義。這使得在DLL和應用程序中,使用統一的一個宏就可以表示出輸出和輸入的不同意思。宏定義AFX_CLASS_IMPORT__declspec<dllexport>AFX_API_IMPORT__declspec<dllexport>AFX_DATA_IMPORT__declspec<dllexport>AFX_CLASS_EXPORT__declspec<dllexport>AFX_API_EXPORT__declspec<dllexport>AFX_DATA_EXPORT__declspec<dllexport>AFX_EXT_CLASS#ifdef_AFXEXT

AFX_CLASS_EXPORT

#else

AFX_CLASS_IMPORTAFX_EXT_API#ifdef_AFXEXT

AFX_API_EXPORT

#else

AFX_API_IMPORTAFX_EXT_DATA#ifdef_AFXEXT

AFX_DATA_EXPORT

#else

AFX_DATA_IMPORT4.2.MFC擴展DLL導出MFC派生類在下述例子中,我們將新建一個名為"ExtDll"的MFC擴展DLL工程,在這個DLL中導出一個對話框類,這個對話框類派生自MFC類CDialog。圖4-2-1創建MFC擴展DLL圖4-2-2創建MFC擴展DLL使用MFC向導生成MFC擴展DLL時,系統會自動添加如下代碼:staticAFX_EXTENSION_MODULEExtDllDLL={NULL,NULL};

extern"C"intAPIENTRY

DllMain<HINSTANCEhInstance,DWORDdwReason,LPVOIDlpReserved>

{

//RemovethisifyouuselpReserved

UNREFERENCED_PARAMETER<lpReserved>;

//說明:lpReserved是一個被系統所保留的參數,對于隱式鏈接是一個非零值,對于顯式鏈接值是零

if<dwReason==DLL_PROCESS_ATTACH>

{

TRACE0<"EXTDLL.DLLInitializing!\n">;

//ExtensionDLLone-timeinitialization

if<!AfxInitExtensionModule<ExtDllDLL,hInstance>>

return0;

//InsertthisDLLintotheresourcechain

newCDynLinkLibrary<ExtDllDLL>;

}

elseif<dwReason==DLL_PROCESS_DETACH>

{

TRACE0<"EXTDLL.DLLTerminating!\n">;

//Terminatethelibrarybeforedestructorsarecalled

AfxTermExtensionModule<ExtDllDLL>;

}

return1;//ok

}代碼分析如下:

〔1上述代碼完成MFC擴展DLL的初始化和終止處理;

〔2初始化期間所創建的CDynLinkLibrary對象使MFC擴展DLL可以將DLL中的CRuntimeClass對象或資源導出到應用程序;

〔3AfxInitExtensionModule函數捕獲模塊的CRuntimeClass結構和在創建CDynLinkLibrary對象時使用的對象工廠〔COleObjectFactory對象;

〔4AfxTermExtensionModule函數使MFC得以在每個進程與擴展DLL分離時〔進程退出或使用AfxFreeLibrary卸載DLL時清除擴展DLL;

〔5第一條語句staticAFX_EXTENSION_MODULEExtDllDLL={NULL,NULL};定義了一個AFX_EXTENSION_MODULE類的靜態全局對象,AFX_EXTENSION_MODULE的定義如下:structAFX_EXTENSION_MODULE

{

BOOLbInitialized;

HMODULEhModule;

HMODULEhResource;

CRuntimeClass*pFirstSharedClass;

COleObjectFactory*pFirstSharedFactory;

};在資源編輯器中添加一個如下圖所示的對話框,并使用MFC類向導為其添加一個對應的類CExtDialog,系統自動添加了ExtDialog.h和ExtDialog.cpp兩個頭文件。圖4-2-3添加對話框圖4-2-3添加對話框類修改ExtDialog.h中CExtDialog類的聲明為:classAFX_EXT_CLASSCExtDialog:publicCDialog

{

public:

CExtDialog<CWnd*pParent=NULL>;

enum{IDD=IDD_DLL_DIALOG};

protected:

virtualvoidDoDataExchange<CDataExchange*pDX>;

DECLARE_MESSAGE_MAP<>

};這其中最主要的改變是我們在classAFX_EXT_CLASSCExtDialog語句中添加了"AFX_EXT_CLASS"宏,則使得DLL中的CExtDialog類被導出。為對話框按鈕"MFCExtentionDLL"添加消息響應函數voidCExtDialog::OnButton1<>{ //TODO:Addyourcontrolnotificationhandlercodehere MessageBox<"MFCExtentionDLL">;}最后,編譯運行,生成.lib文件和.dll文件。4.3.MFC擴展DLL的加載在上述工程所在的工作區中添加一個LoadExtDllDlg工程,用于演示MFC擴展DLL的加載。在LoadExtDllDlg工程中添加一個如下圖所示的對話框,這個對話框上包括一個"調用DLL"按鈕。圖4-3-1MFC擴展DLL調用工程中的對話框在與上圖對應對話框類實現文件的頭部添加://LoadExtDllDlg.cpp:implementationfile

//

#include"..\ExtDialog.h"

#pragmacomment<lib,"..\Debug\ExtDll.lib">而"調用DLL"按鈕的單擊事件的消息處理函數為:voidCLoadExtDllDlg::OnDllcallButton<>

{

CExtDialogextDialog;

extDialog.DoModal<>;

}最后編譯并運行,運行結果如下:圖4-3-2運行結果從上述加載過程,我們可總結出:

為提供給用戶隱式加載,MFC擴展DLL需要提供三個文件:

〔1描述DLL中擴展類的頭文件;

〔2與動態鏈接庫對應的.LIB文件;

〔3動態鏈接庫.DLL文件本身。

有了這三個文件,應用程序的開發者才可充分利用MFC擴展DLL。五、動態鏈接庫的典型應用動態鏈接庫DLL實現了庫的共享,體現了代碼重用的思想。我們可以把廣泛的、具有共性的、能夠多次被利用的函數和類定義在庫中。這樣,在再次使用這些函數和類的時候,就不再需要重新添加與這些函數和類相關的代碼。因此,動態鏈接庫的應用廣泛,而其主要的典型應用有以下幾方面:5.1.通用的算法圖像處理、視頻音頻解碼、壓縮與解壓縮、加密與解密通常采用某些特定的算法,這些算法較固定且在這類程序中往往經常被使用。如以下的例子:學習過較高級別數學〔概率統計與隨機過程、信號與線性系統及數字信號處理的讀者應該知道,傅立葉變換是一種在信號分析中常用的算法,用于時域和頻域的相互轉換。FFT變換算法通用而有共性,我們適宜把它集成在一個DLL中。我們可在相關資料上獲取到FFT變換算法的函數代碼如下:/*函數名稱:FFT<>

*參數:

*complex<double>*TD-指向時域數組的指針

*complex<double>*FD-指向頻域數組的指針

*r-2的冪數,即迭代次數

*返回值:無。

*說明:該函數用來實現快速傅立葉變換

*/

voidFFT<complex<double>*TD,complex<double>*FD,intr>

{

LONGcount;//傅立葉變換點數

inti,j,k;//循環變量

intbfsize,p;//中間變量

doubleangle;//角度

complex<double>*W,*X1,*X2,*X;

count=1<<r;//傅立葉變換點數

//分配運算所需存儲器

W=newcomplex<double>[count/2];

X1=newcomplex<double>[count];

X2=newcomplex<double>[count];

//計算加權系數

for<i=0;i<count/2;i++>

{

angle=-i*PI*2/count;

W[i]=complex<double><cos<angle>,sin<angle>>;

}

//將時域點寫入X1

memcpy<X1,TD,sizeof<complex<double>>*count>;

//采用蝶形算法進行快速傅立葉變換

for<k=0;k<r;k++>

{

for<j=0;j<1<<k;j++>

{

bfsize=1<<<r-k>;

for<i=0;i<bfsize/2;i++>

{

p=j*bfsize;

X2[i+p]=X1[i+p]+X1[i+p+bfsize/2];

X2[i+p+bfsize/2]=<X1[i+p]-X1[i+p+bfsize/2]>*W[i*<1<<k>];

}

}

X=X1;

X1=X2;

X2=X;

}

//重新排序

for<j=0;j<count;j++>

{

p=0;

for<i=0;i<r;i++>

{

if<j&<1<<i>>

{

p+=1<<<r-i-1>;

}

}

FD[j]=X1[p];

}

//釋放內存

deleteW;

deleteX1;

deleteX2;

}既然有了FFT這個函數,我們要把它做在DLL中,作為DLL的一個接口將是十分簡單的,其步驟如下:〔1利用MFC向導建立一個非MFCDLL;

〔2在工程中添加fft.h和fft.cpp兩個文件;fft.h的源代碼為:#ifndefFFT_H

#defineFFT_H

#include<complex>

usingnamespacestd;

extern"C"void__declspec<dllexport>__stdcallFFT<complex<double>*TD,complex<double>*FD,intr>;

#definePI3.1415926

#endiffft.cpp的源代碼為:/*文件名:fft.cpp*/

#include"fft.h"

void__stdcallFFT<complex<double>*TD,complex<double>*FD,intr>

{

}在任何編程語言中使用Win32APILoadLibrary都可以加載這個DLL,而使用GetProcAddress<hDll,"FFT">則可以獲得函數FFT的地址。

這個DLL中有兩點需要注意:

〔1使用extern"C"修飾函數聲明,否則,生成的DLL只能供C++調用;

〔2使用__stdcall修飾函數聲明及定義,__stdcall是WindowsAPI的函數調用方式。5.2.純資源DLL我們可以從DLL中獲取資源,對于一個支持多種語言的應用程序而言,我們可以判斷操作系統的語言,并自動為應用程序加載與操作系統對應的語言。這是多語言支持應用程序的一般做法。5.3.通信控制DLL串口、網口的通信控制函數如果由DLL提供則可以使應用程序輕松不少。在工業控制、modem程序甚至socket通信中,經常使用通信控制DLL。

在Windows系統,需通過DCB<DeviceControlBlock>對串口進行配置。利用WindowsAPIGetCommState函數可以獲取串口當前配置;利用SetCommState函數則可以設置串口通訊的參數。

串行通信通常按以下四步進行:

<1>打開串口;

<2>配置串口;

<3>數據傳送;

<4>關閉串口。

由此可見,我們需要給串口控制DLL提供如下四個接口函數://打開指定的串口,其參數port為端口號

BOOLComOpen<intport>;//在這個函數里使用默認的參數設置串口

//將打開的串口關閉

voidComClose<intport>;

//將串口接收緩沖區中的數據放到buffer中

intGetComData<char*buf,intbuf_len>;

//將指定長度的數據發送到串口

intSendDataToCom<LPBYTEbuf,intbuf_Len>;下面是DLL接口的主要源代碼框架://com.h:com類通信接口

classAFX_EXT_CLASScom

{

public:

ComOpen<intport>

{

}

intSendDataToCom<LPBYTEbuf,

溫馨提示

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

評論

0/150

提交評論