2004. július 14., szerda

Show the Windows Hierarchy


Problem/Question/Abstract:

There are times when you could do with knowing what different window Handles are for testing messaging apps, etc. Without Loading WinSight (with all it's overheads), or getting WinSpy++, here is a simple digest of Handles, Class Names, and Window Captions.

Answer:

On a Form, place a TreeView Control, and a Button.

Paste in the following 3 procedures/ functions into the implementation Code:

//---

function GetWinInfo(h: HWND): string;
var
  tmp: PChar;
begin
  //Get the HWND value in hex and Decimal
  result := inttohex(h, 8);
  result := result + ' (' + inttostr(h) + ')';
  //Get ClassName, and Window Caption
  //Allow upto 255 Characters
  GetMem(tmp, 255);
  GetClassName(h, tmp, 255);
  result := result + ': ' + tmp;
  tmp[0] := #0;
  GetWindowText(h, tmp, 255);
  result := result + ' - ' + tmp;
  FreeMem(tmp);
end;

procedure GetChildren(h: HWND; n: TTreeNode; T: TTreeview);
var
  Childhw: HWND;
  ChildNode: TTreeNode;
begin
  //Get any Children
  ChildHw := GetWindow(h, GW_CHILD);
  while Childhw > 32 do
  begin
    //Add this Handle
    ChildNode := T.Items.AddChild(n, GetWinInfo(Childhw));
    //Get any Children - Recursive call...
    GetChildren(Childhw, ChildNode, T);
    //Get the next window
    Childhw := GetWindow(Childhw, GW_HWNDNEXT);
  end;
end;

procedure GetWinTree(T: TTreeview);
var
  hw: HWND;
  node: TTreeNode;
begin
  //Loop through all Top Level Windows
  hw := FindWindow(nil, nil);
  while hw > 32 do
  begin
    //Add this Handle
    node := t.items.Add(nil, GetWinInfo(hw));
    //Get any Children
    GetChildren(hw, Node, T);
    //Get the next window
    hw := GetWindow(hw, GW_HWNDNEXT);
  end;
end;

//---

Then put something like this on the ButtonClick Event Handler...

procedure TForm1.Button1Click(Sender: TObject);
begin
  TreeView1.Items.clear;
  GetWinTree(TreeView1);
end;

You will then have a List of All current Window Handles, with all Child Windows listed with then in their correct places.

This could be expanded with searching/ grouping of like classes, etc. But I leave that to you, here is a starting place.

I have used this at various times to get M$ Class names. For instance, if you are using DAO to automatically configure an Access DB to point it's linked tables at a particular SQL Server, I used this to get the Class name of the SQL Server Login form, so that I could search for it and click the OK button before the user gets to it...

Nincsenek megjegyzések:

Megjegyzés küldése