毕业论文——VC++环境下的动态链接库的开发与应用.doc_第1页
毕业论文——VC++环境下的动态链接库的开发与应用.doc_第2页
毕业论文——VC++环境下的动态链接库的开发与应用.doc_第3页
毕业论文——VC++环境下的动态链接库的开发与应用.doc_第4页
毕业论文——VC++环境下的动态链接库的开发与应用.doc_第5页
已阅读5页,还剩33页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

目录目录1中文摘要2Abstract2一、概论31.1. 研究背景31.2. 动态链接库的定义31.3. 动态链接库与静态链接库41.3.1. 静态链接库41.3.2. 动态链接库与静态链接库的区别41.4. 动态链接库的优点41.5. 在以下这些情况下,必须使用动态链接库:51.6. Visual C+支持的动态链接库的类型5二、非MFC动态链接库62.1. Non-MFC DLL动态链接库的创建62.1.1. 创建一个Non-MFC Dll工程“MyDll”62.1.2. 代码分析82.2. 声明导出函数92.3. DLL的调用方式102.4. DllMain函数11三、MFC规则动态链接库的创建133.1. 概述133.2. MFC规则DLL分为两类:133.3. MFC规则DLL的创建143.4. MFC规则DLL的调用183.5. 隐式调用22四、MFC扩展动态链接库的创建24 4.1. 概述24 4.3. MFC扩展DLL的加载30五、动态链接库的典型应用315.4. DLL木马36六、参考文献37七、致谢38中文摘要 动态链接库英文为Dynamic Link Library,英文缩写为DLL,是程序运行时由该程序动态链接调用的函数库,是一些函数、数据和类集合成的可执行模块,程序员可以将动态链接库动态地集成到自己的程序中以使用库中的函数、数据和类。开发和应用动态链接库,有助于数据和资源的共享,简化了软件项目的管理。本文主要介绍动态链接库创建、调用方法,及其典型应用。关键词:动态链接库(DLL),非MFC DLL,MFC规则DLL,MFC扩展DLLAbstractDynamic Link Library (DLL) encapsulates the shared resource and codeIn exploring the application based on Windows,the use of DLL technology can greatly save the memoryUsing DLL developing project can simplify the project management and speed up the explorationThis paper,introducing the implicit and explicit linking of DLL with instances,provides technical support to technicians in exploring and using DLL Key words:Dynamic Link Library (DLL) , Non-MFC DLL ,MFC Regular DLL , MFC Extension DLL一、概论1.1. 研究背景自从微软推出16位的Windows操作系统起,此后每种版本的Windows操作系统都非常依赖于动态链接库(DLL)中的函数和数据,实际上Windows操作系统中几乎所有的内容都由DLL以一种或另外一种形式代表着,例如显示的字体和图标存储在GDI DLL中、显示Windows桌面和处理用户的输入所需要的代码被存储在一个User DLL中、Windows编程所需要的大量的API函数也被包含在Kernel DLL中。在Windows操作系统中使用DLL有很多优点,最主要的一点是多个应用程序、甚至是不同语言编写的应用程序可以共享一个DLL文件,真正实现了资源共享,大大缩小了应用程序的执行代码,更加有效的利用了内存;使用DLL的另一个优点是DLL文件作为一个单独的程序模块,封装性、独立性好,在软件需要升级的时候,开发人员只需要修改相应的DLL文件就可以了,而且,当DLL中的函数改变后,只要不是参数的改变,程序代码并不需要重新编译。这在编程时十分有用,大大提高了软件开发和维护的效率。既然DLL那么重要,所以搞清楚什么是DLL、如何在Windows操作系统中开发使用DLL是程序开发人员不得不解决的一个问题。本文针对这些问题,通过一个简单的例子,全面地解析了在Visual C+编译环境下编程实现DLL的过程。1.2. 动态链接库的定义动态链接库英文为Dynamic Link Library,英文缩写为DLL,是程序运行时由该程序动态链接调用的函数库,是一些函数、数据和类集合成的可执行模块,程序员可以将动态链接库动态地集成到自己的程序中以使用库中的函数、数据和类。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。多个应用程序可同时访问内存中单个DLL 副本的内容。1.3. 动态链接库与静态链接库1.3.1. 静态链接库静态链接库就是你使用的.lib文件,库中的代码最后需要连接到你的可执行文件中去。静态链接库不同于动态链接库(*.dll),在静态库情况下,函数和数据被编译进一个二进制文件(通常扩展名为*.LIB),Visual C+的编译器在链接过程中将从静态库中恢复这些函数和数据并把他们和应用程序中的其他模块组合在一起生成可执行文件。这个过程称为静态链接,此时因为应用程序所需的全部内容都是从库中复制了出来,所以静态库本身并不需要与可执行文件一起发行。用户在交付最终静态链接库时,只需要提供.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. Visual C+支持的动态链接库的类型Visual C+支持三种DLL,它们分别是Non-MFC DLL(非MFC动态库)、MFC Regular DLL(MFC规则DLL)、MFC Extension DLL(MFC扩展DLL)。(1) 非MFC动态库指不使用MFC类库创建的DLL。Win32 DLL中的导出函数通常使用标准的C接口,这些函数可以被MFC或非MFC应用程序调用。(2) MFC规则DLL MFC规则DLL可以使用MFC来创建,可以导出C风格的函数,但不能导出C+类、成员函数或重载函数。它们可以被MFC或非MFC应用程序调用。但这种类型的DLL不能向应用程序传递MFC对象指针,必须使用MFC扩展DLL。MFC常规DLL按照与MFC的链接方式又分动态链接和静态链接两种。(3) MFC扩展DLL表面上更像应用程序而不像一组函数的集合,因为它可以创建MFC派生类。只能以动态方式与MFC链接,而且只能是使用MFC的动态链接版本的应用程序才可以使用这种DLL。在MFC扩展DLL中,可以由现有的MFC类导出自己的类,然后给应用程序一个扩展的MFC版本。支持C+接口,也就是说,该DLL可以导出整个类,客户可以构造这些类的对象或从这些类进行派生。还可以用于在应用程序和DLL之间传递MFC导出对象。对象的成员函数位于创建对象的模块中,应用程序和它加载的扩展DLL之间可以自如地传递MFC或MFC导出对象的指针。 接下来,我们一起来具体讨论一下以上三种动态链接库的创建方法与调用方法。二、非MFC动态链接库2.1. Non-MFC DLL动态链接库的创建在Visual C+6.0开发环境下,打开File/New/Project选项,可以选择Win32 Dynamic-Link Library或MFC AppWizarddll 来以不同的方式来创建Non-MFC Dll、Regular Dll、Extension Dll等不同种类的动态链接库。下面演示以Win32 Dynamic-Link Library方式创建一个简单Non-MFC Dll工程“MyDll”。2.1.1. 创建一个Non-MFC Dll工程“MyDll”(1) 在Visual C+6.0开发环境下,打开File/New/Project选项,选择Win32 Dynamic-Link Library创建一个简单DLL工程,并命名为“MyDll”。图2-1-1 创建Non-MFC Dll工程“MyDll”(2) 在建立的工程中添加lib.h及lib.cpp文件,源代码如下:/* 文件名:lib.h*/#ifndef LIB_H#define LIB_Hextern C int _declspec(dllexport)multi(int x,int y);#endif/* 文件名:lib.cpp*/#include lib.hint multi(int x,int y) return x*y;显然,以上建立的是一个返回两个数的乘积的动态链接库。(3)建立一个与MyDll工程处于同一工作区的应用工程DllCall。图2-1-2 创建应用工程“DllCall”在工程“DllCall”创建源代码文件“DllCall.cpp”,它调用DLL中的函数multi,其源代码如下:#include #include typedef int(*lpmultiFunc)(int,int); /宏定义函数指针类型int main() HINSTANCE hDll; /DLL句柄lpmultiFunc multiFunc; /函数指针hDll = LoadLibrary(.DebugMyDll.dll);if (hDll != NULL) multiFunc = (lpmultiFunc)GetProcAddress(hDll, multi);if (multiFunc != NULL) int result = multiFunc(3,5); /计算3与5的乘积 printf(%dn,result);FreeLibrary(hDll);return 0;(4) 编译,运行结果如下:图2-1-3 运行结果 如上图所示,成功返回3*5的结果,表明此NON-MFC DLL创建成功。2.1.2. 代码分析分析上述代码,Mydll工程中的lib.h对函数multi的声明前面添加了_declspec(dllexport)语句。这个语句的含义是声明函数multi为DLL的导出函数。DLL内的函数分为两种:(1) DLL导出函数,可供应用程序调用;(2) DLL内部函数,只能在DLL程序使用,应用程序无法调用它们。现在分析应用工程dllCall 对 DLL 的调用是如何实现的:首先,语句typedef int ( * lpmultiFun)(int,int)定义了一个与multi函数接受参数类型和返回值均相同的函数指针类型。随后,在main函数中定义了lpmultiFunc的实例multiFunc;其次,在函数main中定义了一个DLL HINSTANCE句柄实例hDll,通过Win32 Api函数LoadLibrary动态加载了DLL模块并将DLL模块句柄赋给了hDll;再次,在函数main中通过Win32 Api函数GetProcAddress得到了所加载DLL模块中函数multi的地址并赋给了multiFunc。经由函数指针multiFunc进行了对DLL中add函数的调用; 最后,应用工程使用完DLL后,在函数main中通过Win32 Api函数FreeLibrary释放了已经加载的DLL模块。从而完成了对dll的调用。通过以上例子分析可得出以下结论:(1)DLL中需以某种特定的方式声明导出函数(或变量、类);(2)应用工程需以某种特定的方式调用DLL的导出函数(或变量、类)。2.2. 声明导出函数DLL中导出函数的声明有两种方式:一是像上述例子一样,在定义函数时使用导出关键字_declspec(dllexport);另外一种方法是在创建DLL文件时使用模块定义文件.def。如以下例子:下面的代码演示了怎样在 .def 文件中将函数multi声明为DLL导出函数(需在MyDll工程中添加lib.def文件):LIBRARY MydllEXPORTSmulti 1def文件的规则为:(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 #pragma comment(lib,MyDll.lib)/.lib文件中仅仅是关于其对应DLL文件中函数的重定位信息extern C _declspec(dllimport) multi(int x,int y);int main(int argc, char* argv )int result = multi(3,5);printf(静态调用结果:%dn,result);return 0;编译运行,运行结果如下:图2-3-2 运行结果由上述代码可以看出,静态调用方式的顺利进行需要完成两个动作:(1) 告诉编译器与DLL相对应的.lib文件所在的路径及文件名,#pragma comment(lib,MyDll.lib)就是起这个作用。程序员在建立一个DLL文件时,连接器会自动为其生成一个对应的.lib文件,该文件包含了DLL 导出函数的符号名及序号(并不含有实际的代码)。在应用程序里,.lib文件将作为DLL的替代文件参与编译。(2) 声明导入函数,extern C _declspec(dllimport)multi(int x,int y)语句中的_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函数的例子BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)switch (ul_reason_for_call)case DLL_PROCESS_ATTACH:printf(nprocess attach of dll);break;case DLL_THREAD_ATTACH:printf(nthread attach of dll);break;case DLL_THREAD_DETACH:printf(nthread detach of dll);break;case DLL_PROCESS_DETACH:printf(nprocess detach of dll);break;return TRUE;DllMain函数在DLL被加载和卸载时被调用,在单个线程启动和终止时,DLLMain函数也被调用,ul_reason_for_call指明了被调用的原因。原因共有4种,即PROCESS_ATTACH、PROCESS_DETACH、THREAD_ATTACH和THREAD_DETACH,以switch语句列出。分析DllMain的函数头BOOL APIENTRY DllMain( HANDLE hModule, WORD ul_reason_for_call, LPVOID lpReserved )APIENTRY被定义为_stdcall,它意味着这个函数以标准Pascal的方式进行调用,也就是WINAPI方式;进程中的每个DLL模块被全局唯一的32字节的HINSTANCE句柄标识,只有在特定的进程内部有效,句柄代表了DLL模块在进程虚拟空间中的起始地址。在Win32中,HINSTANCE和HMODULE的值是相同的,这两种类型可以替换使用,这就是函数参数hModule的来历。三、MFC规则动态链接库的创建3.1. 概述(1) MFC规则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 可以和使用它的可执行文件同时动态链接到 MFC DLL 和任何MFC扩展 DLL。在使用了MFC共享库的时候,默认情况下,MFC使用主应用程序的资源句柄来加载资源模板。这样,当DLL和应用程序中存在相同ID的资源时(即所谓的资源重复问题),系统可能不能获得正确的资源。因此,对于共享MFC DLL的规则DLL,我们必须进行模块切换以使得MFC能够找到正确的资源模板。我们可以在Visual C+中设置MFC规则DLL是静态链接到MFC DLL还是动态链接到MFC DLL。如下图,依次选择Visual C+的project - Settings - General菜单或选项,在Microsoft Foundation Classes中进行设置。图 3-2-1 设置动态/静态链接MFC DLL3.3. MFC规则DLL的创建下面一步步讲述使用MFC向导创建一个简单的MFC规则DLL的过程。 (1)首先在Visual C+6.0开发环境下,打开File/New/Project选项,选择MFC AppWizard(dll)创建一个简单DLL工程,并命名为“regularDll”。图 3-3-1 创建MFC规则DLL点击“确定”进入如下图所示的对话框,选择“动态链接库和MFC静态链接”图 3-3-2 创建MFC规则DLL点击“完成”按钮完成向导。(2)在工程中添加一个对话框,并设计该对话框。图 3-3-3 创建对话框为该对话框新建一个类CDllDialog,图 3-3-4 新建类CDllDialog为对话框上的按钮“MFC Regualr Dll”添加消息响应函数,图 3-3-5 添加消息响应函数并添加以下代码:void CDllDialog:OnButton1() / TODO: Add your control notification handler code hereMessageBox( MFC Regular DLL );在RegularDll.cpp 的最后,添加MFC规则DLL接口函数。extern C _declspec(dllexport) void ShowDlg(void) AFX_MANAGE_STATE(AfxGetStaticModuleState();CDllDialog dllDialog;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)在视类对该菜单项添加消息响应函数,函数代码如下:void CCallRegDllView:OnRegdll() / TODO: Add your command handler code heretypedef void (*lpFun)(void);HINSTANCE hDll=NULL; /DLL句柄hDll = LoadLibrary(RegularDll.dll); if(hDll!=NULL) lpFun pShowDlg = (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。(1) 将DLL工程生成的.lib文件和.dll文件拷入当前工程所在的目录。图 3-4-6 添加.lib文件和.dll文件(2) 并在CCallRegDllView.cpp文件 的顶部添加以下代码:#pragma comment(lib,RegularDll.lib) /extern C _declspec(dllimport) void ShowDlg(void); /(3) 把消息响应函数CCallRegDllView:OnRegDll()修改为以下:void CCallRegDllView:OnRegDll() / TODO: Add your command handler code here ShowDlg(); (4) 编译运行程序,同样能得到正确的结果。图 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类型入口函数非 MFC DLL编程者提供DllMain函数MFC规则 DLLCWinApp对象的InitInstance 和 ExitInstanceMFC扩展 DLLMFC DLL向导生成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 _AFXEXTAFX_CLASS_EXPORT#elseAFX_CLASS_IMPORTAFX_EXT_API#ifdef _AFXEXTAFX_API_EXPORT#elseAFX_API_IMPORTAFX_EXT_DATA#ifdef _AFXEXTAFX_DATA_EXPORT#elseAFX_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时,系统会自动添加如下代码:static AFX_EXTENSION_MODULE ExtDllDLL = NULL, NULL ;extern C int APIENTRYDllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )/ Remove this if you use lpReservedUNREFERENCED_PARAMETER( lpReserved );/说明:lpReserved是一个被系统所保留的参数,对于隐式链接是一个非零值,对于显式链接值是零if (dwReason = DLL_PROCESS_ATTACH)TRACE0( EXTDLL.DLL Initializing!n );/ Extension DLL one-time initializationif ( !AfxInitExtensionModule( ExtDllDLL, hInstance )return 0;/ Insert this DLL into the resource chainnew CDynLinkLibrary( ExtDllDLL );else if (dwReason = DLL_PROCESS_DETACH)TRACE0( EXTDLL.DLL Terminating!n );/ Terminate the library before destructors are calledAfxTermExtensionModule( ExtDllDLL );return 1; / ok代码分析如下:(1)上述代码完成MFC扩展DLL的初始化和终止处理;(2)初始化期间所创建的 CDynLinkLibrary 对象使MFC扩展 DLL 可以将 DLL中的CRuntimeClass 对象或资源导出到应用程序;(3)AfxInitExtensionModule函数捕获模块的CRuntimeClass 结构和在创建 CDynLinkLibrary 对象时使用的对象工厂(COleObjectFactory 对象);(4)AfxTermExtensionModule函数使 MFC 得以在每个进程与扩展 DLL 分离时(进程退出或使用AfxFreeLibrary卸载DLL时)清除扩展 DLL;(5)第一条语句static AFX_EXTENSION_MODULE ExtDllDLL = NULL, NULL ;定义了一个AFX_EXTENSION_MODULE类的静态全局对象,AFX_EXTENSION_MODULE的定义如下:struct AFX_EXTENSION_MODULEBOOL bInitialized;HMODULE hModule;HMODULE hResource;CRuntimeClass* pFirstSharedClass;COleObjectFactory* pFirstSharedFactory; 在资源编辑器中添加一个如下图所示的对话框,并使用MFC类向导为其添加一个对应的类CExtDialog,系统自动添加了ExtDialog.h和ExtDialog.cpp两个头文件。图 4-2-3 添加对话框图 4-2-3 添加对话框类修改ExtDialog.h中CExtDialog类的声明为:class AFX_EXT_CLASS CExtDialog : public CDialogpublic:CExtDialog( CWnd* pParent = NULL );enum IDD = IDD_DLL_DIALOG ;protected:virtual void DoDataExchange( CDataExchange* pDX );DECLARE_MESSAGE_MAP();这其中最主要的改变是我们在class AFX_EXT_CLASS CExtDialog语句中添加了“AFX_EXT_CLASS”宏,则使得DLL中的CExtDialog类被导出。 为对话框按钮“MFC Extention DLL”添加消息响应函数void CExtDialog:OnButton1() / TODO: Add your control notification handler code hereMessageBox( MFC Extention DLL );最后,编译运行,生成.lib文件和.dll文件。4.3. MFC扩展DLL的加载 在上述工程所在的工作区中添加一个LoadExtDllDlg工程,用于演示MFC扩展DLL的加载。在LoadExtDllDlg工程中添加一个如下图所示的对话框,这个对话框上包括一个“调用DLL”按钮。图 4-3-1 MFC扩展DLL调用工程中的对话框在与上图对应对话框类实现文件的头部添加:/ LoadExtDllDlg.cpp : implementation file/#include .ExtDialog.h#pragma comment( lib, .DebugExtDll.lib )而“调用DLL”按钮的单击事件的消息处理函数为:void CLoadExtDllDlg:OnDllcallButton()CExtDialog extDialog;extDialog.DoModal();最后编译并运行,运行结果如下: 图 4-3-2 运行结果从上述加载过程,我们可总结出:为提供给用户隐式加载,MFC扩展DLL需要提供三个文件:(1)描述DLL中扩展类的头文件;(2)与动态链接库对应的.LIB文件;(3)动态链接库.DLL文件本身。有了这三个文件,应用程序的开发者才可充分利用MFC扩展DLL。五、动态链接库的典型应用 动态链接库DLL实现了库的共享,体现了代码重用的思想。我们可以把广泛的、具有共性的、能够多次被利用的函数和类定义在库中。这样,在再次使用这些函数和类的时候,就不再需要重新添加与这些函数和类相关的代码。因此,动态链接库的应用广泛,而其主要的典型应用有以下几方面:5.1. 通用的算法图像处理、视频音频解码、压缩与解压缩、加密与解密通常采用某些特定的算法,这些算法较固定且在这类程序中往往经常被使用。如以下的例子:学习过较高级别数学(概率统计与随机过程)、信号与线性系统及数字信号处理的读者应该知道,傅立叶变换是一种在信号分析中常用的算法,用于时域和频域的相互转换。FFT变换算法通用而有共性,我们适宜把它集成在一个DLL中。我们可在相关资料上获取到FFT变换算法的函数代码如下:/* 函数名称:FFT()* 参数:* complex * TD - 指向时域数组的指针* complex * FD - 指向频域数组的指针* r 2的幂数,即迭代次数* 返回值: 无。* 说明:该函数用来实现快速傅立叶变换*/void FFT(complex * TD, complex * FD, int r)LONG count; / 傅立叶变换点数int i,j,k; / 循环变量int bfsize,p; / 中间变量double angle; / 角度complex *W,*X1,*X2,*X;count = 1 r; /傅立叶变换点数/ 分配运算所需存储器W = new complexcount / 2;X1 = new complexcount;X2 = new complexcount;/ 计算加权系数for(i = 0; i count / 2; i+)angle = -i * PI * 2 / count;Wi = complex (cos(angle), sin(angle);/ 将时域点写入X1memcpy(X1, TD, sizeof(complex) * 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;X2i + p = X1i + p + X1i + p + bfsize / 2;X2i + p + bfsize / 2 = (X1i + p - X1i + p + bfsize / 2) * Wi * (1k);X = X1;X1 = X2;X2 = X;/ 重新排序for(j = 0; j count; j+)p = 0;for(i = 0; i r; i+)if (j&(1i)p+=1(r-i-1);FDj=X1p;/ 释放内存delete W;delete X1;delete X2;既然有了FFT这个函数,我们要把它做在DLL中,作为DLL的一个接口将是十分简单的,其步骤如下:(1)利用MFC向导建立一个非MFC DLL;(2)在工程中添加fft.h和fft.cpp两个文件;fft.h的源代码为:#ifndef FFT_H#define FFT_H#include using namespace std;extern C void _declspec(dllexport) _stdcall FFT(complex * TD, complex * FD, int r);#define PI 3.1415926#endiffft.cpp的源代码为:/

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论