一、DLL动态链接库文件的知识简介:

Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝。动态链接库就是在这种情况下出现的。动态链接库不用重复编译或链接,一旦装入内存,Dlls函数可以被系统中的任何正在运行的应用程序软件所使用,而不必再将DLLs函数的另一拷贝装入内存。 任何应用程序都可以共享由装入内存的DLLs管理的内存资源块。只包含共享数据的DLLs称为资源文件。在Delphi中,一般工程文件的头标用program关键字,而DLLs工程文件头标用library 关键字标识(ActiveX控件也是一样)。不同的关键字通知编译器生成不同的可执行文件。用program关键字生成的是.exe文件,而用library关键字生成的是.dll等其他文件;假如要输出供其它应用程序使用的函数或过程,则必须将这些函数或过程列在Exports子句中。而这些函数或过程本身必须用export编译指令进行编译。、

使用DLL动态链接库技术主要有以下几个原因:

1>、减少可执行文件的大小;

2>、实现资源共享;

3>、便于维护和升级

4>、比较安全

二、DLL动态链接库文件的分类:

根据DLLs完成的功能,我们把DLLs分为如下的三类:

1、完成一般功能的DLLs;

2、用于数据交换的DLLs;

3、用于窗体重用的DLLs。

三、DLL动态链接库文件的基本格式如下:

library  Project1;   // 定义DLL文件的文件名,也是库名。和Unit差不多,会随保存时的文件名一起改变

uses

SysUtils,

Classes,

Unit1 in 'Unit1.pas' {Form1}, // 创建的窗体文件

Unit2 in 'Unit2.pas';   // 创建的单元文件

Type

// 定义自己的数据类型

Var

// 定义变量。

// 自己定义的函数

function   TestDll(i:integer):integer;stdcall; // 与平时的编写差不多,只是多了一个stdcall参数

begin

Result := i+i;

end;

{$R *.res}  // 设置版本信息Project|options,必须有{$R *.res}才能显示。也可以位于函数的定义之前。

// 自己定义的函数

exports   // 将函数或过程输出,供其他程序使用。不用写参数和调用后缀。函数直接用‘,‘分开;

TestDll;

begin

end.

四、创建和调用DLL动态链接库的基本步骤:

1、点击【File】—>【New】—>【Other】菜单项,打开【New Items】,选择【New】;

2、选择【Dll Wizard】选项卡,点击ok,DLL工程创建成功。

3、添加代码。

4、按【Project】的【Build Project1】生成DLL动态链接库文件Project1.DLL。

5、调用DLL动态链接库文件。

//调用程序和Project1.dll在同一个目录中,在implementation下面写, external后指定了Delphi.dll的位置

1>、function TestDll(i:integer):integer;stdcall; external ‘Project1.dll’;

//TestDll 必须跟Dll中函数名一样,区分大小写;Project1不区分大小写;

2>、使用就跟普通的函数是一样的。

五、编写DLL动态链接库时,应该注意的事项:

1、在DLL中编写的函数或过程都必须加上stdcall调用参数。

在Delphi 1或Delphi 2环境下该调用参数是far。从Delphi 3以后将这个参数变为了stdcall,目的是为了使用标准的Win32参数传递技术来代替优化的register参数。忘记使用stdcall参数是常见的错误,这个错误不会影响DLL的编译和生成,但当调用这个DLL时会发生很严重的错误,导致操作系统的死锁。原因是register参数是Delphi的默认参

数。如果确实,就会变成register了。

2、所写的函数和过程应该用exports语句声明为外部函数。

正如大家看到的,TestDll函数被声明为一个外部函数。这样做可以使该函数在外部就能看到,具体方法是单激鼠标右键用“快速查看(Quick View)”功能查看该DLL文件。(如果没有“快速查看”选项可以从Windows CD上安装。)TestDll函数会出现在Export Table栏中。另一个很充分的理由是,如果不这样声明,我们如果不这样声明,我们编写的函数将不能被调用,这是大家都不愿看到的。

3、当使用了长字符串类型的参数、变量时要引用ShareMem,或者避免使用String类型。

Delphi中的string类型很强大,我们知道普通的字符串长度最大为256个字符,但Delphi中string类型在默认情况下长度可以达到2G。(对,您没有看错,确实是两兆。)这时,如果您坚持要使用string类型的参数、变量甚至是记录信息时,就要引用ShareMem单元,而且必须是第一个引用的。既在uses语句后是第一个引用的单元。如下例:uses  ShareMem,  SysUtils,  Classes;

还有一点,在您的工程文件(*.dpr)中而不是单元文件(*.pas)中也要做同样的工作,这一点Delphi自带的帮助文件没有说清楚,造成了很多误会。不这样做的话,您很有可能付出死机的代价? 避免使用string类型的方法是将string类型的参数、变量等声明为Pchar或ShortString(如:s:string[10])类型。同样的问题会出现在当您使用了动态数组时,解决的方法同上所述。

六、在Delphi中调用DLL:

在Delphi中调用DLL动态链接库有两种方法:静态调用方法、动态调用方法;

1、静态调用DLL动态链接库(如上面给出的格式一样)

unit   Unit1;

interface

uses

Windows,   Messages,   SysUtils,   Classes,   Graphics, Controls,   Forms,   Dialogs,   StdCtrls;

type

TForm1   =   class(TForm)

Edit1:   TEdit;     // 编辑框(Edit)

Button1:   TButton; // 按钮(Button)

procedure   Button1Click(Sender:   TObject);

private

{   Private   declarations   }

public

{   Public   declarations   }

end;

var

Form1:   TForm1;

implementation

{$R   *.DFM}

// 本行以下代码为我们真正动手写的代码

function   TestDll(i:integer):integer;stdcall; external   ‘Project1.dll ';

procedure   TForm1.Button1Click(Sender:   TObject);

begin

Edit1.Text:=IntToStr(TestDll(1));

end;

end.

注意事项有以下一些:

1>、调用参数用stdcall。

和前面提到的一样,当引用DLL中的函数和过程时也要使用stdcall参数,原因和前面提到的一样。

2>、用external语句指定被调用的DLL文件的路径和名称。

正如大家看到的,我们在external语句中指定了所要调用的DLL文件的名称。没有写路径是因为该DLL文件和调用它的主程序在同一目录下。如果DLL文件在C:\,则我们可将上面的引用语句写为external 'C:\Delphi.dll '。注意文件的后缀.dll必须写上。

3>、不能从DLL中调用全局变量。

如果我们在DLL中声明了某种全局变量,如:var s:byte。这样在DLL中s这个全局变量是可以正常使用的,但s不能被调用程序使用,既s不能作为全局变量传递给调用程序。不过在调用程序中声明的变量可以作为参数传递给DLL。

4>、被调用的DLL必须存在。

这一点很重要,使用静态调用方法时要求所调用的DLL文件以及要调用的函数或过程等等必须存在。如果不存在或指定的路径和文件名不正确的话,运行主程序时系统会提示“启动程序时出错”或“找不到*.dll文件”等运行错误。

2、动态调用DLL动态链接库

只是将原来的Button1Click过程中的语句用下面的代码替换掉了。

procedure   TForm1.Button1Click(Sender:   TObject);

type

TIntFunc=function(i:integer):integer;stdcall; //定义一个函数类型

var

Th: Thandle;

Tf: TIntFunc;

Tp: TFarProc;

begin

Th := LoadLibrary( ‘Project1.dll');   // 装载DLL文件

if Th>0   then

try

Tp:=GetProcAddress(Th,PChar(‘TestDll’)); // 查找函数的位置

if   Tp<>nil then

begin

Tf := TIntFunc(Tp);

Edit1.Text := IntToStr(Tf(1));   // 调用TestC函数

end

else

ShowMessage(‘TestDll函数没有找到 ');

Finally

FreeLibrary(Th);   // 释放DLL,否则会一直占用内存,知道退出windows或关机为止;

End

else

ShowMessage( 'Project1.dll没有找到 ');

end;

大家已经看到了,这种动态调用技术很复杂,但只要修改参数,如修改LoadLibrary( 'Project1.dll ')中的DLL名称为'Delphi.dll '就可动态更改所调用的DLL。

注意的事项有以下:

1>、定义所要调用的函数或过程的类型。

在上面的代码中我们定义了一个TIntFunc类型,这是对应我们将要调用的函数TestDll的。在其他调用情况下也要做同样的定义工作。并且也要加上stdcall调用参数。

2>、释放所调用的DLL。

我们用LoadLibrary动态的调用了一个DLL,但要记住必须在使用完后手动地用FreeLibrary将该DLL释放掉,否则该DLL将一直占用内存直到您退出Windows或关机为止。

3、两种调用方法之间的优缺点:

静态方法实现简单,易于掌握并且一般来说稍微快一点,也更加安全可靠一些;但是静态方法不能灵活地在运行时装卸所需的DLL,而是在主程序开始运行时就装载指定的DLL直到程序结束时才释放该DLL,另外只有基于编译器和链接器的系统(如Delphi)才可以使用该方法。

动态方法较好地解决了静态方法中存在的不足,可以方便地访问DLL中的函数和过程,甚至一些老版本DLL中新添加的函数或过程;但动态方法难以完全掌握,使用时因为不同的函数或过程要定义很多很复杂的类型和调用方法。对于初学者,笔者建议您使用静态方法,待熟练后再使用动态调用方法。

七、使用DLL的实用技巧:

1、编写技巧:

1>、为了保证DLL的正确性,可先编写成普通的应用程序的一部分,调试无误后再从主程序中分离出来,编译成DLL。

2>、为了保证DLL的通用性,应该在自己编写的DLL中杜绝出现可视化控件的名称,如:Edit1.Text中的Edit1名称;或者自

定义非Windows定义的类型,如某种记录。

3>、为便于调试,每个函数和过程应该尽可能短小精悍,并配合具体详细的注释。

4>、应多利用try-finally来处理可能出现的错误和异常,注意这时要引用SysUtils单元。

5>、尽可能少引用单元以减小DLL的大小,特别是不要引用可视化单元,如Dialogs单元。例如一般情况下,我们可以不

引用Classes单元,这样可使编译后的DLL减小大约16Kb。

2、调用技巧:

1>、在用静态方法时,可以给被调用的函数或过程更名。改写引用函数为

function   TestC(i:integer):integer;stdcall; external   'Project1.dll '     name   'TestDll ';

其中name的作用就是重命名(原名称仍然大小写敏感)。

直接通过名称调用(注意名称大小写敏感)。

function   TestDll (i:integer):integer;stdcall; external   'Project1.dll '   ;

//  如果定义了Index就可以使用,通过索引号调用。程序中可以用与DLL中不一样的名称.

procedure   test2;external   'Project1.dll'   index   1;  // exports   TestDll    index   1;

2>、可把我们编写的DLL放到Windows目录下或者Windows\system目录下。这样做可以在external语句中或LoadLibrary

语句中不写路径而只写DLL的名称。但这样做有些不妥,这两个目录下有大量重要的系统DLL,如果您编的DLL与

它们重名的话其后果简直不堪设想.

3、调试技巧:

1>、我们知道DLL在编写时是不能运行和单步调试的。有一个办法可以,那就是在Run|parameters菜单中设置一个宿

主程序。在Local页的Host Application栏中添上宿主程序的名字。宿主程序是使用它生成的DLL包的程序。然后

再DLL工程中点击【Run】就可进行单步调试、断点观察和运行了。

2>、添加DLL的版本信息。如果包含了版本信息,DLL的大小会增加2Kb。增加这么一点空间是值得的。很不幸我们如

果直接使用Project|options菜单中Version选项是不行的,还必须增加{$R *.res},才会显示版本信息;

3>、为了避免与别的DLL重名,在给自己编写的DLL起名字的时候最好采用字符数字和下划线混合的方式。如:jl_try16.dll。

八、具体的一个例子:用DLL文件封装窗体的实现方法实例:

一个程序不再是单一的一个EXE文件了,而是由一个EXE文件加N个DLL文件组成,这样做的原因是方

便以后的维护与更新,也是跨平台开发的重要一步。

1、打开DELPHI,新建一个Dll Wizard

2、 在新建的Dll里新建一个Form

3、 在新建的Form里uses stdctrls

4、 在var下面写:

Procedure synapp(App:THandle);stdcall;

Procedure showform;stdcall;

5、然后在implementation 下面uses math

6、 在{$R *.dfm}下面写

Procedure synapp(App:THandle);stdcall;
Begin
  Application.Handle:=app;// 防止每显示一个窗体,就在任务栏中显示一个图标
End;

Procedure showform;stdcall;
Begin
  Form1:=Tform1.create(application);
  Form1.show;
End;

7 、在dll的Library文件里的{$R *.res}下面写:

exports
Sysapp,show;
上面到此为止完成了DLL封装窗体的创建

8、下面是调用了

1> 、 在要调用DLL文件的程序的var下写:

Procedure synapp(App:THandle);stdcall;external ‘my.dll’ ;//----你的DLL文件名

Procedure showform;stdcall;external‘my.dll’;//----你的DLL文件名

注:把你写好的DLL放在本程序的同一目录下,和上面一样,要uses math;

2> 、在你的程序的Button的On Click事件下写:

Synapp(applicatiln.Handle);

Showform;

完毕

用DLL文件封装窗体,每一个DLL工程中的窗体都是独立的一个进程。所以任何操作都是独立的。在DLL

工程中使用RegisterClass方法对窗体进行祖册是,在应用程序工程或者其他工程再用FindClass方法查找这个类是无

效的。而对于DLL工程而言,方法指针的传递非常的安全,所以可以维护一个指针列表,用于指向各个DLL工程中

FindClass方法的地址。在需要查找窗体类时,对所以的DLL工程的FindClass方法进行调用即可。

封装在DLL工程中的窗体,每打开一次窗体就会出现一个图标在任务栏区。为了解决这个问题,应在调用

DLL文件时,将应用程序中的Application对象和Screen对象传到DLL工程中,并替换DLL工程中这两个对象。

转自:http://blog.csdn.net/zang141588761/article/details/51248258

Delphi 编写DLL动态链接库文件的知识的更多相关文章

  1. Delphi 编写DLL动态链接库文件的知识和样例(有详细步骤,很清楚)

    一.DLL动态链接库文件的知识简介: Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝.动态链接库就是在这种情况下出现的.动态链接库不用重复编译或链接,一旦装入内存,Dlls函数可 ...

  2. 怎样用VB编写.DLL动态链接库文件

    VB一般可以生成两种特殊的DLL,一个是ActiveX DLL和ActiveX Control(*.ocx).这两种DLL都是VB支持的标准类型,在VB自身的例子中有,你可以参考.更详细的介绍可以参考 ...

  3. delphi编写dll心得, 谢谢原作者的分享。转

    delphi编写dll心得 1.每个函数体(包括exports和非exports函数)后面加 'stdcall;', 以编写出通用的dll2.exports函数后面必须加'export;'(放在'st ...

  4. C++编写DLL动态链接库的步骤与实现方法

    原文:http://www.jb51.net/article/90111.htm 本文实例讲述了C++编写DLL动态链接库的步骤与实现方法.分享给大家供大家参考,具体如下: 在写C++程序时,时常需要 ...

  5. .h头文件、 .lib库文件、 .dll动态链接库文件之间的关系

    转自.h头文件. .lib库文件. .dll动态链接库文件之间的关系 h头文件作用:声明函数接口 dll动态链接库作用:含有函数的可执行代码 lib库有两种: (1)静态链接库(Static Liba ...

  6. delphi编写提取exe文件的ICO图标

    http://www.duote.com/tech/4/11797.html delphi编写提取exe文件的ICO图标 7.0分 出处:天下网吧 时间:2011-08-05 人气:2390 核心提示 ...

  7. 分享一次C#调用Delphi编写Dll程序

    1.前言: 最近接手了一个项目需要和Delphi语言编写的一个系统进行一些接口的对接,数据在传输过程中采用Des加密方式,因为Delphi 平台的加密方式和C#平台的加密方式不互通,所以采用的方式是C ...

  8. 详解VB.net编写DLL(动态链接库、应用程序扩展)文件

    首先,我们启动VS(Visual-Studio简称),我使用的是VS2008版本. 新建一个项目-选择内裤(额...不好意思)→类库 ,名称就默认吧. 编写类库没有窗体设计,因此我们不能使用工具箱中的 ...

  9. .h头文件 .lib库文件 .dll动态链接库文件关系

    .h头文件是编译时必须的,lib是链接时需要的,dll是运行时需要的. 附加依赖项的是.lib不是.dll,若生成了DLL,则肯定也生成 LIB文件.如果要完成源代码的编译和链接,有头文件和lib就够 ...

随机推荐

  1. 【LDAP】LDAP 中 CN, OU, DC 的含义

    1. LDAP的存储规则 区分名(DN,Distinguished Name) 和自然界中的树不同,文件系统/LDAP/电话号码簿目录的每一片枝叶都至少有一个独一无二的属性,这一属性可以帮助我们来区别 ...

  2. stm32 窗口看门狗学习(一)

    什么是窗口看门狗? 1)独立看门狗                限制喂狗时间在0-x内,x由相关寄存器决定.喂狗的时间不能过晚. 2)窗口看门狗               之所以称为窗口就是因为其 ...

  3. BoostrapTable-本地模式(一次性加在所有数据)

    直接上代码 数据: [ { "id": "1001", "name": "yyq", "isAdmin&quo ...

  4. EditPlus编写PHP使用技巧

    1,建立php模板 方法:在EditPlus的文件目录下,新建template.php文件,写入<?php ?>内容保存,再在editplus的模板中 载入应用即可. 2,建立函数自动补齐 ...

  5. pta08-图7 公路村村通 (30分)

    08-图7 公路村村通   (30分) 现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本. 输入格式: 输入数据包括城镇数目正整数N ...

  6. oracle expdp impdp 数据泵方式

    一.不管导入还有导出都要先创建目录 1.登录plsql sqlplus/nolog conn sys/dbwork@orcl 2.创建目录 create directory my_dir as 'd: ...

  7. checkBox 全选、全不选、反选

    checkBox的使用: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http: ...

  8. Fsharp 类中的空字段

    fsharp设计之初就尽可能的避免使用null.在我的编程经验中null真是个错误之源,垃圾代码之源,95%的系统奔溃之源.其实在设计之初就应该考虑你的系统需要null表现什么?是未初始化的状态,还是 ...

  9. Azure进阶攻略 | 你的程序也能察言观色?这个真的可以有!

    前段时间有个网站曾经火爆微博和朋友圈:颜龄机器人.只要随便上传一张包含人面孔的照片,这个网站就可以分析图片,并判断照片中人物的年龄.化妆.美颜 P 图.帽子墨镜之类的配饰,几乎都没法影响这个网站的检测 ...

  10. AOP术语分析

    初看这么多术语,一下子都不好接受,慢慢来,很快就会搞懂. 通知.增强处理(Advice) 就是你想要的功能,也就是上说的安全.事物.日子等.你给先定义好,然后再想用的地方用一下.包含Aspect的一段 ...