Delphi 动态与静态调用DLL
摘要:本文阐述了 Windows 环境下动态链接库的概念和特点,对静态调用和动态调用两种调用方式作出了比较,并给出 Delphi 中应用动态链接库的实例
一、动态链接库的概
动态链接库 Dynamic Link Library ,缩写为 DLL )是一个可以被其它应用程序共享的程序模块,其中封装了一些可以被共享的例程和资源。动态链接库文件的扩展名一般是 dll 也有可能 drv sys fon ,它和可执行文件 exe )非常类似,区别在于 DLL 中虽然包含了可执行代码却不能单独执行,而应 Windows 应用 程序直接或间接调用
动态链接是相对于静态链接而言的。所谓静态链接是指把要调用的函数或者过程链接到可执行文件中,成为可执行文件 的一部分。换句话说,函数和过程的代码就在程序 exe 文件中,该文件包含了运行时所需的全部代码。当多个程序都调用相同函数时,内存中就会存在这个函数 的多个拷贝,这样就浪费了宝贵的内存资源。而动态链接所调用的函数代码并没有被拷贝到应用程序的可执行文件中去,而是仅仅在其中加入了所调用函数的描述信息(往往是一些重定位信息)。仅当应用程序被装入内存开始运行时,在 Windows 的管理下,才在应用程序与相应 DLL 之间建立链接关系。当要执行所 DLL 中的函数时,根据链接产生的重定位信息 Windows 才转去执 DLL 中相应的函数代码
一般情况下,如果一个应用程序使 用了动态链接库 Win32 系统保证内存中只 DLL 的一份复制品,这是通过内存映射文件实现的 DLL 首先被调 Win32 系统的全局堆栈,然后映射到 调用这个 DLL 的进程地址空间。在 Win32 系统中,每个进程拥有自己 32 位线性地址空间,如果一 DLL 被多个进程调用,每个进程都会收到 DLL 一份映像。与 16 Windows 不同,在 Win32 DLL 可以看作是每个进程自己的代码
二、动态链接库的优
1 共享代码、资源和数据
使用 DLL 的主要目的就是为了共享代码, DLL 的代码可以被所有的 Windows 应用程序共享
2 隐藏实现的细
DLL 中的例程可以被应用程序访问,而应用程序并不知道这些例程的细节
3 拓展开发工具如 Delphi 的功
由于 DLL 是与语言无关的,因此可以创建一 DLL ,被 C++ VB 或任何支持动态链接库的语言调用。这样如果一种语言存在不足,就可以通过访问另一种语言创建 DLL 来弥补
三、动态链接库的实现方
1 Load-time Dynamic Linking
这种用法的前提是在编译之前已经明确知道要调用 DLL 中的哪几个函数,编译时在目标文件中只保留必要的链接信息,而不 DLL 函数的代码;当程序执行时,利用链接信息加 DLL 函数代码并在内存中将其链接入调用程序的执行空间中,其主要目的是便于代码共享
2 Run-time Dynamic Linking
这种方式是指在编译之前并不知道将会调用哪 DLL 函数,完全是在运行过程中根据需要决定应调用哪个函数,并 LoadLibrary GetProcAddress 动态获 DLL 函数的入口地址
四DLL 的两种调用方式在Delphi 中的比较
编写DLL 的目的是为了输出例程供其他程序调用,因此DLL 的工程文件中要把输出的例程用Exports 关键字引出。在调用DLL 的应用程序中,需 声明用到DLL 中的方法,声明格式要DLL 中的声明一样。访DLL 中的例程有静态调用和动态调用两种方式。静态调用方式就是在单元 Interface 部分External 指示字列出要DLL 中引入的例程;动态调用方式就是通过调用Windows API 包括 LoadLibrary 函数GetProcAddress 函数以及FreeLibrary 函数动态的引入DLL 中的例程
静态调 方式所需的代码较动态调用方式所需的少,但存在着一些不足,一是如果要加载DLL 不存在或DLL 中没有要引入的例程,这时候程序就自动终止运行;二 DLL 一旦加载就一直驻留在应用程序的地址空间,即DLL 已不再需要了。动态调用方式就可解决以上问题,它在需要用DLL 的时候才通过 LoadLibrary 函数引入,用完后通过FreeLibrary 函数从内存中卸载,而且通过GetProcAddress 函数可以指定不同的例程 最重要的是,如果指定的DLL 出错,至多是API调用失败,不会导致程序终止。以下将通过具体的实例说明说明这调用方式的使用方法
1 静态调用方
示例程序创建了一DLL ,其中仅包含一个求两个整数的和的函数,在主程序中输入两个整数,通过调用DLL ,即可求出两个整数的和,如图1 所示
DLL 的程序代码如下:
|
library AddNum; |
主程序在调用DLL 时,首先interface 部分声明要调用的函数
|
function AddNum(Num1,Num2:integer):integer;stdcall;external 'AddNum.dll' |
然后在按钮控件的事件中写入如下代码:
|
procedure TForm1.Button1Click(Sender: TObject); |
2 .动态调用方
这个示例程序创建了一个显示日期的DLL ,其中包含一个窗体,如图2 所示
程序中定义了一ShowCalendar 函数,返回在这个窗体中设定的日期。函数定义如下:
|
function ShowCalendar(AHandle: THandle; ACaption: String): TDateTime; |
DLL 的工程文件中exports ShowCalendar; 语句引出该函数。下面通过一个简单的应用程序测试一下该DLL 文件。新建一个工程文件,在窗体中放置一Label 控件和一个按钮控件,在按钮控件的OnClick 事件中编写如下代码:
|
procedure TMainForm.Button1Click(Sender: TObject); |
从以上程序中可以看到DLL 的动态调用方式比静态调用方式的优越之处DLL 例程在用到时才被调入,用完后就被卸载,大大减少了系统资源的占用。在调用 LoadLibrary 函数时可以明确指DLL 的完整路径,如果没有指定路径,运行时首先查找应用程序载入的目录,然后Windows 系统 System 目录和环境变Path 设定的路径
五、结束语
由于动态链接库可以实现代码和资源的共享,大大减少系统资源的占用,因此在当今的应用程序开发中起着非常重要的作用Delphi 是现今流行的应用软件开发工具,本文就如何在Delphi 中使用动态链接库给出了一定程度上的阐述
📱 扫码关注公众号
扫描二维码关注我们,获取更多精彩内容
实时更新 · 干货满满