创建DLL动态连接库

 

Windows 的执行文件可以划分为两种形式程序和动态连接库(DLLs)。一般程序运行是用.EXE文件,但应用程序有时也可以调用存储在DLL 中的函数。

     当我们调用Windows 中的API 函数的时候,实际上就是调用存储在DLL 中的函数。

     在如下几种情况下,调用DLL 是合理的:

     
1) 不同的程序使用相同的DLL ,这样只需要将DLL 在内存中装载一次,节省了内存的开销。

     
2) 当某些内容需要升级的时候,如果使用DLL 只需要改变DLL 就可以了,而不需要把整个程序都进行变动。

     
3) 由于DLL 是独立于语言的,所以,当不同语言习惯的人共同开发一个大型项目的时候,使用DLL 便于程序系统的交流,当然,Delphi开发的DLL 也可以在诸如Visual BASIC,C++ 等系

统中使用。

     下面通过几个例子,说明Delphi开发动态连接库的方法和规范。     

     第一节 动态连接库的构建和调用方法

     一、动态连接库构建

     File
---New---Other---DLL Wizard

     这就创建了一个动态连接库的基本模块

     
library Project2;

     
uses

       SysUtils,

       Classes;

    
{$R *.res}

     
begin

     
end.

     把工程名改为Mydll,并写入必要的函数

     
library mydll;

     
uses

       SysUtils,Classes,Dialogs,windows;

     
function Triple(N:Integer):integer;stdcall;

     
begin

       result:
=N+3;

     
end;

     
function Double(N:Integer):integer;stdcall;

     
begin

       result:
=N+2;

     
end;

     
function Triple1(N:Integer):integer;stdcall;

     
begin

       showmessage(
'计算N+3');

       result:
=N+3;

     
end;

     
function Double1(N:Integer):integer;stdcall;

     
begin

       messagebox(
0,'计算N+2','计算N+2',mb_ok);

       result:
=N+2;

     
end;

    
exports

      Triple name 
'Tr',

      Double name 
'Do',

      Triple1 name 
'TrM',

      Double1 name 
'DoM';

     Triple,Double,Triple1,Double1;

   
{$R *.RES}

   
begin

   
end.

     其中函数:Triple:把传入值加三

               Double:把传入值加二 

               Triple1:把传入值加三并显示提示

               Double1:把传入值加二并显示提示

     从这个例子中可以看出DLL 程序的几个规则:

     
1) 在DLL 程序中,输出函数必须被声明为stdcall,以使用标准的Win32 参数传递技术来代替优化的Register。

     (说明:在Delphi中Register方式是缺省的调用约定,这个约定尽量采用寄存器来传递参数,传递次序从左到右,最多可用到3个CPU 的寄存器,如果参数多于3 个,剩下的就通过栈来传送,使用寄存器传送可保证参数传递的速度最快。

     而stdcall 方式是通过Windows 的标准调用来传递参数,传递秩序从左到右,这种方式适合调用Windows 的API ,在DLL 中,当然要使用这种方式)。 

     
2)所有的输出函数都必须列在exports子句下面,这使的子例程在DLL外部就可以看到。

    
exports

      Triple name 
'Tr',

      Double name 
'Do',

      Triple1 name 
'TrM',

      Double1 name 
'DoM';

    

     列出了用户使用这个函数的接口名字。虽然别名不是必须的,但最好给个别名,以便用户程序更容易找到这个函数,同时还要指出,Delphi 
6.0取消了Delphi 5.0中允许使用的index ,如果还用Index来指明接口名字,Delphi 6.0中将提示错误。 

     实例中给出了两种提示方法,主要想说明一个问题: 

     showmessage(
''),是VCL 提供的函数,由于多次编译VCL,做出的程序会比较大。

     而messagebox(
0,'','',mb_ok)   是Windows提供的API 函数,做出的程序会比较小。

     这就是说,编写DLL 程序的时候,要尽量避免多次编译VCL 。作为一个实例,这里把两种方法都列出来了。

     保存

     编译:Projrct
---Build Mydll

     这就完成了一个简单的动态连接库的编写。

     二、动态连接库的调用

     首先在implementation下做调用声明

const

   gdi32
='mydll.dll';

function triple(n:integer):integer;stdcall;external gdi32 name 'Tr';

function Double(N:Integer):integer;stdcall;external gdi32 name 'Do';

function triple1(n:integer):integer;stdcall;external gdi32 name 'TrM';

function Double1(N:Integer):integer;stdcall;external gdi32 name 'DoM';

     以后程序中就可以作为普通的函数使用了,例如:

procedure TForm1.Button1Click(Sender: TObject);

var N:integer;

begin

   N:
=updown1.position;

   edit1.text:
=inttostr(triple(N));

end;

     第二节 DLL 中的Delphi窗体

     一、在DLL 中放置窗的的方法

     在DLL 中,除了放置标准的函数和过程以外,也可以放置已经做好的的delphi窗体,也可以把做好的窗体供其它程序使用,方法是:

    
1)首先按普通方法制作窗体,不过在interface区域,对接口函数做如下声明

    
function Createform(capt:string):string;stdcall;

   

    
2)在implementation下加入接口函数

function Createform(capt:string):string;stdcall;

var   Form1: TForm1;

begin

   form1:
=Tform1.Create(application);

   form1.show;

   form1.caption:
=capt;

end;

   
3)制作DLL 动态连接库,但要声明:

uses

   unit1 
in 'unit1.pas';

exports

{写入接口标示符}

Createform name 
'Myform';

   
4)调用窗体的程序按普通方法制作,但是 在implementation下首先声明要调用的DLL函数

const

   gdi32
='myFormdll.dll';

   
function Createform(capt:string):string;stdcall;external gdi32 name 'Myform';

procedure TForm3.Button1Click(Sender: TObject);

var n,m:string;

begin

   m:
='我的窗体';

   Createform(m);

end;

     二、DLL 中的调用窗体时的数据传递

     在窗体调用时,可以用普通的函数方法传递数据,下面举个例子。

     
1)建立窗体

     做一个改变颜色窗体,放在DLL 中,可以用普通的方法来做,但要作如下声明:

     
function mycolor(col:longint):longint;stdcall;

     
function Getcolor:longint;stdcall;

     其中,mycolor为构造窗体;Getcolor为传递颜色数据。

     在implementation区声明一个窗体内全局的变量

     
var color1:longint;

     下面写出相应的程序

function mycolor(col:longint):longint;stdcall;

var   Form1: TForm1;

begin

   form1:
=Tform1.Create(application);

   form1.show;

   form1.panel1.Color:
=col;

   form1.edit1.Text:
=inttostr(form1.panel1.Color);

   result:
=color1;

end;

function Getcolor:longint;stdcall;

begin

   result:
=color1;

end;

procedure TForm1.ScrollBar1Change(Sender: TObject);

begin

   panel2.Color:
=RGB(ScrollBar1.Position,ScrollBar2.Position,ScrollBar3.Position);

   edit2.Text:
=inttostr(panel2.Color);

   color1:
=panel2.Color;

end;

procedure TForm1.Button2Click(Sender: TObject);

begin

    Free;   
//析构Form1

end;

     
2)建立动态连接库

     运行成功后,再建立动态连接库:

library FormDLL;

{从文件调入}

uses

   unit1 
in 'unit1.pas';

exports

{写入接口标示符}

Mycolor name 
'My',

Getcolor name 
'Get';

begin

end.

     
3)建立调用的程序

     首先声明要调用的DLL函数

const

   gdi32
='formDll.dll';

   
function Mycolor(col:longint):longint;stdcall;external gdi32 name 'My';

   
function Getcolor:longint;stdcall;external gdi32 name 'Get';

     然后写出相应的程序

procedure TForm1.Button1Click(Sender: TObject);

begin

   Mycolor(color);

end;

procedure TForm1.Button2Click(Sender: TObject);

begin

    color:
=getcolor;

end;

posted on 2009-03-17 19:27  光庆  阅读(138)  评论(0)    收藏  举报

导航