创建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);var n,m:string; 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;
我们可以看到,在改变颜色的窗体中做了颜色变化后,当前窗 体的颜色将发生变化。
handle
三、在Visual Basic应用程序中调用Delphi DLL