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

1、DLL的介绍

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

2、DLL的优点:

  • 1,减小可执行文件的大小

    • DLL技术的产生有很大一部分原因是为了减小可执行文件的大小。当操作系统进入Windows时代后,其大小已经达到几十兆乃至几百兆。试想如果还是使用DOS时代的单执行文件体系的话一个可执行文件的大小可能将达到数十兆,这是大家都不能接受的。解决的方法就是采用动态链接技术将一个大的可执行文件分割成许多小的可执行程序。

  • 2,实现资源共享

    • 这里指的资源共享包括很多方面,最多的是内存共享、代码共享等等。DLL还有一个突出的特点就是在内存中只装载一次,这一点可以节省有限的内存,而且可以同时为多个进程服务。

  • 3,便于维护和升级

    • 在软件运行出现问题的时候,我们并不需要重新安装程序,只需要替换相应的DLL文件即可。

  • 4,比较安全

    • 这里说的安全也包括很多方面。比如,DLL文件遭受病毒的侵害机率要比普通的EXE文件低很多。另外,由于是动态链接的,这给一些从事破坏工作的“高手”们多少带来了一些反汇编的困难。

3、Delphi中编写DLL文件

示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
[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语句后的第一个单元。如下:

?
1
2
3
4
5
6
[delphi] view plaincopy
uses
ShareMem,
SysUtils,
Classes;

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

4、 Dll文件的调用

4.1 静态调用

示例:

?
1
2
3
4
5
6
7
[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文件非常灵活。在运行大的程序时可以节省内存空间。我们看下面的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[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

博客园 滔Roy https://www.cnblogs.com/guorongtao 希望内容对你所有帮助,谢谢!
(0)

相关推荐