我想把一个工程做成dll文件 但是不知道怎么样可以调用 我只会把函数做成dll调用窗体就不知怎么用了?
请教高手
小弟这里感谢了!!!
请教高手
小弟这里感谢了!!!
解决方案 »
- Delphi2010或者Delphi2011(XE)的多点触控,有哪位大侠研究的?
- BusinessSkinForm皮肤 字体颜色问题
- 为什么我在LABEL里写了字却在显示的时候横过来了!
- 在98下用TQuickrep制作报表进行编译后在2000下不能运行?在线等待!
- 怎样在程序中实现关闭或开启触发器?
- 【100分】我用SendMessage 发EM_GETTEXTRANGE到一个RichEdit,怎么也得不到正确的TEXT。
- 怎样调用EXE文件?
- 我想取得某个主键下的全部键值,然后赋给一个ListBox,请指点一下方向啊
- Delphi6的ADO问题:
- 求Delphi xxGrid中可以自由定义行或Cell颜色的免费控件
- 请建DELPHI三层数据库讨论群,大家顶一下呀。
- dll返回出错
1.DLL简介; 2.调用DLL; 3.创建DLL; 4.两个技巧; 5.初始化; 6.例外处理。
1、DLL简介
DLL是Dynamic-Link Libraries(动态链接库)的缩写,库里面是一些可执行的模块以及资源(如位图、图标等)。可以认为DLL和EXE基本上是一回事,只是DLL不能直接执行,而必须由应用程序或者其他DLL调用。DLL为应用程序间的资源共享提供了方便,同时也是多语言混合编程的重要手段。由此可见学习使用DLL是Windows程序员必须掌握的一项重要技术。 <Back to Top> 2、如何调用DLL
在Delphi中有两种方法调用DLL中的函数和过程,即外部声明或者动态加载。 <1>外部声明
在Delphi中外部声明是访问外部例程最容易和最常用的方式,有两种声明方式:通过名字、通过索引号。举例如下:在MYDLL.DLL中有两个函数和一个过程,则其外部声明可以写成: function test1:integer;external 'mydll';
//直接通过名称调用test1(注意名称大小写敏感)。
function test11:integer;external 'mydll' name 'test1';
//通过名称调用test1,在程序中使用新名称(原名称仍然大小写敏感)。
procedure test2;external 'mydll' index 1;
//通过索引号调用TEST2。程序中可以用与DLL中不一样的名称.
使用外部声明的缺点是程序启动时如果找不到mydll.dll将无法运行,即使没有调用其中的模块。 动态加载的方法可以避免这种情况。 <2>动态加载
通过调用Windows API中的相关函数,将DLL调入内存并获得指向函数或过程的指针,执行完模块后释放内存。除了节约内存外,这种方法的一个很大的优点是能处理找不到dll或者在装入过程中出错的情况。这样即使某个dll有问题,应用程序的其他部分仍然能够正常运行。动态加载的例子如下: var hDll:THandle;
Test1:function:integer;
begin
hDll:=LoadLibrary('mydll.dll');
if hDll<32 then exit;//如果Dll无法加载则跳出
@Test1:=GetProcAddress(hDll,MakeIntResource(1));
//取得mydll中的第一个函数的地址。
...
FreeLibrary(hDll);
end; <Back to Top> 3、用Delphi创建DLL
用Delphi创建一个DLL是十分简单的,首先需要新建一个DLL的Porject(如果使用Delphi3.0则可以在File->New对话框中选择DLL),当然也可以自己写,现在这个Project是这样的: library Project1;
uses SysUtils,Classes;
begin
end. 当然这是一个空DLL,现在让我们来加入一个函数,让他成为我们的第一个可以使用的DLL。完成后的文件是这样的: library dll1;
uses SysUtils,Classes; function Test1(a,b:integer):integer;
begin
Result:=a+b;
end; exports
Test1 index 1; begin
end. 在这个DLL里我们声明了一个加法函数,然后用exports语句输出它,只有被输出的函数或过程能被其他程序调用。exports语句后的语法是:函数名 [index <n>],index <n>是为函数手工指定索引号,以便其他程序确定函数地址;也可以不指定,如果没有使用Index关键字,Delphi将按照exports后的顺序从1开始自动分配索引号。现在我们可以调用这个DLL了,下面给出一个实例,运行后form1的标题将变成“1+2=3”: 声明部分:function Test1(a,b:integer):integer;external 'dll1';
注意此处是大小写敏感的。
运行部分:form1.caption:='1+2='+inttostr(test1(1,2));
<1>把现有的项目改成DLL
学会制作DLL以前,大多数程序员手中都积攒下来不少已经完成了的项目,如果现在需要把这些项目做成DLL而不是可执行文件,重新写一遍显然是没有必要的,只要按照下面的步骤对已有的项目文件进行修改就可以了:
① 打开项目文件(.DPR),删除单元底部begin和end.之间的所有语句(一般情况下这些语句是由Delphi自动生成的)。如果项目中没有用到Form,则从uses子句中删除表单单元(Form),然后转到第③步。
② 对项目进行修改,令除Main Form之外的所有Form都是动态生成的,这样我们只要在DLL输出的一个函数或者过程中生成Main Form,即可调用执行整个项目。我们假设Main Form的名字是MyMainForm,项目的名字是MyDll,现在在单元底部的begin语句之前加入一个过程,过程的名字为RunMyDll,这个过程将动态生成Main Form,从而运行整个项目。RunMyDll的写法如下:
procedure InitDll2;
begin
Application.CreateForm(TMyMainForm, MyMainForm);
MyMainForm.Show; //如果MyMainForm不可视则需要这一句.
end;
③ 如果想要输出其他函数或者过程,而原来的项目中没有,则可以在单元底部的begin语句之前加入这些代码。
④ 在单元底部的begin语句之前加入一个exports小节,然后写出所有想要输出的函数或过程的名字(最好指定索引号)。注意如果执行了第②步,一定要输出RunMyDll过程。
⑤ 将项目文件顶部的保留字program改为library。
⑥ 编译。
现在就可以在其他程序中调用本项目中的函数和过程了,只要执行RunMyDll就可以执行这个项目,和执行原来的可执行文件一模一样。 <2>创建一个引入文件
如果DLL比较复杂,则为它的声明专门创建一个引入程序单元将是十分有意义的,并且会使这个DLL变得更加容易维护。引入单元的格式如下:
unit MyImport; {Import unit for MyDll.Dll}
interface
procedure RunMyDll;
implementation
procedure RunMyDll;external 'MyDll' index 1;
end.
这样以后想要使用MyDll中的例程时,只要简单的在程序模块中的uses子句中加上MyImport即可。 <Back to Top> 5、DLL的初始化和善后工作
一般的DLL不需要做初始化和善后工作,因此大部分读者可以跳过这一节。但如果你想让你的DLL在被载入时先作一些初始设定,或者退出时释放资源,则可以有三种方法达到目的: <1>利用Unit的Initalization与Finalization这两个小节
可以在Unit的这两个小节中安排Unit的进入和退出,但是Program与Library并没有这两个部分,所以只能写在Unit中。 <2>利用ExitProc变量
在Library的begin..end.中间是可以写代码的,这里可以放置DLL初始化代码。如果想要做善后工作,则可以利用ExitProc变量。我们首先在初始化代码中把ExitProc中包含的默认的善后过程地址保存下来,然后把自定义的过程的地址赋给它,这样DLL退出时就会执行我们制定的程序;在自定义的过程的最后,把ExitProc恢复原来的默认值,以便DLL能够继续完成原来默认的善后工作。下面是示例:
library MyDLL;
...
OldExitProc: pointer;
...
procedure MyExitProc;
begin
... //善后程序
ExitProc := OldExitProc;
end;
...
begin
... //初始化程序
OldExitProc := ExitProc;
ExitProc := @MyExitProc;
end. <3>利用DllProc变量
和ExitProc一样,DllProc也是一个在Systemd单元中预定义的变量。在使用DLLProc时, 必须先写好一个具有以下原型的程序:
procedure DLLHandler(Reason: integer);
并在library的begin..end.之间, 将这个DLLHandler程序的执行地址赋给DLLProc中, 这时就可以根据参数Reason的值分别作出相应的处理。另外注意要将Windows单元加入uses子句。示例如下:
library TestDLL;
...
procedure MyDLLHandler(Reason: integer);
begin
case Reason of
DLL_Process_Attach: //整个DLL的初始化代码
DLL_Process_Detach: //整个DLL的善後程序
DLL_Thread_Attach: //当主叫端开始一个Thread时
DLL_Thread_Detach: //当主叫端终止一个Thread时
end;
end;
...
begin
... //初始化代码
DLLProc := @MyDLLHandler;
MyDLLHandle(DLL_Process_Attach);
end.
由上例可以知道,当DLL支援多进程(Thread)的处理时, DllProc非常适合使用。 <Back to Top> 6、DLL中的例外处理
在用Delphi制作DLL时, 在例外处理方面请留意以下三点: 如果uses子句中没有SysUtils话,无法使用例外处理。
如果DLL中没有对例外进行处理的话,这个例外会想完传导到主叫端的应用程序。如果该应用程序也是Delphi写的话, 这个例外可以由主叫端进行处理。
承上, 如果主叫端的程式不是Delphi或Borland C++ Builder,则例外以作业系统错误的形式来处理,例外编号是$0EEDFACE,ExceptionInformation中第一个进入点是例外发生的地址,第二个进入点是指向的Delphi例外物件的引用。
<Back to Top> DLL编写入门级,我最近也因使用HOOK的原因刚学起来。 动态链接库(DLL)是Windows中最重要的部分之一,Windows中的运
行程序可以共享DLL中的子例程,从而使应用程序可以共享代码,减少
内存占用。本文简要介绍用Delphi创建及使用DLL。 一、创建动态链接库 1.建立一个新的工程文件
由于此工程只是个库文件,因此并不需要Form。首先选择主菜单V
iew|Project Manage, 将自动生成的Unit1及Form1移去,然后选择Fil
e|Save Project As,将此工程取名为 Mydl.d pr存盘(命名可任意 ),
当系统提问是否保存Unit1时回答‘NO’,再选择View|Projectourc
e,将其代码修改如下:
library Mydll;
uses WinTypes;
begin
end.
此文件与一般工程文件主要不同之处在于将标识符"program"改
为"library"。
2.向动态链接库中加入被多个应用程序公用的子例程(过程及函
数 )
建立一个新的Unit,将被多个应用程序公用的子例程在这里声明
及实现。注意在这个Ui t的Interface部分声明的例程尾部要加关键
字"export",表示此例程能够被"引出",也就是能被其它应用程序调用
。例如:有一个公用函数Plus,其作用是将两个整数求和,此Unit的代
码如下:
Unit Content; {公用例程单元,命名可任意}
interface
function plus (a,b:integer):integer;export;
implementation
function plus (a,b:integer):integer;
begin
Result:=a+b;
end;
end. 3.引出公用例程
选择View|Project Source,在Mydll.dpr的uses部分之后加入:
exports
plus; {将公用例程引出}
完整的工程文件如下:
library Mydll;
uses WinTypes,
Content in ‘CONTENT.PAS’;
exports
plus;
begin
end.
以上就完成了DLL库的创建,选择Compile将其编译。
二、使用动态链接库
DLL中的资源可以被多个EXE文件公用,现在可以用Delphi建立多
个应用程序,共同使用y dll.dll中的函数Plus: 1.建立一个新的工程文件 Usedll.dpr, 移去所有的Unit及Form
。
2.为引用 Mydll.dll 中的函数Plus,建立一个新的Unit,其目的
是为了说明要引用的例程存在于哪个DLL库中(用关键字"external"),
此Unit的代码如下:
Unit useunit; {这是使用DLL的单元}
interface
function plus (a,b:integer):integer;
implementation
function plus; external ‘Mydll’;
{说明这个函数是在外部Mydll.dll库中实现的}
end.
可以看出,对于外部例程,在interface部分的声明与普通例程一
样,但是在implementai on部分要使用关键字"external",表示此例程
是在程序外部实现的。
3.在需要使用函数Plus的Unit中,只要在其Implementation部分
用Uses将useunit包含进来即可。
例如:新建一Form,加入Edit及Button控件,为Button增加OnClick
事件,此Form对应Uni的implementation代码如下:
implementation
{$R *.DFM}
uses useunit; {包含useunit单元}
procedure TForm1.Button1Click(Sender: TObject);
{Button1的OnClick事件}
begin
Edit1.Text:=IntToStr (Plus (10,20));
{使用DLL库中的函数}
end;
end.
将此工程编译,生成Usedll.exe,运行时按下Button即可看到Edit
控件的Text变成了30。
依上例可以建立多个EXE文件,共同使用Mydll中的函数Plus,由此
可以看出动态链接库的优越性,特别是在开发大型软件时,动态链接库
经常使用。
Exports
cn; //接口函数名
2.在窗体文件中定义接口函数
procedure cn(d_ip:string;d_sjk:String;d_zg:String;d_user:String;d_username:String;d_year:String;d_month:String);stdcall;
3.实现接口函数
var
Form11: TForm1;
begin
Application.Initialize;
Form11:=TForm1.Create(Application);
try
Form11.cndjpz1.ip:=Trim(d_ip);
Form11.cndjpz1.database:=Trim(d_sjk);
Form11.cndjpz1.zg:=Trim(d_zg);
Form11.cndjpz1.user:=Trim(d_user);
Form11.cndjpz1.username:=Trim(d_username);
Form11.cndjpz1.year:=Trim(d_year);
Form11.cndjpz1.month:=Trim(d_month);
Form11.Showmodal;
finally
Form11.Free;
End;
end;
以上就是dll的定义
以下是调用dll
dll2:=lj+'\dll\cn_yw_djlr.dll';
MyHandle2:=LoadLibrary(Pchar(dll2));
@yecx2:=GetProcAddress(MyHandle2,'cn');
yecx2(Trim(ip),Trim(sjk),Trim(zgbh),Trim(user),Trim(username),Trim(Date_year),Trim(Date_month));
Freelibrary(Myhandle2);