摘要:本文阐述了 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;
uses
SysUtils,
Classes;

{$R *.res}

function AddNumber(Num1,Num2:integer):integer;stdcall; // 定义求和函数
 begin
  result:=Num1+Num2;
 end;
  exports
  AddNumber; // 引出求和函数
 begin
end.

  主程序在调用该DLL 时,首先在interface 部分声明要调用的函数:

function AddNum(Num1,Num2:integer):integer;stdcall;external 'AddNum.dll'
name 'AddNumber';

  然后在按钮控件的事件中写入如下代码:

procedure TForm1.Button1Click(Sender: TObject);
var
 Number1,Number2:integer; 
 Sum:integer;
begin
 Number1:=strtoint(Edit1.Text);
 Number2:=strtoint(Edit2.Text);
 Sum:=AddNum(Number1,Number2); // 调用求和函数计算结果
 Edit3.Text:=inttostr(Sum);
end;

 2 .动态调用方式

  这个示例程序创建了一个显示日期的DLL ,其中包含一个窗体,如图2 所示。

 

  程序中定义了一个ShowCalendar 函数,返回在这个窗体中设定的日期。函数定义如下:

function ShowCalendar(AHandle: THandle; ACaption: String): TDateTime;
var
 DLLForm: TDLLForm;
begin
 Application.Handle := AHandle;
 DLLForm := TDLLForm.Create(Application); // 创建并显示窗体
 try
  DLLForm.Caption := ACaption;
  DLLForm.ShowModal; // 显示方式为模式化
  Result := DLLForm.calDLLCalendar.CalendarDate; // 返回设定日期
 finally
  DLLForm.Free; // 用完后卸载该窗体
 end;
end;

  在DLL 的工程文件中用exports ShowCalendar; 语句引出该函数。下面通过一个简单的应用程序测试一下该DLL 文件。新建一个工程文件,在窗体中放置一个Label 控件和一个按钮控件,在按钮控件的OnClick 事件中编写如下代码:

procedure TMainForm.Button1Click(Sender: TObject);
var
 OneHandle : THandle; // 定义一个句柄变量
begin
 OneHandle := LoadLibrary('Clendar.dll'); // 动态载入DLL ,并返回其句柄
 try
  if OneHandle <> 0 then // 如果载入成功则获取ShowCalendar 函数的地址
   @ShowCalendar := GetProcAddress(OneHandle, 'ShowCalendar');
   if not (@ShowCalendar = nil) then
    // 如果找到该函数则在主窗体的Label1 中显示DLL 窗体中设定的日期
    Label1.Caption := DateToStr(ShowCalendar(Application.Handle, Caption))
   else
    RaiseLastWin32Error;
 finally
  FreeLibrary(OneHandle); // 调用完毕收回DLL 占用的资源
 end;
end;

   从以上程序中可以看到DLL 的动态调用方式比静态调用方式的优越之处。DLL 例程在用到时才被调入,用完后就被卸载,大大减少了系统资源的占用。在调用 LoadLibrary 函数时可以明确指定DLL 的完整路径,如果没有指定路径,运行时首先查找应用程序载入的目录,然后是Windows 系统的 System 目录和环境变量Path 设定的路径。

  五、结束语 

  由于动态链接库可以实现代码和资源的共享,大大减少系统资源的占用,因此在当今的应用程序开发中起着非常重要的作用。Delphi 是现今流行的应用软件开发工具,本文就如何在Delphi 中使用动态链接库给出了一定程度上的阐述。

Delphi 动态与静态调用DLL(最好的资料)的更多相关文章

  1. 在Delphi中静态调用DLL

    在Delphi中静态调用DLL top 调用一个DLL比写一个DLL要容易一些.首先给大家介绍的是静态调用方法,稍后将介绍动态调用方法,并就两种方法做一个比较.同样的,我们先举一个静态调用的例子. u ...

  2. C#如何静态调用C++中的方法(静态调用dll)

    当我们想要在C#中使用C++项目的方法时,这个时候就可以通过调用C++项目的dll来实现,它有静态和动态调用两种方法. DLL(Dynamic Link Library)文件为动态链接库文件,又称“应 ...

  3. VC静态调用DLL(lib)

    1. #pragma comment(lib, "libxml2.lib")#pragma comment(lib, "iconv.lib")#pragma c ...

  4. C++调用DLL有两种方法——静态调用和动态调用

    C++调用DLL有两种方法——静态调用和动态调用 标签: dllc++winapinullc 2011-09-09 09:49 11609人阅读 评论(0) 收藏 举报  分类: cpp(30)  [ ...

  5. delphi 动态加载dll

    引入文件 DLL比较复杂时,可以为它的声明专门创建一个引入单元,这会使该DLL变得更加容易维护和查看.引入单元的格式如下: unit MyDllImport; {Import unit for MyD ...

  6. c++builder delphi 调用dll dll编写

    c++builder动态调用dll // 定义 typedef int __stdcall MyFunction (int x, char *str); ; String dllName = &quo ...

  7. C#程序实现动态调用DLL的研究(转)

    摘 要:在<csdn开发高手>2004年第03期中的<化功大法——将DLL嵌入EXE>一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资 ...

  8. C#程序实现动态调用DLL的研究[转]

    摘   要: 在< csdn 开发高手> 2004 年第 03 期中的<化功大法——将 DLL 嵌入 EXE >一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在 ...

  9. C#程序实现动态调用DLL的研究

    摘 要:在<csdn开发高手>2004年第03期中的<化功大法——将DLL嵌入EXE>一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资 ...

随机推荐

  1. Retrofit2+Rxjava2 okhttp RxBus 使用记录

    学习 博客 http://blog.csdn.net/r17171709/article/details/51149350 @Query 后面跟要添加的字段 @Path 连接url里面{userId} ...

  2. 处理程序“pagehandlerfactory-integrated"在其模块列表中有一个错误模块

    解决方案 管用员权限进入cmd命令提示符界面,执行命令"cd C:\Windows\Microsoft.NET\Framework64\v4.0.30319", 运行: aspne ...

  3. <script language = "javascript">, <script type = "text/javascript">和<script language = "application/javascript">(转)

          application/javascript是服务器端处理js文件的mime类型,text/javascript是浏览器处理js的mime类型,后者兼容性更好(虽然application/ ...

  4. UVa 1595 Symmetry(set)

    We call a figure made of points is left-right symmetric as it is possible to fold the sheet of paper ...

  5. React Native 首次加载白屏优化

    RN首次加载都会有个白屏过程,一般都会有500ms+的白屏时间,原生页面开发同样的页面会能够快速显示而在RN页面中有个明显的等待过程,这个会影响用户体验. 1.使用过渡页面 简单处理可以在白屏过程中加 ...

  6. 从RTTI谈C++的向下转型

    转自:http://blog.chinaunix.net/uid-28541347-id-4251713.html 从RTTI谈C++的向下转型 1.什么是RTTI? RTTI 是“Runtime T ...

  7. 在Objc项目中调用Swift

    之前的文字中记录了在Swift项目中调用OC的相关代码,比较简单直接 传送门 但是在OC中调用swift代码则不是那么的和谐,网络上很多文章业已经有点陈旧.记录步骤如下: 1.创建OC项目 (1)启动 ...

  8. php的opcode缓存原理

    opcode是什么? 它是一种PHP脚本编译后的中间语言,类似java的字节码.   PHP代码执行(Zend引擎)的步骤如下: 1.Scanning(Lexing) ,将PHP代码转换为语言片段(T ...

  9. cookies,sessionStorage 和 localStorage 的区别

    请描述一下 cookies,sessionStorage 和 localStorage 的区别? sessionStorage 和 localStorage 是HTML5 Web Storage AP ...

  10. 【转】MEF程序设计指南五:迟延(Lazy)加载导出部件(Export Part)与元数据(Metadata)

    MEF中使用导出与导入,实质上就是对一个对象的实例化的过程,通过MEF的特性降低了对象的直接依赖,从而让系统的设计达到一种高灵活.高扩展性的效果.在具体的设计开发中,存在着某些对象是不需要在系统运行或 ...