delphidll例子.docx
- 文档编号:26441065
- 上传时间:2023-06-19
- 格式:DOCX
- 页数:20
- 大小:24.54KB
delphidll例子.docx
《delphidll例子.docx》由会员分享,可在线阅读,更多相关《delphidll例子.docx(20页珍藏版)》请在冰豆网上搜索。
delphidll例子
delphidll例子
【篇一:
delphidll例子】
为了让人能快速的理解静态调用、动态调用,现在做一个函数封装在一个dll中,然后在applicationform里面调用这个函数,这个函数处理两个数的和。
用代码和图片说话:
代码如下
libraryproject1;
{importantnoteaboutdllmemorymanagement:
sharememmustbethe
firstunitinyourlibrarysusesclauseandyourprojects(select
project-viewsource)usesclauseifyourdllexportsanyproceduresor
functionsthatpassstringsasparametersorfunctionresults.this
appliestoallstringspassedtoandfromyourdll--eventhosethat
arenestedinrecordsandclasses.sharememistheinterfaceunitto
theborlndmm.dllsharedmemorymanager,whichmustbedeployedalong
withyourdll.toavoidusingborlndmm.dll,passstringinformation
usingpcharorshortstringparameters.}
uses
sysutils,
classes;
functionincc(a,b:
integer):
integer;stdcall;//真正的代码开始;
begin
result:
=a+b;
end;
{$r*.res}
exports//允许调用;
incc;
end.
按ctrl+f9编译以后会在文件夹下面会产生一个project1.dll的dll文件。
下面,我们就开始用静态调用和动态调用两种方式调用这个dll里面的函数。
一:
静态调用
新建一个applicationform在这个窗体上加两个文本框,取名edt1,edt2用代码说话。
unitunit1;
interface
uses
windows,messages,sysutils,variants,classes,graphics,controls,forms,
dialogs,stdctrls;
type
tform1=class(tform)
btn1:
tbutton;
edt1:
tedit;
edt2:
tedit;
procedurebtn1click(sender:
tobject);
private
{privatedeclarations}
public
{publicdeclarations}
end;
var
form1:
tform1;
implementation
functionincc(a,b:
integer):
integer;stdcall;externalproject1.dll;//加载这个动态库。
{$r*.dfm}
proceduretform1.btn1click(sender:
tobject);
var
aa:
integer;
begin
aa:
=incc(strtoint(edt1.text),strtoint(edt2.text));//开始调用
showmessage(inttostr(aa));//弹出结果。
end;
end.
二:
相比静态调用,动态调用占用的资源要小点,哎呀,具体好处我就不说了,现在来看看具体怎么能实现,同样的在建立一个和静态调用的窗体。
再用代码说话。
unitunit11;
interface
uses
windows,messages,sysutils,variants,classes,graphics,controls,forms,
dialogs,stdctrls;
type
tform1=class(tform)
edt1:
tedit;
edt2:
tedit;
btn1:
tbutton;
procedurebtn1click(sender:
tobject);
private
{privatedeclarations}
public
{publicdeclarations}
end;
var
form1:
tform1;
implementation
{$r*.dfm}
type
tmyfun=function(a,b:
integer):
integer;stdcall;//定义一个函数类型,注意一点过程类型种的参数应该与dll中用到的方法的参数一致。
proceduretform1.btn1click(sender:
tobject);
var
myhandle:
thandle;
fpointer:
pointer;
myfun:
tmyfun;
begin
myhandle:
=loadlibrary(c:
\documentsandsettings\administrator\桌面\新建文件夹\project1.dll);//加载这个dll
ifmyhandle0then//加载成功就执行。
try
fpointer:
=getprocaddress(myhandle,pchar(incc));//取函数的地址。
iffpointernilthen//如果函数存在就调用
begin
myfun:
=tmyfun(fpointer);
showmessage(inttostr(myfun(strtoint(edt1.text),strtoint(edt2.text))));//弹出算出的结果。
end;
except
freelibrary(myhandle);
end;
end;
end.
在delphi中静态调用dll
调用一个dll比写一个dll要容易一些。
首先给大家介绍的是静态调用方法,稍后将介绍动态调用方法,并就两种方法做一个比较。
同样的,我们先举一个静态调用的例子。
unitunit1;
interface
uses
windows,messages,sysutils,classes,graphics,
controls,forms,dialogs,stdctrls;
type
tform1=class(tform)
edit1:
tedit;
button1:
tbutton;
procedurebutton1click(sender:
tobject);
private
{privatedeclarations}
public
{publicdeclarations}
end;
var
form1:
tform1;
implementation
{$r*.dfm}
//本行以下代码为我们真正动手写的代码
functiontestdll(i:
integer):
integer;stdcall;
external’delphi.dll’;
proceduretform1.button1click(sender:
tobject);
begin
edit1.text:
=inttostr(testdll
(1));
end;
end.
上面的例子中我们在窗体上放置了一个编辑框(edit)和一个按钮(button),并且书写了很少的代码来测试我们刚刚编写的delphi.dll。
大家可以看到我们唯一做的工作是将testdll函数的说明部分放在了implementation中,并且用external语句指定了delphi.dll的位置。
(本例中调用程序和delphi.dll在同一个目录中。
)让人兴奋的是,我们自己编写的testdll函数很快被delphi认出来了。
您可做这样一个实验:
输入“testdll(”,很快delphi就会用fly-by提示条提示您应该输入的参数是什么,就像我们使用delphi中定义的其他函数一样简单。
注意事项有以下一些:
一、调用参数用stdcall
和前面提到的一样,当引用dll中的函数和过程时也要使用stdcall参数,原因和前面提到的一样。
二、用external语句指定被调用的dll文件的路径和名称
正如大家看到的,我们在external语句中指定了所要调用的dll文件的名称。
没有写路径是因为该dll文件和调用它的主程序在同一目录下。
如果该dll文件在c:
\,则我们可将上面的引用语句写为external’c:
\delphi.dll’。
注意文件的后缀.dll必须写上。
三、不能从dll中调用全局变量
如果我们在dll中声明了某种全局变量,如:
vars:
byte。
这样在dll中s这个全局变量是可以正常使用的,但s不能被调用程序使用,既s不能作为全局变量传递给调用程序。
不过在调用程序中声明的变量可以作为参数传递给dll。
四、被调用的dll必须存在
这一点很重要,使用静态调用方法时要求所调用的dll文件以及要调用的函数或过程等等必须存在。
如果不存在或指定的路径和文件名不正确的话,运行主程序时系统会提示“启动程序时出错”或“找不到*.dll文件”等运行错误。
在delphi中动态调用dll
动态调用dll相对复杂很多,但非常灵活。
为了全面的说明该问题,这次我们举一个调用由c++编写的dll的例子。
首先在c++中编译下面的dll源程序。
#include
extern”c”_declspec(dllexport)
intwinapitestc(inti)
{
returni;
}
【篇二:
delphidll例子】
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动态链接库文件的基本式如下:
libraryproject1;//定义dll文件的文件名,也是库名。
和unit差不多,会随保存时的文件名一起改变
uses
sysutils,
classes,
unit1inunit1.pas{form1},//创建的窗体文件
unit2inunit2.pas;//创建的单元文件
type
//定义自己的数据类型
var
//定义变量。
//自己定义的函数
functiontestdll(i:
integer):
integer;stdcall;//与平时的编写差不多,只是多了一个stdcall参数
begin
result:
=i
end;
{$r*.res}//设置版本信息project|options,必须有{$r*.res}才能显示。
也可以位于函数的定义之前。
//自己定义的函数
exports//将函数或过程输出,供其他程序使用。
不用写参数和调用后缀。
函数直接用‘,‘分开;
testdll;
begin
end.
四、创建和调用dll动态链接库的基本步骤:
1、点击【file】—【new】—【other】菜单项,打开【newitems】,选择【new】;
2、选择【dllwizard】选项卡,点击ok,dll工程创建成功。
3、添加代码。
4、按【project】的【buildproject1】生成dll动态链接库文件project1.dll。
5、调用dll动态链接库文件。
//调用程序和project1.dll在同一个目录中,在implementation下面写,external后指定了delphi.dll的位置
1、functiontestdll(i:
integer):
integer;stdcall;external‘project1.dll’;
//testdll必须跟dll中函数名一样,区分大小写;project1不区分大小写;
2、使用就跟普通的函数是一样的。
五、编写dll动态链接库时,应该注意的事项:
1、在dll中编写的函数或过程都必须加上stdcall调用参数。
在delphi1或delphi2环境下该调用参数是far。
从delphi3以后将这个参数变为了stdcall,目的是为了使用标准的win32参数传递技术来代替优化的register参数。
忘记使用stdcall参数是常见的错误,这个错误不会影响dll的编译和生成,但当调用这个dll时会发生很严重的错误,导致操作系统的死锁。
原因是register参数是delphi的默认参
数。
如果确实,就会变成register了。
2、所写的函数和过程应该用exports语句声明为外部函数。
正如大家看到的,testdll函数被声明为一个外部函数。
这样做可以使该函数在外部就能看到,具体方法是单激鼠标右键用“快速查看(quickview)”功能查看该dll文件。
(如果没有“快速查看”选项可以从windowscd上安装。
)testdll函数会出现在exporttable栏中。
另一个很充分的理由是,如果不这样声明,我们如果不这样声明,我们编写的函数将不能被调用,这是大家都不愿看到的。
3、当使用了长字符串类型的参数、变量时要引用sharemem,或者避免使用string类型。
delphi中的string类型很强大,我们知道普通的字符串长度最大为256个字符,但delphi中string类型在默认情况下长度可以达到2g。
(对,您没有看错,确实是两兆。
)这时,如果您坚持要使用string类型的参数、变量甚至是记录信息时,就要引用sharemem单元,而且必须是第一个引用的。
既在uses语句后是第一个引用的单元。
如下例:
usessharemem,sysutils,classes;
还有一点,在您的工程文件(*.dpr)中而不是单元文件(*.pas)中也要做同样的工作,这一点delphi自带的帮助文件没有说清楚,造成了很多误会。
不这样做的话,您很有可能付出死机的代价?
避免使用string类型的方法是将string类型的参数、变量等声明为pchar或shortstring(如:
s:
string[10])类型。
同样的问题会出现在当您使用了动态数组时,解决的方法同上所述。
六、在delphi中调用dll:
在delphi中调用dll动态链接库有两种方法:
静态调用方法、动态调用方法;
1、静态调用dll动态链接库(如上面给出的式一样)
unitunit1;
interface
uses
windows,messages,sysutils,classes,graphics,controls,forms,dialogs,stdctrls;
type
tform1=class(tform)
edit1:
tedit;//编辑框(edit)
button1:
tbutton;//按钮(button)
procedurebutton1click(sender:
tobject);
private
{privatedeclarations}
public
{publicdeclarations}
end;
var
form1:
tform1;
implementation
{$r*.dfm}
//本行以下代码为我们真正动手写的代码
functiontestdll(i:
integer):
integer;stdcall;external‘project1.dll;
proceduretform1.button1click(sender:
tobject);
begin
edit1.text:
=inttostr(testdll
(1));
end;
end.
注意事项有以下一些:
1、调用参数用stdcall。
和前面提到的一样,当引用dll中的函数和过程时也要使用stdcall参数,原因和前面提到的一样。
2、用external语句指定被调用的dll文件的路径和名称。
正如大家看到的,我们在external语句中指定了所要调用的dll文件的名称。
没有写路径是因为该dll文件和调用它的主程序在同一目录下。
如果dll文件在c:
\,则我们可将上面的引用语句写为externalc:
\delphi.dll。
注意文件的后缀.dll必须写上。
3、不能从dll中调用全局变量。
如果我们在dll中声明了某种全局变量,如:
vars:
byte。
这样在dll中s这个全局变量是可以正常使用的,但s不能被调用程序使用,既s不能作为全局变量传递给调用程序。
不过在调用程序中声明的变量可以作为参数传递给dll。
4、被调用的dll必须存在。
这一点很重要,使用静态调用方法时要求所调用的dll文件以及要调用的函数或过程等等必须存在。
如果不存在或指定的路径和文件名不正确的话,运行主程序时系统会提示“启动程序时出错”或“找不到*.dll文件”等运行错误。
2、动态调用dll动态链接库
只是将原来的button1click过程中的语句用下面的代码替换掉了。
proceduretform1.button1click(sender:
tobject);
type
tintfunc=function(i:
integer):
integer;stdcall;//定义一个函数类型
var
th:
thandle;
tf:
tintfunc;
tp:
tfarproc;
begin
th:
=loadlibrary(‘project1.dll);//装载dll文件
ifth0then
try
tp:
=getprocaddress(th,pchar(‘testdll’));//查找函数的位置
iftpnilthen
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、在用静态方法时,可以给被调用的函数或过程更名。
改写引用函数为
functiontestc(i:
integer):
integer;stdcall;externalproject1.dllnametestdll;
其中name的作用就是重命名(原名称仍然大小写敏感)。
直接通过名称调用(注意名称大小写敏感)。
functiontestdll(i:
integer):
integer;stdcall;externalproject1.dll;
//如果定义了index就可以使用,通过索引号调用。
程序中可以用与dll中不一样的名称.
proceduretest2;externalproject1.dllindex1;//exportstestdllindex1;
2、可把我们编写的dll放到windows目录下或者windows\system目录下。
这样做可以在external语句中或loadlibrary
语句中不写路径而只写dll的名称。
但这样做有些不妥,这两个目录下有大量重要的系统dll,如果您编的dll与
它们重名的话其后果简直不堪设想.
3、调试技巧
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- delphidll 例子