Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2020年11月08日] [更新 2020年11月08日] Delphi サンプルプログラム集
970_Tools API を使用して IDE のメニューに項目を追加
動作確認等 Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32
970_ToolsAPI_DlgTest.zip [5.9 KB] 2020年11月08日版







Tools API を使用して IDE のメニューに項目を追加


Tools API を使用して IDE のメニューに項目を追加する手順の説明記事です.

Tools API は,IDE を構成する VCL オブジェクトに対して操作する Native Tools API と,抽象的なインターフェースを使用する Open Tools API がありますが,一般的には両者を含めて Tools API と言っています.
Tools API は,Delphi の IDEを拡張するためのA PI であると言えます.Tools API の機能を使用するには,uses 部に ToolsAPI を追加します.

本ページの記事では,以下のリンクの記事に掲載されているサンプルコードを使用しています.IDE のソースエディタを操作するサンプルは使用していません.
本ページのサンプルは,IDE のメニューに項目を追加して,その項目を選択したらダイアログを表示するだけの単純なサンプルとなっています.



[備考]
UDE の機能拡張は,IDE プラグインあるいは IDE アドオン機能と呼ばれていますが,エキスハート (IDE Experts) と呼ばれていたこともあります.
Delphi の IDE '( Integrated Development Environment = 統合開発環境 ) 自身も,このようなプラグインによって構成されていると言えます.




01_パッケージの新規作成とインストール


Delphi の IDE のメニューに項目を追加するには,パッケージを作成してインストールします.そして,メニューに項目を追加するコードを書いたユニットファイルを作成して,そのパッケージに追加します.パッケージは IDE の起動時に読み込まれますから,追加した項目もメニューに表示されます.
コンポーネントを作成して,パッケージに登録するのと同じような操作と言えます.

パッケージは,[ファイル] [新規作成] [その他] で表示される以下のダイアログから [パッケージ] を選択すれば作成できます.



図1

プロジェクトマネージャにパッケージの名前が表示されたら,[プロジェク] [ソースの表示] でコードを表示します.requires 部に,設計時の使用を意味する designide (デザイン IDE) を追加します.追加したら [ファイル] [プロジェクトに名前を付けて保存] で任意の場所に保存します.
システム関係のディレクトリや Program Files のフォルダには保存しないようにします.

下のコードは,plIDEDialogTest という名前で保存した結果です.



リスト1
requires 部に designide を追加して,名前を付けて保存したプロジェクトのソースコード
package plIDEDialogTest;

{$R *.res}
{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
{$ALIGN 8}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO ON}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA ON}
{$IOCHECKS ON}
{$LOCALSYMBOLS ON}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION OFF}
{$OVERFLOWCHECKS OFF}
{$RANGECHECKS OFF}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES ON}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST OFF}
{$MINENUMSIZE 1}
{$IMAGEBASE $400000}
{$DEFINE DEBUG}
{$ENDIF IMPLICITBUILDING}
{$IMPLICITBUILD ON}

requires
  rtl,
  designide;  // 追加

end.


パッケージファイル,正確には,パッケージのソースコードのファイルを保存したらインストールします.パッケージ名のポップアップメニューから [インストール] を選択します.


図2
プロジェクトマネージャからパッケージをインストール

インストールすると下図のダイアログが現れます.このダイアログに表示されているパス名は,コンパイルしたパッケージファイルのデフォルトの保存場所です.


図3
インストール完了

以下のフォルダの階層下に Delphi のパーションごとのフォルダがあります.パッケージのデフォルトのインストール先は,そのフォルダ直下の [Bpl] フォルダです.エクスプローラのアドレス欄に以下のパス名を入力して確認できます.

%PUBLIC%\DOCUMENTS\RAD Studio
%PUBLIC%\DOCUMENTS\Embarcadero\Studio   // Delphi XE6 以降




02_[ ヘルプ ] に項目を追加する処理のユニットを作成


パッケージに追加するユニットを作成します.ユニットは [ファイル] [新規作成] [ユニット] で作成できます.作成したら [ファイル] [名前を付けて保存] で,パッケージファイル (拡張子は .dpk) と同じフォルダ内に保存します.今回は plIDialogTest の名前で保存しています.

保存したら,パッケージ名のポップアップメニューから [追加] を選択します.保存先のフォルダから保存したユニットファイルを選択します.



図4
ユニットファイルの追加
  • ユニットを作成したら,[ファイル] [名前を付けて保存] で保存してから追加

ユニットファイルを追加する時に,下図のダイアログが現れることがあります.このダイアログが現れたら,[はい] をクリックして閉じます.


図5
VCL フレームワークの確認ダイアログ

追加したユニットのコードを以下のようにします.IDE の機能拡張のクラスは,TNotifierObject を継承したクラスとします.
コードを記述したらビルド (再構築) して上書き保存します.

このコードで定義したクラスとそのメソッド類は,外部から使用しないので implementation 部に書いています.クラスの登録用の Register 手続きは,interface 部て定義しないと Delphi 自身もアクセスできまません.



リスト2
[ヘルプ] に項目を追加するコードと,その項目を選択したら実行するコード
unit plIDialogTest;

interface

procedure Register;

implementation

uses
  ToolsAPI,
  Winapi.Windows;

//-----------------------------------------------------------------------------
//  [ヘルプ] に項目を追加するウイザードクラスの定義
//  IOTAMenuWizard は IDEの [ヘルプ] に項目を自動登録してくれるインターフェイス
//  継承元のインターフェイスにあるメソッドは必ず実装が必要
//-----------------------------------------------------------------------------
type
  TIDEDialogTestWizard = class(TNotifierObject, IOTAWizard, IOTAMenuWizard)
    function GetIDString: string;
    function GetName: string;
    function GetState: TWizardState;
    function GetMenuText: string;
    procedure Execute;
  end;

//-----------------------------------------------------------------------------
//  IDE がウイザードを識別するためのユニークな名前の設定
//-----------------------------------------------------------------------------
function TIDEDialogTestWizard.GetIDString: string;
begin
  Result := 'TIDEDialogTestWizard.1.0';
end;

//-----------------------------------------------------------------------------
//  ユーザー定義のウイザードの任意の名前の設定
//-----------------------------------------------------------------------------
function TIDEDialogTestWizard.GetName: string;
begin
  Result := 'Delphi TIDE Dialog Test Wizard';
end;

//-----------------------------------------------------------------------------
//  メニュー項目の状態の設定 (有効,無効など)
//-----------------------------------------------------------------------------
function TIDEDialogTestWizard.GetState: TWizardState;
begin
  Result := [wsEnabled];
end;

//-----------------------------------------------------------------------------
//  [ヘルプ] のメニューに追加した項目のキャプション (タイトル)
//-----------------------------------------------------------------------------
function TIDEDialogTestWizard.GetMenuText: string;
begin
  Result := 'ダイアログを表示';
end;

//-----------------------------------------------------------------------------
//  メニュー項目が選択された時に実行されるメソッド
//  uses に Winapi.Windows が必要
//-----------------------------------------------------------------------------
procedure TIDEDialogTestWizard.Execute;
var
  LText : string;
begin
  LText := '[ヘルプ] から表示したダイアログ';
  MessageBox(0, PChar(LText), '情報', MB_ICONINFORMATION);
end;

//-----------------------------------------------------------------------------
//  ウイザードクラスを生成して登録
//-----------------------------------------------------------------------------
procedure Register;
begin
  RegisterPackageWizard(TIDEDialogTestWizard.Create);
end;

end.


ここまでの説明で作成したファイルを添付しています.
ダウンロードしたらブロックを解除してから解凍展開します.解凍展開したら,[IDE_Dialog] フォルダごと任意のフォルダに移動またはコピーします.このフォルダ内の plIDEDialogTest.dpk ファイルを Delphi の IDE で開いてインストールします.


図6
添付のパッケージファイル
  • plIDEDialogTest.dpk ファイルを Delphi の IDE で開いてインストールする

[備考 1]
ビルド (再構築) と上書き保存は,パッケージファイル名のポップアップメニューから実行できます.[Shift] + [F9] でもビルド (再構築) できます.現在アクティブなファイルあれば [Ctrl] + [S] で保存できます.
コードを変更したらビルド (再構築) しないと実行結果として反映されません.

[備考 2]
作成したユニットは,パッケージに追加しないとコード補完機能などが利用できません.




03_[ ヘルプ ] に追加した項目を実行


ここまでの作業の結果,IDE のメニューの [ヘルプ] を開くと [ダイアログを表示] いう項目が追加されています.これを選択するとダイアログを表示します.
Delphi の IDE を閉じて新規の IDE を起動して実行します.同じようにダイアログを表示します.

これで,[ヘルプ] メニューに項目を追加する方法の説明は終了です



図7
[ヘルプ] のメニュー追加された項目
  • クリックするとダイアログを表示する




04_[ ツール ] に項目を追加する処理のユニットを作成


今度は [ツール] メニューに項目を追加してみます.
[ヘルプ] への項目追加では IOTAWizard と,[ヘルプ] に項目を追加する専用インターフェイスを使用しました.[ツール] への項目追加専用のインターフェイスはありません.IOTAWizard インターフェイスだけを使用します.[ツール] への項目追加は,以下のオンラインヘルプにあるように,[ツール] メニューを探し出して操作します.


手順は [ヘルプ] の時と同じです.新規にパッケージを作成したら,そのパッケージに追加するユニットを作成してそのパッケージに追加します.
パッケージ名も,追加するユニットの名前も,クラス名も,既に使用している名前は使用できません.パッケージ名もユニット名も重複しない名前で保存します.

以下がパッケージに追加するユニットのコードです.このコードは [ツール] メニューに [モジュール情報取得] という項目を追加して,その項目を選択したらフォームを表示します.フォームの作成方法は次項で説明しています.そのフォームのユニット名を uses に追加しておきます.



リスト3
[ツール] に項目を追加するコードと,その項目を選択したらフォームを表示するコード
unit plDialogStruct;

interface

procedure Register;

implementation

uses
  ToolsAPI,
  Vcl.Dialogs,
  Vcl.Menus,
  System.AnsiStrings,
  System.SysUtils,
  plDialogStructForm;

 var
   FAddItem : TMenuItem;

//-----------------------------------------------------------------------------
//  [ツール] に項目を追加するウイザードクラスの定義
//  IOTAWizard インターフェイスを使用する
//
//  継承元のインターフェイスにある以下のメソッド類は必ず実装が必要
//  GetIDString, GetNamem, GetState, Execute
//-----------------------------------------------------------------------------
type
  TIDEDialogStructWizard = class(TNotifierObject, IOTAWizard)
    function GetIDString: string;
    function GetName: string;
    function GetState: TWizardState;
    procedure Execute;
    constructor Create;
    destructor Destroy; override;
    procedure OnItemClickEvent(Sender: TObject);
  end;

//-----------------------------------------------------------------------------
//  IDE がウイザードを識別するためのユニークな名前の設定
//-----------------------------------------------------------------------------
function TIDEDialogStructWizard.GetIDString: string;
begin
  Result := 'TIDEDialogStructWizard.1.0';
end;

//-----------------------------------------------------------------------------
//  ユーザー定義のウイザードの任意の名前の設定
//-----------------------------------------------------------------------------
function TIDEDialogStructWizard.GetName: string;
begin
  Result := 'Delphi IDE TIDE Dialog Struct Wizard';
end;

//-----------------------------------------------------------------------------
//  メニュー項目の状態の設定 (有効,無効など)
//-----------------------------------------------------------------------------
function TIDEDialogStructWizard.GetState: TWizardState;
begin
  Result := [wsEnabled];
end;

//-----------------------------------------------------------------------------
//  メニュー項目が選択された時に実行されるメソッド
//  本サンプルでは追加した項目の OnClick イベントで処理するので使用しない
//  使用しなくても継承元の IOTAWizard インターフェイスにあるので実装が必要
//-----------------------------------------------------------------------------
procedure TIDEDialogStructWizard.Execute;
begin
//
end;

//-----------------------------------------------------------------------------
//  クラスのコンストラクタ
//  [ツール] メニューに新規に項目を追加
//
//  uses に以下が必要
//  Vcl.Menus,
//  System.AnsiStrings,
//  System.SysUtils;
//-----------------------------------------------------------------------------
constructor TIDEDialogStructWizard.Create;
var
   LIDESrv   : INTAServices;
   LToolMenu : TMenuItem;
   LIndex    : Integer;
begin
{中略}
  // IDE のオブジェクトを取得
  // INTAServices が IDE の本体
  LIDESrv := BorlandIDEServices as INTAServices;

  LToolMenu := nil;
  // メインメニューの [ツール] を探す
  for LIndex := 0 to LIDESrv.MainMenu.Items.Count - 1 do begin
    if AnsiSameText(LIDESrv.MainMenu.Items[LIndex].Name,'ToolsMenu') then begin
      LToolMenu := LIDESrv.MainMenu.Items[LIndex];
      Break;
    end;
  end;

  // 新しい項目を生成
  FAddItem := TMenuItem.Create(nil);

  // 生成した項目の各種プロパティと OnClick イベントを設定
  FAddItem.Name    := 'plDialogStruct';
  FAddItem.Caption := 'モジュール情報取得';
  FAddItem.OnClick := OnItemClickEvent;
  // [ツール] の 2 番目の項目として追加
  LToolMenu.Insert(1, FAddItem);
end;

//-----------------------------------------------------------------------------
//  生成したクラスのデストラクタ
//  新規に作成したメニュー項目のオブジェクトを破棄
//-----------------------------------------------------------------------------
destructor TIDEDialogStructWizard.Destroy;
begin
  FreeAndNil(FAddItem);
  inherited;
end;

//-----------------------------------------------------------------------------
//  新規に追加したメニュー項目の OnClick イベント処理
//  フォームを表示
//-----------------------------------------------------------------------------
procedure TIDEDialogStructWizard.OnItemClickEvent(Sender: TObject);
begin
  Form1 := TForm1.Create(nil);
  try
    Form1.ShowModal;
  finally
    FreeAndNil(Form1);
  end;
end;

//-----------------------------------------------------------------------------
//  ウイザードクラスを生成して登録
//-----------------------------------------------------------------------------
procedure Register;
begin
  RegisterPackageWizard(TIDEDialogStructWizard.Create);
end;

end.




05_[ ツール ] に追加した項目選択で表示するフォームを作成


[ツール] に追加した項目を選択したら表示するフォームを作成します.作成方法は通常の VCL アプリケーションのフォームと同じです.[ファイル] [新規作成] [VCL フォーム] で作成します.
このフォームに TMemo を 1 つ配置します.


図8
フォームを新規作成

このフォームを [ファイル] [名前を付けて保存] で,拡張子が .dpk のファイルがあるフォルダ内に保存します.今回は plDialogStructForm と言う名前で保存しました.保存したらパッケージに追加しておきます.

ToolsAPI を使用するユニットは,パッケージに追加しないと利用できません.フォームのユニットの場合,フォームを表示しようとすると例外が発生します. uses 部に ToolsAPI が必要ないユニットは,パッケージに追加しなくても利用できます.

単にフォームを表示するだけでは味気ありません.そこで,IDE の構造ペインと同じ情報を取得するコードにしてみました.以下がそのコードです.このコードは,参考リンクに掲載されているコードをそのままコピーして使用しています.
このコードで使用しているインターフェイスは,構造ペインの操作用インターフェイスです.



コーディングが終了したらビルド (再構築) して,上書き保存してパッケージをインストールします.インストールしたら Delphi の IDE を閉じます.



リスト4
[ツール] に追加した項目を選択したら表示するフォームのユニットのコード
unit plDialogStructForm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    procedure FormShow(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

  procedure StructureViewToSL(ASL: TStringList);

var
  Form1: TForm1;

implementation

uses
  ToolsAPI,
  StructureViewAPI;

{$R *.dfm}

{ TForm1 }

//=============================================================================
//  フォームを表示する時のイベント
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
  LStrList : TStringList;
begin
  Self.Caption := '構造';

  Memo1.Lines.Clear;
  Memo1.ScrollBars := ssBoth;
  Memo1.Font.Size  := 11;
  Memo1.Font.Name  := 'Courier New';

  LStrList := TStringList.Create;
  try
    StructureViewToSL(LStrList);
    Memo1.Lines.Text := LStrList.Text;
  finally
  end;
end;

//-----------------------------------------------------------------------------
//  Delphi の IDE の構造ペインと同じ情報を取得して表示
//  現在アクティブなモジュールの情報
//  結果は [ツール| [オプション] [環境オプション] [エクスプローラ] の設定に依存する
//
//  uses に ToolsAPI, StructureViewAPI が必要
//-----------------------------------------------------------------------------
procedure StructureViewToSL(ASL: TStringList);

  procedure TreeToSL(ANode: IOTAStructureNode; ASL: TStringList; const APrefix: string);
  var
    I: Integer;
  begin
    ASL.Add(APrefix + ANode.Caption);
    for I := 0 to ANode.ChildCount - 1 do begin
      TreeToSL(ANode.Child[I], ASL, APrefix + '  ');
    end;
  end;

var
  StructureView: IOTAStructureView;
  StructureContext: IOTAStructureContext;
  Node: IOTAStructureNode;
  I: Integer;
begin
  StructureView := BorlandIDEServices as IOTAStructureView;
  StructureContext := StructureView.GetStructureContext;
  for I := 0 to StructureContext.RootNodeCount - 1 do
  begin
    Node := StructureContext.GetRootStructureNode(I);
    TreeToSL(Node, ASL, '');
  end;
end;

end.


上のサンプルコーでは,インターフェイスのオブジェクトの取得に as 演算子を使用しています.
Supports 関数,あるいは QueryInterface メソッドを使用する場合は以下のように書けます.


  // 上のサンプルコード ( as 演算子によるオブジェクトの取得)
  StructureView := BorlandIDEServices as IOTAStructureView;


  // Supports 関数を使用する例 (戻り値は論理値)
  if Supports(BorlandIDEServices, IOTAStructureView, StructureView) then begin
    // StructureView を使用する各種処理 
  end;  

  // QueryInterface メソッドを使用する例 (戻り値は HRESULT 型)
  if BorlandIDEServices.QueryInterface(IOTAStructureView, StructureView) = S_OK then begin
    // StructureView を使用する各種処理
  end; 




06_現在のモジュール構造の情報を取得して表示


ここで言うモジュールは,プロジェクト,アプリケーションの構成要素としてのモジュールを意味します.それらは,ユニット,フォーム,パッケージ,あるいは EXE, DLL 等です.

Delphi の IDE を起動して新規に VCL フォームアプリケーションを作成します.コードエディタを表示して type 節に TMyClass というクラスの定義を追加します.[F12] でフォームを表示したら TButton を 2 つ配置します.


type
  TMyClass = class(TObject);

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;


メニューの [ツール] から [モジュール情報取得] を選択します.


図9
[ツール] に追加した項目を選択

下図のようになります.現在アクティブなモジュールは From1 です.その構造が確認できます.


図10
Form1 の構造

[ツール] から表示したフォームを閉じて,[F12] で Unit1 をアクティブにします.そして[ツール] に追加した項目を選択します.下図のようになります.現在アクティブなモジュールである Unit1 の構造が確認できます.


図11
Unit1 の構造




07_パッケージの説明テキストの変更方法


パッケージをインストールすると,[コンポーネント] [パッケージのインストール] で表示されるダイアログに,インストールしたパッケージが追加されます.
本ページの手順で作成したパッケージの場合は下図のようになりまりす.説明のテキストが,コンパイルしたパッケージファイルのフルパス名なっています.この説明テキストの変更方法です.


図12
インストールしたパッケージの説明テキスト

拡張子が .dpk のパッケージファイルを開きます.[プロジェクト] [オプション] のダイアログの [説明] の部分に説明として表示するテキストを入力します.


図13
パッケージの説明テキストを入力

アンインストールして再度インストールします.


図14
アンインストールして再度インストール

下図のように変更されます.[上書き保存] してからパッケージを閉じます.あるいは Delphi の IDE を閉じます.


図15
変更結果




08_パッケージのアンインストール方法


パッケージのアンインストール方法もコンポーネント関係のパッケージと同じです.
[コンポーネント] [パッケージのインストール] の下図のダイアログで,該当パッケージを選択して [削除] でアンインストールできます.


図16
パッケージの削除

パッケージを開いている状態であれば,下図のように,パッケージ名のポップアップメニューで [アンインストール] を選択すればアンインストールできます.
どちらの方法も,そのパッケージを登録から削除して使用できないようにするだけです.関係ファイルの削除はしません.該当パッケージ関係のファイルは手作業で削除します.


図17
パッケージのアンインストール