一、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. ubuntu 更改源

    1) 备份原来的源 cp /etc/apt/source.list /etc/apt/source.list.old 2) 用下面的文件覆盖 /etc/apt/source.list # 163(非教 ...

  2. JavaFX--第3天窗口布局

    1.windows之间的交互 2.关闭程序 3.布局镶嵌 1.windows之间的交互 我们要实现“确定”.“取消”之类的功能:就像我们平时使用Word的时候要关闭会提示要不要保存的信息. 步骤如下: ...

  3. 【小程序报错】 TLS 版本必须大于等于 1.2

    服务器是windows 2008 server 环境是IIS7SSL是申请用的阿里免费.微信小程序发现wx.request,调试报错: 小程序要求的 TLS 版本必须大于等于 1.2 直接说解决办法吧 ...

  4. apache部署多域名,同个ip部署多个网站

    写个总结笔记,让以后的自己知道怎么部署. 首先apache的版本是2.4.7,然后系统是Ubuntu 14.04.1 LTS.(因为好像配置文件和目录有差异) 首先进到apache2目录下, 我们要探 ...

  5. Android Studio 导入 AOSP 源码

    有了 AOSP 源码,接下来就是如何看了,可以直接文本看,可以用 Source Insight,我当然选择 Android Studio,Android Studio 是我熟悉且十分强大的工具.问题来 ...

  6. lucene中Field简介

    Lucene 6.1.0中存在的field种类如下(后缀是Field): 下面介绍几个常用的Field类型: TextField A field that is indexed and tokeniz ...

  7. SpringBoot支持Xml数据格式显示

    第一步:pom文件添加依赖 <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> < ...

  8. python3绘图示例4(基于matplotlib:箱线图、散点图等)

    #!/usr/bin/env python# -*- coding:utf-8 -*- from matplotlib.pyplot import * x=[1,2,3,4]y=[5,4,3,2] # ...

  9. 前端怎样学习react

    这是一个很长的话题.....慢慢写

  10. 【CSS】等高布局

    1. 负margin:   margin-bottom:-3000px; padding-bottom:3000px; 再配合父标签的overflow:hidden属性即可实现高度自动相等的效果.   ...