unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, Menus;

type
  TfrmMain = class(TForm)
    tree: TTreeView;
    MainMenu1: TMainMenu;
    N1: TMenuItem;
    mnuExit: TMenuItem;
    N3: TMenuItem;
    mnuRefresh: TMenuItem;
    N2: TMenuItem;
    mnuWindowProp: TMenuItem;
    mnuMessages: TMenuItem;
    procedure mnuExitClick(Sender: TObject);
    procedure mnuRefreshClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure mnuWindowPropClick(Sender: TObject);
    procedure mnuMessagesClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    procedure LoadWindowsTree();
  end;

var
  frmMain: TfrmMain;

implementation

uses Unit2, Unit3;
{$R *.dfm}
Type
  TEnumInfo = Record
    tree: TTreeView;
    parent: TTreeNode;
  end;
var
  enInfo: TEnumInfo;

//Функция собирает информацию об окне и добавляет узел окна в дерево
function AddWindowToTree(wnd: HWND): TTreeNode;
var
  caption, classname: String;
  text: String;
  node: TTreeNode;
begin
  //Получение текста окна
  SetLength(caption, SendMessage(wnd, WM_GETTEXTLENGTH, 0, 0) + 1);
  SetLength(caption, SendMessage(wnd, WM_GETTEXT, Length(caption),
            Integer(PAnsiChar(caption))));
  //Имя класса окна
  SetLength(classname, 1024);
  SetLength(classname, GetClassName(wnd, PAnsiChar(classname), 100));

  //Формирование текста для элемента и добавление его в дерево
  text := '"' + caption + '" ' + classname;
  node := enInfo.tree.Items.AddChild( enInfo.parent, text );
  node.Data := Pointer(wnd); //Не забываемо запомнить дексриптор окна
  AddWindowToTree := node;
end;

//Функция вызывается при нахождении нового окна
function NewWindow(wnd: HWND; param: LPARAM):BOOL; stdcall;
var
  wndNode, parentNode: TTreeNode;
begin
  wndNode := AddWindowToTree(wnd); //Добавление информации об окне в дерево

  //Перечисление дочерних окон
  parentNode := enInfo.parent;
  enInfo.parent := wndNode;
  EnumChildWindows(wnd, Addr(NewWindow), param);
  enInfo.parent := parentNode;

  //Продолжать перечисление (после перечисления всех дочерних окон)
  NewWindow := TRUE;
end;


//Процедура формирования дерева (иерархии открытых окон)
procedure TfrmMain.LoadWindowsTree();
var
  desktop: TTreeNode;
  //enInfo: TEnumInfo;
begin
  tree.Items.Clear;
  //Добавление узла для рабочего стола
  desktop := tree.Items.Add(tree.Items.GetFirstNode, 'Рабочий стол');
  //Перечисление окон
  enInfo.tree := tree;
  enInfo.parent := desktop;
  EnumWindows(Addr(NewWindow), Integer(Addr(enInfo)));
end;

procedure TfrmMain.mnuExitClick(Sender: TObject);
begin
  Application.Terminate;
end;

procedure TfrmMain.mnuRefreshClick(Sender: TObject);
begin
  LoadWindowsTree();
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  LoadWindowsTree();
end;

procedure TfrmMain.mnuWindowPropClick(Sender: TObject);
begin
  if (tree.Selected <> nil) and (tree.Selected.Data <> nil) then
  begin
    //Показываем свойства выбранного окна
    frmWindowProp.ShowWindowProp(HWND(tree.Selected.Data));
  end;
end;

procedure TfrmMain.mnuMessagesClick(Sender: TObject);
begin
  if (tree.Selected <> nil) and (tree.Selected.Data <> nil) then
  begin
    //Показываем форму перехвата сообщений
    frmMessages.ShowMessages(HWND(tree.Selected.Data));
  end;
end;

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  //Удаление ловушки при закрытии
  RemoveHook();
end;

end.
