分享
 
 
 

Delphi Open Tools Api实例研究(一)

王朝delphi·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

先行知识:Delphi/接口/VCL组件包/COM(了解)

难度:★★☆☆☆

在这篇文章正式开始以前,首先向大家道歉。因为这个月的专栏文章本该很早就发布,但由于一些事情所以一直推迟到现在,并且这个月也只发布了这么一篇。另外,关于这篇文章我觉得我应该感谢csdn上的几位朋友,他们是chechy、FrameSniper、pankun,特别感谢chechy,让我认识到Delphi Open Tools Api(以下简称OTA)的有趣,并决定在其上面投入一些精力。并向我介绍了相当不错的资料。另外还要说明的是虽然题目叫xxxxx(一),但接下来的文章可能不是xxxxx(二)因为这个系列文章的每一篇都会是一个独立的内容,之所以叫xxx(一)是因为我会在以后的文章中不连续的些一写关于OTA的东西。

呵呵,说了那么多的废话,现在开始!但在开头还要再罗嗦一下,大概的介绍一下OTA OTA是delphi的各个版本中都有提供的一套有趣的接口,运用它你可以任意的扩展delphi的IDE,使之符合自己的需要。例如你可以扩展IDE的菜单、代码编辑器、窗口设计器、属性编辑器和控件编辑器(这个已经在前面的一系列关于VCL开发的文章中说明过)等等,几乎你想得到的所有地方,甚至是code inside功能你都能够扩展!这个激动人心的特性在delphi5以后得到了更好的发展,变的更易于使用。使开发者可以用很少的、很基础的代码完成这些有趣的扩展实现强大的功能。通过OTA也使你能够领略到delphi IDE完美的设计,建立在COM技术基础上使得delphi IDE能够轻易被客户扩展而无须重新编译IDE。

在进行这次的例子前应该指出想要学习OTA的最好资料是位于delphi安装目录下的SourceàToolsAPI里的ToolsAPI.pas文件,它列出了所有OTA的接口并有比较详细的注释说明。另外关于OTA的站点,你可以去http://delphi.about.com/library/weekly/aa033099.htmhttp://www.tempest-sw.com/opentools/看看,还可以去borland的新闻组borland.public.delphi.opentoolsapi参与讨论。当然,《delphi5开发者指南》中的26章也介绍了一些OTA的知识,并演示了如何自己实现一个delphi中的向导(本文就不讲述这个了),你们也可以去看看。

由于delphi OTA的版本差异性比较大,这个文章中的内容都以使用delphi7为前提。当delphi IDE处于运行中的时候有一个我们应该清楚的一个重要的实例(Instance)是BorlandIDEServices,它实现了众多OTA接口,换句话说我们可以从BorlandIDEServices得到很多接口,并且这些接口在delphi运行时已经被实现,我们只用通过接口调用接口方法就可以轻松的得到IDE的很多东西,比如菜单、窗口等等,有了这些,扩展delphi IDE便成为了现实。为了能够扩展delphi IDE我们必须要在delphi处于运行时进入,这意味着我们可以有两种方法来实现我们的delphi扩展(也可以叫插件)并向外发布,一种办法是将插件做成设计时VCL组件包(本文采取这种形式,关于VCL组件包请参看我在之前发表的文章),让客户在delphi运行时安装。另一种办法是将插件基于一个DLL并在注册表中的H K E Y _ C U R R E N T_ U S E R \ S o f t w a r e \ B o r l a n d \D e l p h i \ 7 . 0 \ E x p e r t s注册,并在DLL中以一个特殊的导出函数作为入口点,delphi IDE在重新启动以后便会加载你的插件(这个方法将在以后的文章中说明)。后者为建立简单化的插件安装程序提供了可能,前者需要用户在delphi运行中如同安装组件一样的进行安装。我们的例子将向delphi的主菜单中添加一个有两项的菜单(名字叫做hk.barton),点击第一项将向当前工程的第一个代码编辑器的代码中插入一句指定的代码,第2项简单的显示一个关于信息。当你不想使用这个菜单的时候只需要象一般组件的卸载一样将其卸载就可以了。最先还是来看看组件包的项目文件,如果大家看过我之前的关于VCL的文章就应该很熟悉了:

package Package1;

//…省略编译器指示,注意将这个组件设计为设计时(Design Time)的

requires

rtl,

vcl,

designide;

contains

NTAMenu in 'NTAMenu.pas';

end.

可以看到我们将在NTAMenu.pas中实现我们的插件,在这个文件中我们主要用到了以下的接口:IOTAServices,被BorlandIDEServices直接实现的接口,是OTA的一个基础接口,我们用它的GetParentHandle方法来取得delphi IDE的句柄;INTAServices,在delphi运行时被实现的接口,可以用它的方法直接得到delphi IDE的MainMenu、ImageLis、ActionList、ToolBar这样我们就可以直接做很多操作了;IOTAModuleServices、IOTAModule、IOTAEditor、IOTASourceEditor、IOTAEditView,在代码中可以看到我们用这些接口来一步一步得到代码编辑器并最后得到一个可以在代码中当前的光标位置处理数据的IOTAEditPosition接口,我们就用它来向当前光标处插入一句代码,插入大量的代码段还可以使用IOTAEditWriter接口。关于在下面的代码中使用到的接口方法我们会在注释中做说明,没有使用到的接口和其它方法别忘了查看ToolsApi.pas文件。另外可以注意到下面的代码在很多地方进行检测以保证代码在运行后尽量不要出问题以及在出现异常时能够合理释放资源。别忘了,我们的目的是扩展delphi,而并不是要把delphi IDE弄的面目全非。

unit NTAMenu;

interface

uses

SysUtils, Classes,Menus,ToolsApi,Controls,ImgList,Graphics,Forms,ComCtrls,windows;

type

TNTATest = class

private

FMainMenu:TMainMenu;//用来存贮delphi IDE的主菜单

NewMenu:TMenuItem;//我们将要插入的菜单

FImageList:TCustomImageList;//用来存贮delphi IDE主菜单和工具栏的ImageList

ImageIndex1:integer;//检测量,请参看后面的代码

IDEHandle:HWND;//存贮IDE的handle

protected

procedure AddMenu;//加入我们的菜单

procedure ReMoveMenu;//卸载我们的菜单

procedure ReCodeEditer(sender:TObject);//菜单项一的事件

procedure AboutForm(sender:TObject);//菜单项二的事件

public

constructor Create;

destructor Destroy;override;

end;

procedure Register;

var

MyNTATest:TNTATest;

implementation

procedure Register;

begin

MyNTATest.AddMenu;

//和传统组件的同名方法不同,这里没有在组件面板上安装图标

//而是直接调用AddMenu方法添加我们的菜单

end;

{ TNTATest }

constructor TNTATest.Create;

begin

IDEHandle:=(BorlandIDEServices as IOTAServices).GetParentHandle;

//我们用IOTAServices接口的GetParentHandle方法取得了ide的handle

end;

procedure TNTATest.AddMenu;

var

MenuItem:array [0..2] of TMenuItem;

i:integer;

Icon1:TIcon;//菜单项一的图标

begin

FMainMenu:=(BorlandIDEServices as INTAServices).MainMenu;

//我们用 INTAServices的MainMenu属性直接得到了IDE的主菜单

FImageList:=(BorlandIDEServices as INTAServices).ImageList;

//我们用 INTAServices的ImageList属性直接得到了IDE的图象列表

NewMenu:=TMenuItem.Create(FMainMenu);

//创建我们的菜单

NewMenu.Caption:='hk.barton';

ImageIndex1:=-1;//没有载入图标

//下面的代码使用for和case来添加两个菜单项有点小题大作,但

//我们展示了一种更通用的方法使你能够添加更多的菜单项,而不必简单的复制代码。

for i:=0 to 2 do

begin

MenuItem[i]:=TMenuItem.Create(NewMenu);//创建子菜单项

case i of

0:

begin

MenuItem[i].Caption:='InsertText';

Icon1:=TIcon.Create;

try

Icon1.LoadFromFile('D:\MyWorks\MyComponent\OTATest\NewForm.ico');

//我从硬盘的文件上载入了一个图标作为菜单项一的图标

except

On E:Exception do

begin

raise Exception.Create(E.Message);

exit;

end;

end;

ImageIndex1:=FImageList.AddIcon(Icon1);

//加入那个载入的图标并返回一个ImageIndex

MenuItem[i].ImageIndex:=ImageIndex1;

MenuItem[i].OnClick:=ReCodeEditer;//添加事件处理程序

end;

1:MenuItem[i].Caption:='-';//当然还有一个分割符号,其实是3个菜单项

2:

begin

MenuItem[i].Caption:='About';

MenuItem[i].OnClick:=AboutForm;

end;

end;

NewMenu.Add(MenuItem[i]);//添加菜单项

end;

FMainMenu.Items.Add(NewMenu);//最后添加我们的菜单到IDE主菜单

end;

procedure TNTATest.ReCodeEditer(sender:TObject);

var

Module:IOTAModuleServices;

CurentMoudle: IOTAModule;

IntfEditor:IOTAEditor;

Editor:IOTASourceEditor;

EditView:IOTAEditView;

EditWriterPos:IOTAEditPosition;

i:integer;

begin

Module:=BorlandIDEServices as IOTAModuleServices;

CurentMoudle:=Module.CurrentModule;

//使用IOTAModuleServices的CurrentModule方法得到当前打开的工程模块

if CurentMoudle=nil then

begin

messagebox(IDEHandle,'当前没有打开项目文件','hkTest',MB_ICONINFORMATION);

exit;

end;

//遍历已打开工程中所有的文件

for i:=0 to CurentMoudle.ModuleFileCount-1 do

begin

IntfEditor:=CurentMoudle.ModuleFileEditors[i];

//IOTAModule的ModuleFileEditors[]属性得到一个IOTAEditor

if IntfEditor.QueryInterface(IOTASourceEditor,Editor)=S_OK then

//查看遍历到的文件是否是代码文件并已开始在代码编辑器中编辑。

//如果是便通过一个out参数Editor得到一个实现IOTASourceEditor的实例

break;

end;

if Editor=nil then

begin

messagebox(IDEHandle,'当前没有代码编辑窗口','hkTest',MB_ICONINFORMATION);

exit;

end;

EditView:=Editor.EditViews[i];

//使用IOTASourceEditor的 EditViews[]属性得到一个IOTAEditView

EditWriterPos:=EditView.Position;

//使用IOTAEditView的Position属性最终得到一个IOTAEditPosition

EditWriterPos.InsertText('{/// This is add by the OTATest of hk.barton,enjoy days! ///}');

//IOTAEditPosition的InsertText方法向当前光标位置插入一行代码,这里是一行注释。

end;

procedure TNTATest.AboutForm(sender: TObject);

//一个简单的关于对话框,注意参数中的IDEHandle

begin

messagebox(IDEHandle,'This is a test of OTA write by hk.barton','hkTest',MB_ICONINFORMATION);

end;

procedure TNTATest.ReMoveMenu;

//卸载菜单

begin

if assigned(NewMenu) then

NewMenu.Free;

end;

destructor TNTATest.Destroy;

begin

MyNTATest.ReMoveMenu;

if ImageIndex1<>-1 then

//如果在前面加载图标的工作出现异常就不释放图标,否则会释放到delphi本身使用的图标

MyNTATest.FImageList.Delete(MyNTATest.ImageIndex1);

inherited;

end;

initialization

//在组件第一次被安装时创建了TNTATest

MyNTATest:=TNTATest.Create;

finalization

//在组件被卸载时释放了MyNTATest

MyNTATest.Free;

end.

请注意上面代码中的注释。单就这个例子可能并没有多少用处,然而只要你稍微扩展就可以让这个例子有一点实际用处,你可以加入很多菜单项,每一个项对应一些用户常用的但烦琐的代码,这样就可以免去在开发中输入同样代码的烦琐了,甚至你还可以设置快捷键,也可以做一个设置窗口允许用户自己设置需要的代码和动态的添加菜单项目。当然要完成更复杂的插件你还需要其他的OTA知识,我会在以后的专栏文章中不连续的介绍这些。这次就写到这里,我已经在文章开始的地方推荐了一些学习OTA的资料。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有