附录A使用OPENTOOLSAPI的D扩展示例(1)

上传人:痛*** 文档编号:82732349 上传时间:2022-04-29 格式:DOCX 页数:32 大小:107.20KB
收藏 版权申诉 举报 下载
附录A使用OPENTOOLSAPI的D扩展示例(1)_第1页
第1页 / 共32页
附录A使用OPENTOOLSAPI的D扩展示例(1)_第2页
第2页 / 共32页
附录A使用OPENTOOLSAPI的D扩展示例(1)_第3页
第3页 / 共32页
资源描述:

《附录A使用OPENTOOLSAPI的D扩展示例(1)》由会员分享,可在线阅读,更多相关《附录A使用OPENTOOLSAPI的D扩展示例(1)(32页珍藏版)》请在装配图网上搜索。

1、附录A 使用OPENTOOLS API的Delphi扩展示例附录A与第11章的内容前后承继。阅读第11章之后,您已经了解了创建定制组件的大部分知识。附录A也很重要,它示范了如何创建组件编辑器以及使用OpenTools API对Delphi自身进行扩展。二者分属不同的主题:一个与组件相关,另一个则是要扩展Delphi。之所以将二者放到附录中,是因为它们没有其他技术那样常用。但要用到二者的时候,它们都是很有用的。定制组件编辑器可以定义设计时对话框,编辑器在Object Inspector不够用时,使得用户能够可视化地修改特定于该组件的每个方面。一个很好的例子就是TChart组件,由Dave Ber

2、neda开发。另外,在设计时您还可以从组件的上下文菜单中运行该组件所包含的代码。假定您使用Delphi已经有一段时间了,而您认为Delphi缺乏某些必要的特征。我三年前在一个工程上工作时,就发生了这样的情况。当时正在对Rational Rose所定义的系统结构模型进行编码,我们已经厌烦了手工定义类并编写函数体。实在是太烦了。创建一个类来读取类的声明并编写函数体,这看来是个不错的主意。使用OpenTools API,有时候再借助一下Ray Lischner的书Hidden Paths of Delphi 3: Experts, Wizards, and the Open Tools API,我们

3、最终向Delphi添加了一个能够调用类生成器的菜单项。结果终于摆脱了这本来可以自动完成的、烦人的任务(可惜的是我们没有一本语法分析方面的好书,我有点离题了)。这准确地描述了Inprise公司在决定向Delphi专业版和企业版用户提供OpenTools API时的想法。当需要Delphi具有某些功能时,添加上去就行了。Delphi现在还具有“Complete class at cursor”的代码生成功能,因此我们可以创建一个尚不存在的专家:可以生成专家的专家。当您阅读本章后,可以了解到如何创建组件编辑器以及怎样使用专家对Delphi进行定制。有一个工具可用于开发定制专家,这使得创建专家与创建组

4、件一样容易。A.1 OpenTools API介绍OpenTools API原来定义为抽象虚类,即它使用了Delphi接口,而我们可以继承它以便向Delphi添加扩展。原来的那些单元仍然存在于你安装的Delphi的SourceToolsAPI子目录下,但在大多数情况下它们已经让位于ToolsAPI.pas单元中定义的COM接口。注意:ToolsAPI单元与Delphi专业版和企业版一同发布。您也可以对Delphi标准版进行定制,只是包含相应接口的单元在Delphi标准版中是没有的。如果您对Delphi抽象接口比较熟悉,那么比从零开始要好一些。不管怎样,您都应该学习COM接口,这正是我们在本章中

5、要做的。A.1.1 OpenTools接口大多数情况下,OpenTools接口都是位于SourceToolsAPIToolsAPI.pas单元中的COM接口。为提高后向兼容性,该目录下也定义了风格较老的Delphi接口。表A.1完整地列出了ToolsAPI中的所有单元。带有星号的单元包含了风格较老的Delphi接口,通常应该避免在较新的代码中使用。警告:很差的是,这些单元在帮助文件中并没有很好的文档。首先要参考单元中的代码;代码中的注释很有帮助,但默认某些知识;而经过仔细查找,我们发现几乎完全没有集成化的帮助。这真是个不幸,如果要进行扩展,您必须阅读许多代码并进行实验。表A.1 Delphi

6、ToolsAPI单元列表。通过实现ToolsAPI.pas单元中定义的COM接口,可以访问Delphi的大部分功能单元描述toolsapi.pas包含了新的COM接口,它替换了在其他单元中可以找到的风格较老的接口(本章中将广泛地使用该单元的接口)vcsintf.pas包含了与版本控制系统进行链接的COM接口dsgnintf.pas包含了特性编辑器、组件编辑器以及注册过程所需的接口(例如,RegisterComponentEditor)editintf.pas*风格较老的Delphi抽象接口,用于访问编辑器缓存,例如单元的文本exptintf.pas*风格较老的单元,其中包括了用于定义专家的抽象

7、虚类TIExpert;新代码应使用ToolsAPI单元中的COM接口fileintf.pas*风格较老的单元,其中包括了用于访问文件系统功能的抽象虚接口istreams.pas*包含了流、内存流、文件流的接口toolintf.pas*与Delphi菜单和ToolServices相关的接口;在新代码中应使用ToolsAPI单元中的BorlandIDEServices COM对象以及IOTAMenuWizardvirtinft.pas*包含了TInterface的定义,以及Delphi对基本的COM接口IUnknown的实现注意:本章中可能会交替使用向导和专家这两个词。它们都是指Delphi中的专

8、家。之所以使用两个词,是因为Inprise也并未确定使用单个词。注册过程使用向导这个词,而COM接口也包含了向导这个词。在Delphi中进行讨论时,对这两个词进行区分是没有意义的。现在已经无需了解进一步的细节了,我们来创建一个Delphi专家。A.1.2 创建向导对Delphi向导进行扩展的最为直接的途径就是实现IOTAWizard和IOTAMenuWizard接口。这两个接口都定义在ToolsAPI单元中,而且您可以看到,它们非常容易实现。注意:首字母缩略词前缀IOTA指的是Interface for OpenTools API(我是这样认为的!),它也可能是指一幕希腊剧,意思是指非常小的数

9、量(因为只有很少量的代码需要实现)。实现IOTAWizard和IOTAMenuWizard最容易实现的向导是非常基本的IOTAWizard接口,它使用IOTAMenuWizard类来实现。IOTAWizard接口需要实现四个方法,而IOTAMenuWizard则把一个菜单项放置到Help菜单上。由于刚刚起步,我们将以向导的形式实现一个Hello World例子。为使读者不至于失望,将在下一节实现一个较为有用的向导。下面的代码定义IOTAWizard和IOTAMenuWizard。实现基本的向导并显示在Help菜单上,需要实现IOTAWizard接口的四个方法:GetIDString、GetNa

10、me、GetState和Execute。由于IOTAWizard继承了IOTANotifier接口,您还需要实现IOTANotifier接口。可以使用TNotifierObject存根类作为IOTANotifier接口的实现。IOTANotifier接口引入了AfterSave、BeforeSave、Destroyed和Modified方法,以便对事件进行响应。对这个练习而言,该存根类就足够了。IOTAMenuWizard继承了IOTAWizard接口。在IOTAMenuWizard类中,惟一需要实现的方法是GetMenuText,该方法返回在Help菜单上显示的文本。IOTAWizard =

11、 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-00608CCBF153function GetMenuText:

12、 string;end;这个没有实际功能的向导定义为TDummyWizard类,该类是TNotifierObject、IOTAWizard以及IOTAMenuWizard的子类。它实现了上面代码所列出的接口中的五个方法。完整的实现代码如下。unit UDummyWizard;/ UDummyWizard.pas - Demonstrates basic wizard interface/ Copyright (c) 2000. All Rights Reserved./ By Software Conceptions, Inc. / Written by Paul Kimmel. Okemos

13、, MI USAinterfaceusesWindows, ToolsAPI;typeTDummyWizard = class(TNotifierObject, IOTAWizard,IOTAMenuWizard)publicfunction GetIDString : String;function GetName : String;function GetState : TWizardState;procedure Execute;function GetMenuText : String;end;procedure Register;implementationusesDialogs;p

14、rocedure Register;beginRegisterPackageWizard(TDummyWizard.Create);end; TDummyWizard procedure TDummyWizard.Execute;beginMessageDlg( Building Delphi 6 Applications, mtInformation,mbOk, 0 );end;function TDummyWizard.GetIDString: String;beginresult := SoftConcepts.DummyWizard;end;function TDummyWizard.

15、GetMenuText: String;beginresult := Dummy Wizard;end;function TDummyWizard.GetName: String;beginresult := Dummy Wizard;end;function TDummyWizard.GetState: TWizardState;beginresult := wsEnabled;end;end.Register过程以TDummyWizard的一个实例为参数调用了RegisterPackageWizard。您可以像安装组件一样把专家安装到包中,如上例。实际上,进行安装最容易的方法就是使用Del

16、phi中的Component | Install Component菜单项。当用户单击添加的菜单项时,即可调用这个非常基本的向导。当单击菜单项时,将调用向导实现的Execute方法来响应。TDummyWizard在一个TMessageDlg对话框中显示本书的标题。当然,如果您确定的话,可以在Execute方法中加入几乎任何级别的复杂行为。GetIDString方法返回向导的字符串标识符。按照惯例,该ID的前缀是您公司的名字,这里使用了Software Concepts, Inc公司的注册商标SoftConcepts,并将其通过圆点连接到向导的名字。GetMenuText的实现代码中包含了显示在

17、帮助菜单上的菜单项文本。当每次单击Delphi的Help菜单上相应菜单项时,都会调用该方法。GetName方法返回向导的名字,而GetState方法则返回TWizardState类型值。该类型定义如下:TWizardState = set of wsEnabled, wsChecked;wsEnable表示该向导是否是活动的,而wsChecked值则在菜单项上放置一个检查标记。从代码可以看到,基本的Help菜单向导所需的代码非常少。当安装向导后,Delphi的帮助菜单上出现了一个新的菜单项Dummy Wizard。当用户单击向导时,将调用Execute方法,从而在TMessageDlg对话框上

18、显示文本“Building Delphi 6 Applications”。关于相应的菜单项和单击后的反应,可以参见图A.1和A.2。图A.1 Dummy Wizard添加到Delphi的Help菜单图A.2 当单击Dummy Wizard菜单项时,将显示TMessageDlg对话框,其代码可以参见Execute方法注册向导把向导添加到包,并像组件一样对其进行安装,即可扩展Delphi。当把包编译为BPL库之后,将调用上一节的Register过程来进行安装。如上一小节的代码所示,RegisterPackageWizard需要向导的一个实例作为参数。RegisterPackageWizard定义在

19、ToolsAPI.pas单元中,其参数为IOTAWizard类型的常量引用,该过程声明如下:procedure RegisterPackageWizard(const Wizard: IOTAWizard);要安装向导,可以按照下列步骤进行。1. 在Delphi中,单击Component | Install Component菜单项。2. 在Install Component对话框中,如果单元尚未显示在Unit file name域中,则单击Browse按钮找到相应的单元。3. 如果要在当前包中安装专家,单击OK。否则单击Into new package属性页(见图A.3),并给出包的名字及描

20、述。图A.3 图中为Install Component向导,用于将向 导安装到包。所需步骤与安装组件时相同4. 当单击OK后,给出的包将在包编辑器中打开(见图A.4)。单击Compile按钮(见图A.4)。5. 对包进行编译之后,Install已经可用,单击该按钮。要记住,包在本质上是动态链接库,也是一种应用程序。因此,可以而且应该像其他程序一样对选项进行设置。要加入路径和版本消息,并记得设置对所处的开发阶段可用的编译器选项。可以参考前面的第18章,在测试时使用运行时错误和调试选项,而在测试结束后、应用程序打包之前去掉这些选项。图A.4 包编辑器用于编译并安装包A.2 创建定制向导像New C

21、omponent Wizard这样有用的向导,可以减少编写代码的数量,使得不必手工编写一些可以自动完成的代码;而且有助于开发者在越过障碍之后发现Delphi的一些新的功能。为保持向导的这种功能,本节给出了一个New Expert专家;正如同New Component对话框跳过了开始组件单元的步骤一样,New Expert的作用也是类似的。A.2.1 定义New Expert WizardNew Expert的功能是,它可以生成一些与本章开头的Dummy Wizard类似的专家。而New Expert本身将安装在Component菜单上New Component菜单项之后。要建立该向导并将其安装

22、到Component菜单上,我们需要实现IOTACreator和IOTAModuleCreate,而且还需要查询BorlandIDEServices以获得INTAServices40。INTAServices40对象定义了向特定的Delphi菜单添加菜单项的行为。向导的类是TNewExpertWizard。当单击Component | New Expert菜单项(见图A.5)时,它生成一个与TDummyWizard几乎相同的类。将特定的行为添加到生成的Execute方法,然后就可以了。完整的代码列表如下,对相关部分的描述分为小节,以便使您能够清楚地了解其作用。图A.5 将New Expert向

23、导添加到INTAServices40对象之后unit UNewExpertWizard;/ UNewExpertWizard.pas - An example of a wizard that generatesthe code for a wizard/ Copyright (c) 2000. All Rights Reserved./ By Software Conceptions, Inc. / Written by Paul Kimmel. Okemos, MI USAinterfaceusesWindows, Controls, ToolsAPI, Forms, Menus, Cla

24、sses, SysUtils;typeTNewExpertWizard = class(TNotifierObject, IOTAWizard,IOTACreator,IOTAModuleCreator)privateFNewClassName : string;FMenuText : string;FExpertIDString : string;FExpertName : string;FUnitName : String;FWizardState : TWizardState;FMenuItem : TMenuItem;procedure AddMenuItem;procedure On

25、Click( Sender : TObject );procedure GenerateCode;publicconstructor Create; virtual;destructor Destroy; override; IOTAWizard function GetIDString : String;function GetName : String;function GetState : TWizardState;procedure Execute; IOTACreator function GetCreatorType : string;function GetExisting :

26、Boolean;function GetFileSystem : string;function GetOwner : IOTAModule;function GetUnnamed : Boolean; IOTAModuleCreator function GetAncestorName : string;function GetImplFileName : string;function GetIntfFileName : string;function GetFormName : string;function GetMainForm : Boolean;function GetShowF

27、orm : Boolean;function GetShowSource : Boolean;function NewFormFile( const FormIdent, AncestorIdent : string) : IOTAFile;function NewImplSource( const ModuleIdent, FormIdent,AncestorIdent : string ) : IOTAFile;function NewIntfSource( const ModuleIDent, FormIdent,AncestorIdent : string ) : IOTAFile;p

28、rocedure FormCreated( const FormEditor : IOTAFormEditor );end;procedure Register;implementationuses UFormMain, Dialogs, UExpertUnit;$R *.RESprocedure Register;beginRegisterPackageWizard(TNewExpertWizard.Create);end; TNewExpertWizard constructor TNewExpertWizard.Create;begininherited;AddMenuItem;end;

29、destructor TNewExpertWizard.Destroy;beginif( Assigned(FMenuItem) thenFMenuItem.Free;inherited;end;procedure TNewExpertWizard.OnClick( Sender : TObject );beginExecute;end;procedure TNewExpertWizard.AddMenuItem;varNTAServices40 : INTAServices40;ComponentMenuItem : TMenuItem;beginNTAServices40 := Borla

30、ndIDEServices As INTAServices40;if( Not Assigned(NTAServices40) then exit;ComponentMenuItem :=NTAServices40.MainMenu.Items.Find(&Component);if( Not Assigned( ComponentMenuItem) then Exit;FMenuItem := TMenuItem.Create( ComponentMenuItem );tryFMenuItem.Caption := New &Expert.;FMenuItem.OnClick := OnCl

31、ick;ComponentMenuItem.Insert( 1, FMenuItem );exceptFreeAndNil(FMenuItem);end;end;procedure TNewExpertWizard.Execute;varForm : TFormMain;beginForm := TFormMain.Create(Application);tryif( Form.ShowModal = mrOK ) thenbeginFNewClassName := Form.NewClassName;FMenuText := Form.MenuText;FExpertIDString :=

32、Form.ExpertIDString;FExpertName := Form.ExpertName;FUnitName := Form.UnitName;FWizardState := Form.WizardState;GenerateCode;end;finallyForm.Free;end;end;function TNewExpertWizard.GetIDString: String;beginresult := SoftConcepts.NewExpertWizard;end;function TNewExpertWizard.GetName: String;beginresult

33、 := Expert;end;function TNewExpertWizard.GetState: TWizardState;beginresult := wsEnabled;end;function TNewExpertWizard.NewImplSource(const ModuleIdent,FormIdent,AncestorIdent: string): IOTAFile;beginresult := TExpertUnit.Create( FNewClassName, FMenuText,FExpertIDString,FExpertName, FUnitName, FWizar

34、dState );end;procedure TNewExpertWizard.GenerateCode;begin(BorlandIDEServices as IOTAModuleServices).CreateModule(Self);end;procedure TNewExpertWizard.FormCreated(const FormEditor:IOTAFormEditor);begin/ Intentionally left blankend;function TNewExpertWizard.GetAncestorName: string;beginresult := ;end

35、;function TNewExpertWizard.GetFormName: string;beginresult := ;end;function TNewExpertWizard.GetImplFileName: string;beginresult := FUnitName;end;function TNewExpertWizard.GetIntfFileName: string;beginresult := ;end;function TNewExpertWizard.GetMainForm: Boolean;beginresult := False;end;function TNe

36、wExpertWizard.GetShowForm: Boolean;beginresult := False;end;function TNewExpertWizard.GetShowSource: Boolean;beginresult := True;end;function TNewExpertWizard.NewFormFile(const FormIdent,AncestorIdent: string): IOTAFile;beginresult := Nil;end;function TNewExpertWizard.NewIntfSource(const ModuleIDent

37、,FormIdent,AncestorIdent: string): IOTAFile;beginresult := Nil;end;function TNewExpertWizard.GetCreatorType: string;beginresult := sUnit;end;function TNewExpertWizard.GetExisting: Boolean;beginresult := False;end;function TNewExpertWizard.GetFileSystem: string;beginresult := ;end;function TNewExpert

38、Wizard.GetOwner: IOTAModule;beginresult := nil;end;function TNewExpertWizard.GetUnnamed: Boolean;beginresult := False;end;end.New Expert的类定义TNewExpertWizard类继承了TNotifierObject存根类,以及IOTAWizard、IOTACreator和IOTAModuleCreator接口。IOTAWizard是基本的向导接口,而TNotifierObject则对该接口中某些基本的事件处理程序实现了一个存根。要创建一个基本的向导,您得实现I

39、OTAWizard接口。IOTACreator和IOTAModuleCreator用于与Delphi的文件视图协同工作,它们也包含了创建窗体和单元的能力。过一会儿我们继续讨论各个接口的实现。向导类的私有部分包含了几个字段,用于正确地创建单元。FNewClassName存储将要生成的向导的类名。而FMenuText则存储要生成的向导的菜单文本。FExpertIDString包含了专家的ID字符串。FExpertName字段包含了专家名。FUnitName是生成的.PAS单元的名字,而FWizardState包含了wsEnabled和wsChecked值。上述的每个特性都用于生成对接口的IOTAW

40、izard部分的基本响应。例如,IOTAMenuWizard需要用所显示的菜单文本来响应。代码生成器将从IOTAMenuWizard.GetMenuText得到FMenuText的值。私有部分还有FMenuItem,该字段用于维护对向导所添加菜单的引用。菜单项是通过构造函数中调用的AddMenuItem过程添加到Delphi的。OnClick事件处理程序包含了当用户单击New Expert菜单项时(见图A.6)的响应代码。当用户填写好如图A.6所示的New Expert对话框之后,将调用私有方法GenerateCode。对话框中询问了一些用于完成专家的必要的问题。专家类的名字是什么?用于触发E

41、xecute方法的菜单项的文本是什么?创建的ID字符串是什么?专家的名字是什么?专家所对应的单元名是什么?Wizard State中的复选框用于生成GetState的实现代码。类的公有部分包括一些方法的声明,这些方法是必须实现的,以履行接口继承所形成的契约。另外,除了从接口继承的方法之外,还包括构造函数和析构函数。构造函数将New Expert菜单项添加到Delphi,而析构函数负责释放相应的内存。图A.6 用于生成Delphi专家的New Expert对话框实现IOTAWizard IOTAWizard接口需要实现GetIDString、GetName、GetState以及Execute方法

42、。GetIDString方法返回SoftConcepts.NewExpertWizard。按照惯例,ID字符串包括公司名和向导名,用圆点连接。GetName返回Expert,这是该向导所显示的名字。GetState返回包含wsEnabled的TWizardState集合,确保Component菜单上的向导是可用的。IOTAWizard接口中惟一较为困难的方法是Execute。当单击New Expert菜单项时(见图A.5),将调用Execute方法。Execute方法显示一个对话框,如图A.6所示。填写New Expert对话框的所有域,然后单击OK。由New Expert对话框得到的数据存储

43、在相关的私有字段中,然后调用GenerateCode方法。GenerateCode调用IOTAModuleServices.CreateModule方法。由于TNewExpertWizard继承了IOTACreator,因此它可用作CreateModule的参数。接着,CreateModule调用IOTAModuleCreator的方法,包括用于生成代码的NewImplSource方法(参考“向Delphi的菜单添加菜单项”一节,那里提供了关于如何从COM对象BorlandIDEServices查询ToolsAPI服务的简要讨论)。实现IOTACreator IOTACreator定义了用于与

44、Delphi的文件系统视图协同工作的接口。IOTACreator用于为生成代码提供方便。对于IOTACreator,我们实现了GetCreatorType、GetExisting、GetFileSystem、GetOwner以及GetUnnamed方法。从本节开头列出的代码可用看出,这些方法相对较为直观。GetCreatorType返回ToolsAPI.pas中定义的sUnit。常量sUnit包含了值Unit,表示将创建单元。GetExisting返回False,因为我们正在创建新的单元;如果引用已有的单元,那么该方法将返回True。GetFileSystem返回TFileSystem对象的I

45、D字符串,向导将使用该对象来读写文件。它并不是必须的,因此该方法返回了空字符串。GetOwner返回对拥有模块的引用。例如要将该模块添加到一个已有的工程,我们需要查询BorlandIDEServices以获得已有的工程或包。我们将使用包编辑器来将新的专家添加到某个特定的包。GetOwner方法可以返回Nil。最后是GetUnnamed方法,如果我们返回未命名的单元,该方法将返回True。如果GetUnnamed返回True,Delphi将在第一次保存单元时提示用户输入文件名。如图A.6的New Expert对话框所示,我们已经提供了单元名。要自动生成模块并添加到打开的包,您可以修改GetOwn

46、er方法,查找活动工程组并将其作为GetOwner的结果返回。下面的代码就足够了。function TNewExpertWizard.GetOwner: IOTAModule;varModuleServices : IOTAModuleServices;ProjectGroup : IOTAProjectGroup;I : Integer;beginresult := Nil;ModuleServices := BorlandIDEServices As IOTAModuleServices;for I := 0 to ModuleServices.ModuleCount - 1 dobegi

47、nwith ModuleServices.ModulesI doif( Pos( .bpg, FileName ) 0 ) thenif( QueryInterface( IOTAProjectGroup, ProjectGroup ) =S_OK )thenbeginresult := ProjectGroup.GetActiveProject;exit;end;end;end;ModuleServices对象是由BorlandIDEServices对象返回的。将查找所有的模块,以找到包含.bpg包扩展名的模块。当找到一个包以后,QueryInterface会测试该模块是否实现了IOTAPr

48、ojectGroup接口。如果已经实现了该接口,那么将把ActiveProject作为函数结果返回。实现IOTAModuleCreator 在这个练习中,IOTAModuleCreator包含的方法数目是最多的。为与IOTA前缀的来源相一致,这些方法也都相对直观而易于实现。表A.2包含了用于实现IOTAMoudleCreator接口的方法。虽然该表较小,但也够用了,因为描述都相对较短。表A.2 为IOTAModuleCreator接口所实现的方法。对New Expert向导最重要的是NewImplSource方法,该方法返回生成的源代码接口方法描述GetAncestorName返回模块所继承的

49、祖先名;我们使用了空字符串GetFormName该函数返回窗体名;由于并不生成窗体,所以我们也返回空字符串GetImplFileName返回由New Expert对话框读取的、存储在FUnitName中的单元名(续表)接口方法描述GetIntfFileNameCPP头文件名,这里返回空字符串,要记得Delphi与C+ Builder共享VCL代码GetMainForm由于本模块并非主窗体,所以GetMainForm返回FalseGetShowForm由于该向导并不与窗体相关联,所以仍然返回FalseGetShowSource由于我们需要完成生成的专家向导中的Execute行为,因此返回True

50、以显示新的单元NewFormFile返回IOTAFile对象,表示窗体文件的实例;如果生成的专家不需要窗体,则返回NilNewImplSource这是个关键性的方法:该方法返回IOTAFile的子类,包含了生成的专家的源代码。从代码可以看到,该方法返回了TExpertUnit类的实例(在“建立代码生成器”一节中,我们将继续讨论TExpertUnit单元)NewIntFSource该方法返回C+头文件的源代码;它与我们的目的是不相关的FormCreatedFormCreated是有窗体创建时所调用的事件方法;由于New Expert向导没有窗体,因此该事件处理程序是空白的现在我们已经实现了向导,

51、并涵盖了所有用于定义向导的接口,接下来我们需要讨论使用BorlandIDEServices对象添加菜单项。最后我们将实现生成代码的IOTAFile部分以及IOTARepository接口,并结束本节。存储库接口将把我们创建的向导放置到New Items对话框中,这样可以使得它与New Component功能相一致。A.2.2 向Delphi的菜单添加菜单项BorlandIDEServices全局变量定义在ToolsAPI.pas单元中。当对COM对象使用as操作符时,它与向一个对象查询是否支持某接口是等效的。例如,如果BorlandIDEServices实现了IOTAModuleService

52、s接口,BorlandIDEServices as IOTAModuleServices将返回IOTAModuleServices的实例。可以使用BorlandIDEServices对象来访问所有与ToolsAPI相关的COM对象,名字形如somenameservices。下面的代码片断摘自定义New Expert向导一节。procedure TNewExpertWizard.AddMenuItem;varNTAServices40 : INTAServices40;ComponentMenuItem : TMenuItem;beginNTAServices40 := BorlandIDESe

53、rvices As INTAServices40;if( Not Assigned(NTAServices40) then exit;ComponentMenuItem :=NTAServices40.MainMenu.Items.Find(&Component);if( Not Assigned( ComponentMenuItem) then Exit;FMenuItem := TMenuItem.Create( ComponentMenuItem );tryFMenuItem.Caption := New &Expert.;FMenuItem.OnClick := OnClick;Com

54、ponentMenuItem.Insert( 1, FMenuItem );exceptFreeAndNil(FMenuItem);end;end;我们首先需要通过BorlandIDEServices获取对INTAServices40接口的访问权限。INTAServices40可以访问Delphi的主菜单。TMainMenu.Items.Find方法可用于获取Items集合中Component菜单的引用。加速键字符&会被忽略,使用与否都是可以的。两种情况下find都能正确工作。如果找到了Component菜单,将创建一个新的菜单项并将其赋值给FMenuItem字段变量。再初始化菜单项的Capt

55、ion和OnClick特性,然后插入菜单项。当以索引位置1插入菜单项时,该菜单项将出现在New Component菜单项之后。最后,如果发生异常,将释放FMenuItem对象。假定其他的开发者经常添加专家(现在他们已经创建了New Expert专家,这是可能的)。为确保您的专家总是放在正确的位置上,您可以使用一点搜索逻辑来查找相对于另一菜单的正确位置。下面的修改确保了New Expert总是出现在New Component菜单项之后(原来的代码是ComponentMenuItem.Insert( 1, FMenuItem);)。varI : Integer; / added an intege

56、r variableNewComponentMenuItem : TMenuItem;/ original variablesbegin/ original codeNewComponentMenuItem := ComponentMenuItem.Find(New Component);I := ComponentMenuItem.IndexOf( NewComponentMenuItem );ComponentMenuItem.Insert( I + 1, FMenuItem );修改后的版本替换掉了原来对Insert的单独一行的调用。ComponentMenuItem.Insert(Co

57、mponentMenuItem.IndexOf(ComponentMenuItem.Find(Install Component.) + 1,FMenuItem );当然,如果使用原来的版本,可以添加一个注释,而且不需要额外的局部变量I和NewComponentMenuItem。A.2.3 建立代码生成器在很大程度上,每个向导都包含了一些相同的基本代码。新的向导需要一个单元,其中包括单元名、接口和实现部分、引用ToolsAPI单元的uses子句、注册过程、以及对IOTAWizard和IOTAMenuWizard接口的实现。有个方便的方法能够定义要生成的代码,即使用源代码的参数化的字符串,并将其

58、放置在资源文件中。当通过IOTAModuleCreator.CreateModule方法创建IOTAFile的后代类的实例时,该实例可读出资源字符串并对参数化的空白部分进行填充。TExpertUnit类就是这样实现的。我们首先看一下资源文件的定义。定义代码资源文件可以将源代码定义为常量,但使用资源文件更为可取。定义源代码的过程可分为四步。第一步,我们从DemosExperts目录下的例子中找一些源代码,然后创建名为codegen.txt的文本文件,其中包括参数化的源代码。通过使用参数,可以用Delphi的format函数插入实际的值。第二步:创建资源代码文件,资源编译器将使用该文件生成code

59、gen.res,这就是要链接到New Expert 向导的资源文件。第三步:使用Brcc32.exe资源编译器编译资源文件。第四步:使用$R CODEGEN.RES编译指令,以确保将codegen.res链接到程序中。A.3 CODEGEN.TXT下面列出了参数化的源代码。仔细观察,可以注意到该文本与TDummyWizard非常相似。实际上,它就是从TDummyWizard向导复制过来的,一些因向导而异的关键值使用参数进行了替换。例如,单元名替换为%0:s。因此,如果对资源字符串使用Format函数,那么使用%0:s之处将替换为Format调用中的第一个字符串参数,如此等等。unit %0:s

60、;/ %0:s.pas - Raison d etre/ Copyright (c) 2000. All Rights Reserved./ By Your Company Name Here, Inc. / Written by Your Name Here. City, State USAinterfaceusesWindows, Messages, SysUtils, Classes, Graphics, Controls, Forms,Dialogs,ToolsAPI;type%1:s = class(TNotifierObject, IOTAWizard, IOTAMenuWizar

61、d)publicfunction GetIDString : String;function GetName : String;function GetState : TWizardState;procedure Execute;function GetMenuText : String;end;procedure Register;implementationprocedure Register;beginRegisterPackageWizard(%1:s.Create);end; %1:s procedure %1:s.Execute;beginMessageDlg( Add execu

62、te behavior here!, mtInformation, mbOK,0);end;function %1:s.GetIDString: String;beginBy Convention CompanyName.WizardNameresult := %5:s;end;function %1:s.GetMenuText: String;begin Add menu text here! result := %3:s;end;function %1:s.GetName: String;begin Add wizard name here! result := %4:s;end;function %1:s.GetState: TWizardState;beginresult := %2:s;end;end.CODEGEN.RC .RC(资

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!