(*  GREATIS WINDOW INFORMATION                *)
(*  Copyright (C) 2005-2008 Greatis Software  *)
(*  http://www.greatis.com/delphicb/wininfo/  *)
(*  http://www.greatis.com/bteam.html         *)
(*                                            *)
(*  GREATIS DELPHI TOYS                       *)
(*  http://www.greatis.com/delphicb/toys/     *)

unit WIMain;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  WinInfo, StdCtrls, ExtCtrls, ComCtrls, ImgList;

type
  TfrmWinInfoMain = class(TForm)
    cmpWindowInformation: TWindowInformation;
    pgcWindows: TPageControl;
    tshList: TTabSheet;
    tshTree: TTabSheet;
    lsvWindows: TListView;
    trvWindows: TTreeView;
    imlWindows: TImageList;
    pnlSplit: TPanel;
    pnlBottom: TPanel;
    pnlButtons: TPanel;
    memDetails: TMemo;
    grbEdit: TGroupBox;
    lblLeft: TLabel;
    lblTop: TLabel;
    lblWidth: TLabel;
    lblHeight: TLabel;
    lblText: TLabel;
    btnApply: TButton;
    edtLeft: TEdit;
    edtTop: TEdit;
    edtWidth: TEdit;
    edtHeight: TEdit;
    rgrState: TRadioGroup;
    chbVisible: TCheckBox;
    chbEnabled: TCheckBox;
    chbStayOnTop: TCheckBox;
    chbEdit: TCheckBox;
    memText: TMemo;
    pnlSearchOptions: TPanel;
    grbSearchFilters: TGroupBox;
    chbKind: TCheckBox;
    chbExact: TCheckBox;
    chbClass: TCheckBox;
    chbText: TCheckBox;
    rgrSearchKind: TRadioGroup;
    lblSearchClass: TLabel;
    edtSearchClass: TEdit;
    SearchText: TLabel;
    edtSearchText: TEdit;
    btnRefresh: TButton;
    lblWindows: TLabel;
    btnReset: TButton;
    procedure eveRefresh(Sender: TObject);
    procedure chbEditClick(Sender: TObject);
    procedure lsvWindowsChange(Sender: TObject; Item: TListItem;
      Change: TItemChange);
    procedure trvWindowsChange(Sender: TObject; Node: TTreeNode);
    procedure btnApplyClick(Sender: TObject);
    procedure btnResetClick(Sender: TObject);
    procedure edtKeyPress(Sender: TObject; var Key: Char);
  private
    { Private declarations }
    FEditing: Boolean;
    FWindow: TWindow;
    procedure RefreshData;
    procedure ShowDetails(W: TWindow);
    procedure EmptyDetails;
  public
    { Public declarations }
  end;

var
  frmWinInfoMain: TfrmWinInfoMain;

implementation

{$R *.DFM}

procedure TfrmWinInfoMain.RefreshData;
var
  i: Integer;

  procedure AddChildren(Node: TTreeNode; W: HWND);
  var
    i: Integer;
    INode: TTreeNode;
  begin
    with cmpWindowInformation do
      for i:=0 to Pred(WindowCount) do
        with Windows[i] do
          if ParentHandle=W then
          begin
            INode:=trvWindows.Items.AddChildObjectFirst(Node,'"'+Text+'" ['+WindowClassName+']',Windows[i]);
            with INode do
            begin
              ImageIndex:=Integer(WindowKind);
              SelectedIndex:=ImageIndex;
            end;
            AddChildren(INode,Handle);
          end;
  end;

  function OneLineText(S: string): string;
  var
    i: Integer;
  begin
    Result:='';
    for i:=1 to Length(S) do
    begin
      case S[i] of
        #13: Result:=Result+' ';
        #10: ;
      else Result:=Result+S[i];
      end;
      if i>1024 then Break;
    end;
  end;

begin
  with cmpWindowInformation do
  begin
    memDetails.Text:='';
    Refresh;
    lblWindows.Caption:=IntToStr(WindowCount)+' window(s) found';
    with lsvWindows.Items do
    begin
      BeginUpdate;
      try
        Clear;
        for i:=0 to Pred(WindowCount) do
          with Add,Windows[i] do
          begin
            ImageIndex:=Integer(WindowKind);
            Caption:=' '+WindowClassName;
            Subitems.Text:=
              OneLineText(Text)+#13+
              IntToStr(Left)+#13+
              IntToStr(Top)+#13+
              IntToStr(Width)+#13+
              IntToStr(Height);
            Data:=Windows[i];
          end;
      finally
        EndUpdate;
      end;
    end;
    with trvWindows.Items do
    begin
      BeginUpdate;
      try
        Clear;
        AddChildren(AddObject(nil,'Desktop',nil),0);
        Item[0].Expand(False);
      finally
        EndUpdate;
      end;
    end;
  end;
  EmptyDetails;
end;

procedure TfrmWinInfoMain.ShowDetails(W: TWindow);

  function Hex(I: Integer): string;
  begin
    Result:=IntToHex(I,8);
  end;

begin
  FWindow:=W;
  if Assigned(W) then
    with W do
    begin
      memDetails.Text:=
        'Handle     '#9#9+Hex(Handle)+#13#10+
        'ResourceID '#9#9+Hex(ResourceID)+#13#10+
        'ProcessID '#9#9+Hex(ProcessID)+#13#10+
        'AppInstance '#9#9+Hex(AppInstance)+#13#10+
        'ParentHandle '#9#9+Hex(ParentHandle)+#13#10+
        'ControlID '#9#9+Hex(ControlID)+#13#10+
        'WindowFunction '#9#9+Hex(WindowFunction)+#13#10+
        'MenuHandle '#9#9+Hex(MenuHandle)+#13#10+
        'Style        '#9#9+Hex(Style)+#13#10+
        'ExStyle    '#9#9+Hex(ExStyle)+#13#10+
        'ClassFunction '#9#9+Hex(ClassFunction)+#13#10+
        'IconHandle '#9#9+Hex(IconHandle)+#13#10+
        'SmallIconHandle '#9#9+Hex(SmallIconHandle)+#13#10+
        'CursorHandle '#9#9+Hex(CursorHandle)+#13#10+
        'BrushHandle '#9#9+Hex(BrushHandle)+#13#10+
        'ClassStyle '#9#9+Hex(ClassStyle);
      edtLeft.Text:=IntToStr(Left);
      edtTop.Text:=IntToStr(Top);
      edtWidth.Text:=IntToStr(Width);
      edtHeight.Text:=IntToStr(Height);
      memText.Text:=Text;
      rgrState.ItemIndex:=Integer(WindowState);
      rgrState.Enabled:=chbEdit.Checked and (WindowKind=wkWindow);
      chbVisible.Checked:=Visible;
      chbEnabled.Checked:=Enabled;
      chbStayOnTop.Checked:=StayOnTop;
    end
  else EmptyDetails;
end;

procedure TfrmWinInfoMain.EmptyDetails;
begin
  memDetails.Text:='';
  rgrState.ItemIndex:=0;
  chbVisible.Checked:=False;
  chbEnabled.Checked:=False;
  chbStayOnTop.Checked:=False;
  edtLeft.Text:='';
  edtTop.Text:='';
  edtWidth.Text:='';
  edtHeight.Text:='';
end;

procedure TfrmWinInfoMain.eveRefresh(Sender: TObject);
begin
  with cmpWindowInformation do
  begin
    SearchFilters:=[];
    if chbKind.Checked then SearchFilters:=SearchFilters+[sfKind];
    if chbExact.Checked then SearchFilters:=SearchFilters+[sfExact];
    if chbClass.Checked then SearchFilters:=SearchFilters+[sfClass];
    if chbText.Checked then SearchFilters:=SearchFilters+[sfText];
    SearchKind:=TWindowKind(rgrSearchKind.ItemIndex);
    SearchClass:=edtSearchClass.Text;
    SearchText:=edtSearchText.Text;
  end;
  RefreshData;
end;

procedure TfrmWinInfoMain.chbEditClick(Sender: TObject);
var
  i: Integer;
begin
  if not FEditing and chbEdit.Checked then
    FEditing:=MessageDlg(
      'Changing of some windows can be dangerous for your system.'#13'Enable edit anyway?',
      mtWarning,[mbYes,mbNo],0)=mrYes;
  if FEditing then
  begin
    with grbEdit do
      for i:=0 to Pred(ControlCount) do
        with Controls[i] do
          if Tag=0 then Enabled:=chbEdit.Checked;
    chbEdit.Enabled:=False;
  end
  else chbEdit.Checked:=False;
end;

procedure TfrmWinInfoMain.lsvWindowsChange(Sender: TObject; Item: TListItem;
  Change: TItemChange);
begin
  with lsvWindows do
    if Assigned(Selected) then
      ShowDetails(TWindow(Selected.Data))
end;

procedure TfrmWinInfoMain.trvWindowsChange(Sender: TObject; Node: TTreeNode);
begin
  if Assigned(Node) then
    ShowDetails(TWindow(Node.Data));
end;

procedure TfrmWinInfoMain.btnApplyClick(Sender: TObject);
begin
  if Assigned(FWindow) then
    with FWindow do
    begin
      WindowState:=TWindowState(rgrState.ItemIndex);
      Visible:=chbVisible.Checked;
      Enabled:=chbEnabled.Checked;
      StayOnTop:=chbStayOnTop.Checked;
      Left:=StrToInt(edtLeft.Text);
      Top:=StrToInt(edtTop.Text);
      Width:=StrToInt(edtWidth.Text);
      Height:=StrToInt(edtHeight.Text);
      Text:=memText.Text;
    end;
end;

procedure TfrmWinInfoMain.btnResetClick(Sender: TObject);
begin
  ShowDetails(FWindow);
end;

procedure TfrmWinInfoMain.edtKeyPress(Sender: TObject; var Key: Char);
begin
  if not (Key in ['0'..'9','-','+']) then
  begin
    Key:=#0;
    MessageBeep(0);
  end;
end;

end.
