第13章动态链接库_第1页
第13章动态链接库_第2页
第13章动态链接库_第3页
第13章动态链接库_第4页
第13章动态链接库_第5页
已阅读5页,还剩60页未读 继续免费阅读

下载本文档

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

文档简介

1、第13章 动态链接库动态链接库是由用户自己开发的、可以加入到应用程序中作为提供某一特定功能的函数和类的集合。它可以被多个应用程序共享,并且只在运行时动态装载库文件。学习本章,读者可以掌握动态链接库的基本知识,同时可以了解动态链接库在钩子技术中的实际应用。13.1 什么是动态链接库动态链接库(Dynamic Link Library,DLL)是由函数等组成的二进制库文件,它可以被多个应用程序使用。应用程序在链接动态链接库时,并不把动态链接库中的函数复制到应用程序中,而只是记录函数的位置信息,程序在执行时,根据所记录的信息就可以找到目标函数的位置。可见动态链接库的动态含义就是执行时才真正地进行动态

2、链接。静态链接库是应用程序链接时将其全部代码复制到应用程序中,在链接完成以后,应用程序就不再需要静态链接库的支持。所谓动态和静态的含义就是说应用程序对链接库装入的时刻不同。动态链接库与静态链接库相比有着更多的优势。节省空间,动态链接库可以被多个程序共享,而静态链接库把库文件中的代码复制到应用程序中,这样使得应用程序占用的空间要增大许多。同时由于动态链接库支持多个应用程序共享DLL在内存中的同一份复制,这样就节省了内存空间,提高了程序的效率。独立性好,DLL文件是完全独立于可执行文件的,因此如果需要向DLL中增加新的函数或改变函数功能,只要原有函数的参数和返回值等属性不变,那么所有使用该DLL的

3、应用程序都可以使用改变后的DLL文件。但是由于应用程序是动态地调用动态链接库中的函数,这样无疑增加了一些程序运行时的开销,但这种开销对程序的执行效率并不明显,而且它的优势是静态链接库根本就无法实现的。动态链接库是一个可执行模块。但是它与应用程序有很大不同。它本身不能运行,必须在应用程序中使用。动态链接库包含了其所提供的函数的目标代码,在应用程序中可以使用它提供的函数。但是应用程序对动态链接库中的函数调用并不是把程序段复制到应用程序中,而是利用一个记录了动态链接库中函数信息的文件对函数进行动态链接。在应用程序中需要使用动态链接库函数的地方调用链接库的函数。在Windows系统中,很多资源的共享配

4、置,软件的设计都使用了动态链接库。其中在软件设计中,动态链接库最为常用的是语言资源的动态链接库。例如在Visual C+使用AppWizard生成应用程序时,可以指定资源文件使用的语言,这就是通过提供不同的动态链接库实现的。注意:使用动态链接库时,随同应用程序还要提供动态链接库文件(DLL文件)。例如,发布Visual C+编写的程序时,如果使用了动态连接,则在提供可执行文件的同时还需要提供Visual C+的动态链接库。在大多情况下,动态链接库和静态链接库的使用没有多大界限,但在某些情况下必须使用动态链接库。这些情况包括:在全局钩子函数中必须使用动态链接库;设备驱动程序必须是动态连接库。为了

5、实现应用程序的国际化,往往需要使用动态链接库。使用动态链接库可以将针对某一国家、地区的某种语言的信息存放在其中。上面介绍了动态链接库的基本概念,使用它可以实现软件的模块化设计。在Visual C+中对动态链接库的创建提供了支持。同时在Visual C+中可以方便地使用动态链接库进行程序设计。在13.2节将介绍在Visual C+中创建动态链接库的基本过程。13.2 创建动态链接库在Visual C+ 6.0中可以方便地创建动态链接库,它支持两种类型的动态链接库,即使用MFC的动态链接库和不使用MFC的Win32动态链接库,本节对这两种类型的动态链接库的创建进行介绍。13.2.1 创建MFC动态

6、链接库利用Visual C+ 6.0的应用程序向导可以方便地创建MFC动态链接库,具体步骤如下:(1)单击桌面上的Visual C+ 6.0应用程序图标,启动Visual C+ 6.0应用程序。(2)选择File | New命令,弹出New对话框,如图13.1所示。图13.1 New对话框(3)选择Peojects标签,选择MFC AppWizarddll选项,在“Project name:”文本框中输入工程文件名test。在“Location:”文本框中指定应用程序创建的位置。单击OK按钮,弹出MFC AppWizard Step 1 of 1对话框,如图13.2所示。图13.2 MFCAp

7、pWizard Step 1 of 1对话框图(4)在MFC AppWizard Step 1 of 1对话框中可以选择创建动态链接库的类型,下面对这3种类型进行介绍。Regular DLL With MFC statically linked:创建与MFC静态链接的常规DLL工程。MFC类库静态链接到将生成的DLL中,DLL中定义的函数可以被一般的Wn32应用程序和MFC应用程序使用。Regular DLL With MFC shared linked:创建与MFC动态链接的常规DLL工程,MFC类库动态地链接到将生成的DLL中,DLL中定义的函数可以被一般的Win32应用程序和MFC应用程

8、序使用。MFC Extension DLL:创建与MFC动态链接的扩展DLL,MFC类库动态地链接到将生成的DLL中,DLL中定义的函数只可以被MFC应用程序使用。选择一种创建类型后,单击Finish按钮,弹出New Project Information对话框,如图13.3所示。13.3 New Project Information对话框(5)在New Project Information对话框中列出了所建工程的信息,单击“OK”按钮,这时已经生成一个动态链接库工程。(6)编译、连接,在当前目录下的“Debug”文件夹下可以看到生成的DLL文件,此时并没有编写代码,向导生成了一个完整的动

9、态链接库工程。关于如何修改该工程和添加新的功能,在下一节进行介绍。13.2.2 创建Win32动态链接库在Visual C+ 6.0中也可以方便地创建不使用MFC的动态链接库,具体步骤如下:(1)单击桌面上的Visual C+ 6.0应用程序图标,启动Visual C+ 6.0。(2)选择File|New命令,弹出New对话框,如图13.4所示。图13.4 New对话框(3)选择Peojects标签,选择Win32 Dynamic Link Library选项,在“Project name:”文本框中输入工程文件名:test。在“Location:”文本框中指定应用程序创建的位置。单击OK按钮

10、,弹出Win32Dynamic-Link Library-Step 1 of 1对话框,如图13.5所示。图13.5 Win32 Dynamic-Link Library Step 1 of 1对话框(4)在MFC AppWizard Step1 of 1对话框中可以选择创建动态链接库的类型,下面对三种类型进行介绍。An empty DLL project:创建一个空的DLL工程,它自动生成dsw、dsp、ncb三个文件,但是不包含任何具有实际意义的文件,例如源文件、资源文件等。A Simple DLL project:创建一个简单的DLL工程,它生成一个完整的DLL工程。A DLL that

11、 exports some symbols:导出变量和函数的DLL工程。选择一种创建类型后,单击Finish按钮,弹出New Project Information对话框,如图13.6所示。图13.6 New Project Information对话框(5)在New Project Information对话框中列出了所建工程的信息,单击OK按钮,这时已经生成一个动态链接库工程。(6)如果选择的是后面两种类型,那么可以进行编译、连接,在当前目录下的“Debug”文件夹下可以看到生成的DLL文件。此时并没有编写代码,向导生成了一个完整的动态链接库工程。关于如何修改该工程和添加新的功能,在下一节

12、进行介绍。本节介绍了在Visual C+ 6.0中如何创建DLL工程。实际上此时创建的工程还没有起任何作用,甚至说不能是一个完整的动态链接库工程,在下面将对动态链接库的函数的编写,变量和函数的导出,以及在应用程序中加载的问题进行介绍。13.3 使用动态链接库文件前面介绍了在Visual C+ 6.0中创建动态链接库的一般步骤,本节介绍动态链接库文件的创建和应用程序中对动态链接库的加载过程。13.3.1 动态链接库的入口函数在C及C+程序中都有一个入口函数main(),在MFC应用程序中也有一个WinMain()函数,那么是不是动态链接库也有一个入口函数呢?答案是肯定的,这个入口函数是DllMa

13、in()函数,它负责进行初始化和终止工作。在新建的Win32动态链接库中,如果选择后面两种形式,读者都可以找到DllMain()函数,即使在MFC动态链接库工程中也可有DllMain()函数,只不过它被封装在了类中。下面给出DllMain()函数的原型:BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved);下面对其各个参数进行介绍:hinstDLL:DLL模块的句柄。fdwReason:入口函数被调用的标志,其取值及取值的含义如下:DLL_PROCESS_ATTACH:表明作为进程启动和调用Load

14、Library()的结果,DLL被调进当前进程的虚拟地址空间,它可以进行数据的初始化。DLL_THREAD_ATTACH:表明当前进程正在创建一个线程,这时系统调用当前链接到进程的所有DLL的入口函数。DLL_THREAD_DETACH:表明一个线程正在退出。DLL_PROCESS_DETACH:表明作为退出进程或调用FreeLibrary()的结果。lpvReserved:指定DLL的初始化及终止的进一步问题。创建动态链接库文件即需要编写入口函数,然后再编写其他欲实现某些功能的函数。13.3.2 动态链接库中数据和函数的导出动态链接库与可执行文件十分相似,不同之处在于DLL中含有导出表。导出

15、表包含DLL中全部函数的名字,这些函数是使用DLL的应用程序进入DLL入口的入口点。也就是说应用程序利用导出表得到相应的函数的位置,然后进入到DLL的函数中。那么如何得到导出表呢?导出表是应用程序得到DLL函数位置的一种工具。一般来说在DLL工程中利用导出函数即可得到导出表的方法,常见的有下面两种:(1)创建模块定义文件。(2)使用关键字_declspec(dllexport)。下面对两种方法分别进行介绍:1创建模块定义文件模块定义文件(.def)是由一个或多个用于描述DLL属性的模块组织语句构成的文件,一般来说模块定义文件至少包括以下几条语句:LIBRARY语句:指出DLL文件的名字。EXP

16、ORT语句和一系列函数名,每个函数名用来声明一个被导出的函数。【示例13.1】 创建了模块定义文件。LIBRARY ADDDESCRIPTION 加法;描述DLL的功能,可选语句EXPORTADD分析:当创建一个MFC DLL时,向导会自动生成一个模块定义文件,并加入到工程中,对于Win32的动态链接库,用户必须自己创建模块定义文件,将其加入到工程中。当用户定义好模块定义文件时,链接器利用该文件创建一个导出文件和一个导入文件(.lib),然后利用该导出文件创建DLL文件。说明:可以利用记事本编写模块定义文件,完成后,将后缀名改为“.def”即可。2使用关键字_declspec(dllexpor

17、t)可以使用_declspec(dllexport)从DLL中导出函数和变量,以及类或者类的成员,此时不再需要定义模块定义文件。【示例13.2】 _declspec(dllexport)的使用,下面利用关键字_declspec(dllexport)导出动态链接库中的add()函数。int _declspec(dllexport) _cdecl add(int a,int b)_declspec(dllexport)也可以导出类的所有成员。具体例子如下。【示例13.3】 使用_declspec(dllexport)导出类的成员。Class _declspec(dllexport) MyCLASS

18、上面介绍了动态链接库中数据和函数导出的两种方法。在实际应用中,读者一般可以选择自己熟悉的方法进行操作。13.3.3 动态链接库的加载动态链接库完成以后得到.DLL文件,下面介绍将此文件加载到可执行程序中的方法:隐式链接和显示链接。1隐式链接所谓隐式链接是指动态链接库的链接过程不出现在代码中。只需要在Visual C+中进行相关设置即可,下面对这一过程进行介绍。将动态链接库的库文件(.lib)导入到工程中。具体步骤如下所述。(1)选择“Project”|“Settings”命令,弹出Project Settings对话框,如图13.7所示。图13.7 Project Settings对话框(2)

19、选择“Link”标签,在“Objects/Library modules”文本框中输入需要导入的库文件,如果该库文件和应用程序在同一目录下,只要写入文件名就可以了,否则需要将路径也加入进来,这样才可以找到该库文件,如图13.8所示。图13.8 导入库文件(3)将DLL放到相应的路径下,只有这样应用程序才可以加载到应用程序中去。通过上面的步骤就把动态链接库文件和当前的应用程序联系了起来。此时应用程序调用动态链接库的函数。2显示链接显示链接是在应用程序中调用一些函数,动态地加载和释放动态链接库,一般情况下显示链接的步骤如下:(1)调用LoadLibrary()函数加载DLL。函数原型如下:HINS

20、TANCE LoadLibrary(LPCTSTR lpLibFileName );函数的返回值为指向动态链接库的句柄,加载成功,该返回值不为NULL。(2)调用GetProcAddress()函数获取导出函数的指针。函数原型如下:FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName );第一个参数是HMODULE类型的参数,实际中使用的是LoadLibrary()的返回值,即指向DLL的句柄,第二个参数指定要获取的函数。调用失败,返回NULL,否则返回指向要获取的函数的指针。(3)调用FreeLibrary()释放动态链接库函数原

21、型如下:BOOL FreeLibrary(HMODULE hLibModule);在使用完成后,调用该函数释放动态链接库,参数是指向动态链接库的句柄,函数调用成功,返回TRUE,否则返回FALSE。13.4 动态链接库应用实战上面介绍了动态链接库的创建和使用方法,本节结合实例讲解动态链接库的具体应用方法。13.4.1 MFC动态链接库应用实例在13.2节介绍了创建MFC动态链接库的基本步骤,下面结合实例讲解MFC动态链接库的应用实例。【示例13.4】 创建一个MFC动态链接库,添加一个输出一个字符串的函数,然后在对话框应用程序中调用该函数进行字符串的输出。具体步骤如下:(1)创建一个MFC动态

22、链接库,在13.2.1节中的第(4)步选择“Regular DLL With MFC shared linked”类型,即创建与MFC动态链接的常规DLL,MFC类库动态地链接到将生成到DLL中,DLL中定义的函数可以被一般的Win32应用程序和MFC应用程序使用。(2)添加函数。在生成的工程的test.h文件中添加语句如下:#include resource.h/ main symbols/ CTestApp/ See test.cpp for the implementation of this class/extern C void _declspec(dllexport) print(

23、);上面添加的是函数的声明语句,然后在.cpp文件中编写函数体。代码如下:01extern C void _declspec(dllexport) print()0203CString str=动态链接库编程实例;04AfxMessageBox(str);/弹出消息框05上面的代码加入到语句:CTestApp theApp;的后面。(3)编译、连接。在当前目录的debug文件夹下生成DLL及LIB文件。(4)创建一个基于对话框的应用程序,添加一个按钮控件。(5)添加按钮控件的单击的消息映射,编写消息响应函数如下:01void CTsDlg:OnButton1() 0203/ TODO: Add

24、 your control notification handler code here04HMODULE hdll=LoadLibrary(test.dll);/导入动态链接库05if(hdll)0607typedef void(*PROCTYPE)(); 08/得到函数地址09PROCTYPE myprint=(PROCTYPE)GetProcAddress(hdll,print); 10(*myprint)();1112FreeLibrary(hdll);/释放库13说明:要把上面生成的DLL文件复制到当前工程目录下。否则会出现错误。(6)编译、连接,运行后,单击“输出”按钮,运行结果如

25、图13.9所示。图13.9 运行结果上面使用的是利用关键字导出动态链接库的函数,并且在使用动态链接库时使用的是显示链接方式。在下面的章节中将会看到其他方式的使用。13.4.2 Win32动态链接库应用实例上面使用的是关键字_declspec(dllexport)导出动态链接库,并且使用的是显示链接。下面介绍使用模块定义文件导出动态链接库,并且采用隐式链接的方式使用动态链接库的编程实例。【示例13.5】 创建一个Win32动态链接库,在其中利用函数fun(int a,int b)求解出a和b的最小公倍数。新建一个对话框应用程序,添加三个编辑框,调用该函数,实现数字的输入及结果的输出。具体步骤如下

26、:(1)根据13.2.2节的步骤创建一个空的Win32动态链接库工程。(2)添加C+源文件。选择File | New命令,在弹出的对话框中选择C+源文件,填入文件名后,单击“OK”按钮。(3)在代码编辑区编写函数fun(int a,int b)。(4)添加一个头文件test.h。选择File|New命令,在弹出的对话框中选择C+头文件,填入文件名后,单击OK按钮。在头文件中添加fun(int a,int b)函数的声明语句:int fun(int a,int b);(5)添加一个模块定义文件。首先新建一个记事本文件,写上下面内容:; test.def : Declares the module

27、 parameters for the DLL.LIBRARY testDESCRIPTION test Windows Dynamic Link LibraryEXPORTSfun; Explicit exports can go here说明:“;”后面的内容为注释语句,即“;”相当于C+中的“/”。将记事本的后缀名修改为.def。(6)将模块定义文件加入到工程中。选择项目工作区的FileView面板,右击文件的小图标。在弹出的快捷菜单中选择Add File To Project命令,弹出Insert Files into Project对话框,如图13.10所示。找到刚才所写的模块定义文

28、件,单击“OK”按钮。此时已经将此文件加入到工程中了。图13.10 Insert Files into Project对话框(7)编译、连接。在当前的目录下生成了DLL文件和lib文件。(8)新建一个基于对话框的应用程序,在对话框上添加三个编辑框控件和一个按钮控件。设置按钮的标题为“计算最小公倍数”。(9)在类向导中分别为三个控件添加三个整型变量,如图13.11所示。图13.11 添加变量(10)利用类向导添加单击“计算最小公倍数”按钮控件的消息映射,编写消息响应代码。(11)将前面生成的DLL文件、lib文件和test.h文件复制到当前目录下。并且在testDlg.cpp文件中添加语句:#i

29、nclude test.h(12)选择Project|Settings命令,弹出Project Settings对话框。选择“Link”标签,在“Objects/Library modules”文本框中输入需要导入的库文件的文件名。(13)编译、连接,运行结果如图13.12所示。图13.12 运行结果本节介绍了两种动态链接库的应用实例,详细介绍了显示链接和隐式链接,以及利用函数和模块定义文件导出动态链接库的两种方法。13.5 钩 子 函 数钩子是Windows消息机制的要点,利用钩子函数可以拦截Windows应用程序的某些特定消息,或者对消息进行一些处理,从而解决了消息传递中的一些问题。13.

30、5.1 钩子技术介绍钩子是Windows消息处理机制的要点,Windows消息从硬件的输入到应用程序之间的传递如图13.13所示。图13.13 Windows消息传递当在应用程序中设置多个钩子函数以后,应用程序中的钩子函数组成一个与钩子相关联的指向钩子函数的指针列表。当钩子函数监视的消息到达以后,Windows系统首先将消息送到指针列表所指向的第一个钩子函数中,这个钩子函数对消息进行监视、修改、控制后,再将消息传递到下一个钩子函数中,再次进行处理,这样直到到达钩子链表的最后。在钩子链表对消息处理完成以后,消息仍然被送到应用程序的窗口中进行处理。钩子函数拦截了消息,并且进行了一些处理,这显然影响

31、了程序的效率,但是这种付出的回报是程序员可以对某些感兴趣的消息进行控制。钩子函数的本质就是一个处理系统消息的函数,通过应用程序将函数挂入到系统中,对系统消息进行拦截和处理。警告:如果利用钩子函数屏蔽掉所有的按键消息和鼠标消息,此时控制电脑将出现问题,请读者切莫尝试。13.5.2 钩子类型和范围根据钩子函数监视的消息的范围不同,钩子分为全局钩子和线程局部钩子。线程局部钩子仅仅是对本进程中的某个线程的消息进行拦截和处理。全局钩子则是对系统的全部消息进行拦截。全局钩子的实现要比局部钩子困难一些,它要监视所有的系统消息并进行处理。全局钩子函数的实现必须封装在独立的动态链接库中,才可以被各种各样的相关联

32、的应用程序所使用。局部钩子不一定在动态链接库中实现,但经常的做法是仍然在动态链接库中实现,这样可以被多个应用程序所使用,这正是动态链接库的优势所在。13.5.3 安装和解除钩子系统通过调用钩子链表的最开始的钩子函数进行消息的拦截和处理,应用程序中调用钩子函数必须把钩子函数放置在链表的链首,这样该函数会首先被调用。钩子函数与普通的函数有所不同,它是一个回调函数。回调函数是应用程序中一种特殊的函数,同时该函数也是最为常用的。它是指程序在调用一个函数时,将自己的函数的地址作为参数传递给程序调用的函数。使用回调函数解决了钩子函数对消息处理的过程。钩子的安装是通过SetWindowsHookEx()将钩子函数放置在钩子链表的首部的,其函数原型如下:HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINST

温馨提示

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

评论

0/150

提交评论