文章分类
文章搜索
相关文章
GOOGLE 广告
Delphi 中动态链接库(dll)的建立和使用
动态链接库是一个能够被应用程序和其它的 DLL 调用的过程和函数的集合体,它里面包含的是公共代码或资源。由于 DLL 代码使用了内存共享技术,在某些地方 windows 也给了 DLL 一些更高的权限,因而 DLL 中可以实现一些一般程序所不能实现的功能,如实现 windows 的 HOOK、ISAPI 等。同时,DLL 还为不同语言间代码共享提供了一条方便的途径。因而 DLL 在编程时应用较为广泛,本文将介绍如何在 Delphi 中建立和使用 DLL。
一.DLL 库内存共享机制
从使用效果看,DLL 和 unit 很像,它们都可以被别的工程模块所调用,但二者在内部的实现机制上确存在着差别。如果一个程序模块中用 uses 语句引用了某个 unit,编译程序在编译该模块时,便会连同 unit 一起编译,并把编译后的可执行代码链接到本程序模块中,这就是一个程序模块能够调用所引用 unit 中过程和函数的原因。当同一个 unit 被多个工程所引用时,则每个工程中都含有该 unit 的可执行代码,当含有该 unit 的多个工程同时执行时,unit 的可执行代码会随不同工程而多次被调入内存,造成内存资源的浪费。DLL 则不同,它即使被某个工程调用,编译后仍是独立的,也就是说编译后,一个 DLL 库形成一个单独的可执行文件,而不与任何其它的可执行文件连接在一起,因而 DLL 库并不从属于某个特定的工程,当多个工程调用同一个 DLL 库时只有第一个工程把 DLL 库调入内存,其余工程并不重复调入同一个 DLL 库到内存,而是到同一个共享内存区读取。并且,DLL 的执行代码是在程序运行期间动态调入的,而不是如 unit 在程序运行时就与整个工程一起调入内存。这样便可消除 unit 带来的相同代码多处占用内存的弊病。
二 Delphi 中 DLL 库的建立
在 Delphi 环境中,编写一个 DLL 同编写一个一般的应用程序并没有太大的区别。事实上作为 DLL 主体的 DLL 函数的编写,除了在内存、资源的管理上有所不同外,并不需要其它特别的手段。
一般工程文件的格式为:
program 工程标题;
uses 子句;
程序体
而 DLLs 工程文件的格式为:
library 工程标题;
uses 子句;
exprots 子句;
程序体
它们主要的区别有两点:
1.一般工程文件的头标用 program 关键字,而 DLL 工程文件头标用 library 关键字。不同的关键字通知编译器生成不同的可执行文件。用 program 关键字生成的是.exe 文件,而用 library 关键字生成的是.dll 文件;
2.假如 DLL 要输出供其它应用程序使用的函数或过程,则必须将这些函数或过程列在 exports 子句中。而这些函数或过程本身必须用 export 编译指令进行编译。
在 Delphi 主菜单 file 中选 new...项,在弹出的窗口中双击 DLL 图标,便会自动给出 DLL 源模块框架,如下:
以下是引用片段:
Library project1;
{...注释...}
uses
SysUtils, Classes;
begin
end
接下来便可在 USES 和 begin 之间加入想在该 DLL 中实现的过程和函数的定义,并用 export 和 exprots 保字把它们引出,以便别的模块引用,在 begin 和 end 之间加入初始化代码,初始化代码是用来对 DLL 变量初始化的。应注意,即便无初始化代码 begin 与 end 也不可省略,如下例:
以下是引用片段:
library minmax;
function Min(X, Y: Integer): Integer; export;
begin
if X < Y then Min := X else Min := Y;
end;
function Max(X, Y: Integer): Integer; export;
begin
if X > Y then Max := X else Max := Y;
end;
exports
Min index 1,
Max index 2;
egin
end.
经编译后,并以 minmax.DLL 存盘后,一个 DLL 库文件便形成了。
delphi 中动态链接库(dll)的建立和使用 来自: 免费论文网
三 DLL 库的访问
访问 DLL 库有两种方式,一种是静态引用,另一种是动态引用。
用静态引用这种方法装入 DLL 要做两件事情:为 DLL 库创建一个输入单元,以及
用 USES 把输入单元连接到要使用 DLL 函数的程序模块中。为 DLL 库创建的输入单元与普通的单元的区别仅在于:在它的接口处声明的过程、函数,并不在它的实现部分给出真正的实现代码,而是用 external 关键字把过程、函数的实现细节委托给外部 DLL 模块。
external 命令的使用语法如下:
procedure /function 过程/函数名;external DLL 模块名;
下面给出为上面创建的 minmax.DLL 库写的输入单元源文件 testdll .pas,从中可看出输入单元 与一般 单元的一些差别,代码如下所示:
以下是引用片段:
unit testdll;
interface
uses
function Min (X, Y: Integer): Integer;
function Max (X, Y: Integer): Integer;
implementation
function Min; external ‘minmax.DLL’;
function Max; external ‘minmax.DLL’;
end.
一个应用程序若想调用 minmax.DLL 中的函数,只须在其 uses 语句中加入 testdll 单元即可。
动态装入 DLL,要用到 Windows 的三个 API 函数。Loadlibrary、Freelibrary 和 GetprocAddress 。loadlibrary函数用来装入 DLL 库,其调用格式如下:
function loadlobrary (DLLfileName:Pchar): THandle:
当不再需要一个 DLL 库时,应调用 FreeLibrary 函数将其释放,以空出宝贵的内存资源,其调用格式如下:
procedure FreeLibrary (Libmodule:THandle)
Libmodule 为由 LoadLibrary 调用得到的 DLL 库句柄。在用 loadlobrary 函数装入某个 DLL 库和调用 FreeLibrary 释放该 DLL 库之间的程序段中, 可以使用该 DLL 库中的过程和函数,具体使用方法是:用 GetprocAddress 函数把 DLL 库中函数的地址传递给程序中某个函数变量,再用该变量实现 DLL 函数的调用。GetprocAddress 函数声名如下,
以下是引用片段:
function GetprocAddress (Libmodule:THandle:procname:pchar):TFarProc:
如下例所示:
type
TTimeRec = record
Second: Integer;
Minute: Integer;
Hour: Integer;
end;
TGetTime = procedure(var Time: TTimeRec);
THandle = Integer;
var
Time: TTimeRec;
Handle: THandle;
GetTime: TGetTime;
..
begin
Handle := LoadLibrary('DATETIME.DLL');
if Handle <> 0 then
begin
@GetTime := GetProcAddress(Handle, 'GetTime');
if @GetTime <> nil then
begin
GetTime(Time);
with Time do
WriteLn('The time is ', Hour, ':', Minute, ':', Second);
end;
FreeLibrary(Handle);
end;
end;
在调用动态链接库时应注意, 所需动态链接库须与应用程序在同一目录或 Windows System 目录下。
动态链接库是 Windows 下程序组织的一种重要方式,使用动态链接库可以极大地保护用户在不同开发工具、不同时期所做的工作,提高编程效率。
- 上篇文章:基于Delphi的屏幕抓图技术的实现
- 下篇文章:捕获vcl控件的离开消息
- 文章出处:论坛整理







