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

 我来答
一袭可爱风1718
2022-10-26 · TA获得超过1.2万个赞
知道大有可为答主
回答量:6066
采纳率:99%
帮助的人:32.3万
展开全部

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

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

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

  入门

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

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

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

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

  procedure TfrmMain LoadPlugins;   var   sr: TSearchRec;   path: string;  Found: Integer;   begin  path := ExtractFilePath(Application Exename);   try  Found := FindFirst(path + cPLUGIN_MASK sr);   while Found = 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 $#@ ;$#@ ; 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] );   end;  end  else  MessageDlg( An error occurred loading the plug in +  sr Name + mtError [mbOK] );   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单元放在最前面

  uses  Sharemem SysUtils Classes   main in main pas ;

  {$E plg }

  exports  DescribePlugin;

  begin

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

  第一个例子插件的代码是很简单的 注意 DescribePlugin原型与外壳应用程序中的TpluginDescribe类型相一致 使用附加的export保留字指定该过程将被导出 被导出的过程名称也将会出现在主工程源代码的exports段中

  unit main;

  interface

  procedure DescribePlugin(var Desc: string);  export; stdcall;

  implementation

  procedure DescribePlugin(var Desc: string);  begin  Desc := Test plugin v ;   end;

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

  调试

lishixinzhi/Article/program/Delphi/201311/8484

已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式