第 10章 动态链接库( DLL)
应用编程本章要点:
动态链接库 ( DLL) 的概念
动态链接库的编写
动态链接库的隐式调用和显示调用
利用动态链接库实现窗体重用的方法
10.1 循序渐进学理论
10.1.1 动态链接库( DLL)概述
1,DLL的概念
DLL是一个可以执行的并可以被多个 Windows应用程序共享的程序模块(称为 Module),模块中包含了一些可以被多个 Windows应用程序或 DLL共享的代码、
数据和资源。
动态连接库文件的扩展名一般是 dll,也有可能是
drv,sys和 fon(它们分别对应的是设备驱动文件、
系统文件和字体资源文件)。
2.静态链接和动态链接
( 1)静态链接传统的库函数是通过静态链接链到应用程序中的。
这些库函数可能来自编程语言提供的标准库,也可能是由操作系统提供的 API。
( 2)动态链接动态链接是指在把应用程序的目标代码链接成
EXE文件时并没有将函数库中的函数复制到应用程序的可执行文件中,而是在程序运行时动态地加载所需的函数。
3.使用 DLL的优点使用动态链接库还有以下优点:
( 1)应用范围广。
( 2)便于开发大型软件。
( 3)便于对系统进行升级。
( 4)隐藏细节。
( 5)独立于编程语言。
10.1.2 动态链接库( DLL)编写根据动态链接库完成的功能,可把 DLL
分成三类:完成一般功能的 DLL、用于数据交换的 DLL和用于窗体重用的 DLL。
【 例 10-1】 创建一个动态链接库,该动态链接库中包含两个函数,分别用于求三个数的最大值和最小值。为编写该动态链接库,需经过以下步骤:
( 1)建立 DLL程序框架在 Delphi 7.0集成环境中,执行 【 File】 →
【 New】 → 【 Other】 命令,将会出现 【 New Items】
对话框窗口,在该窗口中找到 【 DLL Wizard】 图标,
如图 10-3所示。
图 10-3,New Items”对话框
2.建立过程和函数为该动态链接库项目增加如下两个函数:
Function Max(x,y,z:Integer):Integer;stdcall;//求三个数的最大值函数
·······
Function Min(x,y,z:Integer):Integer;stdcall;//求三个数的最小值函数
·······
( 3)用 exports语句声明供其它应用程序调用的函数和过程名函数或过程定义好后,为了能够被其它应用程序调用,
还必须用 Exports子句把函数名列出 。 本例使用的
Exports语句如下:
exports
Max,Min;
Exports语句的格式与功能如下:
exports
entry1,entry2,……,entryn;
( 4) 生成 DLL文件执行 【 Project】 → 【 Build Exam_10_1】 命令
(,Exam_10_1”为动态链接库项目文件名 ),将自动生成名为,Exam_10_1.dll”的动态链接库文件 。
10.1.3 加载动态链接库( DLL)的方法
1.静态载入 DLL
这种方法是将 DLL文件映像映射到调用进程地址空间的最简单的办法。
静态载入 DLL的前提是在编译之前已经明确知道要调用 DLL中的哪几个函数,编译时在目标文件中只保留必要的链接信息,而不包含 DLL函数的代码。在程序执行时,利用链接信息加载 DLL函数代码并在内存中将其链接进入调用程序的执行空间,从而实现了代码的重用。
2.动态载入 DLL
动态载入方式是指在编译之前并不知道将会调用哪些 DLL函数,完全是在运行过程中根据需要决定应调用哪些函数,并用 LoadLibrary函数加载动态链接库到内存,用 GetProcAddress函数动态获得 DLL函数的入口地址。
动态调用使用的 Windows API函数主要有 3个,分别是 LoadLibrary,GetProcAddress和 FreeLibrary。
( 1) LoadLibrary函数
[格式 ]:
functionLoadLibrary(LibFileName:PChar):Thandle;
[功能 ]:加载由参数 LibFileName指定的 DLL文件。
( 2) GetProcAddress函数
[格式 ]:
functionGetProcAddress(Module:Thandle;ProcName
:PChar):TfarProc;
[功能 ]:返回参数 Module指定的模块中,由参数
ProcName指定的过程或函数的入口地址。
( 3) FreeLibrary函数
[格式 ],procedure FreeLibrary(Module:Thandle);
[功能 ]:将由参数 Module指定的 DLL文件从内存中卸载 1
次。
10.1.4 调用动态链接库( DLL)
中的过程和函数在应用程序中,调用动态链接库也有两种方法。
分别是隐式调用和显示调用。
1.隐式调用隐式调用又称静态调用或装载时调用,对应于 DLL
的静态载入。要在应用程序中隐式调用某个动态链接库中的函数,一般要做以下两件事情:
( 1) 用 extern子句声明要调用的过程或函数及其所在的 DLL文件名;
( 2) 在应用程序中直接调用用 extern子句声明的过程 。
【 例 10-2】 编写一个应用程序用来调用例
10-1所建立的动态链接库中的 Max和 Min函数,
要求使用隐式调用。程序的设计界面如图 10-4
所示,函数的运行界面如图 10-5所示。程序运行时输入三个数到三个编辑框中,然后按
【 求最大值 】 按钮,将会求出三个数的最大值并显示在第四个文本框中,如果按 【 求最小值 】 按钮,将会求出三个数的最小值并显示在第四个文本框中。
图 10-4 例 10-2程序设计界面 图 10-5 例 10-2程序运行界面
2.显式调用静态调用 DLL中的函数,程序实现比较简单,代码较少,但也有一些不足,主要表现在:
( 1) 如果加载的 DLL文件不存在或者 DLL中没有要引入的例程,程序将自动终止运行;
( 2) DLL文件一旦加载就一直驻留在应用程序的地址空间,即使后面已不再使用它了 。
显式调用动态链接库中的函数一般需经历以下步骤:
( 1) 定义一个与调用函数一致的函数类型;
( 2) 用 LoadLibrary或 SafeLoadLibrary函数动态载入动态链接库;
( 3) 用 GetProcAddress得到要调用的函数或过程的地址;
( 4) 利用定义的函数类型生成一个同类型的函数变量 ( 本题为
Myfunct) ;
( 5) 进行函数调用 ( 本题调用语句为,Myfunct(x,y,z);) ;
( 6) 利用 FreeLibrary函数卸载动态链接库 。
【 例 10-3】 编写一个应用程序用来调用例 10-1所建立的动态链接库中的 Max
和 Min函数,要求使用显示调用 。 程序的设计界面和运行界面及程序功能同例
10-2。
10.1.5 在动态链接库( DLL)
中实现窗体重用利用 DLL实现窗体重用一般需经历以下几步:
( 1) 在 Delphi的集成开发环境中,设计出需要重用的窗体;
( 2) 编写一个用于输出的函数或过程,在该函数或过程中,对设计的窗体进行创建使它实例化;
( 3) 如果要把多个窗体编译在一个 DLL文件中,可重复
( 1) 和 ( 2),直到所有需要的窗体建立完毕,所有对窗体进行实例化的函数或过程创建完毕;
( 4) 为适应生成,DLL文件的需要,对工程文件进行相应修改;
( 5) 编译工程文件以生成 DLL文件;
( 6) 在需要该窗体的其它应用程序中重用该窗体 。
【 例 10-4】 在许多应用程序中都有在两个列表框中移动选项的窗体,请设计一个这样的可重用窗体,
设计界面如图 10-6所示。该窗体运行时,在左边的列表框中选中若干个选项后按 【 >】 按钮,将把选中的选项移动到右边的列表框中;在右边的列表框中选中若干个选项后按 【 <】 按钮,将把选中的选项移动到左边的列表框中;按 【 >>】 按钮将把左边的列表框中的所有选项移动到右边的列表框中;按 【 <<】 按钮将把右边的列表框中的所有选项移动到左边的列表框中。
然后再编写一个应用程序用来调用该窗体。
图 10-6 设计界面为完成本题的功能,应经历以下步骤。
( 1)设计窗体。
新建一个应用程序,按图 10-6所示给 Form1添加组件对象。
( 2)编写输出函数或过程,实例化窗体。
( 3)修改工程文件,使之能生成 DLL文件窗体单元编制完成之后,可把应用程序项目转换为 DLL。首先执行 【 Proiect】 → 【 View】 Source】 命令来打开,dpr项目文件,并在代码编辑器中做如下修改:
①把 program改为 Library;
② 从 Uses指令中删除 Forms;
③ 在 {$R}资源指令和工程的 uses指令的最后一行之间,
插入关键字 export,后跟单元的访问过程或函数名称
( 在本例中,就是 ListMoveF),如果有多个窗体要重用,可列出多个函数或过程名;
④删除 begin和 end之间的所有语句,让初始化代码块留空。
( 4)生成 DLL文件执行 【 Project】 → 【 Build EXAMDLL】 命令,生成
EXAMDLL.DLL动态链接库文件。
( 5)编写一个应用程序调用该窗体图 10-7 调用程序设计界面 图 10-8 弹出的可重用窗体图 10-9 程序的运行结果界面
10.2 典型实例练能力
10.2.1 典型实例一:显式调用动态链接库中的多种形式的函数
【 实例题目 】
编写一个动态链接库文件,取名为 FUNDLL4,该库中有三个函数 AlphNum,DigNum和 HuiWen,它们的功能分别是求出字符中字母字符的个数、数字字符的个数和字符串是否为回文。然后编写一个项目文件,
在该项目文件中对这三个函数进行调用。要求:在项目文件中采用显式调用的方法调用动态链接库中的函数。程序的设计界面与运行界面分别如图 10-10和图
10-11所示。程序执行时在 Edit1编辑框中输入字符串,
接着在 ComboBox1复选框中选择操作种类,然后单击
【 执行操作 】 按钮将调用相应的函数,得到执行结果。
图 10-10 程序设计界面图 10-11 程序运行界面
10.3 上机练习重应用
10.3.1 上机练习一:一维数组求值相关算法动态链接库的编制
【 练习 题目 】
编写一个动态链接库 MyDLL.DLL,为该动态链接库创建四个函数 Max,Min,Sum和 Aver,分别用来求具有 N(参数)个元素的一维数组的最大值、最小值、总和及平均值。然后再创建一个应用程序,通过对这些函数进行显式调用(又称动态调用)
来求产生的由 10个两位随机数组成的一维数组的最大值、最小值、总和及平均值。程序的设计界面如图 10-12所示,程序的运行界面如图 10-13所示。程序运行时单击 【 产生数组 】 将产生 10
个两位随机数并存放一个一维数组中,同时把数组元素的值显示在第一个编辑框中。然后在组合框中选中相应的运算类型,
再单击 【 计算 】 按钮将根据运算类型得到相应的结果并显示在第二个编辑框中。
图 10-12 调用程序设计界面图 10-13 调用程序运行界面