动态链接库的生成和链接
2011-10-21褚姝韫李冀东王晋
褚姝韫 李冀东 王晋
摘要:动态链接库英文为DLL,是Dynamic Link Library 的缩写形式,DLL是一个包含可由多个程序同时使用的代码和数据的库,动态链接库使进程可以调用不属于其可执行代码的函数,还有助于共享数据和资源。通过使用 DLL,程序可以实现模块化,由相对独立的组件组成,可以更为容易地将更新应用于各个模块,而不会影响该程序的其他部分,为程序的开发带来了很大的便利。这篇文章研究了VC下动态链接库的生成和调用。
关键词:动态链接库;DLL;程序;模塊;共享数据
中图分类号:TP311.52
1 引 言
动态链接库英文为DLL,是Dynamic Link Library 的缩写形式,DLL是一个包含可由多个程序同时使用的代码和数据的库,动态链接库使进程可以调用不属于其可执行代码的函数,还有助于共享数据和资源。
当程序使用DLL时,具有的优点如下:
(1) 使用较少的资源
当多个程序使用同一个函数库时,DLL 可以减少在磁盘和物理内存中加载的代码的重复量。使前台的程序得到良好的运行,而且可以大大减少对其它程序的影响。
(2) 推广模块式体系结构
DLL有助于促进模块式程序的开发,这可以帮助您开发要求提供多个语言版本的大型程序或要求具有模块式体系结构的程序。
(3) 简化部署和安装
当 DLL 中的函数需要更新或修复时,部署和安装 DLL 不要求重新建立程序与该 DLL 的链接。此外,如果多个程序使用同一个 DLL,那么多个程序都将从该更新或修复中获益。当您使用定期更新或修复的第三方 DLL 时,会大大简化程序的更新步骤。
DLL在程序开发中具有无可替代的作用,本文介绍了DLL的生成和链接。
2 动态链接库的生成和链接
动态链接库其实就是为应用程序提供服务并具有某一特定功能的函数和类的集合,与它相对的是静态链接库。
静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。但是若使用DLL,该DLL不必被包含在最终EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。
下面简要的介绍一下在VC下可以生成的动态链接库的分类。
2.1 动态链接库的分类
使用VC模板可以生成以下三种不同类型的DLL:
(1)Win32DLL
只能导出C函数和变量,但可以使用除CObject派生的类。不能在导出函数中建立对话框,因为不能进行模块环境转换。
(2)MFC常规DLL
只能导出C函数和变量,但可以使用MFC中所有的类,在使用DLL中的资源时要进行模块环境转换,在每个要导出的函数最前面加上
AFX_MANAGE_STATE(AfxGetStaticModuleState()),也可以使用以下人工转换:HINSTANCE hCurContext=AfxGetResourceHandle();
AfxSetResourceHandle(GetModuleHandle("temp.dll"));//可以使用DLL中的资源了。
HRSRC hRes = FindResource(hCurContext,MAKEINTRESOURCE(129),
RT_DIALOG); //可以创建窗口了
AfxSetResourceHandle(hCurContext);
另外标准C语言中不支持重载,因为C语言的调用协定(__cdecl)生成的代码中函数名只有一个_(下划线)做前缀,所有该类型的DLL不能导出重载函数。
(3)MFC扩展DLL
支持C++接口,可以导出C++类,成员函数及重载函数,只支持动态MFC库。
每一个DLL必须有一个入口点,DllMain是一个缺省的入口函数。dllMain负责初始化(Initialization)和结束(Termination)工作,每当一个新的进程或者该进程的新的线程访问DLL时,或者访问DLL的每一个进程或者线程不再使用DLL或者结束时,都会调用DllMain。但是,使用TerminateProcess或TerminateThread结束进程或者线程,不会调用DllMain。
下面以一个简单的小程序为例,说明动态动态链接库的生成和链接。
2.2 动态链接库的生成
动态链接库的生成有两种方法:
(1)使用导出函数关键字_declspec(dllexport)创建MyDll.dll,该动态链接库中有两个函数,分别用来实现得到两个数的最大和最小数。
在MyDll.h添加:
extern "C" _declspec(dllexport) int Max(int a, int b);
extern "C" _declspec(dllexport) int Min(int a, int b);
在MyDLL.cpp中添加:
#include"MyDll.h"
int Max(int a, int b)
{……。。//要实现的功能代码}
int Min(int a, int b)
{…………//要实现的功能代码}
该动态链接库编译成功后,打开MyDll工程中的debug目录,可以看到MyDll.dll、MyDll.lib两个文件。LIB文件中包含DLL文件名和DLL文件中的函数名等,该LIB文件只是对应该DLL文件的“映像文件”,与DLL文件相比,LIB文件的长度要小的多,在进行隐式链接DLL时要用到它。读者可能已经注意到在MyDll.h中有关键字"extern C",它可以使其他编程语言访问你编写的DLL中的函数。
(2)用.def文件创建工程MyDll
为了用.def文件创建DLL,请先删除上个例子创建的工程中的MyDll.h文件,保留MyDll.cpp并在该文件头删除#include MyDll.h语句,同时往该工程中加入一个文本文件,命名为MyDll.def,再在该文件中加入如下代码:
LIBRARY MyDll
EXPORTS
MaxMin
其中LIBRARY语句说明该def文件是属于相应DLL的,EXPORTS语句下列出要导出的函数名称。我们可以在.def文件中的导出函数后加@n,如Max@1,Min@2,表示要导出的函数顺序号,在进行显式连时可以用到它。该DLL编译成功后,打开工程中的Debug目录,同样也会看到MyDll.dll和MyDll.lib文件。
2.3 动态链接库的链接
应用程序使用DLL可以采用两种方式:一种是隐式链接,另一种是显式链接。在使用DLL之前首先要知道DLL中函数的结构信息。Visual C++6.0在VCin目录下提供了一个名为Dumpbin.exe的小程序,用它可以查看DLL文件中的函数结构。另外,Windows系统将遵循下面的搜索顺序来定位DLL: ① 包含EXE文件的目录;② 进程的当前工作目录; ③ Windows系统目录; ④ Windows目录;⑤ 列在Path环境变量中的一系列目录。
(1)隐式链接
隐式链接就是在程序开始执行时就将DLL文件加载到应用程序当中。实现隐式链接很容易,只要将导入函数关键字_declspec(dllimport)函数名等写到应用程序相应的头文件中就可以了。下面的例子通过隐式链接调用MyDll.dll库中的Min函数。
在创建DllTest.exe文件之前,要先将MyDll.dll和MyDll.lib拷贝到当前工程所在的目录下面,也可以拷贝到windows的System目录下。如果DLL使用的是def文件,要删除TestDll.h文件中关键字“extern C”。TestDll.h文件中的关键字Progam commit是要Visual C+的编译器在link时,链接到MyDll.lib文件,当然,开发人员也可以不使用#pragma comment(lib,"MyDll.lib")语句,而直接在工程的Setting->Link页的Object/Moduls栏填入MyDll.lib既可。
(2)显式链接
显式链接是应用程序在执行过程中随时可以加载DLL文件,也可以随时卸载DLL文件,这是隐式链接所无法作到的,所以显式链接具有更好的灵活性,对于解释性语言更为合适。不过实现显式链接要麻烦一些。在应用程序中用LoadLibrary或MFC提供的AfxLoadLibrary显式的将自己所做的动态链接库调进来,动态链接库的文件名即是上述两个函数的参数,此后再用GetProcAddress()獲取想要引入的函数。自此,你就可以象使用如同在应用程序自定义的函数一样来调用此引入函数了。在应用程序退出之前,应该用FreeLibrary或MFC提供的AfxFreeLibrary释放动态链接库。下面是通过显式链接调用DLL中的Max函数的例子。
在通过显式链接调用DLL中的Max函数中使用类型定义关键字typedef,定义指向和DLL中相同的函数原型指针,然后通过LoadLibray()将DLL加载到当前的应用程序中并返回当前DLL文件的句柄,然后通过GetProcAddress()函数获取导入到应用程序中的函数指针,函数调用完毕后,使用FreeLibrary()卸载DLL文件。在编译程序之前,首先要将DLL文件拷贝到工程所在的目录或Windows系统目录下。
使用显式链接应用程序编译时不需要使用相应的Lib文件。另外,使用GetProcAddress()函数时,可以利用MAKEINTRESOURCE()函数直接使用DLL中函数出现的顺序号,如将GetProcAddress(hDLL,"Min")改为GetProcAddress(hDLL, MAKEINTRESOURCE(2))(函数Min()在DLL中的顺序号是2),这样调用DLL中的函数速度很快,但是要记住函数的使用序号,否则会发生错误。
3 结 论
本文介绍了VC模板下动态链接库的生成和链接,动态链接库使进程可以调用不属于其可执行代码的函数,还有助于共享数据和资源,促进模块化程序的开发,简化程序更新的步骤,在实际开发中要多运用动态链接库。
参考文献
[1]宋宝华. VC++动态链接库编程之基本概念[0L]. http://dev.yesky.com/228/2141728.shtml
[2]何鹏飞.WINDOWS动态连接库技术的探讨[J].计算机应用研究,1995,3:18-20.