delphi_dll文件详解
- 格式:doc
- 大小:63.00 KB
- 文档页数:13
非本人原创,从其他网络上下载而来的一、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差不多,会随保存时的文件名一起改变usesSysUtils,Classes,Unit1 in 'Unit1.pas' {Form1}, // 创建的窗体文件Unit2 in 'Unit2.pas'; // 创建的单元文件Type// 定义自己的数据类型Var// 定义变量。
// 自己定义的函数function TestDll(i:integer):integer;stdcall; // 与平时的编写差不多,只是多了一个stdcall参数beginResult := i+i;end;{$R *.res} // 设置版本信息Project|options,必须有{$R *.res}才能显示。
也可以位于函数的定义之前。
// 自己定义的函数exports // 将函数或过程输出,供其他程序使用。
不用写参数和调用后缀。
函数直接用‘,‘分开;TestDll;beginend.四、创建和调用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;interfaceusesWindows, Messages, SysUtils, Classes, Graphics,Controls, Forms, Dialogs, StdCtrls;typeTForm1 = class(TForm)Edit1: TEdit; // 编辑框(Edit)Button1: TButton; // 按钮(Button)procedure Button1Click(Sender: TObject);private{ Private declarations }public{ Public declarations }end;varForm1: TForm1;implementation{$R *.DFM}// 本行以下代码为我们真正动手写的代码function TestDll(i:integer):integer;stdcall;external ‘Project1.dll ';procedure TForm1.Button1Click(Sender: TObject);beginEdit1.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);typeTIntFunc=function(i:integer):integer;stdcall; //定义一个函数类型varTh: Thandle;Tf: TIntFunc;Tp: TFarProc;beginTh := LoadLibrary( ‘Project1.dll'); // 装载DLL文件if Th>0 thentryTp:=GetProcAddress(Th,PChar(‘TestDll’)); // 查找函数的位置if Tp<>nil thenbeginTf := TIntFunc(Tp);Edit1.Text := IntToStr(Tf(1)); // 调用TestC函数endelseShowMessage(‘TestD ll函数没有找到 ');FinallyFreeLibrary(Th); // 释放DLL,否则会一直占用内存,知道退出windows或关机为止;EndelseShowMessage( '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)才可以使用该方法。