第10章静态链接庠和动态链接庠
第10章 静态链接库和动态链接库
在 Windows操作系统环境中,我们编写程序是离不开系统提供的库函数, 有些常规运算和系统调用等函数都是通过库函数方式提供的。 Windows库中 函数都是可执行代码,其库类型主要有两种 静态链接库( Static Link library,即Ljb) 动态链接库( Dynamic- Link library,即DLL) 这两种库使用的主要区别是使用静态链接库的应用程序从函数库中得 到所引用的函数的执行代码,然后把执行代码放进程序自身的执行文件中 这样,应用程序在运行时就可以不再需要静态函数库的支持了;而动态链 接库是一种用来为其它可执行文件(包括EXE文件和其它DL)提供共享的 函数库,通常我们编写的应用程序中需要使用DL的应用程序,我们可以调 用DL中的导出函数( imported function),在我们应用程序本身的执行 代码中并不包含这些函数的执行代码,它们经过编译和链接之后,独立的 保存在DLL中,使用DL的应用程序只包括了用于从DL中定位所引用的函数 的信息,而没有函数具体实现,要等到程序运行时才从DL中获得函数的实 现代码。显然,我们开发的使用了DL的应用程序在运行时必须要有相应的 DL的支持。这是一种和过去常用的静态链接不同的方式
在Windows操作系统环境中,我们编写程序是离不开系统提供的库函数, 有些常规运算和系统调用等函数都是通过库函数方式提供的。Windows库中 函数都是可执行代码,其库类型主要有两种: l 静态链接库(StaticLink Library, 即Lib) l 动态链接库(Dynamic-Link Library, 即DLL) 这两种库使用的主要区别是使用静态链接库的应用程序从函数库中得 到所引用的函数的执行代码,然后把执行代码放进程序自身的执行文件中, 这样,应用程序在运行时就可以不再需要静态函数库的支持了;而动态链 接库是一种用来为其它可执行文件(包括EXE文件和其它DLL)提供共享的 函数库,通常我们编写的应用程序中需要使用DLL的应用程序,我们可以调 用DLL中的导出函数(imported function),在我们应用程序本身的执行 代码中并不包含这些函数的执行代码,它们经过编译和链接之后,独立的 保存在DLL中,使用DLL的应用程序只包括了用于从DLL中定位所引用的函数 的信息,而没有函数具体实现,要等到程序运行时才从DLL中获得函数的实 现代码。显然,我们开发的使用了DLL的应用程序在运行时必须要有相应的 DLL的支持。这是一种和过去常用的静态链接不同的方式
静态链接库 静态链接库的扩展名为Jib。如前所述,使用静态链接库的 应用程序是从函数库中得到所引用的函数的执行代码,然后 把执行代码放进程序自身的执行文件中,这样,应用程序在 运行时就可以不再需要静态函数库的支持了,通常库中存放 是常见的数学函数等。 在许多高级编程语言里都有静态链接库,如 FORTRAN7有 Math.1ib和 Fortran.lib两个静态链接库。目前, Windows编程 主要使用动态链接库,但也有许多是使用静态链接库
静态链接库 静态链接库的扩展名为.lib 。如前所述,使用静态链接库的 应用程序是从函数库中得到所引用的函数的执行代码,然后 把执行代码放进程序自身的执行文件中,这样,应用程序在 运行时就可以不再需要静态函数库的支持了,通常库中存放 是常见的数学函数等。 在许多高级编程语言里都有静态链接库,如FORTRAN77有 Math.lib和Fortran.lib两个静态链接库。目前,Windows编程 主要使用动态链接库,但也有许多是使用静态链接库
动态链接库 目前,动态链接库(DLL)在 Windows编程中得到了广泛的应用。 Windows ap函数中的相当一部分程序就是由一组DLL所提供的,这些 DLL从安装 Windows之后起就存在于操作系统环境之中了。事实上,我 们早就在使用DLL进行编程了,只不过我们所使用的DLL都是现成的, 并且所有调用DLL的操作都由 Visual c艹+的编译和链接程序替我们完成 的。使用DL与传统的静态链接库相比具有更多的优势。 首先,动态链接库实现了多个应用程序共享数据和代码的方式。由于 多个应用程序共享同一个DLL中的函数,因而使用DLL可以显著的节 省磁盘空间。尤其对于 Windows应用程序,有很多的操作都是“标准 化”了的,如果使用传统的静态链接,每一个需要完成这些操作的应 用程序都必须在自己的执行文件中包括相同的执行代码,这不但使单 个的应用程序变得更大,也浪费了磁盘空间
动态链接库 目前,动态链接库(DLL)在Windows编程中得到了广泛的应用。 Windows API函数中的相当一部分程序就是由一组DLL所提供的,这些 DLL从安装Windows之后起就存在于操作系统环境之中了。事实上,我 们早就在使用DLL进行编程了,只不过我们所使用的DLL都是现成的, 并且所有调用DLL的操作都由Visual C++的编译和链接程序替我们完成 的。使用DLL与传统的静态链接库相比具有更多的优势。 首先,动态链接库实现了多个应用程序共享数据和代码的方式。由于 多个应用程序共享同一个DLL中的函数,因而使用DLL可以显著的节 省磁盘空间。尤其对于Windows应用程序,有很多的操作都是“标准 化”了的,如果使用传统的静态链接,每一个需要完成这些操作的应 用程序都必须在自己的执行文件中包括相同的执行代码,这不但使单 个的应用程序变得更大,也浪费了磁盘空间
其次,由于上述原因,多个应用程序还可以同时共享动态链接库在内存年同 份拷贝,这样就有效的节省了应用程序所占用的内存资源,减少了频繁的内存 交换,从而提高了应用程序的执行效率和运行速度。 再者,由于动态链接库是独立于可执行文件的,因此,如果需要向动态链接库 中增加新的函数或是增强现有函数的功能,只要原有函数的参数和返回值等属性 不变,那么,所有使用该DLL的原有应用程序都可以在升级后的DLL的支持下运 行,而不需要重新编译。这就极大的方便了应用程序的升级和售后支持。 另外,动态链接库除了包括函数的执行代码以外,还可以只包括如图标、位图、 字符串和对话框之类的资源,因此可以把应用程序所使用的资源独立出来做成 DLL。对于一些常用的资源,把它们做到DLL中后,就可为多个应用程序所共享。 最后,动态链接库便于建立多语言的应用程序。我们可以把多语言应用程序中 所使用的与语言相关的函数做到DLL中,只要不同语言的应用程序所调用的函数 都具有相同的接口,这样就可以通过简单地更换DLL来实现多语言支持 然而,我们使用动态链接库也有其不足之处。最典型的就是应用程序在运行时必 须要有相应的DLL的支持。另外,使用DLL也增大了程序运行的开销,但这种额 外的开销对于大多数应用程序的影响并不是很明显,我们也只是在某些对运行速 度要求苛刻的特殊场合,才不得不考虑这一点
其次,由于上述原因,多个应用程序还可以同时共享动态链接库在内存中的同 一份拷贝,这样就有效的节省了应用程序所占用的内存资源,减少了频繁的内存 交换,从而提高了应用程序的执行效率和运行速度。 再者,由于动态链接库是独立于可执行文件的,因此,如果需要向动态链接库 中增加新的函数或是增强现有函数的功能,只要原有函数的参数和返回值等属性 不变,那么,所有使用该DLL的原有应用程序都可以在升级后的DLL的支持下运 行,而不需要重新编译。这就极大的方便了应用程序的升级和售后支持。 另外,动态链接库除了包括函数的执行代码以外,还可以只包括如图标、位图、 字符串和对话框之类的资源,因此可以把应用程序所使用的资源独立出来做成 DLL。对于一些常用的资源,把它们做到DLL中后,就可为多个应用程序所共享。 最后,动态链接库便于建立多语言的应用程序。我们可以把多语言应用程序中 所使用的与语言相关的函数做到DLL中,只要不同语言的应用程序所调用的函数 都具有相同的接口,这样就可以通过简单地更换DLL来实现多语言支持。 然而,我们使用动态链接库也有其不足之处。最典型的就是应用程序在运行时必 须要有相应的DLL的支持。另外,使用DLL也增大了程序运行的开销,但这种额 外的开销对于大多数应用程序的影响并不是很明显,我们也只是在某些对运行速 度要求苛刻的特殊场合,才不得不考虑这一点
Visual o++6.0支持多种DLL,包括: EEMFC DLL 静态链接到MFC的常规DLL 动态链接劲MFC的常规DLL MFC扩展DLL 般来说,悲 MFC DLL(non- MFC DLL)的内部不使用MFC,非 MFC DLL的 导出函数都使用标准的C接口( standard C interface),调用非 MFC DLL提供的导 出函数的可执行程序可以使用MFC,也可以不使用MFC。其余三种DLL的内部都 使用了MFC。 顾名思义,静态链接到MFC的常规DLL( regular DLL statically linking to MFC) 和动态链接到MFC的常规DL( regular DLL dynamically linking to MFC)的区别 在于一个使用的是MFC的静态链接库,而另一个使用的是MFC的DLL。这和一般 的MFC应用程序的情况是很类似的。 MFC扩展DLL一般用来提供派生于MFC的可重用的类,以扩展已有的MFC类库的 功能。MFC扩展DLL使用MFC的动态链接版本。只有使用MFC动态链接的可执行 程序(无论是EXE还是DLL)才能访问MFC扩展DLL。MFC扩展DLL的另一个有 用的功能是它可以在应用程序和它所加载的MFC扩展DLL之间传递MFC和MFC派 生对象的指针。在其它情况下,这样做是可能导致某些问题
Visual C++ 6.0支持多种DLL,包括: l 非MFC DLL l 静态链接到MFC的常规DLL l 动态链接到MFC的常规DLL l MFC扩展DLL 一般来说,非MFC DLL(non-MFC DLL)的内部不使用MFC,非MFC DLL的 导出函数都使用标准的C接口(standard C interface),调用非MFC DLL提供的导 出函数的可执行程序可以使用MFC,也可以不使用MFC。其余三种DLL的内部都 使用了MFC。 顾名思义,静态链接到MFC的常规DLL(regular DLL statically linking to MFC) 和动态链接到MFC的常规DLL(regular DLL dynamically linking to MFC)的区别 在于一个使用的是MFC的静态链接库,而另一个使用的是MFC的DLL。这和一般 的MFC应用程序的情况是很类似的。 MFC扩展DLL一般用来提供派生于MFC的可重用的类,以扩展已有的MFC类库的 功能。MFC扩展DLL使用MFC的动态链接版本。只有使用MFC动态链接的可执行 程序(无论是EXE还是DLL)才能访问MFC扩展DLL。MFC扩展DLL的另一个有 用的功能是它可以在应用程序和它所加载的MFC扩展DLL之间传递MFC和MFC派 生对象的指针。在其它情况下,这样做是可能导致某些问题
我们选择那一种DL的类型可以从以下几个方面来考虑 相比之下,我们对使用MFC的DLL而言,非 MFC DLL显得更 为短小精悍。因此,如果DL不需要使用MFC,那么使用非MFC DLL是一个很好的选择,它将显著地节省磁盘和内存空间。同时,无 论应用程序是否使用了MFC,都可以调用非 MFC DLLI中所导出的函 数 如果需要创建使用了MFC的DLL,并希望MFC和非MFC应用 程序都能使用所创建的DLL,那么可以选择的范围包括静态链接到 MFC的常规DLL和动态链接到MFC的常规DLL。动态链接到MFC的 常规DLL比较短小,因此可以节省磁盘和内存,但是,在分发动态链 接到MFC的常规DLL时,必须同时分发MFC的支持DLL,如 MFCx0.DLL和 MSVCRTDLL等。而使用静态链接到MFC的常规DLL 则不存在这种问题。 如果希望在DLL中实现从MFC派生的可重用的类,或者是希望在应用 程序和DLL之间传递MFC的派生对象时,必须选择MFC扩展DLL
我们选择那一种DLL的类型可以从以下几个方面来考虑: l 相比之下,我们对使用MFC的DLL而言,非MFC DLL显得更 为短小精悍。因此,如果DLL不需要使用MFC,那么使用非MFC DLL是一个很好的选择,它将显著地节省磁盘和内存空间。同时,无 论应用程序是否使用了MFC,都可以调用非MFC DLL中所导出的函 数。 l 如果需要创建使用了MFC的DLL,并希望MFC和非MFC应用 程序都能使用所创建的DLL,那么可以选择的范围包括静态链接到 MFC的常规DLL和动态链接到MFC的常规DLL。动态链接到MFC的 常规DLL比较短小,因此可以节省磁盘和内存,但是,在分发动态链 接 到 MFC 的常规 DLL时 , 必 须 同 时分 发 MFC的支持 DLL , 如 MFCx0.DLL和MSVCRT.DLL等。而使用静态链接到MFC的常规DLL 则不存在这种问题。 如果希望在DLL中实现从MFC派生的可重用的类,或者是希望在应用 程序和DLL之间传递MFC的派生对象时,必须选择MFC扩展DLL
动态链接库DLL中一般定义有两种类型的函数:导出函数 ( export function)和内部函数( internal function)。导出函数是 可以被外部程序调用的函数,内部函数只能在DLL内部使用。尽 管DLL类型各异,但每个DLL都含有一个入口点函数 DIMain。 DOmAin的作用是初始化DLL,并在卸载时清理DLL DLL文件与可执行文件非常相似,不同点在于DLL包含有导出表 ( Export Table)。导出表包含DLL中每个导出函数的名字,这 些函数是进入DLL的入口点。只有导出表中的函数可以被外部程 序调用。DLL中的导出表可以使用带 EXPORTS开关的 DUMPBIN 工具来查看。从DLL中导出函数有以下两种方法: 创建模块定义文件(DEF)并在建立DLL时使用DEF文 件 在导出函数的定义中使用关键字 declspec( dllexport)
动态 链接 库DLL中一 般定 义有 两种 类 型的 函数 :导 出函 数 (export function)和内部函数(internal function)。导出函数是 可以被外部程序调用的函数, 内部函数只能在DLL内部使用。尽 管DLL类型各异, 但每个DLL都含有一个入口点函数DllMain。 DllMain的作用是初始化DLL, 并在卸载时清理DLL。 DLL文件与可执行文件非常相似, 不同点在于DLL包含有导出表 (Export Table)。 导出表包含DLL中每个导出函数的名字,这 些函数是进入DLL的入口点。只有导出表中的函数可以被外部程 序调用。DLL中的导出表可以使用带/EXPORTS开关的DUMPBIN 工具来查看。从DLL中导出函数有以下两种方法: l 创建模块定义文件(.DEF)并在建立DLL时使用 .DEF文 件。 在导出函数的定义中使用关键字__declspec(dllexport)
模块定义文件(DEF)是由一个或多个用于描述DL属性 的模块语句组成的文本文件。如果不使用关键字 declspec( dllexport)导出DL函数,那么必须使用DEF文 件。每个DEF文件至少必须包含以下模块定义语句: 第一个语句必须是 LIBRARY语句,这个语句指出 DLL的名字,链接器将这个名字放到DLL导入库( Import library)中,DL导入库包含了指向外部DLL的函数索引指 针 ● EXPORTS语句列出被导出函数的名字,以及导出函 数的数值(由@号与数字构成)。序数值可以省略,编译 器( Compiler)会为每个导出函数指定一个,但这样指定 的值不如自己指定的明确。 使用 DESCRIPTION语句描述DLL的用途,这个语句可以省 略
模块定义文件(.DEF)是由一个或多个用于描述DLL属性 的模块语句组成的文本文件 。 如 果 不 使 用 关 键 字 __declspec(dllexport()导出DLL函数, 那么必须使用 .DEF文 件。每个 .DEF文件至少必须包含以下模块定义语句: l 第一个语句必须是LIBRARY语句, 这个语句指出 DLL的名字, 链接器将这个名字放到DLL导入库(import library)中, DLL导入库包含了指向外部DLL的函数索引指 针。 l EXPORTS 语句列出被导出函数的名字, 以及导出函 数的数值(由@号与数字构成)。序数值可以省略, 编译 器(Compiler)会为每个导出函数指定一个, 但这样指定 的值不如自己指定的明确。 使用DESCRIPTION语句描述DLL的用途, 这个语句可以省 略
静态链接库和动态链接库的使用 如果是win32静态链接库,我们只要把静态链接库如 MyStaticLib lib 和其头文件如 Square. h复制到客户的工程中,然后再选择菜单“工程” (即 Project)下的“设置”(即 Setting)菜单项或按Alt+F7弹出设置对话框, 选择“Iink选项卡,在“对象/库模块”编辑框中指明静态链接库的路径 如“ D: MyAppProject MyStaticLib.lib”。 我们开发的应用程序与DLL的链接有两种方法:一种是隐含链接,另 种为显式链接。 隐含链接有时又称为静态加载。如果应用程序使用了隐含链接,操作 系统在加载应用程序的同时加载应用程序所使用的DLL。显式链接有时又 称为动态加载。使用动态加载的应用程序必须在代码中明确的加载所使 用的DLL,并使用指针来调用DLL中的导出函数,在使用完毕之后,应用 程序必须卸载所使用的DLL。同一个DL可以被应用程序隐含链接,也可 以被显式链接,这取决于应用程序的目的和实现
静态链接库和动态链接库的使用 如果是Win32静态链接库,我们只要把静态链接库如MyStaticLib.lib 和其头文件如Square.h复制到客户的工程中,然后再选择菜单“工程” (即Project)下的“设置”(即Setting)菜单项或按Alt+F7弹出设置对话框, 选择“Link”选项卡,在“对象/库模块”编辑框中指明静态链接库的路径 如 “D:\MyAppProject\MyStaticLib.lib”。 我们开发的应用程序与DLL的链接有两种方法:一种是隐含链接,另 一种为显式链接。 隐含链接有时又称为静态加载。如果应用程序使用了隐含链接,操作 系统在加载应用程序的同时加载应用程序所使用的DLL。显式链接有时又 称为动态加载。使用动态加载的应用程序必须在代码中明确的加载所使 用的DLL,并使用指针来调用DLL中的导出函数,在使用完毕之后,应用 程序必须卸载所使用的DLL。同一个DLL可以被应用程序隐含链接,也可 以被显式链接,这取决于应用程序的目的和实现