




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
.PAGE.1目錄TOC\o"1-3"\h\u10536目錄111610中文摘要25598Abstract2438一、概論3327571.1.研究背景3271611.2.動態(tài)鏈接庫的定義3159921.3.動態(tài)鏈接庫與靜態(tài)鏈接庫411931.3.1.靜態(tài)鏈接庫4135941.3.2.動態(tài)鏈接庫與靜態(tài)鏈接庫的區(qū)別4296721.4.動態(tài)鏈接庫的優(yōu)點4316241.5.在以下這些情況下,必須使用動態(tài)鏈接庫: 5151661.6.VisualC++支持的動態(tài)鏈接庫的類型520557二、非MFC動態(tài)鏈接庫6196472.1.Non-MFCDLL動態(tài)鏈接庫的創(chuàng)建6153542.1.1.創(chuàng)建一個Non-MFCDll工程"MyDll"6149152.1.2.代碼分析8118872.2.聲明導出函數(shù) 9194582.3.DLL的調(diào)用方式 10285312.4.DllMain函數(shù) 114437三、MFC規(guī)則動態(tài)鏈接庫的創(chuàng)建13176603.1.概述13256823.2.MFC規(guī)則DLL分為兩類: 1312433.3.MFC規(guī)則DLL的創(chuàng)建 14244033.4.MFC規(guī)則DLL的調(diào)用 18134783.5.隱式調(diào)用2231657四、MFC擴展動態(tài)鏈接庫的創(chuàng)建24128254.1.概述2428344.3.MFC擴展DLL的加載3028477五、動態(tài)鏈接庫的典型應用3124705.4.DLL木馬3626909六、參考文獻3729778七、致謝38中文摘要動態(tài)鏈接庫英文為DynamicLinkLibrary,英文縮寫為DLL,是程序運行時由該程序動態(tài)鏈接調(diào)用的函數(shù)庫,是一些函數(shù)、數(shù)據(jù)和類集合成的可執(zhí)行模塊,程序員可以將動態(tài)鏈接庫動態(tài)地集成到自己的程序中以使用庫中的函數(shù)、數(shù)據(jù)和類。開發(fā)和應用動態(tài)鏈接庫,有助于數(shù)據(jù)和資源的共享,簡化了軟件項目的管理。本文主要介紹動態(tài)鏈接庫創(chuàng)建、調(diào)用方法,及其典型應用。關(guān)鍵詞:動態(tài)鏈接庫〔DLL,非MFCDLL,MFC規(guī)則DLL,MFC擴展DLLAbstractDynamicLinkLibrary<DLL>encapsulatesthesharedresourceandcode.InexploringtheapplicationbasedonWindows,theuseofDLLtechnologycangreatlysavethememory.UsingDLLdevelopingprojectcansimplifytheprojectmanagementandspeeduptheexploration.Thispaper,introducingtheimplicitandexplicitlinkingofDLLwithinstances,providestechnicalsupporttotechniciansinexploringandusingDLL.Keywords:DynamicLinkLibrary<DLL>,Non-MFCDLL,MFCRegularDLL,MFCExtensionDLL一、概論1.1.研究背景自從微軟推出16位的Windows操作系統(tǒng)起,此后每種版本的Windows操作系統(tǒng)都非常依賴于動態(tài)鏈接庫<DLL>中的函數(shù)和數(shù)據(jù),實際上Windows操作系統(tǒng)中幾乎所有的內(nèi)容都由DLL以一種或另外一種形式代表著,例如顯示的字體和圖標存儲在GDIDLL中、顯示W(wǎng)indows桌面和處理用戶的輸入所需要的代碼被存儲在一個UserDLL中、Windows編程所需要的大量的API函數(shù)也被包含在KernelDLL中。在Windows操作系統(tǒng)中使用DLL有很多優(yōu)點,最主要的一點是多個應用程序、甚至是不同語言編寫的應用程序可以共享一個DLL文件,真正實現(xiàn)了資源"共享",大大縮小了應用程序的執(zhí)行代碼,更加有效的利用了內(nèi)存;使用DLL的另一個優(yōu)點是DLL文件作為一個單獨的程序模塊,封裝性、獨立性好,在軟件需要升級的時候,開發(fā)人員只需要修改相應的DLL文件就可以了,而且,當DLL中的函數(shù)改變后,只要不是參數(shù)的改變,程序代碼并不需要重新編譯。這在編程時十分有用,大大提高了軟件開發(fā)和維護的效率。既然DLL那么重要,所以搞清楚什么是DLL、如何在Windows操作系統(tǒng)中開發(fā)使用DLL是程序開發(fā)人員不得不解決的一個問題。本文針對這些問題,通過一個簡單的例子,全面地解析了在VisualC++編譯環(huán)境下編程實現(xiàn)DLL的過程。1.2.動態(tài)鏈接庫的定義動態(tài)鏈接庫英文為DynamicLinkLibrary,英文縮寫為DLL,是程序運行時由該程序動態(tài)鏈接調(diào)用的函數(shù)庫,是一些函數(shù)、數(shù)據(jù)和類集合成的可執(zhí)行模塊,程序員可以將動態(tài)鏈接庫動態(tài)地集成到自己的程序中以使用庫中的函數(shù)、數(shù)據(jù)和類。動態(tài)鏈接提供了一種方法,使進程可以調(diào)用不屬于其可執(zhí)行代碼的函數(shù)。函數(shù)的可執(zhí)行代碼位于一個DLL中,該DLL包含一個或多個已被編譯、鏈接并與使用它們的進程分開存儲的函數(shù)。多個應用程序可同時訪問內(nèi)存中單個DLL副本的內(nèi)容。1.3.動態(tài)鏈接庫與靜態(tài)鏈接庫1.3.1.靜態(tài)鏈接庫靜態(tài)鏈接庫就是你使用的.lib文件,庫中的代碼最后需要連接到你的可執(zhí)行文件中去。靜態(tài)鏈接庫不同于動態(tài)鏈接庫〔*.dll,在靜態(tài)庫情況下,函數(shù)和數(shù)據(jù)被編譯進一個二進制文件〔通常擴展名為*.LIB,VisualC++的編譯器在鏈接過程中將從靜態(tài)庫中恢復這些函數(shù)和數(shù)據(jù)并把他們和應用程序中的其他模塊組合在一起生成可執(zhí)行文件。這個過程稱為"靜態(tài)鏈接",此時因為應用程序所需的全部內(nèi)容都是從庫中復制了出來,所以靜態(tài)庫本身并不需要與可執(zhí)行文件一起發(fā)行。用戶在交付最終靜態(tài)鏈接庫時,只需要提供.lib文件和相應的頭文件,不需要再提供庫的源代碼。在需要使用靜態(tài)庫的工程中,包含相應的頭文件,并把.lib文件加入工程中就可以了。1.3.2.動態(tài)鏈接庫與靜態(tài)鏈接庫的區(qū)別動態(tài)鏈接發(fā)生在程序運行時,動態(tài)鏈接的函數(shù)代碼不出現(xiàn)在程序的EXE文件中,它僅僅包含了應用程序運行過程中所調(diào)用的DLL函數(shù)的一些最基本信息〔例如DLL文件位置、函數(shù)名等;而靜態(tài)鏈接發(fā)生在編譯時,靜態(tài)鏈接的函數(shù)代碼實際被插入到程序的EXE文件中。1.4.動態(tài)鏈接庫的優(yōu)點動態(tài)鏈接庫隨處可見,無論大型系統(tǒng)還是小規(guī)模軟件,都應用了動態(tài)鏈接庫,有效地實現(xiàn)了資源共享。在軟件開發(fā)中,應用動態(tài)鏈接庫具有以下優(yōu)點:〔1擴展了應用程序的特性;〔2可以用許多種編程語言來編寫;〔3簡化了軟件項目的管理;〔4有助于節(jié)省內(nèi)存;〔5有助于資源共享;〔6有助于應用程序的本地化;〔7有助于解決平臺差異。1.5.在以下這些情況下,必須使用動態(tài)鏈接庫:〔1多個應用程序共享代碼和數(shù)據(jù)〔2在各子程序過濾系統(tǒng)消息時必須使用動態(tài)鏈接庫〔3設備驅(qū)動程序必須是動態(tài)鏈接庫〔4在對話框編輯器中使用自己定義的控件,也必須使用動態(tài)鏈接庫〔5為了實現(xiàn)應用程序的國際化,往往需要使用動態(tài)鏈接庫1.6.VisualC++支持的動態(tài)鏈接庫的類型VisualC++支持三種DLL,它們分別是Non-MFCDLL〔非MFC動態(tài)庫、MFCRegularDLL〔MFC規(guī)則DLL、MFCExtensionDLL〔MFC擴展DLL。〔1非MFC動態(tài)庫指不使用MFC類庫創(chuàng)建的DLL。Win32DLL中的導出函數(shù)通常使用標準的C接口,這些函數(shù)可以被MFC或非MFC應用程序調(diào)用?!?MFC規(guī)則DLLMFC規(guī)則DLL可以使用MFC來創(chuàng)建,可以導出C風格的函數(shù),但不能導出C++類、成員函數(shù)或重載函數(shù)。它們可以被MFC或非MFC應用程序調(diào)用。但這種類型的DLL不能向應用程序傳遞MFC對象指針,必須使用MFC擴展DLL。MFC常規(guī)DLL按照與MFC的鏈接方式又分動態(tài)鏈接和靜態(tài)鏈接兩種?!?MFC擴展DLL表面上更像應用程序而不像一組函數(shù)的集合,因為它可以創(chuàng)建MFC派生類。只能以動態(tài)方式與MFC鏈接,而且只能是使用MFC的動態(tài)鏈接版本的應用程序才可以使用這種DLL。在MFC擴展DLL中,可以由現(xiàn)有的MFC類導出自己的類,然后給應用程序一個擴展的MFC版本。支持C++接口,也就是說,該DLL可以導出整個類,客戶可以構(gòu)造這些類的對象或從這些類進行派生。還可以用于在應用程序和DLL之間傳遞MFC導出對象。對象的成員函數(shù)位于創(chuàng)建對象的模塊中,應用程序和它加載的擴展DLL之間可以自如地傳遞MFC或MFC導出對象的指針。接下來,我們一起來具體討論一下以上三種動態(tài)鏈接庫的創(chuàng)建方法與調(diào)用方法。二、非MFC動態(tài)鏈接庫2.1.Non-MFCDLL動態(tài)鏈接庫的創(chuàng)建在VisualC++6.0開發(fā)環(huán)境下,打開File/New/Project選項,可以選擇Win32Dynamic-LinkLibrary或MFCAppWizard[dll]來以不同的方式來創(chuàng)建Non-MFCDll、RegularDll、ExtensionDll等不同種類的動態(tài)鏈接庫。下面演示以Win32Dynamic-LinkLibrary方式創(chuàng)建一個簡單Non-MFCDll工程"MyDll"。2.1.1.創(chuàng)建一個Non-MFCDll工程"MyDll"在VisualC++6.0開發(fā)環(huán)境下,打開File/New/Project選項,選擇Win32Dynamic-LinkLibrary創(chuàng)建一個簡單DLL工程,并命名為"MyDll"。圖2-1-1創(chuàng)建Non-MFCDll工程"MyDll"在建立的工程中添加lib.h及l(fā)ib.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;}顯然,以上建立的是一個返回兩個數(shù)的乘積的動態(tài)鏈接庫?!?建立一個與MyDll工程處于同一工作區(qū)的應用工程DllCall。圖2-1-2創(chuàng)建應用工程"DllCall"在工程"DllCall"創(chuàng)建源代碼文件"DllCall.cpp",它調(diào)用DLL中的函數(shù)multi,其源代碼如下:#include<stdio.h>#include<windows.h>typedefint<*lpmultiFunc><int,int>;//宏定義函數(shù)指針類型intmain<>{ HINSTANCEhDll;//DLL句柄 lpmultiFuncmultiFunc;//函數(shù)指針 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;}編譯,運行結(jié)果如下:圖2-1-3運行結(jié)果如上圖所示,成功返回3*5的結(jié)果,表明此NON-MFCDLL創(chuàng)建成功。2.1.2.代碼分析分析上述代碼,Mydll工程中的lib.h對函數(shù)multi的聲明前面添加了__declspec<dllexport>語句。這個語句的含義是聲明函數(shù)multi為DLL的導出函數(shù)。DLL內(nèi)的函數(shù)分為兩種:<1>DLL導出函數(shù),可供應用程序調(diào)用;<2>DLL內(nèi)部函數(shù),只能在DLL程序使用,應用程序無法調(diào)用它們。現(xiàn)在分析應用工程dllCall對DLL的調(diào)用是如何實現(xiàn)的:首先,語句typedefint<*lpmultiFun><int,int>定義了一個與multi函數(shù)接受參數(shù)類型和返回值均相同的函數(shù)指針類型。隨后,在main函數(shù)中定義了lpmultiFunc的實例multiFunc;其次,在函數(shù)main中定義了一個DLLHINSTANCE句柄實例hDll,通過Win32Api函數(shù)LoadLibrary動態(tài)加載了DLL模塊并將DLL模塊句柄賦給了hDll;再次,在函數(shù)main中通過Win32Api函數(shù)GetProcAddress得到了所加載DLL模塊中函數(shù)multi的地址并賦給了multiFunc。經(jīng)由函數(shù)指針multiFunc進行了對DLL中add函數(shù)的調(diào)用;最后,應用工程使用完DLL后,在函數(shù)main中通過Win32Api函數(shù)FreeLibrary釋放了已經(jīng)加載的DLL模塊。從而完成了對dll的調(diào)用。通過以上例子分析可得出以下結(jié)論:<1>DLL中需以某種特定的方式聲明導出函數(shù)〔或變量、類;<2>應用工程需以某種特定的方式調(diào)用DLL的導出函數(shù)〔或變量、類。2.2.聲明導出函數(shù)DLL中導出函數(shù)的聲明有兩種方式:一是像上述例子一樣,在定義函數(shù)時使用導出關(guān)鍵字_declspec<dllexport>;另外一種方法是在創(chuàng)建DLL文件時使用模塊定義文件.def。如以下例子:下面的代碼演示了怎樣在.def文件中將函數(shù)multi聲明為DLL導出函數(shù)〔需在MyDll工程中添加lib.def文件:LIBRARYMydllEXPORTSmulti1def文件的規(guī)則為:<1>LIBRARY語句說明.def文件相應的DLL;<2>EXPORTS語句后列出要導出函數(shù)的名稱??梢栽?def文件中的導出函數(shù)名后加n,表示要導出函數(shù)的序號為n〔在進行函數(shù)調(diào)用時,這個序號將發(fā)揮其作用;<3>.def文件中的注釋由每個注釋行開始處的分號<;>指定,且注釋不能與語句共享一行。由此可以看出,例子中l(wèi)ib.def文件的含義為生成名為"MyDll"的動態(tài)鏈接庫,導出其中的multi函數(shù),并指定multi函數(shù)的序號為1。2.3.DLL的調(diào)用方式DLL有兩種調(diào)用方式:〔1動態(tài)調(diào)用在上述的例子中我們看到了由"LoadLibrary-GetProcAddress-FreeLibrary"系統(tǒng)Api提供的三位一體"DLL加載-DLL函數(shù)地址獲取-DLL釋放"方式,這種調(diào)用方式稱為DLL的動態(tài)調(diào)用。
動態(tài)調(diào)用方式的特點是完全由編程者用API函數(shù)加載和卸載DLL,程序員可以決定DLL文件何時加載或不加載,顯式鏈接在運行時決定加載哪個DLL文件?!?靜態(tài)調(diào)用靜態(tài)調(diào)用方式的特點是由編譯系統(tǒng)完成對DLL的加載和應用程序結(jié)束時DLL的卸載。當調(diào)用某DLL的應用程序結(jié)束時,若系統(tǒng)中還有其它程序使用該DLL,則Windows對DLL的應用記錄減1,直到所有使用該DLL的程序都結(jié)束時才釋放它。靜態(tài)調(diào)用方式簡單實用,但不如動態(tài)調(diào)用方式靈活。如以下例子所示:將編譯MyDll工程所生成的.lib和.dll文件拷入dllCall工程所在的路徑,圖2-3-1添加MyDll.lib和MyDll.dll文件在dllCall源文件下執(zhí)行下列代碼:#include<stdio.h>#pragmacomment<lib,"MyDll.lib">//.lib文件中僅僅是關(guān)于其對應DLL文件中函數(shù)的重定位信息extern"C"__declspec<dllimport>multi<intx,inty>;intmain<intargc,char*argv[]>
{intresult=multi<3,5>;printf<"靜態(tài)調(diào)用結(jié)果:%d\n",result>;return0;}編譯運行,運行結(jié)果如下:圖2-3-2運行結(jié)果由上述代碼可以看出,靜態(tài)調(diào)用方式的順利進行需要完成兩個動作:告訴編譯器與DLL相對應的.lib文件所在的路徑及文件名,#pragmacomment<lib,"MyDll.lib">就是起這個作用。程序員在建立一個DLL文件時,連接器會自動為其生成一個對應的.lib文件,該文件包含了DLL導出函數(shù)的符號名及序號〔并不含有實際的代碼。在應用程序里,.lib文件將作為DLL的替代文件參與編譯。〔2聲明導入函數(shù),extern"C"__declspec<dllimport>multi<intx,inty>語句中的__declspec<dllimport>發(fā)揮這個作用。靜態(tài)調(diào)用方式不再需要使用系統(tǒng)API來加載、卸載DLL以及獲取DLL中導出函數(shù)的地址。這是因為,當程序員通過靜態(tài)鏈接方式編譯生成應用程序時,應用程序中調(diào)用的與.lib文件中導出符號相匹配的函數(shù)符號將進入到生成的EXE文件中,.lib文件中所包含的與之對應的DLL文件的文件名也被編譯器存儲在EXE文件內(nèi)部。當應用程序運行過程中需要加載DLL文件時,Windows將根據(jù)這些信息發(fā)現(xiàn)并加載DLL,然后通過符號名實現(xiàn)對DLL函數(shù)的動態(tài)鏈接。這樣,EXE將能直接通過函數(shù)名調(diào)用DLL的輸出函數(shù),就象調(diào)用程序內(nèi)部的其他函數(shù)一樣。2.4.DllMain函數(shù)Windows在加載DLL的時候,需要一個入口函數(shù),就如同控制臺或DOS程序需要main函數(shù)、WIN32程序需要WinMain函數(shù)一樣。在前面的例子中,DLL并沒有提供DllMain函數(shù),應用工程也能成功引用DLL,這是因為Windows在找不到DllMain的時候,系統(tǒng)會從其它運行庫中引入一個不做任何操作的缺省DllMain函數(shù)版本,并不意味著DLL可以放棄DllMain函數(shù)。根據(jù)編寫規(guī)范,Windows必須查找并執(zhí)行DLL里的DllMain函數(shù)作為加載DLL的依據(jù),它使得DLL得以保留在內(nèi)存里。這個函數(shù)并不屬于導出函數(shù),而是DLL的內(nèi)部函數(shù)。這意味著不能直接在應用工程中引用DllMain函數(shù),DllMain是自動被調(diào)用的。以下是一個DllMain函數(shù)的例子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函數(shù)在DLL被加載和卸載時被調(diào)用,在單個線程啟動和終止時,DLLMain函數(shù)也被調(diào)用,ul_reason_for_call指明了被調(diào)用的原因。原因共有4種,即PROCESS_ATTACH、PROCESS_DETACH、THREAD_ATTACH和THREAD_DETACH,以switch語句列出。分析DllMain的函數(shù)頭BOOLAPIENTRYDllMain<HANDLEhModule,WORDul_reason_for_call,LPVOIDlpReserved>APIENTRY被定義為__stdcall,它意味著這個函數(shù)以標準Pascal的方式進行調(diào)用,也就是WINAPI方式;進程中的每個DLL模塊被全局唯一的32字節(jié)的HINSTANCE句柄標識,只有在特定的進程內(nèi)部有效,句柄代表了DLL模塊在進程虛擬空間中的起始地址。在Win32中,HINSTANCE和HMODULE的值是相同的,這兩種類型可以替換使用,這就是函數(shù)參數(shù)hModule的來歷。三、MFC規(guī)則動態(tài)鏈接庫的創(chuàng)建3.1.概述〔1MFC規(guī)則DLL,顧名思義,可以在這種DLL的內(nèi)部使用MFC;〔2它是規(guī)則的,意味著它不同于MFC擴展DLL,在MFC規(guī)則DLL的內(nèi)部雖然可以使用MFC,但是其與應用程序的接口不能是MFC。而MFC擴展DLL與應用程序的接口可以是MFC,可以從MFC擴展DLL中導出一個MFC類的派生類。MFC規(guī)則DLL能夠被所有支持DLL技術(shù)的語言所編寫的應用程序調(diào)用,當然也包括使用MFC的應用程序。在這種動態(tài)連接庫中,包含一個從CWinApp繼承下來的類,DllMain函數(shù)則由MFC自動提供。3.2.MFC規(guī)則DLL分為兩類:〔1靜態(tài)鏈接到MFC的規(guī)則DLL靜態(tài)鏈接到MFC的規(guī)則DLL與MFC庫〔包括MFC擴展DLL靜態(tài)鏈接,將MFC庫的代碼直接生成在.dll文件中。在調(diào)用這種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)鏈接到MFCDLL和任何MFC擴展DLL。在使用了MFC共享庫的時候,默認情況下,MFC使用主應用程序的資源句柄來加載資源模板。這樣,當DLL和應用程序中存在相同ID的資源時〔即所謂的資源重復問題,系統(tǒng)可能不能獲得正確的資源。因此,對于共享MFCDLL的規(guī)則DLL,我們必須進行模塊切換以使得MFC能夠找到正確的資源模板。我們可以在VisualC++中設置MFC規(guī)則DLL是靜態(tài)鏈接到MFCDLL還是動態(tài)鏈接到MFCDLL。如下圖,依次選擇VisualC++的project->Settings->General菜單或選項,在MicrosoftFoundationClasses中進行設置。圖3-2-1設置動態(tài)/靜態(tài)鏈接MFCDLL3.3.MFC規(guī)則DLL的創(chuàng)建下面一步步講述使用MFC向?qū)?chuàng)建一個簡單的MFC規(guī)則DLL的過程?!?首先在VisualC++6.0開發(fā)環(huán)境下,打開File/New/Project選項,選擇MFCAppWizard<dll>創(chuàng)建一個簡單DLL工程,并命名為"regularDll"。圖3-3-1創(chuàng)建MFC規(guī)則DLL點擊"確定"進入如下圖所示的對話框,選擇"動態(tài)鏈接庫和MFC靜態(tài)鏈接"圖3-3-2創(chuàng)建MFC規(guī)則DLL點擊"完成"按鈕完成向?qū)?。?在工程中添加一個對話框,并設計該對話框。圖3-3-3創(chuàng)建對話框為該對話框新建一個類CDllDialog,圖3-3-4新建類CDllDialog為對話框上的按鈕"MFCRegualrDll"添加消息響應函數(shù),圖3-3-5添加消息響應函數(shù)并添加以下代碼:voidCDllDialog::OnButton1<>{ //TODO:Addyourcontrolnotificationhandlercodehere MessageBox<"MFCRegularDLL">;}在RegularDll.cpp的最后,添加MFC規(guī)則DLL接口函數(shù)。extern"C"__declspec<dllexport>voidShowDlg<void>{ AFX_MANAGE_STATE<AfxGetStaticModuleState<>> ; CDllDialogdllDialog; dllDialog.DoModal<>;}圖3-3-6添加MFC規(guī)則DLL接口函數(shù)在RegularDll.cpp的前面,添加#include"DllDialog.h"圖3-3-7添加MFC規(guī)則DLL接口函數(shù)完成上述步驟后,就可以編譯并生成Dll文件了。圖3-3-8添加MFC規(guī)則DLL接口函數(shù)3.4.MFC規(guī)則DLL的調(diào)用〔1首先,創(chuàng)建一個基于MFC的單文檔應用程序"CallRegDll"。圖3-4-1創(chuàng)建MFC的單文檔應用程序CallRegDll〔2添加一個菜單項"CallRegDll"。圖3-4-2添加一個菜單項〔3在視類對該菜單項添加消息響應函數(shù),函數(shù)代碼如下: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中函數(shù)尋找失敗">;}} else { MessageBox<"沒有找到相應的dll">; }}〔4編譯并運行程序。點擊菜單項,會彈出如下界面:圖3-4-3運行結(jié)果〔5將RegularDll.dll和復制到RegularDll.lib復制到CallRegDll工程的debug目錄下。圖3-4-4復制RegularDll.lib和RegularDll.dll再次編譯,運行程序,結(jié)果如下:圖3-4-5運行結(jié)果3.5.隱式調(diào)用上述例子中給出的是顯式調(diào)用的方式,我們也可以在EXE程序中隱式調(diào)用MFC規(guī)則DLL。將DLL工程生成的.lib文件和.dll文件拷入當前工程所在的目錄。圖3-4-6添加.lib文件和.dll文件并在CCallRegDllView.cpp文件的頂部添加以下代碼:#pragmacomment<lib,"RegularDll.lib">//extern"C"__declspec<dllimport>voidShowDlg<void>;//把消息響應函數(shù)CCallRegDllView::OnRegDll<>修改為以下:voidCCallRegDllView::OnRegDll<>{ //TODO:Addyourcommandhandlercodehere ShowDlg<>;}編譯運行程序,同樣能得到正確的結(jié)果。圖3-4-7運行結(jié)果四、MFC擴展動態(tài)鏈接庫的創(chuàng)建4.1.概述MFC擴展DLL與MFC規(guī)則DLL的相同點在于在兩種DLL的內(nèi)部都可以使用MFC類庫,其不同點在于MFC擴展DLL與應用程序的接口可以是MFC的。MFC擴展DLL的含義在于它是MFC的擴展,其主要功能是實現(xiàn)從現(xiàn)有MFC庫類中派生出可重用的類。MFC擴展DLL使用MFC動態(tài)鏈接庫版本,因此只有用共享MFC版本生成的MFC可執(zhí)行文件〔應用程序或規(guī)則DLL才能使用MFC擴展DLL。MFC規(guī)則DLL被MFC向?qū)ё詣犹砑恿艘粋€CWinApp的對象,而MFC擴展DLL則不包含該對象,它只是被自動添加了DllMain函數(shù)。對于MFC擴展DLL,開發(fā)人員必須在DLL的DllMain函數(shù)中添加初始化和結(jié)束代碼。
總結(jié)三種DLL對DllMain入口函數(shù)的不同處理方式,可得出下表:
DLL類型入口函數(shù)非MFCDLL編程者提供DllMain函數(shù)MFC規(guī)則DLLCWinApp對象的InitInstance和ExitInstanceMFC擴展DLLMFCDLL向?qū)蒁llMain函數(shù)對于MFC擴展DLL,系統(tǒng)會自動在工程中添加如下表所示的宏,這些宏為DLL和應用程序的編寫提供了方便。像AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA這樣的宏,在DLL和應用程序中將具有不同的定義,這取決于_AFXEXT宏是否被定義。這使得在DLL和應用程序中,使用統(tǒng)一的一個宏就可以表示出輸出和輸入的不同意思。宏定義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創(chuàng)建MFC擴展DLL圖4-2-2創(chuàng)建MFC擴展DLL使用MFC向?qū)蒑FC擴展DLL時,系統(tǒng)會自動添加如下代碼:staticAFX_EXTENSION_MODULEExtDllDLL={NULL,NULL};
extern"C"intAPIENTRY
DllMain<HINSTANCEhInstance,DWORDdwReason,LPVOIDlpReserved>
{
//RemovethisifyouuselpReserved
UNREFERENCED_PARAMETER<lpReserved>;
//說明:lpReserved是一個被系統(tǒng)所保留的參數(shù),對于隱式鏈接是一個非零值,對于顯式鏈接值是零
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初始化期間所創(chuàng)建的CDynLinkLibrary對象使MFC擴展DLL可以將DLL中的CRuntimeClass對象或資源導出到應用程序;
〔3AfxInitExtensionModule函數(shù)捕獲模塊的CRuntimeClass結(jié)構(gòu)和在創(chuàng)建CDynLinkLibrary對象時使用的對象工廠〔COleObjectFactory對象;
〔4AfxTermExtensionModule函數(shù)使MFC得以在每個進程與擴展DLL分離時〔進程退出或使用AfxFreeLibrary卸載DLL時清除擴展DLL;
〔5第一條語句staticAFX_EXTENSION_MODULEExtDllDLL={NULL,NULL};定義了一個AFX_EXTENSION_MODULE類的靜態(tài)全局對象,AFX_EXTENSION_MODULE的定義如下:structAFX_EXTENSION_MODULE
{
BOOLbInitialized;
HMODULEhModule;
HMODULEhResource;
CRuntimeClass*pFirstSharedClass;
COleObjectFactory*pFirstSharedFactory;
};在資源編輯器中添加一個如下圖所示的對話框,并使用MFC類向?qū)槠涮砑右粋€對應的類CExtDialog,系統(tǒng)自動添加了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"添加消息響應函數(shù)voidCExtDialog::OnButton1<>{ //TODO:Addyourcontrolnotificationhandlercodehere MessageBox<"MFCExtentionDLL">;}最后,編譯運行,生成.lib文件和.dll文件。4.3.MFC擴展DLL的加載在上述工程所在的工作區(qū)中添加一個LoadExtDllDlg工程,用于演示MFC擴展DLL的加載。在LoadExtDllDlg工程中添加一個如下圖所示的對話框,這個對話框上包括一個"調(diào)用DLL"按鈕。圖4-3-1MFC擴展DLL調(diào)用工程中的對話框在與上圖對應對話框類實現(xiàn)文件的頭部添加://LoadExtDllDlg.cpp:implementationfile
//
#include"..\ExtDialog.h"
#pragmacomment<lib,"..\Debug\ExtDll.lib">而"調(diào)用DLL"按鈕的單擊事件的消息處理函數(shù)為:voidCLoadExtDllDlg::OnDllcallButton<>
{
CExtDialogextDialog;
extDialog.DoModal<>;
}最后編譯并運行,運行結(jié)果如下:圖4-3-2運行結(jié)果從上述加載過程,我們可總結(jié)出:
為提供給用戶隱式加載,MFC擴展DLL需要提供三個文件:
〔1描述DLL中擴展類的頭文件;
〔2與動態(tài)鏈接庫對應的.LIB文件;
〔3動態(tài)鏈接庫.DLL文件本身。
有了這三個文件,應用程序的開發(fā)者才可充分利用MFC擴展DLL。五、動態(tài)鏈接庫的典型應用動態(tài)鏈接庫DLL實現(xiàn)了庫的共享,體現(xiàn)了代碼重用的思想。我們可以把廣泛的、具有共性的、能夠多次被利用的函數(shù)和類定義在庫中。這樣,在再次使用這些函數(shù)和類的時候,就不再需要重新添加與這些函數(shù)和類相關(guān)的代碼。因此,動態(tài)鏈接庫的應用廣泛,而其主要的典型應用有以下幾方面:5.1.通用的算法圖像處理、視頻音頻解碼、壓縮與解壓縮、加密與解密通常采用某些特定的算法,這些算法較固定且在這類程序中往往經(jīng)常被使用。如以下的例子:學習過較高級別數(shù)學〔概率統(tǒng)計與隨機過程、信號與線性系統(tǒng)及數(shù)字信號處理的讀者應該知道,傅立葉變換是一種在信號分析中常用的算法,用于時域和頻域的相互轉(zhuǎn)換。FFT變換算法通用而有共性,我們適宜把它集成在一個DLL中。我們可在相關(guān)資料上獲取到FFT變換算法的函數(shù)代碼如下:/*函數(shù)名稱:FFT<>
*參數(shù):
*complex<double>*TD-指向時域數(shù)組的指針
*complex<double>*FD-指向頻域數(shù)組的指針
*r-2的冪數(shù),即迭代次數(shù)
*返回值:無。
*說明:該函數(shù)用來實現(xiàn)快速傅立葉變換
*/
voidFFT<complex<double>*TD,complex<double>*FD,intr>
{
LONGcount;//傅立葉變換點數(shù)
inti,j,k;//循環(huán)變量
intbfsize,p;//中間變量
doubleangle;//角度
complex<double>*W,*X1,*X2,*X;
count=1<<r;//傅立葉變換點數(shù)
//分配運算所需存儲器
W=newcomplex<double>[count/2];
X1=newcomplex<double>[count];
X2=newcomplex<double>[count];
//計算加權(quán)系數(shù)
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];
}
//釋放內(nèi)存
deleteW;
deleteX1;
deleteX2;
}既然有了FFT這個函數(shù),我們要把它做在DLL中,作為DLL的一個接口將是十分簡單的,其步驟如下:〔1利用MFC向?qū)Ы⒁粋€非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">則可以獲得函數(shù)FFT的地址。
這個DLL中有兩點需要注意:
〔1使用extern"C"修飾函數(shù)聲明,否則,生成的DLL只能供C++調(diào)用;
〔2使用__stdcall修飾函數(shù)聲明及定義,__stdcall是WindowsAPI的函數(shù)調(diào)用方式。5.2.純資源DLL我們可以從DLL中獲取資源,對于一個支持多種語言的應用程序而言,我們可以判斷操作系統(tǒng)的語言,并自動為應用程序加載與操作系統(tǒng)對應的語言。這是多語言支持應用程序的一般做法。5.3.通信控制DLL串口、網(wǎng)口的通信控制函數(shù)如果由DLL提供則可以使應用程序輕松不少。在工業(yè)控制、modem程序甚至socket通信中,經(jīng)常使用通信控制DLL。
在Windows系統(tǒng),需通過DCB<DeviceControlBlock>對串口進行配置。利用WindowsAPIGetCommState函數(shù)可以獲取串口當前配置;利用SetCommState函數(shù)則可以設置串口通訊的參數(shù)。
串行通信通常按以下四步進行:
<1>打開串口;
<2>配置串口;
<3>數(shù)據(jù)傳送;
<4>關(guān)閉串口。
由此可見,我們需要給串口控制DLL提供如下四個接口函數(shù)://打開指定的串口,其參數(shù)port為端口號
BOOLComOpen<intport>;//在這個函數(shù)里使用默認的參數(shù)設置串口
//將打開的串口關(guān)閉
voidComClose<intport>;
//將串口接收緩沖區(qū)中的數(shù)據(jù)放到buffer中
intGetComData<char*buf,intbuf_len>;
//將指定長度的數(shù)據(jù)發(fā)送到串口
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. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 寄賣合同協(xié)議書
- 小孩上學租房合同
- 翻譯服務協(xié)議合同
- 天花吊頂裝修合同
- 合同之店員聘用合同
- 房屋中介居間合同
- 學校食堂肉類供貨合同年
- 有關(guān)設備購銷合同
- 新材料生產(chǎn)加工合同
- 星酒店投資技術(shù)服務合同
- 春季安全行車培訓資料
- 2024年流感季節(jié)諾如病毒防護教案分享
- 大型活動突發(fā)公共衛(wèi)生事件應急方案
- GB/T 44826-2024生物制造丙交酯
- 《Python程序設計》課件-1:Python編程規(guī)范與注釋
- 2023年輔導員職業(yè)技能大賽試題及答案
- 快消品行業(yè)高端水品牌全案策劃案例
- 紡織服裝面料創(chuàng)意設計
- 四川義務教育三年級生命生態(tài)與安全教案下冊
- EPC總承包項目工程設計各階段的服務承諾
- 2024-2030年中國達克羅行業(yè)運行態(tài)勢與前景展望分析報告
評論
0/150
提交評論