Delphi DLL的介绍、创建、静态 以及动态调用

Delphi DLL的介绍、创建、静态 以及动态调用

1、DLL的介绍

Dynamic Link Library的缩写。DLL是一个包含可由多个程序,同时使用的代码和数据的库。

2、DLL的优点:

  • 1,减小可执行文件的大小
    • DLL技术的产生有很大一部分原因是为了减小可执行文件的大小。当操作系统进入Windows时代后,其大小已经达到几十兆乃至几百兆。试想如果还是使用DOS时代的单执行文件体系的话一个可执行文件的大小可能将达到数十兆,这是大家都不能接受的。解决的方法就是采用动态链接技术将一个大的可执行文件分割成许多小的可执行程序。
  • 2,实现资源共享
    • 这里指的资源共享包括很多方面,最多的是内存共享、代码共享等等。DLL还有一个突出的特点就是在内存中只装载一次,这一点可以节省有限的内存,而且可以同时为多个进程服务。
  • 3,便于维护和升级
    • 在软件运行出现问题的时候,我们并不需要重新安装程序,只需要替换相应的DLL文件即可。
  • 4,比较安全
    • 这里说的安全也包括很多方面。比如,DLL文件遭受病毒的侵害机率要比普通的EXE文件低很多。另外,由于是动态链接的,这给一些从事破坏工作的“高手”们多少带来了一些反汇编的困难。

3、Delphi中编写DLL文件

示例:

[delphi] view plaincopy

library DLL; 

{ Important note about DLL memory management: ShareMem must be the 
first unit in your library's USES clause AND your project's (select 
Project-View Source) USES clause if your DLL exports any procedures or 
functions that pass strings as parameters or function results. This 
applies to all strings passed to and from your DLL--even those that 
are nested in records and classes. ShareMem is the interface unit to 
the BORLNDMM.DLL shared memory manager, which must be deployed along 
with your DLL. To avoid using BORLNDMM.DLL, pass string information 
using PChar or ShortString parameters. } 

uses 
ShareMem, 
SysUtils, 
Classes; 

function testStr: TStringList; stdcall; 
var 
  str: string; 
  strlist: TStringList; 
begin 
  strlist := TStringList.Create; 
  strlist.Add('hello'); 
  strlist.Add('world'); 
  str := 'hello world'; 
  result := strlist; 
end; 

function testInt(i: Integer): Integer; stdcall; 
begin 
  Inc(i); 
  result := i; 
end; 
{$R *.res} 

exports 
testStr, 
testInt; 

begin 
end. 

在上面的Dll文件中我们封装了两个函数。跟一般Delphi编写的程序基本相同,只是在DLL文件中的函数后面多了一个stdcall参数,并且用exports声明需要引出的函数。只要编译上述代码就可以得到一个动态链接库的Dll文件。

1,在Dll中编写的函数必须在后面加上stdcall调用参数,如果忘记添加stdcall参数的话虽然编译可以通过,但在调用这个DLL时会出现很严重的错误,导致操作系统的死锁。

2,所写的函数和过程必须用exports声明为外部函数。若没有声明,那Dll内部的函数是不可调用的,这一点显然不是我们想看到的。

3,当使用了长字符串类型的参数、变量时,如string,要引用ShareMem。虽然Delphi中的string功能很强大,但若是您编写的Dll文件要供其它编程语言调用时,最好使用PChar类型。如果您要坚持使用string类型的参数时、变量甚至是记录信息时,就要引用ShareMem单元,而且这个单元必须是第一个引用的,即在uses语句后的第一个单元。如下:

[delphi] view plaincopy

uses 
ShareMem, 
SysUtils, 
Classes; 

另外,还有一个地方我们需要添加ShareMem单元,即在您的工程文件中(*.dpr)中的uses下第一个引用ShareMem单元。这里需要注意的是在*.dpr文件中而不是单元文件(*.pas)中添加相同的单元,这一点Delphi自带的帮助文件没有说清楚,造成了许多误会。若不这样做的话,您可能付出死机的代价。避免使用string类型的方法是将其转换为PChar或ShortString类型。

 

4、 Dll文件的调用

4.1 静态调用

示例:

[delphi] view plaincopy

function testInt(i: Integer): Integer; stdcall; external 'DLL.dll'; 
procedure TForm1.btn2Click(Sender: TObject); 
begin 
  showMessage(inttostr(testInt(1))); 
end;  

大家可以看到我们做的唯一的工作是将Dll中的函数说明放在implementation下(或是放在文件单元的var下),并且用external语句指定了Dlll的位置。这样我们就可以直接使用Dll中的函数了。

  • 1、调用参数stdcall,在引用Dll中的函数时也要使用stdcalll参数。
  • 2、用external声明Dll文件的位置。注意文件的后缀名必须加上。
  • 3、不能从Dll中调用全局变量。如果我们在DLL中声明了某种全局变量,如:var s:byte 。这样在DLL中s这个全局变量是可以正常使用的,但s不能被调用程序使用,既s不能作为全局变量传递给调用程序。不过在调用程序中声明的变量可以作为参数传递给DLL。

4.2 动态调用

动态调用Dll文件非常灵活。在运行大的程序时可以节省内存空间。我们看下面的例子:

[delphi] view plaincopy

procedure TForm1.btn1Click(Sender: TObject); 
type 
  Taddc = function: TStringList; stdcall; 
var 
  hh: THandle; 
  addc: Taddc; 
  temp: TStringList; 
  i: Integer; 
begin 
  hh := LoadLibrary('DLL.dll'); 
  try 
  if hh <> 0 then 
  @addc := GetProcAddress(hh, PChar('testStr')); 
  if not (@addc = nil) then 
  begin 
    temp := addc; 
    for i := 0 to temp.Count - 1 do 
    showMessage(temp[i]); 
  end 
  else 
  begin 
    RaiseLastWin32Error; 
  end; 
  finally 
    FreeLibrary(hh); 
  end; 
end;  

由上面代码可以看到,这种动态调用技术很复杂。但只要更改参数就可动态更改所调用Dll文件的名字。

  • 在type中定义所要调用的函数或过程的类型,在这里同样也要加上stdcall参数。
  • 释放Dll。在上面程序中我们使用LoadLibray函数加载了dll文件,在使用完Dll文件时切记调用FreeLibrary函数来释放Dll,否则Dll将会一直占用你的内存直至您退出Windows或是关机为止。在这里需要注意的是要确保在释放dll的时候没有任何指针指向该dll中所定义的变量、过程等,否则无法正常释放,招聘访问冲突异常。或是导致程序出现空指针,导致程序意外中止。
  • 在动态调用的Dll函数中我们使用了string类型,由于在两处文件内都引用了ShareMem,所以string类型的数据可以正使用,以及作为参数来传递。

5、静态和动态调用的对比

  • 静态方法实现简单,易于掌握。并且一般来说速度比较快,也更加安全可靠一些。但静态方法不能灵活地在运行时装卸所需的Dll,而主程序在开始运行时就装载了Dll只到程序结束时才释放该Dll。
  • 动态方法很好地解决了静态方法中的不足,可以方便的访问Dll中的函数和过程。但动态方法难以完全掌握,使用时因为不同的函数或过程需要定义很多复杂的类型和调用方法。

 6、常用dll

 

  • USER32.DLL-------- 于windows管理有关的函数。消息、菜单、光标、计时器、通信和其他大多数非现实函数都可以从这里找到;
  • GDI32.DLL-------- 图形设备接口库。于设备输出有关的函数:大多数绘图、显示场景、图元文件、坐标及其字体函数都可以从这里找到;
  • COMDLG32.DLL\LZ32.DLL\VERSION.DLL\ -------- 这都是提供一些附加函数的库,包括通用对话框、文件压缩、版本控制的支持;
  • COMCTL32.DLL -------- 一个新的windows控件集合,比如TreeView和RichTextBox等等,最初这个是为了win95而制作的,但是现在也使用于NT中;
  • MAPI32.DLL--------- 提供了一套电子邮件的专用函数;
  • NETAPI32.DLL-------- 提供了一套访问和控制网络的函数;
  • ODBC32.DLL-------- ODBC功能的DLL之一;
  • WINMM.DLL-------- 是多媒体控制访问函数集合;

 

 

 

创建时间:2015.12.12  更新时间:2020.10.16

 

posted on 2015-12-12 11:08  滔Roy  阅读(1210)  评论(0编辑  收藏  举报

导航