Delphi Open Tools Api例項研究(一) (轉)

worldblog發表於2007-08-17
Delphi Open Tools Api例項研究(一) (轉)[@more@]

Open Tools 例項研究(一):namespace prefix = o ns = "urn:schemas--com::office" />

先行知識:Delphi/介面/VCL包/COM(瞭解)

難度:★★☆☆☆

 

在這篇文章正式開始以前,首先向大家道歉。因為這個月的專欄文章本該很早就釋出,但由於一些事情所以一直推遲到現在,並且這個月也只發布了這麼一篇。另外,關於這篇文章我覺得我應該感謝csdn上的幾位朋友,他們是chechy、FrameSniper、pankun,特別感謝chechy,讓我認識到Delphi Open Tools Api(以下簡稱OTA)的有趣,並決定在其上面投入一些精力。並向我介紹了相當不錯的資料。另外還要說明的是雖然題目叫xxxxx(一),但接下來的文章可能不是xxxxx(二)因為這個系列文章的每一篇都會是一個獨立的內容,之所以叫xxx(一)是因為我會在以後的文章中不連續的些一寫關於O他的東西。

呵呵,說了那麼多的廢話,現在開始!但在開頭還要再羅嗦一下,大概的介紹一下OTA  OTA是delphi的各個版本中都有提供的一套有趣的介面,運用它你可以任意的擴充套件delphi的,使之符合自己的需要。例如你可以擴充套件IDE的選單、程式碼編輯器、視窗設計器、屬性編輯器和編輯器(這個已經在前面的一系列關於VCL開發的文章中說明過)等等,幾乎你想得到的所有地方,甚至是code inside功能你都能夠擴充套件!這個激動人心的特性在delphi5以後得到了更好的發展,變的更易於使用。使開發者可以用很少的、很基礎的程式碼完成這些有趣的擴充套件實現強大的功能。透過OTA也使你能夠領略到delphi IDE完美的設計,建立在COM技術基礎上使得delphi IDE能夠輕易被客戶擴充套件而無須重新編譯IDE。

在進行這次的例子前應該指出想要學習O他的最好資料是位於delphi目錄下的àToolsAPI裡的ToolsAPI.pas,它列出了所有O他的介面並有比較詳細的註釋說明。另外關於O他的站點,你可以去和,還可以去borland的新聞組borland.public.delphi.opentoolsapi參與討論。當然,《delphi5開發者指南》中的26章也介紹了一些O他的知識,並演示瞭如何自己實現一個delphi中的嚮導(本文就不講述這個了),你們也可以去看看。

由於delphi O他的版本差異性比較大,這個文章中的內容都以使用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直接實現的介面,是O他的一個基礎介面,我們用它的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,;

 

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:T);//選單項一的事件

  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:MyWorksMyComponentOTATestNewForm.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知識,我會在以後的專欄文章中不連續的介紹這些。這次就寫到這裡,我已經在文章開始的地方推薦了一些學習O他的資料,另外如果需要這個例子的全部程式碼,請給我來信索取:to:hk.barton@sohu.com">hk.barton@sohu.com。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-963025/,如需轉載,請註明出處,否則將追究法律責任。

相關文章