Borland Delphi/C++Builder OTA Hakkında Bilgi

OTA Nedir ?

Delphi IDE’ni kullandığı ve IDE içinde kullanılan servislere kısaca OTA (Open Tools API) denir. Diğer bir deyişle Delphi IDE için yazılan Plug-in’ler olarak da bilinirler. OTA açıklamaları ve class tanımları ToolsAPI.pas içindedir. Delphi help içerisinde OTA konusunda herhangi bir dokumana rastlanmamaktadır. Daha fazla bilgi için ToolsAPI.pas incelenebilir. Bulunduğu yer, Delphi’yi kurduğunuz klasörün altında BDS\4.0\Source\ToolsAPI\ToolsAPI.pas. (Delphi 2005 için 3.0)

ToolsAPI.pas bakıldığında bazı global değişkenler göze çarpacaktır.

Bunlar:

  BorlandIDEServices: IBorlandIDEServices;

  SplashScreenServices: IOTASplashScreenServices;

 

SplashScreenServices: Delphi açılırken global olarak bu değişkeni tanımlar. Bu değişken Delphi açıldığında ilk geçerli olan değişkendir.

 

BorlandIDEServices: Delphi açıldığı zaman global olarak bu değişken geçerli hale gelir. Bu değişken SplashScreenServices değişkeninden sonra geçerli hale gelir. Çeşitli servislere ulaşmak için bu global değişkenden faydalanılır. Bütün IxxxServices ile başlayan servislere ulaşmak için BorlandIDEServices değişkeni temel olarak alınır.

Örneklemek gerekirse, IOTAModuleServices servisini kullanmak için kısaca QueryInterface metodunu çağırarak mu metodun var olup olmadığını kontrol ederiz. Çünkü bazı servisler bazı Delphi modellerinde tanımı olmayabilirler. Örneğin, IOTAToDoServices servisi yalnızca Delphi Professional ve Delphi Enterprise versiyonlarında tanımlıdır.

Kullanımı şöyle kontrol edilir.

var
  ms : IOTAToDoServices;
begin
  ...
  ...
  if BorlandIDEServices.QueryInterface(IOTAToDoServices, ms) = S_OK then
  
//ya da if Supports(BorlandIDEServices, IOTAToDoServices, ms) then
  begin
    //Delphi IDE bu servisi destekler, bu durumda dönen değer 

    //ms ile bu servis özellikleri kullanılabilir,
    ms.UpdateList;
    ...
    ...
  end;
  ...
end;

 

Bir Delphi IDE servisini Delphi’ye tanımlamak için Register adlı procedur kullanılır.

Delphi bunu otomatik olarak arar ve çalıştırır.

 

Örnek programlar

SplashScreen servisi:

Şimdi basit bir SplashScreen IDE servisi yazalım.

Not: Delphi 2006 kullanıyorum, diğer Delphi versiyonlarında da hemen hemen benzer menüler vardır.

 

    1.Delphi Win32  package yaratalım. (File->New->Package)

    2.Bu bir DesignTime package olduğu için Project Manager’da Requires üzerinde Sağ tıklayarak designide.dcp ekleyelim.

    3.Yeni bir Unit ekleyiniz (File->New->Unit)

    4.MainUnit olarak save ediniz.

    5.MainUnit.pas dosyasını aşağıdaki biçimde değiştiriniz.

     

    unit MainUnit;

    interface

    uses
      ToolsAPI;

    procedure Register;

    implementation

    uses
      Graphics;

    {$R IMAJ_DEPOSU.RES}

    const
      BMP = 
    'BMP_SCREEN';

    procedure InstallSplash;
    var
      lBitmap: TBitmap;
    begin
      if SplashScreenServices = nil then
         Exit;
      lBitmap := TBitmap.Create;
      try
        lBitmap.LoadFromResourceName(hInstance, BMP);
        SplashScreenServices.AddPluginBitmap(
    'Yükleniyor...', lBitmap.Handle, False, 'Version 0.0.1', 'Klavye servisi');  //Buradaki False True yapılırsa, yazı kırmızı renkte çıkar
      finally
        lBitmap.Free;
      end;
    end;


    procedure Register;
    begin
      InstallSplash;
    end;

    end.

     

    6.Compile (Ctrl-F9) ettiğimiz zaman “File not found: IMAJ_DEPOSU.RES” mesajı verecektir.

    7.IMAJ_DEPOSU.RES dosyasını hazarlamamız gerekir, bunun için

    a. Bir tane 48x48 idel boyutlarda olmak üzere (16x16 da olabilir) bir tane bitmap dosyası bulalım. BK3.BMP olsun.

    b.Notepad de ya da herhanig bir test editörde IMAJ_DEPOSU.RC (Resource File) adlı bir dosya yaratalım.

    c. IMAJ_DEPOSU.RC  dosyası içine BMP_SCREEN Bitmap "BK3.bmp" satırını aşağıdaki gibi ekleyelim.


       d.IMAJ_DEPOSU.RES dosyasını yaratmak için projeyi save ettiğiniz klasörde command prompt satırında aşağıdaki komutu kullanınız. (brc32 –r IMAJ_DEPOSU.RC)

     

    8.IMAJ_DEPOSU.RES dosyamız hazır olduğu için artık compile (Ctrl-F9) edebiliriz.

    9.Bu package design time package olduğu için bunu tanımlamamız gerekir. Bunu yapmak için package üzerinde sağ tıklayarak Options seçiniz. Aşağıdaki gibi değişiklik yapınız.

         


    10.OK ile onaylayınız, artık bu package install edebilir.

    11.Install etmek için Project Manager'de package üzerinde sağ tıklayarak Install seçeneğini seçiniz.

    12.Package’in install edildiğine dair ekrana bir mesaj çıkacaktır.

    13.Ayrıca Install edildiğiniz Delphi menüsünden de görebiliriz. “Component->Install Packages...” ile ekran aşağıdaki gibi olmalıdır.

         


    14.Delphi’yi kapatıp açtığınızda package’niz ile ilgili mesaj, ekranda aşağıdaki gibi çıkacaktır.

       Delphi IDE’nizin sizden başka kimsenin açmasını istemiyorsanız.            

    1.Daha önce hazırladığımız unit MainUnit dosyası üzerinde bazı değişiklikler yapalım.

    2.unit MainUnit dosyamızı aşağıdaki gibi değiştirelim.


    unit MainUnit;

    interface

    uses
      ToolsAPI;

    procedure Register;

    implementation

    uses
      Graphics, Dialogs;

    {$R IMAJ_DEPOSU.RES}

    const
      BMP_SCREEN = 
    'BMP_SCREEN';

    procedure InstallSplash;
    var
      lBitmap: TBitmap;
      str:string;
      rc : Boolean;
    begin
      if SplashScreenServices = nil then
         Exit;
      lBitmap := TBitmap.Create;
      try
        lBitmap.LoadFromResourceName(hInstance, BMP_SCREEN);

        //Buradaki False True yapılırsa, yazı kırmızı renkte çıkar
        SplashScreenServices.AddPluginBitmap(
    'Loading...', 

    lBitmap.Handle, True, 'Version 0.0.1', 'Testing'); 
        str := 
    '';
        rc := InputQuery(
    'Şifre', 'Kod:', str);
        if not rc then Halt(1); 
    {Programdan çıkınız, yani 

    IDE'nin çalışmasına izin vermeyiniz.}
        if str <> 
    'GizliSifre' then Halt; //Aynı şekilde byee.
      finally
        lBitmap.Free;
      end;
    end;

    procedure Register;
    begin
      InstallSplash;
    end;

    end.

     

      3.Herşeyimizi tekrar Save edelim. (Şifre sorduğunda yanlışlıkla ESC basarsak Delpi kapanır!)

      4.Compile (Ctrl-F9) edelim, package daha önce install edildiği için ayrıca tekrar Install etmemize gerek yoktur.

      5.Delphi’den çıkıp tekrar çalıştırdığımızda, bir süre sonra sizden şifre isteyecektir.

      6.'GizliSifre' dışında ya da ESC tuşuna ya da Cancel butonuna basarsak Delphi KAPANIR!!.

      7.Böylece install ettiğiniz package’yi koruma altına aldıktan sonra Delphi’nizi sizden başka kimse kullanamayacaktır.

      Not1: InputQuery yerine sizin kullandığınız herhangi bir Form da kullanabilirsiniz.

      Not2: Bu servisi değiştirip Compile ettiğimizde her durumda Register çalışacaktır.

       

       

      Klavye servisi:

      Daha önce yaptığımız örneği geliştirerek Ctrl+Shift+D tuş kombinasyonları yardımı ile Delphi içinde çalıştığımız bir dosyada bir kelimeyi işaretleyip hafızaya kopyalayalım. Normal olarak bir kelineyi kopyalamak için kelimeyi işaretyelip Ctrl-C tuşuna basarız. Bu servisde ise kelime üzerindeyken  (Kelimeyi işaretlemeye gerek yok) Ctrl+Shift+D tuş yardımı ile işaretleyip hafızaya kopyalarız.  Kısaca nasıl yapıldığına bakalım.

      Bu özelliği kullanmak için IOTAKeyboardBinding servisinden yararlanılır.

      ToolsAPI.pas dosyasına baktığımızda,  IOTAKeyboardBinding elemanları kısaca şöyledir:

       

      IOTAKeyboardBinding = interface(IOTANotifier)
        [
      '{F8CAF8D7-D263-11D2-ABD8-00C04FB16FB3}']
        function GetBindingType: TBindingType;
        function GetDisplayName: string;
        function GetName: string;
        procedure BindKeyboard(const BindingServices: IOTAKeyBindingServices);

        property BindingType: TBindingType read GetBindingType;
        property DisplayName: string read GetDisplayName;
        property Name: string read GetName;
      end;

       

      Metodları kısaca açıklamak gerekirse:

      function GetBindingType: Burada Delphi’ye kullanılacak tuş setinin tipini tanıtıyoruz, yeni bir set mi (btComplete) yoksa sadece var olan bir setini mi genişletiyoruz (btPartial) ?
      function GetDisplayName:
      Editor options da Key Mapping kısmında görülecek isim.

      function GetName: Servis için kullanılan Unique bir isim. Format olarak, genellikle adiniz.servisadi. Türkçe karakterler kullanılmamalıdır.

      procedure BindKeyboard(const BindingServices: IOTAKeyBindingServices): Servisi Delphi sistemine tanıtıyoruz. Bunun için IOTAKeyBindingServices servisinin AddKeyBinding metodunu çağırırız.

      Daha önce yaptığımız kod üzerinde aşağıdaki değişikliği yapalım.

      Şimdilik şifre sorma kısmını iptal edelim gerektiğinde tekrar ekleriz.

      unit MainUnit;

      interface

      uses
        ToolsAPI, Menus, Classes;

      type
        TycKeyboardBinding = class(TNotifierObject, IOTAKeyboardBinding)
        private
          
      { IOTAKeyboardBinding }
          procedure BindKeyboard(const BindingServices: IOTAKeyBindingServices);
          function GetBindingType: TBindingType;
          function GetDisplayName: string;
          function GetName: string;
          procedure TusExecute(const Context: IOTAKeyContext; 

                            KeyCode: TShortcut; 

                            var BindingResult: TKeyBindingResult);
        end;

      procedure Register;

      implementation

      uses
        Graphics, Dialogs, SysUtils;

      {$R IMAJ_DEPOSU.RES}

      const
        BMP_SCREEN = 
      'BMP_SCREEN';

      procedure InstallSplash;
      var
        lBitmap: TBitmap;
      //  str:string;
      //  rc : Boolean;
      begin
        if SplashScreenServices = nil then
           Exit;
        lBitmap := TBitmap.Create;
        try
          lBitmap.LoadFromResourceName(hInstance, BMP_SCREEN);
          SplashScreenServices.AddPluginBitmap(
      'Loading...', 

                 lBitmap.Handle, True, 'Version 0.0.1', 

                 'Klavye servisi'); {Buradaki False değeri True

                                    yapılırsa, yazı kırmızı renkte çıkar}
      {!!Şimdilik iptal edelim
          str := '';
          rc := InputQuery('Şifre', 'Kod:', str);
          if not rc then Halt(1); //Programdan çıkınız, yani IDE'nin çalışmasına 

                                         //izin vermeyiniz.
          if str <> 'GizliSifre' then Halt;
          }
        finally
          lBitmap.Free;
        end;
      end;


      var
        TusTakimiIndex : Integer;

      procedure Register;
      var
        KeyboardServices: IOTAKeyboardServices;
      begin
        TusTakimiIndex := -1;
        InstallSplash;
        if Supports(BorlandIDEServices, IOTAKeyboardServices, 

           KeyboardServices) then
           TusTakimiIndex := KeyboardServices.AddKeyboardBinding

                             (TycKeyboardBinding.Create);
      end;

      { TycKeyboardBinding }

      procedure TycKeyboardBinding.BindKeyboard(
        const BindingServices: IOTAKeyBindingServices);
      begin
        BindingServices.AddKeyBinding([ShortCut(Ord(
      'D'), 

                 [ssCtrl, ssShift])], TusExecute, nil);
      end;

      function TycKeyboardBinding.GetBindingType: TBindingType;
      begin
        //Sadece var olan bir tuş setini genişletiyoruz (btPartial)
        Result := btPartial;
      end;

      function TycKeyboardBinding.GetDisplayName: string;
      begin
        //Editor options da görülecektir
        Result := 'Test servisim'
      end;

      function TycKeyboardBinding.GetName: string;
      begin
        //Unique bir isim
        Result := 'YusufCELIK.KlavyeTest'
      end;



      //Ctrl+Shift+D tuş kombinasyonuna basıldığında çalışacak rutin.
      procedure TycKeyboardBinding.TusExecute(const Context: IOTAKeyContext;
        KeyCode: TShortcut; var BindingResult: TKeyBindingResult); 

      const
      CharSet = [
      ' ', ';', '(', ')', '=', ':', ',', '.', '-', '+', '''',
                 
      '[', ']', '>', '<', '*', '/', '\'];
      var
        Row : Integer;
        ColStart : Integer;
        ilkCol : Integer;
        Col : Integer;
        ColEnd : Integer; 
        i : Integer;
        str : string;
      begin
      {BindingResult değerine göre Delphi karar verir:
        
      krUnhandled : Tuş kombinasyonu bu procedur içinde işlem görmedi, 

                      bu tuş kombinasyonun kullanan bir sonraki 

                      procedur de kullanılabilir.

                      Yani Delphi IDE'sinde bu tuş kombinasyonunu 

                      kullanan bir menu var ise işlem görür.

        krHandled   : Tuş kombinasyonu bu procedur içinde işlem gördü, 

                      bu tuş kombinasyonu ile ilgili başka işlem 

                      yapılmayacaktır.
        
      krNextProc  : Bu tuşu kullanan bir sonraki procedur bu tuşu 

                      kullanabilir, ancak hiç bir menu işlem 

                      görmez.
        
                    Yani Delphi IDE'sinde bu tuş kombinasyonunu 

                      kullanan bir menu var ise işlem görmez.

      }
        BindingResult := krHandled;

       

        //Context.EditBuffer.EditPosition editorle ilgili 

        //bilgilere ulaşabilirsiniz
        Row := Context.EditBuffer.EditPosition.Row; //Cursor satırını al
        Col := Context.EditBuffer.EditPosition.Column;
      //Cursor sütununu al

        Context.EditBuffer.EditPosition.MoveEOL; 

        //satırdaki karakter sayısını bulalım
        i := Context.EditBuffer.EditPosition.Column;

        Context.EditBuffer.EditPosition.MoveBOL; 
        str := Context.EditBuffer.EditPosition.Read(i); //satırı kopyalayalım
        ColEnd := Length(str)+1; 
        ColStart := Col; 
        while ColStart > 0 do 
        begin 
          if not (str[ColStart] in CharSet) then 
             Break; 
          Dec(ColStart) 
        end; 
        ilkCol := ColStart; 
        for i := ColStart to Length(str) do 
        begin 
          if str[i] in CharSet then 
          begin 
            ColEnd := i; 
            Break; 
          end; 
        end; 
        ColStart := 0; 
        for i := ilkCol downto 1 do 
        begin 
          if str[i] in CharSet then 
          begin 
            ColStart := i+1; 
            Break; 
          end; 
        end; 
        if (ColStart <> 0) and (ColEnd <> 0) then 
        begin

          //Cursor’u Row satır ColStar sütuna götür 
          Context.EditBuffer.EditPosition.Move(Row, ColStart); 
          //Bu satır ve kolondan işaretlemeye başla  
          Context.EditBuffer.EditBlock.BeginBlock; 
          // Cursor’u Row satır ColEnd sütuna götür  
          Context.EditBuffer.EditPosition.Move(Row, ColEnd); 
          //Bu satır ve kolondan işaretlemeye bitir  
          Context.EditBuffer.EditBlock.EndBlock; 
          //İşaretlenen kelimeyi ClipBoarda kopyala  
         
      //Buradaki False, ClipBoard’daki değer ezilsin demektir  
          Context.EditBuffer.EditBlock.Copy(False); 
          //Aşağıdaki satır neyi kopyaladığımızı görmek içindir. 
          
      //Çalıştığından emin olduktan sonra silebiliriz. 
          str := Copy(str, ColStart, ColEnd-ColStart); 
          ShowMessage(
      'Kopyalandı...'+#13#10+ 
                      
      'Kopyalanan değer:['+str+']');
        end 
        else 
        begin 
          Context.EditBuffer.EditPosition.Move(Row, Col); //eski satır/kolona gidelim
        end; 
      end;

      initialization

      finalization
        //Regiter procedurunda yapılanın tam tersi, yani servisi uninstall eder.  
        if TusTakimiIndex <> -1 then
           (BorlandIDEServices as IOTAKeyboardServices).RemoveKeyboardBinding(

                   TusTakimiIndex);
      end.

       

      Yapılan son değişikliklerden sonra Compile edersek ekrana bir mesaj çıkarak servisi yükler.

      Editor Options’a bakıldığında daha önce belirttiğimiz gibi aşağıdaki isimle kayıt edildiğini görürüz.

      function TycKeyboardBinding.GetDisplayName: string;
      begin
        //Editor options da görülecektir
        Result := 'Test servisim'
      end;

       

      Bir sonraki konumuza geçmeden önce yukarıdaki örnekte sıkça kullandığımız interface IOTAEditPosition hakkında bilgi verelim. Önce yapısına bakalım.

      IOTAEditPosition = interface(IUnknown)
          [
      '{9C510464-C7BC-11D2-9AEB-00A02457621F}']
          procedure Align(Magnitude: Integer);
          function BackspaceDelete(HowMany: Integer): Boolean;
          function Delete(HowMany: Integer): Boolean;
          function DistanceToTab(Direction: TSearchDirection): Integer;
          ...
          ...
          function GotoLine(LineNumber: Integer): Boolean;
          procedure InsertBlock(const Block: IOTAEditBlock);
          procedure InsertCharacter(Character: Char);
          procedure InsertFile(const FileName: string);
          procedure InsertText(const Text: string);
          function Move(Row, Col: Integer): Boolean;
          function MoveBOL: Boolean;
          function MoveCursor(MoveMask: TMoveCursorMasks): Boolean;
          function MoveEOF: Boolean;
          function MoveEOL: Boolean;
          function MoveReal(Row, Col: Integer): Boolean;
          function MoveRelative(Row, Col: Integer): Boolean;
          procedure Paste;
          function Read(NumberOfCharacters: Integer): string;
          function RepeatLastSearchOrReplace: Boolean;
          function Replace(const Pattern, ReplaceText: string; 

                           CaseSensitive, RegularExpression, 

                           WholeFile: Boolean; Direction: TSearchDirection;

                           var ErrorCode: Integer): Integer; overload;
           
          function Replace: Integer; overload;
           
          function ReplaceAgain: Integer;
          procedure Restore;
          function RipText(const ValidChars: TSysCharSet; 

                           RipFlags: Integer): string; overload;
          function RipText(const ValidChars: string; 

                           RipFlags: Integer): string; overload;
           
          procedure Save;
          function Search(const Pattern: string; CaseSensitive, 

                          RegularExpression,
            WholeFile: Boolean; Direction: TSearchDirection;
            var ErrorCode: Integer): Boolean; overload;
           
          function Search: Boolean; overload; 
          function SearchAgain: Boolean;
          procedure Tab(Magnitude: Integer);

          property Character: Char read GetCharacter;
          property Column: Integer read GetColumn;
          property IsSpecialCharacter: Boolean read GetIsSpecialCharacter;
          property IsWhiteSpace: Boolean read GetIsWhiteSpace;
          property IsWordCharacter: Boolean read GetIsWordCharacter;
          property LastRow: Integer read GetLastRow;
          property ReplaceOptions: IOTAReplaceOptions read GetReplaceOptions;
          property Row: Integer read GetRow;
          property SearchOptions: IOTASearchOptions read GetSearchOptions;
        end;

      Interface IOTAEditPosition kısaca, Delphi içinde iken, o anda kod ya da başka bişey yazdığınız yazı üzerinde bulunan cursor ile ilgili bilgileri içerir. Bu bilgiler şöyle özetlenebilir.

      Cursorun üzerinde bulunduğu, karakter nedir (Context.EditBuffer.EditPosition.Character) ?

      Cursor kaçıncı satırda,  kaçıncı sütündadır

      (Context.EditBuffer.EditPosition.Column ya da Row ) ?   

      Bir kelime mi (Context.EditBuffer.EditPosition.IsWordCharacter) ?

      Üzerinde çalışılan dosyanın son satır sayısı (Context.EditBuffer.EditPosition. LastRow) ?

      Editör’de hangi satıra gitmek istiyorsunuz (Context.EditBuffer.EditPosition. GotoLine) ?

      Editör’de hangi satır/sütün gitmek istiyorsunuz (Context.EditBuffer.EditPosition. Move) ?

      Bulunduğumuz satırın sonuna gitmek (Context.EditBuffer.EditPosition.MoveEOL) ?

      Bulunduğumuz satırın başına gitmek (Context.EditBuffer.EditPosition.MoveBOL) ?

      Dosyanın sonuna gitmek (Context.EditBuffer.EditPosition.MoveEOF) ?

      Clipbordakini yapıştırmak (Context.EditBuffer.EditPosition.Paste) ?

      Karakter dizisi insert etmek için (Context.EditBuffer.EditPosition.InsertText) ?

      İstenilen kadar karakter okumak (Context.EditBuffer.EditPosition.Read) ?

      Cursor pozisyonun saklayıp daha sonra geri dönmek

      (Context.EditBuffer.EditPosition.Save / Restore) ?

      Görüldüğü gibi üzerinde çalıştığımız dosyaya hemen hemen herşeyi yaptırmak mümkündür.

       

      Delphi IDE’sine menu ekleme, menü servisi:

      Daha önce yaptığımız örnek üzerinde devam edelim. Bu sefer Delphi IDE’sine kendi menümüzü ekleyelim. Bu özelliği kullanmak için IOTAWizard interface’inden yaralanırız.

      ToolsAPI.pas dosyasına baktığımızda,  IOTAWizard elemanları kısaca şöyledir:

       

      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;

      Metodları kısaca açıklamak gerekirse:

      function GetIDString: string: Burada unique bir isim veriyoruz, Delphi tarafından internal olarak kullanılıyor. Format olarak, genellikle adiniz.servisadi.
      function GetName: string:
      Delphi tarafından internal olarak kullanılıyor. Türkçe karakterler kullanılmamalıdır

      function GetState: TWizardState: Delphi IDE de kullanılacak menunun durumunu gösterir.

      TWizardState = set of (wsEnabled, wsChecked); Olarak tanımlanmıştır.

      procedure Execute: Yararacağımız menu Help içinde ise, bu procedur çağrılır, IDE menusüne kendi menümüzü ekleyecek isek bu procedure bir işe yaramaz.

      Daha önce yaptığımız kod üzerinde aşağıdaki değişikliği yapalım.

       


      Type ve uses daki değişiklikler.

      uses
        ToolsAPI, Menus, Classes;

      type
        ...
        ...
        TycMenuEkleme = class(TNotifierObject, IOTAWizard)
        private
          delMenu : TMenuItem; 
      //Delphi IDE'sine eklenecek
          procedure CreateMenu;
          procedure MenuClick(Sender:TObject);
        public
          constructor Create;
          destructor Destroy; override;
          procedure YukluPackageGoster;
          
      {IOTAWizard}
          
      { Expert UI strings }
          function GetIDString: string;
          function GetName: string;
          function GetState: TWizardState;

          
      { Launch the AddIn }
          procedure Execute;
        end;

       

      Wizard çalıştığında ilk olarak Create metodunu çağıracaktır.

      constructor TycMenuEkleme.Create;
      var
        intf : INTAServices; 
      //Delphi IDE ile ilgili servistir
      begin
        delMenu := nil;
        if not Supports(BorlandIDEServices, INTAServices, intf) then Exit;
        delMenu := TMenuItem.Create(nil);
        delMenu.Caption := 
      'YCMenu'; //Delpi IDE’de görünecek menu
        CreateMenu;
      //Delpi IDE’de menu yaratalım
      end;

       


      Delpih IDE’sinde 'YCMenu' adlı menünün alt menülerini hazırlayalım

      procedure TycMenuEkleme.CreateMenu;
      var
        itm: TMenuItem;
        DelphiAnaMenu : TMainMenu;
        bmp : TBitmap;

        il : TCustomImageList;
      begin
        itm := TMenuItem.Create(delMenu);
        itm.Caption := 
      'Menu1';
        itm.Tag     := 0;
        //Menu seçildiğinde MenuClick çağrılacaktır.
        itm.OnClick := MenuClick;
        delMenu.Add(itm);

        itm := TMenuItem.Create(delMenu);
        itm.Caption := 
      'Menu2';
        itm.Tag     := 1;
        itm.OnClick := MenuClick;
        delMenu.Add(itm);

        //Open menu item icin icon kullanalim
        itm := TMenuItem.Create(delMenu);
        itm.Caption := 
      'Open...';
        itm.Tag     := 2;
        itm.OnClick := MenuClick;
        bmp := TBitmap.Create;
        try
          bmp.LoadFromResourceName(hInstance, BMP_SCREEN);
          //Bitmap'i Open menusune ekleyelim icin kullanalim.
          itm.ImageIndex := (BorlandIDEServices as INTAServices).

                             AddMasked(bmp, clBlack)
        finally
          bmp.Free;
        end;
        delMenu.Add(itm);

        //Not: Diger menu itemlari icin imaj eklemek icin yukardaki yontem
        
      //kullanilabilir. Designer'da kullanıldığı gibi TAction da kullanılabilir. 

        itm := TMenuItem.Create(delMenu);
        itm.Caption := 
      'Yüklü packageleri göster...';
        itm.Tag     := 3;
        itm.OnClick := MenuClick;
        delMenu.Add(itm);

        itm := TMenuItem.Create(delMenu);
        itm.Caption := 
      '-';
        delMenu.Add(itm);

        itm := TMenuItem.Create(delMenu);
        itm.Caption := 
      'Hakkında...';
        itm.Tag     := 4; 
        bmp := TBitmap.Create;

        try

          //Delphi IDE’sinde bulunan bütün imajları kullanalım

          il := (BorlandIDEServices as INTAServices).ImageList;

          il.GetBitmap(100, bmp); //Hakkında... için 100 numaralı imajı kullanalım

          itm.ImageIndex := (BorlandIDEServices as INTAServices).

                             AddMasked(bmp, clBlack);

        finally

          bmp.Free;

        end;

        itm.OnClick := MenuClick;
        delMenu.Add(itm);

        //Delphi menüsünü alalım
        DelphiAnaMenu := (BorlandIDEServices as INTAServices).MainMenu;
        //Kendi menumuzu Delphi ana menusune ekleyelim
        DelphiAnaMenu.Items.Add(delMenu);
      end;

       


      Menu seçildiğinde alınan aksiyonu tanımlayalım.

      procedure TycMenuEkleme.MenuClick(Sender: TObject);
      var
        mi : TCustomAction;
        cap : string;
        itomod : IOTAModuleServices;
      begin
        mi := Sender as TCustomAction;
        cap := mi.Caption;
        case mi.Tag of
          0 : ShowMessage(
      '1 numaralı menu tıklandı');
          1 : ShowMessage(
      '2 numaralı menu tıklandı');
          2 : 
      //Bir dosyayı Delphi'de açalım
          begin
            with TOpenDialog.Create(nil) do
            try
              if Execute() then
              begin
                
      //Dosyayı delphi'ye yükleyelim
                if Supports(BorlandIDEServices, IOTAModuleServices, 

                   itomod) then
                begin
                  itomod.OpenModule(FileName).Show;
                end;
              end;
            finally
              Free;
            end;
          end;
          3 : YukluPackageGoster();    

          4 : ShowMessage('Bu Delpi IDE Plug-'+

                          'In Yusuf ÇELIK tarafından yazılmıştır');
        end;
      end;

      Yüklü packagelerin gösterilmesi. Burada IOTAPackageServices interface’inden yararlanılmıştır. IOTAPackageServices interface’i kısaca şöyle tanımlanmıştır.

      IOTAPackageServices = interface(IUnknown)
          [
      '{26EB0E4D-F97B-11D1-AB27-00C04FB16FB3}']
          ...
          ...
          property PackageCount: Integer read GetPackageCount;
          property PackageNames[Index: Integer]: string 

                                read GetPackageName;
          property ComponentCount[PkgIndex: Integer]: Integer 

                                  read GetComponentCount;
          property ComponentNames[PkgIndex, CompIndex: Integer]: string 

                                  read GetComponentName;
        end;

      PackageCount: Delphi içinde yüklü package sayısını döner.

      PackageNames[Index: Integer]: Index numaralı package adını verir.

      ComponentCount[PkgIndex: Integer]: PkgIndex numaralı package da kaç tane component olduğu bilgisini verir.

      ComponentNames[PkgIndex, CompIndex: Integer]: PkgIndex numaralı package da CompIndex numaralı component adını verir.


      Yukardaki bilgileri baz alarak, Delphi içinde yüklü package ve bu package lerde bulunan component’ları bulabiliriz. Şimdilik package adlarını bulmamız yeterli.

      procedure TycMenuEkleme.YukluPackageGoster;
      var
        ps : IOTAPackageServices;
        i : Integer;
        str : string;
      begin
        if not Supports(BorlandIDEServices, IOTAPackageServices, ps) then
        begin
          ShowMessage(
      'Desteklenmemektedir');
          Exit;
        end;
        ps := BorlandIDEServices as IOTAPackageServices;
        str := 
      '';
        for i := 0 to ps.PackageCount - 1 do
        begin
          str := str + ps.PackageNames[i] + 
      #13#10;
        end;
        ShowMessage(str);
      end;

      Daha da ileri gidelim ve bu package isimlerini Delphi’nin Compile hatalarını gösterdiği Mesaj alanına yazalım. Bunun için IOTAMessageServices servisinden yaralanabiliriz.

      Yukardaki YukluPackageGoster procedur’unu farklı bir biçimde yazabiliriz.

       

      function ms: IOTAMessageServices;
      begin
        Result := (BorlandIDEServices as IOTAMessageServices);
        if not Assigned(Result) then

           raise Exception.Create('IOTAMessageServices desteklenmemektedir');

      end;

       

      procedure TycMenuEkleme.YukluPackageGoster;
      var
        ps : IOTAPackageServices;
        i : Integer;
      begin
        if not Supports(BorlandIDEServices, IOTAPackageServices, ps) then
        begin
          ShowMessage(
      'Desteklenmemektedir');
          Exit;
        end;
        ps := BorlandIDEServices as IOTAPackageServices;

        ms.ShowMessageView(nil); //Önce Messages ekranını açalım 
        ms.ClearAllMessages;
      //Daha önceki mesajları silelim 

        //Ve kendi mesajlarımızı ekleyelim
        ms.AddTitleMessage(
      'Yüklenen packaga listesi');
        ms.AddTitleMessage(
      '------------------------');
        for i := 0 to ps.PackageCount - 1 do
        begin
          ms.AddTitleMessage(ps.PackageNames[i]);
        end;
      end;

      Bu durumda 'Yüklenen packaga listesi' Delphi’de aşağıdaki gibi görülür.

      Aynı yöntemle package’lardaki component adlarını da bulabiliriz.

       

      Wizarda UnInstall olduğunda Destroy otomatik olarak çağrılır.

      Destroy metodunda da daha önce Create metodunda yaratttığım componentları memory’den silelim.

      destructor TycMenuEkleme.Destroy;
      begin
        if Assigned(delMenu) then
           delMenu.Free;
        inherited;
      end;

      Geri kalanları da kısaca yazalım.

      procedure TycMenuEkleme.Execute;
      begin

        //Burası çağrılmaz, ancak Help altına install edersek çağrılır.

        //Ancak bizim yazdığımız Delphi’ye ek bir menü
        ShowMessage('Execute');
      end;

      function TycMenuEkleme.GetIDString: string;
      begin
        //Unique bir isim
        Result := 'Yusuf.CELIK.MenuEkleme'
      end;

      //Delphi tarafından kullanılır
      function TycMenuEkleme.GetName: string;
      begin
        Result := 
      'Yusuf CELIK menu';
      end;

      //Menu durumunu gösterir, Enabled ya da Checked
      function TycMenuEkleme.GetState: TWizardState;
      begin
        Result := [wsEnabled];
      end;

       

      Şimdi bunu Delphi IDE’sine kayıt etmemiz gerekir. Bu da Register procedurunda yapılır.

      procedure Register;
      var
        KeyboardServices: IOTAKeyboardServices;
      begin
        TusTakimiIndex := -1;
        InstallSplash;
        if Supports(BorlandIDEServices, IOTAKeyboardServices, 

                    KeyboardServices) then
           TusTakimiIndex := KeyboardServices.AddKeyboardBinding

                             (TycKeyboardBinding.Create);
        RegisterPackageWizard(TycMenuEkleme.Create);
      end;

      Artık Delphi IDE’mizde bir menumüz vardır.

      Delphi IDE’sinin son hali, yaklaşık olarak aşağıdaki gibi olur.

       

      Yukarda anlatılanlar yalnızca Delphi OTA (OTAPI ya da Plug-In de denir) denizinde minik bir su birikintisidir.

      Delphi OTA hakkında daha fazla bilgi için aşağıdaki sitelerden yararlanabilirsiniz.

      http://www.gexperts.org/opentools/

      http://www.tempest-sw.com/opentools/

      http://www.mustangpeak.net/opentoolsape.htm

      Sorularınız için bana yusufcelik@gmail.com adresinden ulaşabilirsiniz.

       

      Not: Yukardaki örnekler Borland Delphi 2005 ve 2006 da test edilmiştir.