Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2020年11月08日] [更新 2020年11月10日] Delphi サンプルプログラム集
974_パッケージ名とコンポーネント名の列挙
動作確認等 Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32
974_PackageCompoList.zip [1.8 MB] 2020年11月10日版 (EXE 同梱)







パッケージ名とコンポーネント名の列挙


Delphi 自身が使用する, つまり Delphi の IDE が使用するパッケージ群の列挙と,それらのパッケージに登録されているコンポーネント名の列挙に関するサンプルです.

本ページでは,最初と最後のサンプル以外は,以下の記事で説明している手順で作成したパッケージを使用しています.それらのパッケージをインストールして,[ツール] メニューに追加した項目からフォームを表示しています.本文中の「IDE から実行」や「IDE から表示」という記述は,そのことを意味しています.






01_実行時にロードして使用するモジュール名を列挙


EXE 起動時にどのようなモジュールがロードされるのかを確認してみます.現在のプロセスが実行時に読み込んだモジュールは,Windows API の EnumProcessModules 関数で列挙できます.

このサンプルは実行時パッケージを使用していません.したがって,拡張子が .bpl のパッケージファイルはリストされていません.実行時パッケージ使用の有無は,グローバル変数 ModuleIsPackage (SysInit.pas) で確認することができます.



図1
プロセスが使用するモジュール名を列挙
  • 実行時パッケージを使用していないので BPL ファイルはリストにない

リスト1
現在のプロセス (EXE) が使用するモジュール名を列挙
unit Unit1;

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 FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

  function EnumModules(AMemo: TMemo): Boolean;

var
  Form1: TForm1;

implementation

uses
 Winapi.PsAPI;

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Clear;
  Memo1.ScrollBars := ssBoth;
  Memo1.Font.Size  := 11;
  Memo1.Font.Name  := 'Courier New';
end;

//=============================================================================
//  フォーム表示開始時の処理
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
  Memo1.Lines.BeginUpdate;
  EnumModules(Memo1);
  Memo1.Lines.EndUpdate;
end;

//-----------------------------------------------------------------------------
//  現在のプロセスで使用しているモジュールを列挙
//
//  uses に Winapi.PsAPI が必要
//-----------------------------------------------------------------------------
function EnumModules(AMemo: TMemo): Boolean;
var
  LhProcess     : THandle;
  LSizeNeeded   : Cardinal;
  LhModuleArray : array of HMODULE;
  LhModule      : HMODULE;
  LModulePath   : string;
  LIndex        : Integer;
begin
  Result := False;

  // 現在のプロセスのハンドルを取得
  LhProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,
                           False,
                           GetCurrentProcessId);
  if LhProcess = 0 then
    RaiseLastOSError;

  try
    // モジュールハンドルの値格納に必要なメモリのバイト数を取得
    LSizeNeeded := 0;
    EnumProcessModules(LhProcess, nil, 0, LSizeNeeded);
    if LSizeNeeded = 0 then Exit;

    // モジュールハンドルの値を格納する配列の要素数ょ設定
    SetLength(LhModuleArray, LSizeNeeded div SizeOf(HMODULE));

    // モジュールハンドル値を列挙
    if EnumProcessModules(LhProcess,
                          PHMODULE(LhModuleArray),
                          LSizeNeeded,
                          LSizeNeeded) then begin

      // モジュールがある場所 (フルパス) を取得して表示
      for LIndex := 0 to Length(LhModuleArray) - 1 do begin
        LhModule := LhModuleArray[LIndex];

        // 自分自身 (このプログラム EXE ) は除外
        if LhModule <> HInstance then begin
          LModulePath := GetModuleName(LhModule);
          AMemo.Lines.Add(LModulePath);
        end;
      end;

      AMemo.Lines.Add('モジュール数 : ' +  IntToStr(Length(LhModuleArray) - 1));
      if ModuleIsPackage then begin
        AMemo.Lines.Add('実行時パッケージあり');
      end else begin
        AMemo.Lines.Add('実行時パッケージなし');
      end;

      Result := True;
    end;
  finally
    CloseHandle(LhProcess);
  end;
end;

end.




02_Delphi が使用するモジュール名を列挙


前項のコードを IDE から表示すると下図のようになります.現在のプロセスが IDE ということになりますから,実行時にパッケージを読み込んでいるのと同じです.

添付の [IDE_EnumModule] フォルダ内の plEnumModule.dpk をインストールすると,[ツール] に [モジュールの一覧取得] が追加されます.その項目を選択すると,下図の結果を確認できます.



図2
Delphi が使用するモジュール
  • 拡張子が .bpl のパッケージファイルも含まれる




03_Tools API を使用したパッケージ名 ( .BPL ) の列挙


上のサンプルコードで,TMemo に表示する部分を次のようにすれば,拡張子が .bpl のパッケージ名だけを列挙することができます.

          LModulePath := GetModuleName(LhModule);
          LFileExt := ExtractFileExt(LModulePath);

          // 指定拡張子のみ処理
          if CompareText(LFileExt, '.BPL') = 0 then begin
            AMemo.Lines.Add(LModulePath);
            Inc(LCount);
          end;


ToolsAPI に IOTAPackageServices インターフェイスがあります.これはパッケージの操作用です.このインターフェイスの Package プロパティは,パッケージのオブジェクトである IOTAPackageInfo インタフェイス型です.このプロパティを使用すると,図の下に示すようなコードで,拡張子が .bpl のパッケージ名を列挙できます.

このコードのフォームを IDE から表示すると下図のようになります.



図3
IDE からパッケージを列挙した結果
  • 標準コンポーネントのパッケージ dclstd190.bpl がある

最後までスクロールした状態が下図です.テストした筆者の環境では全部で 116 でした.実行時専用パッケージを除外すると 59 になりました.この値は設計時に使用可能なパッケージ数ということになります.この値には,[コンポーネント] [パッケージのインストール] のパッケージのリストで,チェックがないパッケージは含まれていません.
これらは IDE 自身が使用するパッケージを除外した数です.IDE 自身が使用するパッケージと実行時専用パッケージを含めると 195 でした.

下図の最後の 3 つのパッケージは,今回のテストで,IDE からフォームを表示するために作成してインストールしたパッケージです.



図4
パッケージ数は 116
  • IDE 自身が使用するパッケージを除外した数
  • IDE 自身が使用するパッケージを含めると 195

添付の [IDE_PackageList] フォルダ内の plPackageList.dpk をインストールすると,[ツール] に [パッケージ名の列挙] が追加されます.その項目を選択すると,上の図の結果を確認できます.



リスト2
パッケージ名を列挙するために,IDE から表示するフォームのコード
unit plPackageListForm;

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);
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  ToolsAPI;

{$R *.dfm}

{ TForm1 }

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Clear;
  Memo1.ScrollBars := ssBoth;
  Memo1.Font.Size  := 11;
  Memo1.Font.Name  := 'Courier New';
end;

//=============================================================================
//  フォームを表示する時の処理
//  パッケージ名 (拡張子は .bpl) を列挙
//
//  uses に ToolsAPI が必要
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
  LPkgeServices : IOTAPackageServices;
  LPackage      : IOTAPackageInfo;
  LIndex        : Integer;
begin
  Memo1.Lines.BeginUpdate;

  // インターフェイスのオブジェクトを取得
  LPkgeServices := BorlandIDEServices as IOTAPackageServices;

  for LIndex := 0 to  LPkgeServices.PackageCount - 1 do begin
    LPackage := LPkgeServices.Package[LIndex];
    // IDE 自身が使用するパッケージは除外
    if LPackage.IDEPackage then Continue;
    // 実行時パッケージで使用可能なパッケージだけを列挙する時は以下を追加
    // if LPackage.RuntimeOnly then Continue;

    // LPackage.FileName にすればフルパス
    Memo1.Lines.Add(LPackage.Name);
  end;
  Memo1.Lines.Add(IntToStr(Memo1.Lines.Count));

  Memo1.Lines.EndUpdate;
end;

end.




04_パッケージ名の列挙と各パッケージの情報取得


前項と同じ Package プロパティのインターフェイスである IOTAPackageInfo を使用して,パッケージの各種の情報を取得するサンプルです.
このインターフェイスには,パッケージの Contains,Requires 部のリストを取得するメソッドや,その他の情報を取得するプロパティがあります.それらを使用して,パッケージの情報を TTreeView に表示します.

図の下に示すコードのフォームを IDE から表示すると下図ようになります.
これは,構造ペインに表示される内容と同じです.パッケージの構造ということになります.



図5
パッケージの構造
  • plPackageListInfo.bpl は,このフォームを表示するために作成したパッケージ

下図は標準パッケージ dclstd190.bpl の情報 (構造) です.



図6
標準コンポーネントのパッケージ dclstd190.bpl の構造

添付の [IDE_PackageList_Info] フォルダ内の plPackageListInfo.dpk をインストールすると,IDE の [ツール] メニューに [パッケージの情報取得] が追加されます.その項目を選択すると,上の図の結果を確認できます.



リスト3
パッケージの情報 (構造) を取得して表示するために,IDE から表示するフォームのコード
unit plPackageListInfoForm;

interface

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

type
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    procedure FormShow(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    procedure EachPackageInfo(APackage: IOTAPackageInfo; ATVItems: TTreeNodes);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  TreeView1.Items.Clear;
  TreeView1.Font.Size  := 11;
  TreeView1.Font.Name  := 'Courier New';
end;

//=============================================================================
//  フォームを表示する時の処理
//  インストールされているパッケージ名を列挙
//  列挙した各パッケージの情報を取得してツリー表示
//
//  uses に ToolsAPI が必要
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
  LPkgeServices : IOTAPackageServices;
  LPackage      : IOTAPackageInfo;
  LIndex        : Integer;
begin
  TreeView1.Items.Clear;
  TreeView1.Items.BeginUpdate;

  // インターフェイスのオブジェクトを取得
  LPkgeServices := BorlandIDEServices as IOTAPackageServices;

  for LIndex := 0 to  LPkgeServices.PackageCount - 1 do begin
    LPackage := LPkgeServices.Package[LIndex];

    // IDE 自身が使用するパッケージは除外
    if LPackage.IDEPackage then Continue;
    // 実行時パッケージで使用可能なパッケージだけにする時は以下を追加
    // if LPackage.RuntimeOnly then Continue;

    // Loaded が True でないパッケージは Contains 部の情報が取得できない
    LPackage.Loaded := True;
    EachPackageInfo(LPackage, TreeView1.Items);
  end;

  TreeView1.Items.EndUpdate;
end;

//-----------------------------------------------------------------------------
//  引数で指定するパッケージの情報を TTreeView に表示
//
//  uses に ToolsAPI が必要
//-----------------------------------------------------------------------------
procedure TForm1.EachPackageInfo(APackage: IOTAPackageInfo; ATVItems: TTreeNodes);
var
  LStrList  : TStringList;
  LRootNode : TTreeNode;
  LContNode : TTreeNode;
  LReqNode  : TTreeNode;
  LIndex    : Integer;
begin
  LStrList := TStringList.Create;
  try
    // ルートノードはパッケージ名
    LRootNode := ATVItems.Add(nil, APackage.Name);

    // Contains 部のリストを取得して子ノードとして追加
    APackage.GetContainsList(LStrList);
    LContNode := ATVItems.AddChild(LRootNode, 'Contains');
    for LIndex := 0 to LStrList.Count - 1 do begin
      ATVItems.AddChild(LContNode, LStrList[LIndex]);
    end;

    // Requires 部のリストを取得して子ノードとして追加
    APackage.GetRequiresList(LStrList);
    LReqNode := ATVItems.AddChild(LRootNode, 'Requires');
    for LIndex := 0 to LStrList.Count - 1 do begin
      ATVItems.AddChild(LReqNode, LStrList[LIndex]);
    end;

    // その他の情報を追加
    if APackage.RuntimeOnly then
      ATVItems.AddChild(LRootNode, 'RunTimeOnly');
    if APackage.DesigntimeOnly then
      ATVItems.AddChild(LRootNode, 'DesigntimeOnly');

    // パッケージの説明テキストを追加  
    ATVItems.AddChild(LRootNode, APackage.Description);
  finally
    FreeAndNil(LStrList);
  end;
end;

end.




05_パッケージ内のコンポーネント名を列挙


パッケージ名を TListBox にリスト表示して,パッケージ名を選択すると,そのパッケージに登録されているコンポーネント名を列挙する例です.
IOTAPackageServices インターフェイスの GetComponentName メソッドを使用すると,指定パッケージに登録されているコンポーネント名が取得できます.パッケージはインデックスで指定します.

本サンプルでは,TListBox の Objects プロパティにパッケージのインデックスの値を代入しておきます.その値を使用してコンポーネント名を取得します.

右の TListBox に表示するのはコンポーネントのクラス名です.例えば TListBox は Listbox ではありません.プリフィックスの T が付いた TListBox です.



図7
標準コンポーネントのリスト
  • 左がパッケージ名
  • 右は選択したパッケージに登録されているコンポーネント名のリスト

添付の [IDE_PackageListCompo] フォルダ内の plPackageListCompo.dpk をインストールすると,IDE の [ツール] メニューに [パッケージ内のコンポーネント列挙] が追加されます.その項目を選択すると,上の図の結果を確認できます.



リスト4
パッケージ内のコンポーネント名を列挙するために,IDE から表示するフォームのコード
unit plPackageListCompoForm;

interface

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

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Splitter1: TSplitter;
    ListBox2: TListBox;
    procedure FormShow(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ListBox1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  ToolsAPI;

{$R *.dfm}

{ TForm1 }

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Splitter1.ResizeStyle := rsUpdate;

  ListBox1.Items.Clear;
  ListBox1.Font.Size  := 11;
  ListBox1.Font.Name  := 'Courier New';
  ListBox2.Items.Clear;
  ListBox2.Font.Size  := 11;
  ListBox2.Font.Name  := 'Courier New';
end;

//=============================================================================
//  フォームを表示する時の処理
//  インストールされているパッケージ名を TListBox にリスト
//
//  uses に ToolsAPI が必要
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
  LPkgeServices : IOTAPackageServices;
  LPackage      : IOTAPackageInfo;
  LIndex        : Integer;
begin
  ListBox1.Items.Clear;
  ListBox1.Items.BeginUpdate;

  // インターフェイスのオブジェクトを取得
  LPkgeServices := BorlandIDEServices as IOTAPackageServices;

  for LIndex := 0 to  LPkgeServices.PackageCount - 1 do begin
    LPackage := LPkgeServices.Package[LIndex];

    // IDE 自身が使用するパッケージは除外
    if LPackage.IDEPackage then Continue;
    // 実行時パッケージで使用可能なパッケージだけにする時は以下を追加
    // if LPackage.RuntimeOnly then Continue;

    // Loaded が True でないパッケージは Contains 部の情報が取得できない
    LPackage.Loaded := True;
    ListBox1.AddItem(LPackage.Name, TObject(LIndex));
  end;

  ListBox1.Items.EndUpdate;
end;

//=============================================================================
//  ListBox1 の OnClick イベント処理
//  クリックしたパッケージ内のコンポーネント名を別の TListBox にリスト
//
//  uses に ToolsAPI が必要
//=============================================================================
procedure TForm1.ListBox1Click(Sender: TObject);
var
  LIndex        : Integer;
  LPkgIndex     : Integer;
  LPkgeServices : IOTAPackageServices;
begin
  LIndex := ListBox1.ItemIndex;
  if LIndex < 0 then Exit;

  LPkgIndex := Integer(ListBox1.Items.Objects[LIndex]);
  // インターフェイスのオブジェクトを取得
  LPkgeServices := BorlandIDEServices as IOTAPackageServices;

  // 指定したインデックスのパッケージ内のコンパーネント名を順番に取得
  ListBox2.Items.Clear;
  ListBox2.Items.BeginUpdate;
  for LIndex := 0 to LPkgeServices.ComponentCount[LPkgIndex] - 1 do begin
    ListBox2.Items.Add(LPkgeServices.GetComponentName(LPkgIndex, LIndex));
  end;
  ListBox2.Items.EndUpdate;
end;

end.




06_実行時における指定パッケージの情報取得


本ページの最初のサンプルで確認したように,拡張子が .bpl のパッケージは,実行時パッケージを使用しない限り EXE 実行時には読み込まれません.Delphi がインストールされていない環境には,基本的に Delphi のパッケージは存在しません.このことから,パッケージの関係の操作は,Tools API を使用して IDE の拡張機能として実装するのが適切と思われます.

単独のパッケージであれば,実行時に現在のプロセスでロードして,GetPackageInfo 手続きを使用して情報を取得することができます.実際のパッケージの情報は,GetPackageInfo 手続きのコールバック関数内で取得します.パッケージは LoadPackage 関数で読み込みます.



図8
テストで作成してインストールしたパッケージの情報

モジュールとして自分自身の EXE の情報を取得した結果です.EXE で使用しているユニットファイル名が確認できます.



図9
自分自身のモジュールとしての EXE の情報
  • どのユニットを使用しているかを確認できる

リスト5
実行時にロードしたパッケージの情報 (構造) を取得して表示
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    TreeView1: TTreeView;
    Button2: TButton;
    Button3: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

  function EachModuleInfo(ATVItems: TTreeNodes;  AhModule: HMODULE;
    Data: Pointer): Boolean;
  procedure PackageInfoProc(const Name: string; NameType: TNameType;
    Flags: Byte; Param: Pointer);

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  FContNode : TTreeNode;
  FReqNode  : TTreeNode;

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  TreeView1.Items.Clear;
  TreeView1.Font.Size  := 11;
  TreeView1.Font.Name  := 'Courier New';
end;

//=============================================================================
//  筆者がインストールしたパッケージの情報を取得
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LPkgPath : string;
  LhMODULE : HMODULE;
begin
  LPkgPath := 'C:\Users\Public\Documents\RAD Studio\12.0\Bpl\plEnumModule.bpl';

  LhMODULE := LoadPackage(LPkgPath);

  TreeView1.Items.Clear;
  TreeView1.Items.BeginUpdate;
  EachModuleInfo(TreeView1.Items, LhMODULE, nil);
  TreeView1.Items.EndUpdate;

  TreeView1.TopItem.Expand(True);
  TreeView1.TopItem := TreeView1.Items[0];
end;

//=============================================================================
//  自分自身 (HInstance) の情報を取得
//  自分自身の EXE をモジュールとしての情報
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LhMODULE : HMODULE;
begin
  LhMODULE := HInstance;

  TreeView1.Items.Clear;
  TreeView1.Items.BeginUpdate;
  EachModuleInfo(TreeView1.Items, LhMODULE, nil);
  TreeView1.TopItem := nil;
  TreeView1.Items.EndUpdate;

  TreeView1.TopItem.Expand(True);
  TreeView1.TopItem := TreeView1.Items[0];
end;

//=============================================================================
//  dclstd190.bpl (Delphi XE5 標準コンポーネント) パッケージの情報を取得
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  LPkgPath : string;
  LhMODULE : HMODULE;
begin
  LPkgPath := 'C:\Program Files (x86)\Embarcadero\RAD Studio\12.0\bin\dclstd190.bpl';

  LhMODULE := LoadPackage(LPkgPath);

  TreeView1.Items.Clear;
  TreeView1.Items.BeginUpdate;
  EachModuleInfo(TreeView1.Items, LhMODULE, nil);
  TreeView1.Items.EndUpdate;

  TreeView1.TopItem.Expand(True);
  TreeView1.TopItem := TreeView1.Items[0];
end;

//-----------------------------------------------------------------------------
//  引数で指定したモジュールの情報を取得して TTreeView に表示
//-----------------------------------------------------------------------------
function EachModuleInfo(ATVItems: TTreeNodes; AhModule: HMODULE;
  Data: Pointer): Boolean;
var
  LRootNode   : TTreeNode;
  LModuleName : string;
  LModuleDesc : string;
  LFlags      : Integer;
begin
  LModuleName := GetModuleName(AhModule);
  LRootNode   := ATVItems.Add (nil, LModuleName);

  LModuleDesc := GetPackageDescription (PChar (LModuleName));
  FContNode   := ATVItems.AddChild (LRootNode, 'Contains');
  FReqNode    := ATVItems.AddChild (LRootNode, 'Requires');

  // GetPackageInfo 手続きを実行
  // 第 2 引数は手続きに渡す任意の値 (Pointer 型)
  // 第 3 引数は手続きからの戻り値
  // 第 4 引数はコールバック関数
  GetPackageInfo(AhModule, ATVItems, LFlags, PackageInfoProc);

  // パッケージの説明テキストがない場合
  // IDE 自身が使用するパッケージと見なして除外
  if LModuleDesc <> '' then begin
    ATVItems.AddChild (LRootNode, 'Description: ' + LModuleDesc);

    if LFlags and pfDesignOnly = pfDesignOnly then
      ATVItems.AddChild (LRootNode, 'Design Only');

    if LFlags and pfRunOnly = pfRunOnly then
      ATVItems.AddChild (LRootNode, 'Run Only');
  end;
  Result := True;
end;

//-----------------------------------------------------------------------------
//  GetPackageInfo 手続きのコールバック関数
//  TTreeview のノード FContNode, ReqNode (TTreeNode) の階層下に項目を追加
//  FContNode, FReqNode はルート直下のノードでグローバル変数
//-----------------------------------------------------------------------------
procedure PackageInfoProc(const Name: string; NameType: TNameType;
  Flags: Byte; Param: Pointer);
var
  FlagStr  : string;
  LTVItems : TTreeNodes;
begin
  LTVItems := TTreeNodes(Param);

  FlagStr := ' ';
  if Flags and ufMainUnit <> 0 then
    FlagStr := FlagStr + 'Main Unit ';

  if Flags and ufPackageUnit <> 0 then
    FlagStr := FlagStr + 'Package Unit ';

  if Flags and ufWeakUnit <> 0 then
    FlagStr := FlagStr + 'Weak Unit ';

  if FlagStr <> ' ' then
    FlagStr := ' (' + FlagStr + ')';

    case NameType of
      ntContainsUnit    : LTVItems.AddChild (FContNode, Name + FlagStr);
      ntRequiresPackage : LTVItems.AddChild (FReqNode, Name);
    end;
end;

end.