说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

Delphi 插件创建、调试与使用应用程序扩展

HTML文档下载 WORD文档下载 PDF文档下载
Delphi 插件创建、调试与使用应用程序扩展

有没有使用过Adobe Photoshop如果用过,你就会对插件的概念比较熟悉。对外行人来说,插件仅仅是从外部提供给应用程序的代码块而已(举个例子来说,在一个DLL中)。一个插件和一个普通DLL之间的差异在于插件具有扩展父应用程序功能的能力。例如,Photoshop本身并不具备进行大量的图像处理功能。插件的加入使其获得了产生诸如模糊、斑点,以及其他所有风格的奇怪效果,而其中任何一项功能都不是父应用程序自身所具有的。

对于图像处理程序来说这很不错,可是为什么要花偌大的力气去完成支持插件的商业应用程序呢?假设,我们举个例子,你的应用程序要产生一些报表。你的客户肯定会一直要求更新或者增加新的报表。你可以使用一个诸如Report Smith的外部报表生成器,这是个不怎么样的解决方案,需要发布附加的文件,要对用户进行额外的培训,等等。你也可以使用QuickReport,不过这会使你身处版本控制的噩梦之中——如果每改变一次字体你就要Rebuild你的应用程序的话。

然而,只要你把报表做到插件中,你就可以使用它。需要一个新的报表吗?没问题,只要安装一个DLL,下次应用程序启动时就会看见它了。另外一个例子是处理来自外部设备(比如条形码扫描器)的数据的应用程序,为了给用户更多的选择,你不得不支持半打的各种设备。通过将每种设备接口处理例程写成插件,不用对父应用程序作任何变动就可以获得最大程度的可伸缩性。

入门

在开始写代码之前最重要的事情就是搞清楚你的应用程序到底需要扩展哪些功能。这是因为插件是通过一个特定的接口与父应用程序交互的,而这个接口将根据你的需要来定义。在本文中,我们将建立3个插件,以便展示插件与父应用程序相交互的几种方式。

我们将把插件制作成DLL。不过,在做这项工作之前,我们得先制作一个外壳程序来载入和测试它们。图1显示的是加载了第一个插件以后的测试程序。第一个插件没有完成什么大不了的功能,实际上,它所做的只是返回一个描述自己的字符串。不过,它证明了很重要的一点——不管有没有插件应用程序都可以正常运行。如果没有插件,它就不会出现在已安装的插件列表中,但是应用程序仍然可以正常的行使功能。

我们的插件外壳程序与普通应用程序之间的唯一不同就在于工程源文件中出现在uses子句中的Sharemem单元和加载插件文件的代码。任何在自身与子DLL之间传递字符串参数的应用程序都需要Sharemem单元,它是DelphiMM.dll(Delphi提供该文件)的接口。要测试这个外壳,需要将DelphiMM.dll文件从Delphi\Bin目录复制到path环境变量所包含的路径或者应用程序所在目录中。发布最终版本时也需要同时分发该文件。

插件通过LoadPlugins过程载入到这个测试外壳中,这个过程在主窗口的FormCreate事件中调用,见图2。该过程使用FindFirst和FindNext函数在应用程序所在目录中查找插件文件。找到一个文件以后,就使用图3所示的LoadPlugins过程将其载入。

{ 在应用程序目录下查找插件文件 }

procedure TfrmMain.LoadPlugins;

var

sr: TSearchRec;

path: string;

Found: Integer;

begin

path := ExtractFilePath(Application.Exename);

try

Found := FindFirst(path + cPLUGIN_MASK

0

sr);

while Found = 0 do begin

LoadPlugin(sr);

Found := FindNext(sr);

end;

finally

FindClose(sr);

end;

end;

{ 加载指定的插件 DLL. }

procedure TfrmMain.LoadPlugin(sr: TSearchRec);

var

Description: string;

LibHandle: Integer;

DescribeProc: TPluginDescribe;

begin

LibHandle := LoadLibrary(Pchar(sr.Name));

if LibHandle <> 0 then

begin

DescribeProc := GetProcAddress(LibHandle

cPLUGIN_DESCRIBE);

if Assigned(DescribeProc) then

begin

DescribeProc(Description);

memPlugins.Lines.Add(Description);

end

else

begin

MessageDlg(’File "’ + sr.Name + ’" is not a valid plug-in.’

mtInformation

[mbOK]

0);

end;

end

else

MessageDlg(’An error occurred loading the plug-in "’ +

sr.Name + ’".’

mtError

[mbOK]

0);

end;

LoadPlugin方法展示了插件机制的核心。首先,插件被写成DLL。其次,通过LoadLibrary API它被动态的加载。一旦DLL被加载,我们就需要一个访问它所包含的过程和函数的途径。API调用GetProcAddress提供这种机制,它返回一个指向所需例程的指针。在我们这个简单的演示中,插件仅仅包含一个名为DescribePlugin的过程,由常数cPLUGIN_DESCRIBE指定(过程名的大小写非常重要,传递到GetProcAddress的名称必须与包含在DLL中的例程名称完全一致)。如果在DLL中没有找到请求的例程,GetProcAddree将返回nil,这样就允许使用Assigned函数测定返回值。

为了以一种易用的方式存储指向一个函数的指针,有必要为用到的变量创建一个特定的类型。注意,GetProcAddress的返回值被存储在一个变量中,DescribeProc,属于TpluginDescribe类型。下面是它的声明:

type

TPluginDescribe = procedure(var Desc: string); stdcall;

由于过程存在于DLL内部,它通过标准调用转换编译所有导出例程,因此需要使用stdcall指示字。这个过程使用一个var参数,当过程返回的时候它包含插件的描述。

要调用刚刚获得的过程,只需要使用保存地址的变量作为过程名,后面跟上任何参数。就我们的例子而言,声明:

DescribeProc(Description)

将会调用在插件中获得的描述过程,并且用描述插件功能的字符串填充Description变量。

构造插件

我们已经创建好了父应用程序,现在该轮到创建我们希望加载的插件了。插件文件是一个标准的Delphi DLL,所以我们从Delphi IDE中创建一个新DLL工程,保存它。由于导出的插件函数将用到字符串参数,所以要在工程的uses子句中把Sharemen单元放在最前面。图4列出的就是我们这个简单插件的工程源文件。

uses

Sharemem

SysUtils

Classes

main in ’main.pas’;

{$E plg.}

exports

DescribePlugin;

begin

end.

虽然插件是一个DLL文件,但是没有必要一定要给它一个.DLL的扩展名。实际上,一个原因就足以让我们有理由改变扩展名:当父应用程序寻找要加载的文件时,新的扩展名可以作为特定的文件掩模。通过使用别的扩展名(我们的例子使用了*.plg),你可以在一定程度上确信应用程序只会载入相应的文件。编译指示字$X可以实现这个改变,也可以通过Project Options对话框的Application页来设置扩展名。

第一个例子插件的代码是很简单的。图5显示了包含在一个新单元中的代码。注意,DescribePlugin原型与外壳应用程序中的TpluginDescribe类型相一致,使用附加的export保留字指定该过程将被导出。被导出的过程名称也将会出现在主工程源代码的exports段中(在图4中列出)。

unit main;

interface

procedure DescribePlugin(var Desc: string);

export; stdcall;

implementation

procedure DescribePlugin(var Desc: string);

begin

Desc := ’Test plugin v1.00’;

end;

end.

在测试这个插件之前,要先把它复制到主应用程序的路径下。最简单的办法就是在主目录的子目录下创建插件,然后把输出路径设置为主路径(Project Options对话框的Directories/Conditionals也可以作这个设置)。

调试

现在介绍一下Delphi 3中一个较好的功能:从IDE中调试DLL的能力。在DLL工程中可以通过Run paramaters对话框指定某程序为宿主应用程序,这就是指向将调用DLL的应用程序的路径(在我们这个例子中,就是刚刚创建的测试外壳程序)。然后你就可以在DLL代码中设置断点并且按F9运行它——就像在一个普通应用程序中做的那样。Delphi会运行指定的宿主程序,并且,通过编译带有调试信息的DLL,把你指引到DLL代码内的断点处。

Android过后Chrome OS又是如何开发? Android安全模型导致开发时功能受限 Android导出一个JAR库 APK汉化原理及方法 APK文件格式分析,Android反编译入门(一) ApiDemos中的Android Widget例子解析 APK签名导出向导 - Use the Export Wizard 剖析Android自带Widget - Music播放器 剖析Android自带Widget - Clock指针钟表 C#取得Excel工作簿工作表名称 C#中用Automation自动化方式对Excel的操作 VB如何打开或保存为有密码保护的Excel sheets工作表 VB在Excel表格文件中搜索指定内容 VB复制Excel表到另外一个Excel中 Java实现生成网站快照缩略图片 php实现生成网站快照缩略图片 C#实现生成网站快照缩略图片 VB比较两个Excel表格的内容 VB实现Excel按列或行排序 VB删除EXCEL表格指定行 用vb.net写的验证码识别代码 VB删除EXCEL表格指定列 Oracle数据库Windows 2003环境自动备份批处理 VB通过ADODB连接EXCEL表格文件读取数据 使用VBScript卸载软件 Discuz X2用户注册过程SQL Android手机参数表 用jQuery改变图片(image src) 用std::atomic實現簡單的讀寫鎖 ChinaPay网上支付网关.NET开发 VOB生成IFO文件用nero刻录DVD详解 reintroduce和overload有什么区别吗? 关于Javadoc的使用 请问如何在程序运行时根据分辨率等比例调整窗体,控件和字体的大小,使得在任何分辨率下均满屏显示 世界杯“蓝色厄运”理论:英格兰胜巴西 德国淘汰美国(转贴) 关于treeview的节点事件问题,把在下高糊涂了,请高手明示。 要毕业了。。。 BCB中数据库控件的错误扑捉怎么写?比如数据库不存在? 请教如何在调运api函数时,建立缓冲区 SetEvent函数调用带来非法内存访问,扭心的问题。 文件和字符混和上传问题 诸位大虾请帮忙? 各位大虾:哪里有vb.net下载啊? 请教:“开始”菜单中的“文档”菜单不见了! 急!急!急! 一个关于模式对话框的问题 oracle 用sql plus /spool 输出 查询结果时怎么把 查询sql 本身 去掉(不输出) ? 世界杯“蓝色厄运”理论:英格兰胜巴西 德国淘汰美国(转贴) !!请 “arxing(阿行)”回答!!about 对象池!!!! 各位老大,怎样将给定的中文根据拼音排序? access97中的报表中显示中文字段时为什么是乱码,怎样解决,急呀!老大们!! 急:在哪儿可以下载java的反编译器jad.exe????? 请帮忙 做过数据分析的高手请进。。。(我感觉很头疼的一个问题!) 共享Interent怎样实现? 请问绿色程序是如何制作的??? Windows API和C 请问怎样把form中的picture属性中的图片删除? 请看看这个问题? 中程书上的错误?(清华) 各位大虾过来看看,救救我啊! flash简单问题 已知IP,求计算机名 求备份方案,oracle 数据库! 求解決方案:怎樣在運行狀態下增加或取消文本輸入框的滾動條. 大家发表些看法! 各位 帮帮忙,关于答复文档的 如何获取手机中的短消息发送结果状态报告,需要懂一点手机短信的朋友 有没有办法去掉jre1.4下向JTextField输入中文时弹出来的那个恶心的输入窗口? 将web工程加到sourcesafe的问题,十万火急,帮忙解决一定给分,分数不够可以其他方式给。 在sqlserver中有字段类型为image,如何往该字段放图象?200分 基础问题 NT ,when boot ,can not find system 关于internet上的控件打包??????????????? 请各位高手帮忙解决!谢谢!! 谁能告诉我那几个网络论坛比较好 如何实现socket 的多线程 高手请这边来瞧瞧 如何在ODBC应用程序中使用CListView? excelapplication控件???教教我吧,我不知道为什么?很简单的。 关于internet上的控件打包??????????????? 谁知道autovuex.ocx 控件(可以显示CAD等图形)哪儿有下载??拒绝up 大家都用VC吧,这个怎么实现? 在长1.6m,宽1.2m的长方形三合板上,裁出半径是20cm的圆最多可裁多少个?哪位认识会啊 急用! 已知圆M:(x+cosA)的平方+(y-sinA)平方=1,直线L:y=kx则:对任意的角A,必存在k,使直线L和圆M相切;对任意的k,必存在角A,使直线L和圆M相切.请问上面两句话是否都正确,为什么/ 一个长30厘米,宽20厘米的长方形能剪几个半径为6厘米的圆 在长1.6米,宽1.2米的长方形三合板上,裁出半径是20厘米的圆,最多可裁多少个? 已知圆C:(x+cosA)^2+(y-sinA)^2=1,那么直线L:y=kx,则下列说法正确的是1,对于已知圆C:(x+cosA)^2+(y-sinA)^2=1,那么直线L:y=kx,则下列说法正确的是(1)对于任意实数A,必存在实数k,使得直线l与M相切; 半径1厘米的圆沿长方形边缘滚,长方形长30厘米,宽20厘米.当硬币滚回原来位置,圆心经过的路程是几厘米 361800欧元英文大写是316800 为什么万里长城要设烽火台 一个环形零件,外圆半径长4厘米,内圆半径长1厘米,圆环的面积是( )平方厘米? 欧元金额怎么大写比如说USD是US dollars那么ERU 要怎么写 胃液中含有盐酸,胃酸过多的人服用适量的小苏打能治疗胃酸过多,反应的离子方程式是_______________ 半命题作文其实我也很—— 4点之前 总价48963.6欧元,英文大写怎么写 四字的有人生哲理的词语最好是能够用做网名的 服用含小苏打的药物可治疗胃酸过多,其反应的化学方程式为______________ 欧元大写EUR 2493.69EUR 10338.56分别是怎样大写 优美的语句(有人生哲理的), 甲乙两同学的身高都是1.6乘10的2次方,但甲说比乙高9CM,有这种可能吗?若有请举例说明. 体积和容积有什么区别? 用铁皮焊10个底面是边长20厘米的正方形,高是3分米的长方体无盖水桶,至少需用多少铁皮 感谢我的(XX) 小孩子把玩具当朋友,我们把朋友当玩具.? 甲乙两学生的身高近似值都是1.7x10的2次方cm,但甲说比乙高9m,问有这种可能吗? 求:那一次,我很XX 550—600字希望六要素齐全 并且题材不泛滥 不要转载 我能看出来 现在的小朋友是喜欢迪迦奥特曼玩具的人多还还是戴拿奥特曼玩具的人多又或是喜欢天线宝宝玩具的人多本人需要筹备一批玩具礼品,请问现在的小朋友是喜欢迪迦奥特曼玩具的人多 还还是 关于爱学习爱劳动的手抄报 修一条路,甲队单独做要12天,乙队单独做每天可修全长的1\18,甲队先单独修了2天,余下的两队合修,完成任务时,乙队修了几天? 1,562,997.8欧元用英文怎么大写 为什么治疗胃酸过多用碳酸氢钠而不用碳酸钠? 用铁皮焊15个底面是边长25厘米的正方形,高4分米的长方体无盖水桶,至少要用多少铁皮?(列一下公式) 有一长方形,长为82cm,宽为55cm,在这个长方形上取直径为20cm的圆,请问最多能取几个 为什么治疗胃酸过多不用苏打而用小苏打还有为什么洗涤时不用小苏打而用苏打 xx,我为你自豪(初中作文)今天就用! 一块长方形木板,长3.2米,宽0.8米,把它据成半径是20cm的圆,最多能据多少个? 使用“春天”“夏天”“秋天”“冬天”四个词,运用修辞方法写一段表达人生感悟的文字.(45字内) 用一张长12.5厘米、宽7.2厘米的长方形彩纸能剪多少个半径是1厘米的圆?说出理由 帮我做一道简单的编程题目(pascal)给出一列数:[(1*1)/2008],[(2*2)/2008],[(3*3)/2008],[(4*4)/2008]…[(n*n)/2008],给出n,要你求出这列数中不同的个数有多少个.(n 使用春天,夏天,秋天,冬天.运用一定修辞手法写一段表达人生感悟的文字!要求修辞合理,语言连贯,用春天,夏天,秋天,冬天.运用一定修辞手法写一段表达人生感悟的文字!要求修辞合理,语言连贯 一张长方形的彩纸,长是28厘米,宽是25厘米,最多能剪多少个半径是2厘米的圆? 幼儿园把新购进的的一批玩具分给小朋友.幼儿园把新购进的的一批玩具分给小朋友,若每人3件,那么还剩余59件,若每人5件,那么最后一个小朋友分到玩具,但不足4件,这批玩具共几件? 使用“春天”“夏天”“秋天”“冬天”写一段表达人生感悟的文字,要求修辞合理,语言连贯,结句带有总结 一张彩纸长6厘米,宽4厘米,最多能剪多少个半径为1厘米的圆? 小明用一张长32cm宽20cm的长方形纸最多能剪成()半径为2cm的圆形纸片 用春天、夏天、秋天、冬天.运用修辞手法写一段人生感悟.45字内 一张长方形彩纸长10厘米,宽9厘米,最多能剪多少个半径是1厘米的圆? 30cm长20cm宽长方形剪半径2cm的圆能剪几个?小孩六年级的题,他说是35个,可我认为最少是36个,谁对? 谁知道郑启华的PASCAL程序设计第五章习题答案用函数解 输入a,b,c,计算M.M=max(a,b,c)/(max(a,b,c)*max(a,b,c)) 将求三个数的最大数max(x,y,z) 1.抄一份稿件,甲单独抄用四分之一小时完成,乙单独抄用五分之一小时完成,甲乙合抄用()小时可以完成甲的工作效率是乙的( ).2.一项工程,甲乙合作10天完成,若甲单独干18天完成,甲比乙单 A为任意实数,求直线x*cosA+y*sinA=cosA+sinA围成的面积大小 一个底面半径是8厘米的圆柱形容器中装有一些水,将一个圆锥放入容器完全浸入水中,这时水面上升了5厘米. 一份稿件,甲独抄5天可以抄完全部的1/4,乙独抄15天可以完成,现在甲乙合抄全部稿件的2/3,需要几天抄完?现谢过了! 形容文章的思想感悟和文字都很美的词? 一个底面半径是8厘米的圆柱形容器中装有一些水,将一个圆锥放入容器中,完全浸入水中,这时水面上升了5厘米求圆锥体积. 一份稿件如果甲独抄5天可以抄完全部的1/4乙独抄15天可以完成现在甲乙合抄全部稿件的2/3需要几天抄完? 请使用春天 夏天 秋天和冬天四个词语 运用一定的修辞手发写一段表达人生感悟的文字要求:修辞合理 语言连贯 结句带有总结性 不少于45个字 甲乙两名学生的身高都是1.70×10²cm,但甲学生说他比乙高9cm,有这种可能吗?请举例说明必须举例 若6-根号13的小数部分和整数部分分别是X,Y求2X-Y的值 还要有作文 圆C:(x-cosa)^2+(y-sina)^2=25与直l:(2m+1)x+(m+1)y-7m-4=0的位置关系是? 什么虫被称为气候者,什么虫被称为建筑工程师?
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘