
附录A使用OPENTOOLSAPI的Delphi扩展示例.pdf
17页附录 A 使用 OPENTOOLS API的 Delphi 扩展示例 附录 A 与第 11 章的内容前后承继阅读第 11 章之后,您已经了解了创建定 制组件的大部分知识附录 A 也很重要,它示范了如何创建组件编辑器以及使用 OpenTools API 对 Delphi 自身进行扩展二者分属不同的主题:一个与组件相关, 另一个则是要扩展 Delphi之所以将二者放到附录中,是因为它们没有其他技术 那样常用但要用到二者的时候,它们都是很有用的 定制组件编辑器可以定义设计时对话框,编辑器在 Object Inspector 不够用 时,使得用户能够可视化地修改特定于该组件的每个方面一个很好的例子就是 TChart 组件,由 Dave Berneda 开发另外,在设计时您还可以从组件的上下文 菜单中运行该组件所包含的代码 假定您使用 Delphi 已经有一段时间了,而您认为 Delphi 缺乏某些必要的特 征我三年前在一个工程上工作时,就发生了这样的情况当时正在对 Rational Rose 所定义的系统结构模型进行编码,我们已经厌烦了手工定义类并编写函数 体实在是太烦了创建一个类来读取类的声明并编写函数体,这看来是个不错 的主意。
使用 OpenTools API, 有时候再借助一下 Ray Lischner的书 《Hidden Paths of Delphi 3: Experts, Wizards, and the Open Tools API》 ,我们最终向 Delphi 添加 了一个能够调用类生成器的菜单项结果终于摆脱了这本来可以自动完成的、烦 人的任务(可惜的是我们没有一本语法分析方面的好书,我有点离题了) 这准确地描述了 Inprise 公司在决定向 Delphi 专业版和企业版用户提供 OpenTools API时的想法 当需要 Delphi具有某些功能时, 添加上去就行了 Delphi 现在还具有“Complete class at cursor”的代码生成功能,因此我们可以创建一个 尚不存在的专家:可以生成专家的专家 当您阅读本章后,可以了解到如何创建组件编辑器以及怎样使用专家对 Delphi 进行定制有一个工具可用于开发定制专家,这使得创建专家与创建组件 一样容易 A.1 OpenTools API 介绍 OpenTools API 原来定义为抽象虚类,即它使用了 Delphi 接口,而我们可以 继承它以便向 Delphi 添加扩展。
原来的那些单元仍然存在于你安装的 Delphi 的 Source\ToolsAPI 子目录下,但在大多数情况下它们已经让位于 ToolsAPI.pas 单 元中定义的 COM 接口 注意: T o o l s A P I 单元与D e l p h i 专业版和企业版一同发布 您也可以对D e l p h i附录 A 使用 OPENTOOLS API 的 Delphi 扩展示例 标准版进行定制,只是包含相应接口的单元在 D e l p h i 标准版中是没有的 如果您对 Delphi 抽象接口比较熟悉,那么比从零开始要好一些不管怎样, 您都应该学习 COM 接口,这正是我们在本章中要做的 A.1.1 OpenTools 接口 大多数情况下, OpenTools 接口都是位于 Source\ToolsAPI\ToolsAPI.pas 单元 中的 COM接口 为提高后向兼容性, 该目录下也定义了风格较老的 Delphi 接口 表 A.1完整地列出了 ToolsAPI 中的所有单元 带有星号的单元包含了风格较老的 Delphi 接口,通常应该避免在较新的代码中使用 警告:很差的是,这些单元在帮助文件中并没有很好的文档。
首先要参考单 元中的代码;代码中的注释很有帮助,但默认某些知识;而经过仔细查找, 我们发现几乎完全没有集成化的帮助这真是个不幸,如果要进行扩展,您 必须阅读许多代码并进行实验 表 A.1 Delphi ToolsAPI 单元列表通过实现 ToolsAPI.pas 单元中 定义的 COM 接口,可以访问 Delphi 的大部分功能 单元 描述 toolsapi.pas 包含了新的 COM 接口,它替换了在其他单元中可以找到的风格较老的接口(本章中将广泛地使用该单元的接口) vcsintf.pas 包含了与版本控制系统进行链接的 COM接口 dsgnintf.pas 包含了特性编辑器、组件编辑器以及注册过程所需的接口(例如,RegisterComponentEditor) editintf.pas* 风格较老的 Delphi 抽象接口,用于访问编辑器缓存,例如单元的文本 exptintf.pas* 风格较老的单元,其中包括了用于定义专家的抽象虚类 TIExpert;新代码应使用 ToolsAPI 单元中的 COM接口 fileintf.pas* 风格较老的单元,其中包括了用于访问文件系统功能的抽象虚接口 istreams.pas* 包含了流、内存流、文件流的接口 toolintf.pas* 与 Delphi 菜单和 ToolServices 相关的接口;在新代码中应使用 ToolsAPI单元中的 BorlandIDEServices COM对象以及 IOTAMenuWizard virtinft.pas* 包含了 TInterface 的定义,以及 Delphi对基本的 COM接口 IUnknown 的实现 注意: 本章中可能会交替使用向导和专家这两个词。
它们都是指 D e l p h i 中的 专家之所以使用两个词,是因为 I n p r i s e 也并未确定使用单个词注册过 程使用向导这个词,而 C O M 接口也包含了向导这个词在 D e l p h i 中进行讨论 时,对这两个词进行区分是没有意义的 现在已经无需了解进一步的细节了,我们来创建一个 Delphi 专家 502 Delphi 6 应用开发指南 A.1.2 创建向导 对 Delphi 向导进行扩展的最为直接的途径就是实现 IOTAWizard 和 IOTAMenuWizard 接口这两个接口都定义在 ToolsAPI 单元中,而且您可以看 到,它们非常容易实现 注意:首字母缩略词前缀 I O T A 指的是 I n t e r f a c e f o r O p e n T o o l s A P I (我是 这样认为的!),它也可能是指一幕希腊剧,意思是指非常小的数量(因为 只有很少量的代码需要实现) 实现 IOTAWizard和 IOTAMenuWizard 最 容 易 实 现 的 向 导 是 非 常 基 本 的IOTAWizard 接 口 , 它 使 用 IOTAMenuWizard 类 来 实 现 。
IOTAWizard 接 口 需 要 实 现 四 个 方 法 , 而 IOTAMenuWizard 则把一个菜单项放置到 Help 菜单上由于刚刚起步,我们将 以向导的形式实现一个 Hello World例子为使读者不至于失望,将在下一节实 现一个较为有用的向导 下面的代码定义 IOTAWizard和 IOTAMenuWizard 实现基本的向导并显示 在 Help菜单上, 需要实现 IOTAWizard接口的四个方法: GetIDString、 GetName、 GetState 和 Execute由于 IOTAWizard继承了 IOTANotifier 接口,您还需要实 现 IOTANotifier接口可以使用 TNotifierObject 存根类作为 IOTANotifier接口 的实现 IOTANotifier 接口引入了 AfterSave、 BeforeSave、 Destroyed和 Modified 方法,以便对事件进行响应对这个练习而言,该存根类就足够了 IOTAMenuWizard 继承了 IOTAWizard接口在 IOTAMenuWizard 类中,惟一 需要实现的方法是 GetMenuText,该方法返回在 Help菜单上显示的文本。
IOTAWizard = interface(IOTANotifier) ['{B75C0CE0-EEA6-11D1-9504-00608CCBF153}'] { Expert UI strings } function GetIDString: string; function GetName: string; function GetState: TWizardState; { Launch the AddIn } procedure Execute; end; IOTAMenuWizard = interface(IOTAWizard) ['{B75C0CE2-EEA6-11D1-9504-00608CCBF153}'] function GetMenuText: string; end; 这 个 没 有 实 际 功 能 的 向 导 定 义 为TDummyWizard 类 , 该 类 是 TNotifierObject、IOTAWizard以及 IOTAMenuWizard 的子类它实现了上面代 码所列出的接口中的五个方法完整的实现代码如下 附录 A 使用 OPENTOOLS API 的 Delphi 扩展示例 unit UDummyWizard; // UDummyWizard.pas - Demonstrates basic wizard interface // Copyright (c) 2000. All Rights Reserved. // By Software Conceptions, Inc. // Written by Paul Kimmel. Okemos, MI USA interface uses Windows, ToolsAPI; type TDummyWizard = class(TNotifierObject, IOTAWizard, IOTAMenuWizard) public function GetIDString : String; function GetName : String; function GetState : TWizardState; procedure Execute; function GetMenuText : String; end; procedure Register; implementation uses Dialogs; procedure Register; begin RegisterPackageWizard(TDummyWizard.Create); end; { TDummyWizard } procedure TDummyWizard.Execute; begin MessageDlg( 'Building Delphi 6 Applications', mtInformation, [mbOk], 0 ); end; function TDummyWizard.GetIDString: String; begin result := 'SoftConcepts.DummyWizard'; end; function TDummyWizard.GetMenuText: String; begin result := 'Dummy Wizard'; 504 Delphi 6 应用开发指南 end; function TDummyWizard.GetName: String; begin result := 'Dummy Wizard'; end; function TDummyWizard.GetSta。
