delphi 基础之三 编写和调用dll文件
delphi 编写和调用dll文件
Windows 的执行文件可以划分为两种形式程序和动态连接库 (DLLs)。一般程序运行是用.EXE文件,但应用程序有时也可以调用存储在DLL的函数。
在如下几种情况下,调用DLL 是合理的:
1) 不同的程序使用相同的DLL ,这样只需要将DLL 在内存中装载一次,节省了内存的开销。
2) 当某些内容需要升级的时候,如果使用DLL 只需要改变DLL 就可以了,而不需要把整个程序都进行变动。
3) 由于DLL 是独立于语言的,所以,当不同语言习惯的人共同开发一个大型项目的时候,使用DLL 便于程序系统的交流,当然,Delphi开发的DLL 也可以在诸如Visual BASIC,C++ 等系统中使用。
下面通过几个例子,说明Delphi开发动态连接库的方法和规范。
第一节 动态连接库的构建和调用方法
一、动态连接库构建
1.创建了一个动态连接库的基本模块
File---New---Other---DLL Wizard
library Project1;
{如果DLL输出的过程或函数带有长字符类型的参数,或者函数返回类型是长字符串或带有长字符串元素的构造类型,Object Pascal规定无论是DLL还是调用它的程序必须把ShareMem单元加到Uses部分。而ShareMem单元是从DelphiMM.DLL这个DLL中引入的接口单元,因此这种程序分发时必须带有DelphiMM.DLL。Delphi建议为了避免使用DELPHIMM.DLL,传递字符串信息时使用PChar或ShortString类型参数。(原文为英文) }
uses
SysUtils, Classes;
( 代码部分)
{$R *.res}
begin
end.
把工程名改为Math(Save Project as …),并写入必要的函数
library Math;
uses
SysUtils,
Classes;
function Mround (d:Double ):Double ;stdcall; //四舍五入函数:数学上的四舍五入函数不begin //同于Delphi的银行家四舍五入法
Result:=Int(d*100+0.5)/100;
end;
exports
Mround ;
{$R *.RES}
begin
end.
从这个例子中可以看出DLL 程序的几个规则:
1) 在DLL 程序中,输出函数必须被声明为stdcall,以使用标准的Win32 参数传递技术来代替优化的Register。参数的调用约定。调用约定如下:
指令 传递顺序 参数删除
stdcall 从左到右 函数方面
cdecl 从右到左 调用方面
Pascal 从左到右 函数方面
register 从左到右 函数方面
(说明:
register,默认,即是 唯一使用 CPU寄存器的参数传递方式,也是传递速度最快的方式; pascal: 调用协议仅用于向后兼容,即向旧的版本兼容;
cdecl: 多用于 C和 C++语言编写的例程,也用于需要由调用者清除参数的例程; stdcall: 和safecall主要用于调用Windows API 函数;其中safecall还用于双重接口。
2)所有的输出函数都必须列在exports子句下面,这使的子例程在DLL外部就可以看到。
exports
Mround[name ‘别名’] ;
列出了用户使用这个函数的接口名字。虽然别名不是必须的,但最好给个别名,以便用户程序更容易找到这个函数,同时还要指出Delphi 6.0取消了Delphi 5.0中允许使用的index ,如果还用Index指明接口名字,Delphi 6.0中将提示错误。
实例中给出了messagebox提示方法,主要想说明一个问题:
而messagebox(0,’’,’’,mb_ok) 是Windows提供的API 函数,做出的程序会比较小。
Showmessage(‘’),是VCL 提供的函数,由于多次编译VCL,做出的程序会比较大。
这就是说,编写DLL 程序的时候,要尽量避免多次编译VCL 。作为一个实例,这里把两种方法都列出来了。
2.保存
3.编译:Projrct---Build Math.DLLl
这就完成了一个简单的动态连接库的编写。
二、 动态连接库的调用
1.静态调用
首先 (如果在窗体中要求在implementation下声明,本例直接在程序文件dpr中运行,不带窗体)做调用声明 function Mround(d: Double): Double; stdcall; external 'Math.dll';
完整调用程序如下:
program test;
uses
Windows,
Messages,
SysUtils,
Forms,
Dialogs,
StdCtrls;
var
d: Double;
info: Double;
{$R *.res}
begin
Application.Initialize; /程序初始化并开始运行
d := StrToFloat(inputbox('输入窗口', '请输入要四舍五入的数字', '0'));
MessageBox(0, pchar(floattostr(Mround(d))), '结果', MB_OK orMB_ICONINFORMATIO
{调用dll函数}
Application.Run;
end.
2.动态调用(实例)
Type TShowForm = function (AHandle: THandle; ACaption: String): BOOL; StdCall; {在此创建一个函数类} EDLLLoadError = class(Exception);//同时创建一个出错记录类
TMAINCLTR = class(TForm) //这里不变,系统自动生成(调用Dll窗体的应用程序的窗体类)
private
{ Private declarations }
public
{ Public declarations }
end;
var
MAINCLTR1: TMAINCLTR;
implementation
{$R *.DFM}
//函数、过程定义
Procedure TMAINCLTR.ToolButton1Click(Sender: TObject); //按钮的调用事件:调用过程
var LibHandle: THandle;
ShowForm: TShowForm;
begin
Application.Title:=' DLL文件测试程式';
{尝试装入DLL文件}
LibHandle := LoadLibrary('MGRFORM.DLL');
try
if LibHandle = 0 then
raise EDLLLoadError.Create('Unable to Load DLL(无法成功装入MGRFORM.DLL)');
@ShowForm := GetProcAddress(LibHandle, 'ShowForm');
if not (@ShowForm = nil) then
ShowForm(Application.Handle, '人事资料管理')//呼叫出窗体
else
RaiseLastWin32Error;
finally
FreeLibrary(LibHandle); // Unload the DLL.
end;
end;
============== END ==================
第二节 DLL 中的Delphi窗体
一、利用DLLs实现窗体重用的步骤是:
1.在集成开发环境(IDE)中,按自己的需要设计一个窗体;
2.编写一个用于输出的函数或过程。在该函数或过程中,设计的窗体被实例化;
方法是:
1)首先按普通方法制作窗体,不过在interface区域,对接口函数做如下声明
function Createform(capt:string):string;stdcall;
2)在implementation下加入接口函数
function Createform(capt:string):string;stdcall;
var Form1: TForm1;
begin
form1:=Tform1.Create(application); 设计的窗体被实例化
{传递一个Application参数,用它建立Form.}
form1.show;
form1.caption:=capt;
end;
3.重复步骤1、2,直到完成所有重用窗体的设计;
4.打开File---New---Other---DLL Wizard建立Dll文件。添加保留字exprots。exports 后是输出函数名或过程名。(生成窗体)
5.编译生成DLLs文件;要声明:
uses
unit1 in ’unit1.pas’;
exports {写入接口标示符}
Createform name ’Myform’;
6.在其它应用程序中调用重用窗体。
重用窗体的调用同一般DLLs函数或过程的调用完全一致
DLL文件在Delphi的创建及调用
一.函数过程的写法:
library ForstDLL;
uses
SysUtils,
Classes;
{$R *.RES}
// 1.定义函数具体过程和输出接口方式
// --------------------------------
// 函数 1
// 功能:数据3倍放大函数
// --------------------------------
function PenniesToSoins(SourceResult:Integer):Integer;stdCall;
begin
if SourceResult>0 then
Result:=SourceResult*3 //结果存放于Result
else
Result:=SourceResult;
end;
exports
PenniesToSoins; //2.函数输出口定义
end.
二.在DLL中创建Form
=======================
1.创建DLL工程,及加入设置好的Form
library MGRFORM;
uses
SysUtils,
Classes,
MGRPERFM in 'MGRPERFM.pas' {FormPERSON};//1.Form的代码(与一般的Form一样)
{$R *.RES}
exports
ShowForm;//2.函数输出口定义
begin
end.
2. 在DLL设定的Form的设置
===========================================
unit MGRPERFM;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ComCtrls, ToolWin, ImgList;
type
TFormPERSON = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
//此变量不再用,给其改个地方,放在implementation中。如下(改变之一)
//var
// FormPERSON: TFormPERSON; {宣布Form函数出口}//改变之二
function ShowForm(AHandle: THandle; ACaption: String):BOOL; StdCall;
{窗体实例化函数}
implementation
{$R *.DFM}
//函数、过程定义
function ShowForm(AHandle: THandle; ACaption: String):BOOL;
var
FormPERSON: TFormPERSON; //定义窗体类(上面的放到了此处)
begin
// Copy application handle to DLL's TApplication object
//拷贝应用程序句柄给DLL的应有程序对象
Application.Handle := AHandle;
FormPERSON := TFormPERSON.Create(Application);//创建控件TForm
try
FormPERSON.Caption := ACaption;
FormPERSON.ShowModal;//显示此Form
// Pass the date back in Result
Result := False; //返回成功值
finally
FormPERSON.Free;
end;
end;
三.DLL中函数及窗体的调用
==========================
1.调用方法一:静态引用
implementation //在此的下方写明调用函数的DLL
{$R *.DFM}
//引用DLL内函数
function PenniesToSoins(SourceResult:Integer):Integer;
StdCall;external 'FORSTDLL.DLL';
........
2.调用方法二:动态引用
==============
type //在此创建一个函数类
// -------------------------------
{ Forst, define a procedural data type, this should reflect the
procedure that is exported from the DLL. }
{ Create a new exception class to reflect a failed DLL load }
TShowForm = function (AHandle: THandle; ACaption: String): BOOL; StdCall;
EDLLLoadError = class(Exception);//同时创建一个出错记录类
// -------------------------------
TMAINCLTR = class(TForm) //这里不变,系统自动生成
......
procedure TMAINCLTR.ToolButton1Click(Sender: TObject);
var //按钮的调用事件:调用过程
LibHandle: THandle;
ShowForm: TShowForm;
begin
Application.Title:=' DLL文件测试程式';
{尝试装入DLL文件}
LibHandle := LoadLibrary('MGRFORM.DLL');
try
if LibHandle = 0 then
raise EDLLLoadError.Create('Unable to Load DLL(无法成功装入MGRFORM.DLL)');
@ShowForm := GetProcAddress(LibHandle, 'ShowForm');
if not (@ShowForm = nil) then
ShowForm(Application.Handle, '人事资料管理')//呼叫出窗体
else
RaiseLastWin32Error;
finally
FreeLibrary(LibHandle); // Unload the DLL.
end;
end;
============== END ==================
delphi 基础之三 编写和调用dll文件的更多相关文章
- java中调用dll文件的两种方法
一中是用JNA方法,另外是用JNative方法,两种都是转载来的, JNA地址:http://blog.csdn.net/shendl/article/details/3589676 JNativ ...
- LabVIEW如何方便地调用DLL文件
转自:http://bbs.elecfans.com/jishu_469502_1_1.html LabVIEW调用DLL文件 LabVIEW支持通过调用DLL文件的方式与其它编程语言混合使用.比 ...
- C++ exe调用dll文件
生成dll程序 extern "C"_declspec(dllexport) void maopao(int *p,int count);void maopao(int *p,in ...
- Java调用.dll文件
因为项目的需求,要在JAVA项目中调用Windows的Dll(动态链接库)文件,之前用Jni调用过C写的Dll文件,比较麻烦,这里不多说,网上也有很多这方面的文档.在网上找到一个开源的组件JNativ ...
- C#调用Dll文件中方法的简单应用
参考:http://www.cnblogs.com/Asuphy/p/4206623.html 直接看代码,最简单的引入,只需要3步: using System; using System.Colle ...
- delphi编写与调用DLL(delphi7下测试通过)
http://blog.sina.com.cn/s/blog_4dbbf76f01000anz.html delphi编写DLL 下面在delphi中编写一个简单的dll,在该dll中只有一个max函 ...
- C#.NET常见问题(FAQ)-如何将cs文件编译成dll文件 exe文件 如何调用dll文件
比如我要把TestDLL.cs文件编译成dll文件,则在命令提示符下,输入下面的命令,生成的文件为TestDLL.dll csc /target:library TestDLL.cs 注意前提是你安装 ...
- C#.NET如何将cs文件编译成dll文件 exe文件 如何调用dll文件
比如我要把TestDLL.cs文件编译成dll文件,则在命令提示符下,输入下面的命令,生成的文件为TestDLL.dll csc /target:library TestDLL.cs 注意前提是你安装 ...
- 如何写类库方法、属性等的注释,才能在其他地方调用dll文件时,在代码里出现智能提示?
我的本意是想整理下以往写过的代码库,给自己的代码增加复用性.一段时间后,可能自己对写过的代码是什么含义会忘掉,或者别人看自己的代码, 增加可懂性的考虑,决定要添加注释.(好像语句不通:)可是发现,在其 ...
随机推荐
- (转)如果知道dll文件是面向32位系统还是面向64位系统的?
本文为转载文章,原文地址:http://www.cnblogs.com/qguohog/archive/2011/09/13/2174897.html,仅仅是记录供后续使用,如有侵权请通知删除. 在发 ...
- Appium + Python -------------元素定位
说在前面 1.https://github.com/appium/python-client/tree/master/test 里面有一些test ,可以看看,研究研究 2.学会使用 uiautom ...
- 【Robot Framework】robot framework 学习以及selenium、appnium、requests实践(二)
之前简单的介绍了如何使用RF,在这一节里,主要介绍下Selenium2Library的API, 在线的地址是http://robotframework.org/Selenium2Library/Sel ...
- Flash图表控件FusionCharts自定义图表y轴最大/最小值
自定义图表y轴的最大值和最小值 用户可以使用FusionCharts图表中<chart>元素的yAxisMaxValue和yAxisMinValue属性设置图表限制. 示例: <ch ...
- 【PL/SQL练习】命名块: 存储过程、函数、触发器、包
创建时定义名称 2.可以被Oracle server 保存 3.可以被任何程序调用 4.可以被共享 存储过程: 1.不带参数的存储过程: SQL> create or replace proce ...
- 请添加 MIME 映射
HTTP 错误 404.3 - Not Found 由于扩展配置问题而无法提供您请求的页面.如果该页面是脚本,请添加处理程序.如果应下载文件,请添加 MIME 映射. 以管理员运行命令:C:\Wind ...
- HTML DOM(学习笔记一)
嗯,工作也有一段时间了,对编程的认识也深入了一些,以前认为HTML/CSS/JAVASCRIPT是比较简单的,看网上的教程就可以了,W3C是我学习这些知识常去的一个网站,非常感谢她让我学习到了更多的一 ...
- java swing 使用按钮关闭窗口
目的是给JButton添加点击操作,使指定JFrame窗口关闭. 网上不少说法是采用frame.dispose();的方法 但是采用frame.dispose();并没有使添加在frame上的wind ...
- PAT1075. PAT Judge
//终于A了,不难却觉着坑多的的题,注意-1的处理,感觉我是受memset置0的束缚了,可以把初试成绩置-1.就不用debug怎么久,注意对于-1的处理,不然漏洞百出 #include<cstd ...
- 八、Linux下的网络服务器模型
服务器设计技术有很多,按使用的协议来分有TCP服务器和UDP服务器,按处理方式来分有循环服务器和并发服务器. 在网络程序里面,一般来说都是许多客户对应一个服务器,为了处理客户的请求,对服务端的程序就提 ...