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

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代码内的断点处。

令人意外:前Windows部门总裁将去哈佛教书 舒迅:产品经理必读的九步法 独家爆料:Facebook移动客户端开发揭秘 一个独立开发者的自白:我如何在一年赚得60万美元 Dropbox收购Snapjoy 意欲打造媒体中心 2012世界“末日”:有经过正确的分析吗?! 23.5亿美元!谷歌出售摩托罗拉机顶盒业务 两家巨头相继放弃移动广告,移动广告形势堪忧? 应用洗牌,还能免费多久?Google推出iPad版Quickoffice 2012末日APP推荐 求生自救必备! Windows8上网利器 不卡死的IE10浏览器 为何Java程序员学习Clojure有优势? 我们是如何阅读代码的? “热水冷却”技术将主导美国国防部数据中心改造 程序员想玩转大数据:需要知晓的12种工具 2012年谷歌应用商店增长迅速 但苹果最赚钱 Apple微软Google都在竞购一家创业公司 违反新条款?苹果强行下架AppShopper 2012移动开发教程盘点:最棒的国外游戏开发站 重思JavaScript的好与坏 细数那些 NeXT 留给 OS X 的遗产 一张图让你知道大数据的生态系统 Camera360开放SDK:拍照和滤镜一行代码搞定 一周消息树:计算机将拥有五感 人类面临威胁? 通晓数学的人就可以当程序员吗? 360发布企业版4.0 可自定义软件白名单 不要总是依赖机器 MongoDB扩展彰显分片功夫 Dell与HP的OpenStack的战略:渠道对抗SLA 路况电台王雷:未来车载系统会是Android的天下 移动周报:2012移动开发工具系列盘点 谷歌不愿错失机会 Android或不再成它人独享 public static void main(String args[])与public static void main(String[] args)有什么区别? WAIT_ABANDONED 我想捐点东西,但是不知道该怎么捐(笑话我的请勿进) 一个关与jspsmartload组件的问题 如何用修改组册表来提高WIN98的安全性?不用其他工具 CString 能存放的字符串最长是多少字节? 我想在[root@localhost /root]#提示符下面键入./my.sh就能进入/home/www/download/目录 hook的问题 server2000恢复时,遇到了一个问题 要怎样才能得分啊? Delphi修改注册表 怎么样重画面版 在VB里调用API打开HTML文件 如何使程序运行时隐藏dialog窗口? 关于datawindow脚本内容! AtlReportError问题 Oracle8i Release 8.1.5 原版电子文档(pdf)--- 谁要!!!!! 如何用delphi实现图像网络传输与存储?请高手介绍方法,包括用什么库,通过TCP/IP怎么办? 请教打印问题 一个菜鸟的提问 在BEAN中,System.out.println("yyy")为什么不能输出呀? 局域网接ADSL,如何限制用户上互联网? 如何不安装oracle的客户端用来连接服务器上的oracle数据库 请问哪有VC关于ADO编程的书籍下载? 关于组件的问题? 用DAO连接数据库,在我的机器上运行没问题,但在其它机器上一运行就挂 谁能告我liulee的个人网页地址呀?? 关于在浏览器中直接运行VB程序的问题 十万火急,我遇上两个奇怪的问题。答者重谢。 请问:如何使用toString? 各位,期待已久的简单任务来了!又是100分!(SQL Server 2000) 好累啊,想放弃了,但又无法回头! Java中,Inner class可不可以使用final修饰符? 谁能告我liulee的个人网页地址呀??急 请教如何在程序运行时修改dbgrid控件options属性中的关于多选控制和整行选择的两个属性? 请推荐UNIX方面的书籍 如何使用toString()方法,谢谢 菜鸟系列:一个简单的编译错误,但我不明白!救命啊!!!! 这就是标准?SJ/T11234 SJ/T11235培训纪实 在哪里看我现在linux系统中用的应用软件的版本号?比如wu-ftp sendmail等等! 操作系统版本不同问题 BCB下怎么调用WINDOWS API函数,急 cpu风扇不转的问题…… 游戏开发的高手或者3维建模的高手,是怎样开发人物模型的呢? 今天下午有没有去微软发布会的????马上回答 关于字体问题!请教会者不难者!!!!!!!! 請問怎麼定義小一點得符點數???? ReadFile超时返回什么? 我的机器装了2000server,2000profession 和NT4.0,现在机器空间不够想把nt4.0和2000profession 卸载,请问应该如何进行?? 怎样用PB代码实现在MDI窗口里的 Ctrl + Tab 的功能 ? 如何将静态库加入项目中,有头文件,SETING出也加入,为何说和系统的库重复定义 青蛙死了为什么会动 二氧化碳和次氯酸钙反应吗?方程式是?该实验可说明相关酸的酸性的强弱顺序是? 碱石灰是用来干什么的? 人们向青蛙玩笑的扔石头、青蛙却认真的死了.我好想明白意思,但是无法表达.谁的文学功底好帮我具体解释一下这句话的内在含义,这句话在什么样的场合什么样的对话中可以使用. 1J/s=多少w 关于压力那的图钉简短的面积是0.2mm²,钉帽的面积是0.75cm²,在向墙里按图钉时,手对帽的压强是6×10四次方Pa,问:(1)手对钉帽的压力是多少?(2)钉尖对墙的压力是多少? 高中有正负的物理量有哪些? 计算机程序与实际生活应用要写报告,求一简单的生活例子 谢谢 一艘船从长江驶入大海浮力改变吗?我认为改变,可老师和我说说浮力不变.我想知道为什么?浮力大小不是和液体的密度,还有浸在液体中的深度有关吗.液体密度变大了,浮力不也变大了吗?那位 高中物理 匀变速直线运动的物理量正负总是混乱加速度 速度 位移,是要根据正方向的选定来写上正负号的吗我学到功率这里了,把先前匀变直运动的正负完全给朦胧了,有些题真是做着费劲、 空间几何在现实生活中的应用 澄清石灰水露置在空气中一段时间,表面常有一层白膜,说明什么,理由是什么这题的题目是下列事实中,你能得出哪些有关空气组成的结论?并说明理由 电场中的物理量的正负场强 电势 电势能 电势差 这些本身有没有正负 正负表什么 根据什么判断 还有这些跟场源电荷或者检验电荷的正负有没有关系 一楼大哥 那什么 我说的是静电场... (1)混合溶液PH=8的原因是(用离子方程式)_________ (2)混合溶液中水的氢离子的密度______0.1摩尔每升...(1)混合溶液PH=8的原因是(用离子方程式)_________ (2)混合溶液中水的氢离子的密度______0.1摩尔每 澄清石灰水长期放置在空气中会有一层白色固体薄膜,说明空气中含有什么 航空母舰有多大面积? 一升PH为一的水溶液所含氢离子是多少摩尔? 取一个大口袋盖的瓶子,在其中加一些冰块,将瓶口及时盖好,瓶子内外会发生什么情况,瓶内的水是由什么变成的 中国现造航空母舰有多少面积?还有世界上最大的航母多大? ph值计算,请问1摩尔和10摩尔的氢离子的PH值是多少? 已知A的5次方=m的5次方n的10次方,求A 现有铁、氧化铁、稀盐酸、氢氧化钙溶液、碳酸钠溶液五种物质,存在如图所示的相互反应和转化反应 场强中 1V/m=1N/C 是怎样得到的 石灰水长期漏置在空气中,瓶壁和石灰水底部均会出现白色固体物质,说明空那个其中含有是水蒸气吗 现有铁、氧化铁、稀盐酸、氢氧化钙溶液、碳酸钠溶液5种物质,存在如图所示的相互反应和转化关系.图中—表示两端的物之间可以发生反应—)表示物质间存在相应的转化关系.下列判断合理 证明:1v/m=1N/C 石灰水长期露置在空气中会出现白色固体物质,说明空间中含有 小狗和青蛙比赛游泳 为什么小狗赢了 谁能解释下为什么 1V = 1J/1C或者告诉我1V的定义是什么 看不懂 1J/1C 功/电荷量? 将稀硫酸,氢氧化钠,硝酸钡在烧杯中混合最后四个空 为什么游泳比赛中青蛙输给了狗?…… 1v*1A*t=1j对吗 3.如图1所示,乒乓球从水面下上浮到漂浮在水面上,下列判断正确的是( )A.露出水面前,浮力逐渐增大;露出水我认为因为水具有惯性所以球露出水面后还继续上升再回到漂浮水面的状态所以浮 青蛙和狗比赛游泳,为什么狗赢了? 碱石灰可以吸水吗? 一 在做托拆实验的时候,如果我将一条一分米长的试管里装满水插入水槽里 .这时候为什么大气压不将水往上压,直把试管压爆呢 外面的大气压比水下面的压强大啊,二 到底湿摩擦大还是干摩 为什么青蛙和狗游泳比赛,青蛙输了? 碱石灰为什么可以吸水 小明将氢氧化钠溶液与硝酸钡溶液混合,发现无明显现象.一段时间后,他再次取敞口放置的上述两种溶液进行混合,结果出现了白色沉淀,请解释可能的原因. 青蛙是什么类动物? 1.教材中定义速度增加量为矢量,有正负.那速度的变化量和速度的增加量是相同的吗?2.速度是矢量,速度的大小是矢量还是标量?(加速度是矢量,)3.速度变化的大小是矢量还标量?4.题目中问速 碱石灰吸水现象 如何判断水果电池的正负极 高中物理: 速度变化量的大小和速度大小的变化量有什么区别... 谢...了! 碱石灰中什么吸水呢 水果电池的正负极用三种方法测出水果电池的正负极 怎么分辨在变化的磁场中,只有电容的金属环,的正负极! 一艘轮船从江河驶入大海后,受到的浮力如何变化?排开水的体积如何变化? 探究稀盐酸,碳酸钠和氢氧化钙溶液能否发生化学反应时,倒入同一个烧杯中,则一定含有的溶质为什么是氯化钠难道不能氢氧化钙和盐酸生成氯化钙,然后氢氧化钙又和碳酸钠生成氢氧化钠吗? 1.(2010年浙江绍兴,20题)将一半径为R的实心金属球,用细线拉着,匀速缓慢地放入水深为2R的盛水容器中,直至容器底部,水未溢出.下图能反映金属球从水面刚接触处开始至容器底部过程中,所 轮船从河流驶入大海,船的浮力(),船在水中的体积().船排开水的体积() 将稀盐酸,碳酸钠溶液,氢氧化钙溶 液倒入同一烧杯中,充分反应后得到固体A 和滤液B 一道弄不懂的物理浮力题,答案给的C,但我认为是A.为什么我的错了?如图所示,甲、乙两台秤上各有一个容器,一个装满水而另一个未满,现各将一手指浸入水中,手指与容器壁、底均不接触.则在 船从海洋到河流,船排出的液体的体积相同吗?G排相同吗?船收到的浮力相同吗?收到的重力相同吗?急!详细点,烁为什么? 将碳酸钠与氢氧化钙溶液反应后的物质倒入烧杯中,又将碳酸钠溶液与稀盐酸反应后的物质倒入该烧杯中,发现烧杯中白色沉淀明显增多,过滤得无色溶液.溶液中一定有的溶质 .溶液中可能有的 当航空母舰上的航载机离航后,航空母舰所受的浮力将如何变化 石灰水长期露制在水中,瓶壁和石灰水底部均会出现白色固体物质 说明空气中含有什么物质? 青蛙是怎么死了的啊? 碱石灰是什么,有什么作用 澄清石灰水长期露置于空气中,瓶壁和液面会出现一些白色的固体物质,说明了什么?
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘