动态链接库——精选推荐

  • 格式:pdf
  • 大小:262.98 KB
  • 文档页数:25

动态链接库

动态链接库

--------------------------------------------------------------------------------

动态链接库(也称为DLL)是Microsoft Windows最重要的组成要素之⼀。⼤多数与Windows相关的磁盘⽂件如果不是程序模块,就是动态

链接程序。迄今为⽌,我们都是在开发Windows应⽤程序;现在是尝试编写动态链接库的时候了。许多您已经学会的编写应⽤程序的规则同

样适⽤于编写这些动态链接库模块,但也有⼀些重要的不同。

动态链接库的基本知识

正如前⾯所看到的,Windows应⽤程序是⼀个可执⾏⽂件,它通常建⽴⼀个或⼏个窗⼝,并使⽤消息循环接收使⽤者输⼊。通常,动态链接

库并不能直接执⾏,也不接收消息。它们是⼀些独⽴的⽂件,其中包含能被程序或其它DLL呼叫来完成⼀定作业的函数。只有在其它模块呼

叫动态链接库中的函数时,它才发挥作⽤。

所谓「动态链接」,是指Windows把⼀个模块中的函数呼叫连结到动态链接库模块中的实际函数上的程序。在程序开发中,您将各种⽬标模

块(.OBJ)、执⾏时期链接库(.LIB)⽂件,以及经常是已编译的资源(.RES)⽂件连结在⼀起,以便建⽴Windows的.EXE⽂件,这时的连结是

「静态连结」。动态链接与此不同,它发⽣在执⾏时期。

KERNEL32.DLL、USER32.DLL和GDI32.DLL、各种驱动程序⽂件如KEYBOARD.DRV、SYSTEM.DRV和MOUSE.DRV和视讯及打印机

驱动程序都是动态链接库。这些动态链接库能被所有Windows应⽤程序使⽤。

有些动态链接库(如字体⽂件等)被称为「纯资源」。它们只包含数据(通常是资源的形式)⽽不包含程序代码。由此可见,动态链接库的

⽬的之⼀就是提供能被许多不同的应⽤程序所使⽤的函数和资源。在⼀般的操作系统中,只有操作系统本⾝才包含其它应⽤程序能够呼叫来

完成某⼀作业的例程。在Windows中,⼀个模块呼叫另⼀个模块函数的程序被推⼴了。结果使得编写⼀个动态链接库,也就是在扩充Windows。当然,也可认为动态链接库(包括构成Windows的那些动态链接库例程)是对使⽤者程序的扩充。

尽管⼀个动态链接库模块可能有其它扩展名(如.EXE或.FON),但标准扩展名是.DLL。只有带.DLL扩展名的动态链接库才能被Windows⾃

动加载。如果⽂件有其它扩展名,则程序必须另外使⽤LoadLibrary或者LoadLibraryEx函数加载该模块。

您通常会发现,动态链接库在⼤型应⽤程序中最有意义。例如,假设要为Windows编写⼀个由⼏个不同的程序组成的⼤型财务软件包,就会

发现这些应⽤程序会使⽤许多共同的例程。可以把这些公共例程放⼊⼀个⼀般性的⽬的码链接库(带.LIB扩展名)中,并在使⽤LINK静态连

结时把它们加⼊各程序模块中。但这种⽅法是很浪费的,因为软件包中的每个程序都包含与公共例程相同的程序代码。⽽且,如果修改了链

接库中的某个例程,就要重新连结使⽤此例程的所有程序。然⽽,如果把这些公共例程放到称为ACCOUNT.DLL的动态链接库中,就可解决

这两个问题。只有动态链接库模块才包含所有程序都要⽤到的例程。这样能为储存⽂件节省磁盘空间,并且在同时执⾏多个应⽤程序时节省

内存,⽽且,可以修改动态链接库模块⽽不⽤重新连结各个程序。

动态链接库实际上是可以独⽴存在的。例如,假设您编写了⼀系列3D绘图例程,并把它们放⼊名为GDI3.DLL的DLL中。如果其它软件开发

者对此链接库很感兴趣,您就可以授权他们将其加⼊他们的图形程序中。使⽤多个这样的图形程序的使⽤者只需要⼀个GDI3.DLL⽂件。

链接库:⼀词多义

动态链接库有着令⼈困惑的印象,部分原因是由于「链接库」这个词被放在⼏种不同的⽤语之后。除了动态链接库之外,我们也⽤它来称呼

「⽬的码链接库」或「引⽤链接库」。

⽬的码链接库是带.LIB扩展名的⽂件。在使⽤连结程序进⾏静态连结时,它的程序代码就会加到程序的.EXE⽂件中。例如,在MicrosoftVisual C++中,连同程序连结的⼀般C执⾏⽬的码链接库被称为LIBC.LIB。

引⽤链接库是⽬的码链接库⽂件的⼀种特殊形式。像⽬的码链接库⼀样,引⽤链接库有.LIB扩展名,并且被连结器⽤来确定程序代码中的函

数呼叫来源。但引⽤链接库不含程序代码,⽽是为连结程序提供信息,以便在.EXE⽂件中建⽴动态链接时要⽤到的复位位表。包含在Microsoft编译器中的KERNEL32.LIB、USER32.LIB和GDI32.LIB⽂件是Windows函数的引⽤链接库。如果⼀个程序呼叫Rectangle函

数,Rectangle将告诉LINK,该函数在GDI32.DLL动态链接库中。该信息被记录在.EXE⽂件中,使得程序执⾏时,Windows能够和GDI32.DLL动态链接库进⾏动态连结。

⽬的码链接库和引⽤链接库只⽤在程序开发期间使⽤,⽽动态链接库在执⾏期间使⽤。当⼀个使⽤动态链接库的程序执⾏时,该动态链接库

必须在磁盘上。当Windows要执⾏⼀个使⽤了动态链接库的程序⽽需要加载该链接库时,动态链接库⽂件必须储存在含有该.EXE程序的⽬

录下、⽬前的⽬录下、Windows系统⽬录下、Windows⽬录下,或者是在通过MS-DOS环境中的PATH可以存取到的⽬录下(Windows会按

顺序搜索这些⽬录)。

⼀个简单的DLL

虽然动态链接库的整体概念是它们可以被多个应⽤程序所使⽤,但您通常最初设计的动态链接库只与⼀个应⽤程序相联系,可能是⼀个「测

试」程序在使⽤DLL。

下⾯就是我们要做的。我们建⽴⼀个名为EDRLIB.DLL的DLL。⽂件名中的「EDR」代表「简便的绘图例程(easy drawing routines)」。

这⾥的EDRLIB只含有⼀个函数(名称为EdrCenterText),但是您还可以将应⽤程序中其它简单的绘图函数添加进去。应⽤程序EDRTEST.EXE将通过呼叫EDRLIB.DLL中的函数来利⽤它。

要做到这⼀点,需要与我们以前所做的略有不同的⽅法,也包括Visual C++ 中我们没有看过的特性。在Visual C++ 中「⼯作空间

(workspaces)」和「项⽬(projects)」不同。项⽬通常与建⽴的应⽤程序(.EXE)或者动态链接库(.DLL)相联系。⼀个⼯作空间可以

包含⼀个或多个项⽬。迄今为⽌,我们所有的⼯作空间都只包含⼀个项⽬。我们现在就建⽴⼀个包含两个项⽬的⼯作空间EDRTEST-⼀个

⽤于建⽴EDRTEST.EXE,⽽另⼀个⽤于建⽴EDRLIB.DLL,即EDRTEST使⽤的动态链接库。

现在就开始。在Visual C++中,从「File」菜单选择「New」,然后选择「Workspaces」页⾯标签。(我们以前从来没有选择过。)在

「Location」栏选择⼯作空间要储存的⽬录,然后在「Workspace Name」栏输⼊「EDRTEST」,按Enter键。

这样就建⽴了⼀个空的⼯作空间。Developer Studio还建⽴了⼀个名为EDRTEST的⼦⽬录,以及⼯作空间⽂件EDRTEST.DSW(就像两个

其它⽂件)。

现在让我们在此⼯作空间⾥建⽴⼀个项⽬。从「File」菜单选择「New」,然后选择「Projects」页⾯标签。尽管过去您选择「Win32Application」,但现在「Win32 Dynamic-Link Library」。另外,单击单选按钮「Add To Current Workspace」,这使得此项⽬是

「EDRTEST」⼯作空间的⼀部分。在「Project Name栏输⼊EDRLIB,但先不要按「OK」按钮。当您在Project Name栏输⼊EDRLIB

时,Visual C++将改变「Location」栏,以显⽰EDRLIB作为EDRTEST的⼀个⼦⽬录。这不是我们要的,所以接着在「Location」栏删除EDRLIB⼦⽬录以便项⽬建⽴在EDRTEST⽬录。现在按「OK」。屏幕将显⽰⼀个对话框,询问您建⽴什么型态的DLL。选择「An Empty

DLL Project」,然后按「Finish」。Visual C++将建⽴⼀个项⽬⽂件EDRLIB.DSP和⼀个构造⽂件EDRLIB.MAK(如果「Tools Options」

对话框的B「uild页⾯卷标中选择了「Export Makefile」选项」。

现在您已经在此项⽬中添加了⼀对⽂件。从「File」菜单选择「New」,然后选择「Files」页⾯标签。选择「C/C++ Header File」,然后

输⼊⽂件名EDRLIB.H。输⼊程序21-1所⽰的⽂件(或者从本书光盘中复制)。再次从「File」菜单中选择「New」,然后选择「Files」页

⾯标签。这次选择「C++ Source File」,然后输⼊⽂件名EDRLIB.C。继续输⼊程序21-1所⽰的程序。

程序21-1 EDRLIB动态链接库

EDRLIB.H

/*--------------------------------------------------------------------------

EDRLIB.H header file

----------------------------------------------------------------------------*/

#ifdef __cplusplus

#define EXPORT extern "C" __declspec (dllexport)

#else

#define EXPORT __declspec (dllexport)

#endif

EXPORT BOOL CALLBACK EdrCenterTextA (HDC, PRECT, PCSTR) ;

EXPORT BOOL CALLBACK EdrCenterTextW (HDC, PRECT, PCWSTR) ;

#ifdef UNICODE

#define EdrCenterText EdrCenterTextW

#else

#define EdrCenterText EdrCenterTextA

#endif

EDRLIB.C

/*---------------------------------------------------------------------------

EDRLIB.C -- Easy Drawing Routine Library module

(c) Charles Petzold, 1998

-----------------------------------------------------------------------------*/