转自DELPHI5开发人员指南本章讨论了Wi n 3 2动态链接库,也就是D L L。D L L是用来编写Wi n d o w s应用程序的关键组成部分。 本章讨论了使用和创建D L L的几个方面,它给出了D L L怎样工作的概述并讨论了怎样创建和使用D L L, 你将学会怎样调入D L L和链接由它们引出的过程和函数的不同方法。本章还包括回调函数的使用并举 例说明在不同调用进程中如何实现共享数据。 9.1 究竟什么是DLL 动态链接库是程序模块,它包括代码、数据或资源,能够被其他的Wi n d o w s应用程序共享。D L L 的主要特点之一是应用程序可以在运行时调入代码执行,而不是在编译时链接代码,因此,多个应用 程序可以共享同一个D L L的代码。事实上,文件K e r n e l 3 2 . d l l、U s e r 3 2 . d l l、G D I 3 2 . d l l就是核心Wi n 3 2系 统的动态链接库。K e r n e l . d l l负责内存、进程和线程的管理。U S E R 3 2 . D L L包含了一些程序,是创建窗 口和处理Wi n 3 2消息的用户接口。G D I 3 2 . D L L负责处理图形。你还会听说其他的系统D L L,譬如 A d v A P I 3 2 . d l l和C o m D l g 3 2 . d l l,它们分别处理对象安全性/注册操作和通用对话框。 使用动态链接库的另一个特点是有利于应用程序的模块化。这样就简化了应用程序的修改,因为 一般只需要修改D L L,而不是整个应用程序。Wi n d o w s环境自身就是模块化类型的典型实例。每当安 装一个新设备,就安装一个设备驱动程序(即D L L ),使设备能够与Wi n d o w s相互通信。 在磁盘上,一个D L L基本上类似于一个Wi n d o w s可执行文件( * . E X E )。一个主要的区别是, D L L不是 一个独立的可执行文件,尽管它可能包含了可执行代码。大部分D L L文件的扩展名是. d l l,也有的可能 是. d r v (设备驱动程序)、. s y s (系统文件)、. f o n (字体文件),这些不包含可执行代码。 注意Delphi引入了一种叫做程序包的特殊用途的DLL,它应用于Delphi和C++编程环境。我们 将在第21章深入探究程序包。 D L L通过动态链接技术(dynamic linking)与其他应用程序共享代码,这将在本章后面部分讨论。总 之,当一个应用程序使用了一个D L L,Wi n 3 2系统会确保内存中只有一个该D L L的拷贝,这是通过内 存映射文件来实现的。D L L首先被调入Wi n 3 2的全局堆,然后映射到调用这个D L L进程的地址空间。 在Wi n 3 2系统中,每个进程都被分配有自己的3 2位线性地址空间。当一个D L L被多个进程调用时,每 个进程都会获得该D L L的一份映像。因此,在1 6位Wi n d o w s中,程序代码、数据、资源不被进程共享, 而在Wi n 3 2中,D L L是可以被看作是属于调用该D L L进程自己的代码。为得到关于Wi n 3 2概念的更多信 息,请参阅第3章“Win32 API”。 但这并不意味着,如果多进程调用一个D L L,物理内存就分配有该D L L的每个实例。通过从系统 的全局堆到调用该D L L的每一进程的地址空间的映射, D L L映像置于每个进程的地址空间。至少在理 想情况下应这样。 设置DLL的首选基地址 如果D L L被调入进程的地址空间时设置了基地址,这样D L L数据就可以被共享。如果D L L 的基地址与已经分配的D L L地址重叠的话,Wi n 3 2重新分配基地址。这样,每一个重新分配的 DLL实例都有自己的物理上的内存空间和交换文件空间。 这是很关键的,通过使用$ I M A G E B A S E指示符,给每个D L L都设置一个基地址,这样不 会引起冲突或不会出现地址重叠。 如果有多个应用程序都调用同一个D L L,设置一个唯一的基地址,这样无论是在进程的低 端地址或者是在一般的D L L (如V C L包)的高端地址,都不会引起冲突。一般可执行文件( E X E和 D L L )缺省的基地址为$ 4 0 0 0 0 0,这就意味着,除非修改D L L的基地址,否则就会与主程序的基 地址引起冲突,因此进程间也就不能共享DLL的数据。 在调用时,D L L不需要重新分配或安装,因为它保存在本地磁盘上,D L L的内存页面被直 接映射到磁盘上的D L L文件。D L L代码不需占用系统页面文件(也叫交换文件)的空间。这就是 为什么系统提交页的总数和大小可能比系统交换文件加内存要大。 你可以参阅Delphi 5的在线帮助中的“Image Base Address”,那里有使用$ I M A G E B A S E指 示符的详细介绍。 有关D L L的一些术语如下: . 应用程序,一个扩展名为. e x e的Wi n d o w s程序。 . 可执行文件,一个包含可执行代码的文件,它包括. d l l文件和. e x e文件。 . 实例,当提到应用程序和D L L时,在内存中出现的可执行文件就是实例。Wi n 3 2系统通过实例句 柄的方式来引用实例。例如,如果一个应用程序运行两次,就会有应用程序的两个实例,同时 就有两个实例句柄。当一个D L L被调入时,实例及其相应的实例句柄同时产生。应该注意的是, 这里所提的实例与类的实例不能混淆。 . 模块,在3 2位Wi n d o w s系统中,模块和实例可以说是同义的。而在1 6位的Wi n d o w s系统中,是建 立一个模块数据库来管理模块的,一个模块对应一个模块句柄。在Wi n 3 2中,应用程序的每一个 实例都拥有自己的地址空间;所以,没有必要为模块单独指定标识符。不过,微软仍然保留了 它自己的术语。注意一点,模块和实例是同一个概念。 . 任务,Wi n d o w s是一个多任务(或任务切换)环境,所以它必须能够为运行的多个实例合理分配系 统资源和时间。于是,Wi n d o w s建立一个任务数据库,这个数据库包括任务的实例句柄和其他必 要信息,以此实现任务切换功能。任务是Wi n d o w s用来管理和分配资源与时间段的重要元素。 9.2 静态链接与动态链接 静态链接是指D e l p h i编译器把要调用的函数和过程编译成可执行代码。函数的代码可存留在应用 程序的. d p r文件或一单元中。当链接用户的应用程序时,这些函数与过程便成为最终的可执行文件的 第9章动态链接库 一部分。也就是说,函数和过程都在程序的. e x e文件中。 程序运行时,函数和过程随程序一起调入内存,它们的位置与程序的位置是相关的。当主程序需 要调用函数或过程时,流程将跳转到函数或过程所在的位置,执行完函数或过程的代码,将返回主程 序调用位置。而函数或过程的相对位置,在链接时就已经确定了。 以上是对D e l p h i编译器进行静态链接这一复杂过程的简单描述。不过,本书并不是要你了解编译 器在背后的具体操作。 注意D e l p h i实现一个智能链接器,可以自动地把项目中没有引用的函数、过程和有类型的常 量去掉,那么,最后的可执行文件就不会有冗余的代码。 假设有两个应用程序,都要调用一个单元的同一个函数,当然,这两个应用程序都要在其u s e s子 句中包含该单元。如果这两个程序要同时运行,那么内存中就存在两份该函数,如果还有第三个这样 的应用程序,内存中就会有第三份该函数的实例,这样,就会三次占据内存。这个小例子就表明了动 态链接的优越性之一。函数通过动态链接,被放到一个D L L中。那么如果一个应用程序把该函数调入 内存,其他应用程序就可以通过映射D L L的映像到自己进程内存空间来共享代码。理论上讲,最终结 果是内存中只存在该D L L的一份实例。 对于动态链接,在程序运行时,通过引用一个外部函数(该函数包含在D L L中)而将该函数链接到 可执行文件中。其中的引用可以在应用程序中声明,但是通常情况下是放在一个专门的引入( i m p o r t )单 元里,在这个单元里可以声明引入的函数、过程以及D L L所需的多种类型的定义。 例如,假设有一个叫M a x L i b . d l l的动态链接库,其中包含一个函数: 这个函数返回两个整数中较大的一个数,一个典型的引入单元如下: 你也许注意到了,这看上去类似于一般的单元,但这个单元没有定义M a x ( )函数。关键字e x t e r n a l 后面的字符串就是该D L L的名称。要使用这个单元,应用程序只需把M a x U n i t加到它的u s e s子句中即可。 当这个程序运行时,该D L L就会自动地被调入内存,并且任何需要调用M a x ( )的程序都被链接到这个 D L L中的M a x ( )函数。 调用D L L有两种方式,这是其中一种,叫隐式调用,就是让Wi n d o w s在应用程序调入时自动地调 入所要调用的D L L;另一种是显式调用,这个将在本章节的后面讨论。
9.3 为什么要使用DLL 使用D L L有若干理由,其中有一些前面已经提到过了。大体说来,使用动态链接库可以共享代码、 系统资源,可以隐藏实现的代码或底层的系统例程、设计自定义控件。下面将分别讨论这几个方面的 内容。 9.3.1 共享代码、资源和数据 在本章节前面已经提到,共享代码是创建动态链接库的主要目的所在。但与单元的代码共享不同, D L L的代码可以被任何Wi n d o w s应用程序共享,而单元代码的共享局限于D e l p h i应用程序。 另外,D L L提供了共享资源的途径,诸如位图、字体、图标等等这些都可以放到一个资源文件中, 并直接链接到应用程序。如果把这些资源放到D L L中,那么就可以让许多应用程序使用,而不必在内存里重复装入这些资源。 在1 6位的Wi n d o w s中,D L L有自己的数据段,于是,所有要调用同一个D L L的应用程序能够访问 同一个全局变量和静态变量。但在Wi n 3 2系统中,这就不同了。因为D L L的映像被映射到每个进程的 地址空间,该D L L的所有数据属于映射到的进程。值得一说的是,尽管进程间不能共享D L L的数据, 但是同一个进程的所有线程可以共享,因为线程是相互独立的,所以在访问某一D L L的全局变量时, 务必小心,防止引起冲突。 但这并不意味着没有办法实现在进程间共享一个D L L的数据。一个技术可以通过内存映射文件的 方法在内存中创建一个共享的区域。一切需调用D L L的应用程序都可以读这些存储在内存中的共享区 域的数据。这个技术将在本章的后面详细介绍。 9.3.2 隐藏实现的细节 有些时候,你可能想隐藏例程实现的细节, D L L就可以实现这一点。不管为何要隐藏你的代码, D L L可以使函数被应用程序访问,而其中的代码细节不被显现,你所要做的只是提供别人能访问D L L的 接口。你也许认为D e l p h i的编译单元( D C U )也可以隐藏细节,但是D C U只适用于D e l p h i应用程序,而且还 受版本的局限。而D L L与语言无关,所以,创建的D L L可以被C + +、V B或其他任何支持D L L的语言调用。 Wi n d o w s单元是Win32 DLL的接口单元。Delphi 5提供了Win32 API的源文件,其一是Wi n d o w s单 元的源文件w i n d o w s . p a s,在该文件的i n t e r f a c e部分有如下定义: 为链接到相应的D L L,在其i m p l e m e n t a t i o n部分,有如下的例子: 这行代码的意思表明,C l i e n t To S r e e n ( )在动态链接库U s e r 3 2 . d l l中,它的名称叫C l i e n t To S r e e n . 9.3.3 自定义控件 自定义控件通常放在D L L中。这些控件不同于D e l p h i的自定义组件。自定义控件是在Wi n d o w s下 注册,并且可以在任何Wi n d o w s开发环境中使用。将这些类型的自定义控件加进D L L中,是考虑到即 使有多个应用程序要使用这些自定义控件,内存中也只有该控件的一份实例。 注意其实将自定义控件加进DLL这种机制已经过时,现在,微软使用OLE和ActiveX控件,自 定义控件已很少见了。
摘录一个D5指南的一段话,希望对你理解有用 动态链接库是程序模块,它包括代码、数据或资源,能够被其他的Wi n d o w s 应用程序共享。D L L的主要特点之一是应用程序可以在运行时调入代码执行,而不是在编译时链接代码,因此,多个应用程序可以共享同一个D L L 的代码。事实上,文件K e r n e l 3 2 . d l l 、U s e r 3 2 . d l l 、G D I 3 2 . d l l 就是核心Wi n 3 2 系 统的动态链接库。K e r n e l . d l l 负责内存、进程和线程的管理。U S E R 3 2 . D L L 包含了一些程序,是创建窗口和处理Wi n 3 2 消息的用户接口。G D I 3 2 . D L L 负责处理图形。你还会听说其他的系统D L L ,譬如A d v A P I 3 2 . d l l 和C o m D l g 3 2 . d l l ,它们分别处理对象安全性/注册操作和通用对话框。使用动态链接库的另一个特点是有利于应用程序的模块化。这样就简化了应用程序的修改,因为 一般只需要修改D L L ,而不是整个应用程序。Wi n d o w s 环境自身就是模块化类型的典型实例。每当安 装一个新设备,就安装一个设备驱动程序(即D L L ),使设备能够与Wi n d o w s 相互通信。 在磁盘上,一个D L L 基本上类似于一个Wi n d o w s 可执行文件( * . E X E )。一个主要的区别是, D L L 不是 一个独立的可执行文件,尽管它可能包含了可执行代码。大部分D L L 文件的扩展名是. d l l ,也有的可能 是. d r v (设备驱动程序)、. s y s (系统文件)、. f o n (字体文件),这些不包含可执行代码。
本章讨论了使用和创建D L L的几个方面,它给出了D L L怎样工作的概述并讨论了怎样创建和使用D L L,
你将学会怎样调入D L L和链接由它们引出的过程和函数的不同方法。本章还包括回调函数的使用并举
例说明在不同调用进程中如何实现共享数据。
9.1 究竟什么是DLL
动态链接库是程序模块,它包括代码、数据或资源,能够被其他的Wi n d o w s应用程序共享。D L L
的主要特点之一是应用程序可以在运行时调入代码执行,而不是在编译时链接代码,因此,多个应用
程序可以共享同一个D L L的代码。事实上,文件K e r n e l 3 2 . d l l、U s e r 3 2 . d l l、G D I 3 2 . d l l就是核心Wi n 3 2系
统的动态链接库。K e r n e l . d l l负责内存、进程和线程的管理。U S E R 3 2 . D L L包含了一些程序,是创建窗
口和处理Wi n 3 2消息的用户接口。G D I 3 2 . D L L负责处理图形。你还会听说其他的系统D L L,譬如
A d v A P I 3 2 . d l l和C o m D l g 3 2 . d l l,它们分别处理对象安全性/注册操作和通用对话框。
使用动态链接库的另一个特点是有利于应用程序的模块化。这样就简化了应用程序的修改,因为
一般只需要修改D L L,而不是整个应用程序。Wi n d o w s环境自身就是模块化类型的典型实例。每当安
装一个新设备,就安装一个设备驱动程序(即D L L ),使设备能够与Wi n d o w s相互通信。
在磁盘上,一个D L L基本上类似于一个Wi n d o w s可执行文件( * . E X E )。一个主要的区别是, D L L不是
一个独立的可执行文件,尽管它可能包含了可执行代码。大部分D L L文件的扩展名是. d l l,也有的可能
是. d r v (设备驱动程序)、. s y s (系统文件)、. f o n (字体文件),这些不包含可执行代码。
注意Delphi引入了一种叫做程序包的特殊用途的DLL,它应用于Delphi和C++编程环境。我们
将在第21章深入探究程序包。
D L L通过动态链接技术(dynamic linking)与其他应用程序共享代码,这将在本章后面部分讨论。总
之,当一个应用程序使用了一个D L L,Wi n 3 2系统会确保内存中只有一个该D L L的拷贝,这是通过内
存映射文件来实现的。D L L首先被调入Wi n 3 2的全局堆,然后映射到调用这个D L L进程的地址空间。
在Wi n 3 2系统中,每个进程都被分配有自己的3 2位线性地址空间。当一个D L L被多个进程调用时,每
个进程都会获得该D L L的一份映像。因此,在1 6位Wi n d o w s中,程序代码、数据、资源不被进程共享,
而在Wi n 3 2中,D L L是可以被看作是属于调用该D L L进程自己的代码。为得到关于Wi n 3 2概念的更多信
息,请参阅第3章“Win32 API”。
但这并不意味着,如果多进程调用一个D L L,物理内存就分配有该D L L的每个实例。通过从系统
的全局堆到调用该D L L的每一进程的地址空间的映射, D L L映像置于每个进程的地址空间。至少在理
想情况下应这样。
设置DLL的首选基地址
如果D L L被调入进程的地址空间时设置了基地址,这样D L L数据就可以被共享。如果D L L
的基地址与已经分配的D L L地址重叠的话,Wi n 3 2重新分配基地址。这样,每一个重新分配的
DLL实例都有自己的物理上的内存空间和交换文件空间。
这是很关键的,通过使用$ I M A G E B A S E指示符,给每个D L L都设置一个基地址,这样不
会引起冲突或不会出现地址重叠。
如果有多个应用程序都调用同一个D L L,设置一个唯一的基地址,这样无论是在进程的低
端地址或者是在一般的D L L (如V C L包)的高端地址,都不会引起冲突。一般可执行文件( E X E和
D L L )缺省的基地址为$ 4 0 0 0 0 0,这就意味着,除非修改D L L的基地址,否则就会与主程序的基
地址引起冲突,因此进程间也就不能共享DLL的数据。
在调用时,D L L不需要重新分配或安装,因为它保存在本地磁盘上,D L L的内存页面被直
接映射到磁盘上的D L L文件。D L L代码不需占用系统页面文件(也叫交换文件)的空间。这就是
为什么系统提交页的总数和大小可能比系统交换文件加内存要大。
你可以参阅Delphi 5的在线帮助中的“Image Base Address”,那里有使用$ I M A G E B A S E指
示符的详细介绍。
有关D L L的一些术语如下:
. 应用程序,一个扩展名为. e x e的Wi n d o w s程序。
. 可执行文件,一个包含可执行代码的文件,它包括. d l l文件和. e x e文件。
. 实例,当提到应用程序和D L L时,在内存中出现的可执行文件就是实例。Wi n 3 2系统通过实例句
柄的方式来引用实例。例如,如果一个应用程序运行两次,就会有应用程序的两个实例,同时
就有两个实例句柄。当一个D L L被调入时,实例及其相应的实例句柄同时产生。应该注意的是,
这里所提的实例与类的实例不能混淆。
. 模块,在3 2位Wi n d o w s系统中,模块和实例可以说是同义的。而在1 6位的Wi n d o w s系统中,是建
立一个模块数据库来管理模块的,一个模块对应一个模块句柄。在Wi n 3 2中,应用程序的每一个
实例都拥有自己的地址空间;所以,没有必要为模块单独指定标识符。不过,微软仍然保留了
它自己的术语。注意一点,模块和实例是同一个概念。
. 任务,Wi n d o w s是一个多任务(或任务切换)环境,所以它必须能够为运行的多个实例合理分配系
统资源和时间。于是,Wi n d o w s建立一个任务数据库,这个数据库包括任务的实例句柄和其他必
要信息,以此实现任务切换功能。任务是Wi n d o w s用来管理和分配资源与时间段的重要元素。
9.2 静态链接与动态链接
静态链接是指D e l p h i编译器把要调用的函数和过程编译成可执行代码。函数的代码可存留在应用
程序的. d p r文件或一单元中。当链接用户的应用程序时,这些函数与过程便成为最终的可执行文件的
第9章动态链接库
一部分。也就是说,函数和过程都在程序的. e x e文件中。
程序运行时,函数和过程随程序一起调入内存,它们的位置与程序的位置是相关的。当主程序需
要调用函数或过程时,流程将跳转到函数或过程所在的位置,执行完函数或过程的代码,将返回主程
序调用位置。而函数或过程的相对位置,在链接时就已经确定了。
以上是对D e l p h i编译器进行静态链接这一复杂过程的简单描述。不过,本书并不是要你了解编译
器在背后的具体操作。
注意D e l p h i实现一个智能链接器,可以自动地把项目中没有引用的函数、过程和有类型的常
量去掉,那么,最后的可执行文件就不会有冗余的代码。
假设有两个应用程序,都要调用一个单元的同一个函数,当然,这两个应用程序都要在其u s e s子
句中包含该单元。如果这两个程序要同时运行,那么内存中就存在两份该函数,如果还有第三个这样
的应用程序,内存中就会有第三份该函数的实例,这样,就会三次占据内存。这个小例子就表明了动
态链接的优越性之一。函数通过动态链接,被放到一个D L L中。那么如果一个应用程序把该函数调入
内存,其他应用程序就可以通过映射D L L的映像到自己进程内存空间来共享代码。理论上讲,最终结
果是内存中只存在该D L L的一份实例。
对于动态链接,在程序运行时,通过引用一个外部函数(该函数包含在D L L中)而将该函数链接到
可执行文件中。其中的引用可以在应用程序中声明,但是通常情况下是放在一个专门的引入( i m p o r t )单
元里,在这个单元里可以声明引入的函数、过程以及D L L所需的多种类型的定义。
例如,假设有一个叫M a x L i b . d l l的动态链接库,其中包含一个函数:
这个函数返回两个整数中较大的一个数,一个典型的引入单元如下:
你也许注意到了,这看上去类似于一般的单元,但这个单元没有定义M a x ( )函数。关键字e x t e r n a l
后面的字符串就是该D L L的名称。要使用这个单元,应用程序只需把M a x U n i t加到它的u s e s子句中即可。
当这个程序运行时,该D L L就会自动地被调入内存,并且任何需要调用M a x ( )的程序都被链接到这个
D L L中的M a x ( )函数。
调用D L L有两种方式,这是其中一种,叫隐式调用,就是让Wi n d o w s在应用程序调入时自动地调
入所要调用的D L L;另一种是显式调用,这个将在本章节的后面讨论。
使用D L L有若干理由,其中有一些前面已经提到过了。大体说来,使用动态链接库可以共享代码、
系统资源,可以隐藏实现的代码或底层的系统例程、设计自定义控件。下面将分别讨论这几个方面的
内容。
9.3.1 共享代码、资源和数据
在本章节前面已经提到,共享代码是创建动态链接库的主要目的所在。但与单元的代码共享不同,
D L L的代码可以被任何Wi n d o w s应用程序共享,而单元代码的共享局限于D e l p h i应用程序。
另外,D L L提供了共享资源的途径,诸如位图、字体、图标等等这些都可以放到一个资源文件中,
并直接链接到应用程序。如果把这些资源放到D L L中,那么就可以让许多应用程序使用,而不必在内存里重复装入这些资源。
在1 6位的Wi n d o w s中,D L L有自己的数据段,于是,所有要调用同一个D L L的应用程序能够访问
同一个全局变量和静态变量。但在Wi n 3 2系统中,这就不同了。因为D L L的映像被映射到每个进程的
地址空间,该D L L的所有数据属于映射到的进程。值得一说的是,尽管进程间不能共享D L L的数据,
但是同一个进程的所有线程可以共享,因为线程是相互独立的,所以在访问某一D L L的全局变量时,
务必小心,防止引起冲突。
但这并不意味着没有办法实现在进程间共享一个D L L的数据。一个技术可以通过内存映射文件的
方法在内存中创建一个共享的区域。一切需调用D L L的应用程序都可以读这些存储在内存中的共享区
域的数据。这个技术将在本章的后面详细介绍。
9.3.2 隐藏实现的细节
有些时候,你可能想隐藏例程实现的细节, D L L就可以实现这一点。不管为何要隐藏你的代码,
D L L可以使函数被应用程序访问,而其中的代码细节不被显现,你所要做的只是提供别人能访问D L L的
接口。你也许认为D e l p h i的编译单元( D C U )也可以隐藏细节,但是D C U只适用于D e l p h i应用程序,而且还
受版本的局限。而D L L与语言无关,所以,创建的D L L可以被C + +、V B或其他任何支持D L L的语言调用。
Wi n d o w s单元是Win32 DLL的接口单元。Delphi 5提供了Win32 API的源文件,其一是Wi n d o w s单
元的源文件w i n d o w s . p a s,在该文件的i n t e r f a c e部分有如下定义:
为链接到相应的D L L,在其i m p l e m e n t a t i o n部分,有如下的例子:
这行代码的意思表明,C l i e n t To S r e e n ( )在动态链接库U s e r 3 2 . d l l中,它的名称叫C l i e n t To S r e e n .
9.3.3 自定义控件
自定义控件通常放在D L L中。这些控件不同于D e l p h i的自定义组件。自定义控件是在Wi n d o w s下
注册,并且可以在任何Wi n d o w s开发环境中使用。将这些类型的自定义控件加进D L L中,是考虑到即
使有多个应用程序要使用这些自定义控件,内存中也只有该控件的一份实例。
注意其实将自定义控件加进DLL这种机制已经过时,现在,微软使用OLE和ActiveX控件,自
定义控件已很少见了。
动态链接库是程序模块,它包括代码、数据或资源,能够被其他的Wi n d o w s 应用程序共享。D L L的主要特点之一是应用程序可以在运行时调入代码执行,而不是在编译时链接代码,因此,多个应用程序可以共享同一个D L L 的代码。事实上,文件K e r n e l 3 2 . d l l 、U s e r 3 2 . d l l 、G D I 3 2 . d l l 就是核心Wi n 3 2 系
统的动态链接库。K e r n e l . d l l 负责内存、进程和线程的管理。U S E R 3 2 . D L L 包含了一些程序,是创建窗口和处理Wi n 3 2 消息的用户接口。G D I 3 2 . D L L 负责处理图形。你还会听说其他的系统D L L ,譬如A d v A P I 3 2 . d l l 和C o m D l g 3 2 . d l l ,它们分别处理对象安全性/注册操作和通用对话框。使用动态链接库的另一个特点是有利于应用程序的模块化。这样就简化了应用程序的修改,因为
一般只需要修改D L L ,而不是整个应用程序。Wi n d o w s 环境自身就是模块化类型的典型实例。每当安
装一个新设备,就安装一个设备驱动程序(即D L L ),使设备能够与Wi n d o w s 相互通信。
在磁盘上,一个D L L 基本上类似于一个Wi n d o w s 可执行文件( * . E X E )。一个主要的区别是, D L L 不是
一个独立的可执行文件,尽管它可能包含了可执行代码。大部分D L L 文件的扩展名是. d l l ,也有的可能
是. d r v (设备驱动程序)、. s y s (系统文件)、. f o n (字体文件),这些不包含可执行代码。