メニューアイテムにサブメニューを追加する

動的にメニューアイテムにサブメニュー項目を追加します。
拙作 MICapture のタスクトレー常駐モード時に実行中のアプリケーションリストを表示するために使用しました。
実行中のアプリケーションリスト取得方法はNifty FDELPHI会議室の発言を参考に(というかママ)しました。
以下のプログラムでは、ポップアップメニューの表示イベントで、メニューアイテム ListSel にサブメニューとして実行中のアプリケーション一覧を追加しています。

private

    // 追加したサブメニューの選択イベント処理用
    procedure ListSelClick(Sender: TObject);


var

    //実行中のアプリケーション(Windows)列挙用
    EnumWin: array[0..128] of string;
    EnumTtl: array[0..128] of string;
    EnumHdl: array[0..128] of THandle;
    EnumWinN: integer;

// ウィンドウハンドルから,EXEファイル名を取得する
function GetExeFileName(Wnd: HWND): String;
var
    ProccessID: Longint;
    hSnapShot: THandle;
    ProcessEntry32: TProcessEntry32;
begin
    Result:= '';
    GetWindowThreadProcessId(Wnd, @ProccessID);
    hSnapShot:= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    try
      ProcessEntry32.dwSize:= SizeOf(TProcessEntry32);
      if Process32First(hSnapShot, ProcessEntry32) then
          repeat
              if ProcessEntry32.th32ProcessID = ProccessID then
                  Result:= String(ProcessEntry32.szExeFile);
          until Process32Next(hSnapShot, ProcessEntry32) = False;
    finally
      CloseHandle(hSnapShot);
    end;
end;

// WindowsAPIコールバック関数 ウィンドウの列挙
function EnumWindowsProc(Wnd: HWND; lParam: Longint): Bool; stdcall;
export;
var
    lpszCaption: array [0..255] of Char;
    lpClassName: array[0..512] of Char;
    ExeFileName: String;
begin
    Result:= True;
    if (GetWindow(Wnd, GW_OWNER) = 0) and IsWindowVisible(Wnd) then
    begin
        GetWindowText(Wnd, lpszCaption, SizeOf(lpszCaption));
        GetClassName(Wnd, lpClassName, SizeOf(lpClassName));
        ExeFileName:= GetExeFileName(Wnd);

        if EnumWinN < 128 then
        begin
            EnumWin[EnumWinN] := ExeFileName;
            EnumTtl[EnumWinN] := lpszCaption;
            EnumHdl[EnumWinN] := Wnd;
            Inc(EnumWinN);
        end;
    end;
end;

// 追加したサブメニューが選択されたときのイベント
procedure TMainForm.ListSelClick(Sender: TObject);
var
    SubMnu: TMenuItem;
    ActiveWin: integer;
    Iconic: ioolean;
begin
    // SubMnu に選択されたサブメニューアイテムを取得して
    // ActiveWin に何番目のアイテムが選択されたのかを得る
    SubMnu := Sender as TMenuItem;
    ActiveWin := ListSel.IndexOf(SubMnu);
    if ActiveWin > -1 then
    begin
        // この場合は、選択されたアプリケーションがアイコン状態なら
        // 元に戻したうえで、キャプチャ用タイマーを起動している
        // ファイル履歴処理など必要に応じた処理をここに書く
        Iconic := IsIconic(EnumHdl[ActiveWin]);
        if Iconic then
            OpenIcon(EnumHdl[ActiveWin]);
        SetForegroundWindow(EnumHdl[ActiveWin]);
        Timer1.Interval := DelayTime;
    end;
end;

// ポップアップメニューのアイテム ListSel にサブメニューとして
// 実行中のアプリケーション一覧を追加する
procedure TMainForm.PopupMenu1Popup(Sender: TObject);
var
    i: integer;
    SubMnu: TMenuItem;
begin
    EnumWinN := 0;
    EnumWindows(@EnumWindowsProc, 0);
    // 一旦サブメニューを削除する
    for i := 0 to  ListSel.Count - 1 do
        ListSel.Delete(0);
    for i := 0 to EnumWinN - 1 do
    begin
        // メニューを追加する。この場合は Caption と OnClick のみ設定
        // 必要に応じて他のプロパティも設定する。
        SubMnu := TMenuItem.Create(Self);
        if EnumTtl[i] <> '' then
            SubMnu.Caption := Format('%2d: ', [i+1]) + EnumTtl[i]
        else
            SubMnu.Caption := Format('%2d: ', [i+1]) + EnumWin[i];
        SubMnu.OnClick := ListSelClick;
        ListSel.Add(SubMnu);
    end;
end;