refactor: Extracted logic of enumerating child windows in WindowEnumerator

This commit is contained in:
Nikolaos Georgiou 2022-09-06 20:12:06 +02:00
parent 6ba70319e0
commit 1866eb19b5
4 changed files with 112 additions and 67 deletions

View File

@ -45,7 +45,7 @@
<PackageName Value="LCL"/> <PackageName Value="LCL"/>
</Item1> </Item1>
</RequiredPackages> </RequiredPackages>
<Units Count="7"> <Units Count="8">
<Unit0> <Unit0>
<Filename Value="Chameleon.lpr"/> <Filename Value="Chameleon.lpr"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
@ -83,6 +83,11 @@
<HasResources Value="True"/> <HasResources Value="True"/>
<ResourceBaseClass Value="Form"/> <ResourceBaseClass Value="Form"/>
</Unit6> </Unit6>
<Unit7>
<Filename Value="windowenumerator.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="WindowEnumerator"/>
</Unit7>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>

View File

@ -8,13 +8,6 @@ uses Windows, Messages, SysUtils, Classes, Forms, Graphics,
Writers; Writers;
type type
PEnumParams = ^TEnumParams;
TEnumParams = record
List: TList;
ParentWnd: HWND;
end;
TKnownControl = ( TKnownControl = (
kcUnknown, kcButton, kcCheckBox, kcComboBox, kcEdit, kcUnknown, kcButton, kcCheckBox, kcComboBox, kcEdit,
kcGroupBox, kcImage, kcLabel, kcListBox, kcListView, kcGroupBox, kcImage, kcLabel, kcListBox, kcListView,
@ -66,7 +59,6 @@ const
function BitTest(Value, Mask: integer): boolean; function BitTest(Value, Mask: integer): boolean;
function GetWndText(wnd: HWND): string; function GetWndText(wnd: HWND): string;
function EnumChildrenProc(wnd: HWND; lp: LPARAM): BOOL; stdcall;
procedure WriteBitmapData(dfm1: TDfmWriter; bmp: HBITMAP; procedure WriteBitmapData(dfm1: TDfmWriter; bmp: HBITMAP;
BelongsToPicture: boolean; const Name: string); BelongsToPicture: boolean; const Name: string);
procedure WriteIconData(dfm1: TDfmWriter; icon: HICON; BelongsToPicture: boolean; procedure WriteIconData(dfm1: TDfmWriter; icon: HICON; BelongsToPicture: boolean;
@ -74,6 +66,8 @@ procedure WriteIconData(dfm1: TDfmWriter; icon: HICON; BelongsToPicture: boolean
implementation implementation
uses WindowEnumerator;
function BitTest(Value, Mask: integer): boolean; function BitTest(Value, Mask: integer): boolean;
begin begin
Result := (Value and Mask) = Mask; Result := (Value and Mask) = Mask;
@ -88,16 +82,6 @@ begin
GetWindowText(wnd, PChar(Result), len + 1); GetWindowText(wnd, PChar(Result), len + 1);
end; end;
function EnumChildrenProc(wnd: HWND; lp: LPARAM): BOOL; stdcall;
var
p: PEnumParams;
begin
p := PEnumParams(lp);
if GetParent(wnd) = p^.ParentWnd then
p^.List.Add(Pointer(wnd));
Result := True;
end;
function GetBorderIconsStr(ABorderIcons: TBorderIcons): string; function GetBorderIconsStr(ABorderIcons: TBorderIcons): string;
const const
biStr: array [TBorderIcon] of string = ( biStr: array [TBorderIcon] of string = (
@ -127,11 +111,9 @@ end;
procedure TDfmBuilder.Build(OutStream: TStream; const frmName: string; wnd: HWND); procedure TDfmBuilder.Build(OutStream: TStream; const frmName: string; wnd: HWND);
var var
InStream: TMemoryStream; InStream: TMemoryStream;
childlist: TList;
i: integer; i: integer;
style, exstyle: longint; style, exstyle: longint;
wndX: HWND; wndX: HWND;
EnumParams: TEnumParams;
procedure WriteBorderIcons; procedure WriteBorderIcons;
var var
@ -156,7 +138,6 @@ begin
FillChar(Counts, sizeof(Counts), #0); FillChar(Counts, sizeof(Counts), #0);
InStream := TMemoryStream.Create; InStream := TMemoryStream.Create;
Dfm1 := TDfmWriter.Create(InStream); Dfm1 := TDfmWriter.Create(InStream);
childlist := TList.Create;
dfm1.WriteLn('object ' + frmName + ': T' + frmName); dfm1.WriteLn('object ' + frmName + ': T' + frmName);
style := GetWindowLong(wnd, GWL_EXSTYLE); style := GetWindowLong(wnd, GWL_EXSTYLE);
@ -175,14 +156,7 @@ begin
dfm1.WriteIntProp('TextHeight', 13); dfm1.WriteIntProp('TextHeight', 13);
// write the children // write the children
EnumParams.List := childlist; EnumerateChildWindows(wnd, Self.PreHandleCtl);
EnumParams.ParentWnd := wnd;
EnumChildWindows(wnd, @EnumChildrenProc, integer(@EnumParams));
for i := 0 to childlist.Count - 1 do
begin
wndX := HWND(childlist[i]);
PreHandleCtl(wndX);
end;
dfm1.Ident := 0; dfm1.Ident := 0;
dfm1.WriteLn('end'); dfm1.WriteLn('end');
InStream.Position := 0; InStream.Position := 0;
@ -190,29 +164,18 @@ begin
ObjectTextToResource(InStream, OutStream); ObjectTextToResource(InStream, OutStream);
// finalization // finalization
childlist.Free;
DFM1.Free; DFM1.Free;
end; end;
procedure TDfmBuilder.HandleUnknown(wnd: HWND; style: integer); procedure TDfmBuilder.HandleUnknown(wnd: HWND; style: integer);
var var
class_name: array [0..100] of char; class_name: array [0..100] of char;
childlist: TList;
EnumParams: TEnumParams;
i: integer; i: integer;
begin begin
// since we don't know what window we're after write the class name // since we don't know what window we're after write the class name
GetClassName(wnd, class_name, 100); GetClassName(wnd, class_name, 100);
dfm1.WriteStringProp('Caption', class_name); dfm1.WriteStringProp('Caption', class_name);
childlist := TList.Create; EnumerateChildWindows(wnd, Self.PreHandleCtl);
EnumParams.List := childlist;
EnumParams.ParentWnd := wnd;
EnumChildWindows(wnd, @EnumChildrenProc, integer(@EnumParams));
for i := 0 to childlist.Count - 1 do
begin
PreHandleCtl(HWND(childlist[i]));
end;
childlist.Free;
end; end;
procedure TDfmBuilder.HandleButton(wnd: HWND; style: integer); procedure TDfmBuilder.HandleButton(wnd: HWND; style: integer);

66
WindowEnumerator.pas Normal file
View File

@ -0,0 +1,66 @@
unit WindowEnumerator;
{$mode Delphi}
interface
uses
Windows;
type
TWndConsumer = procedure (wnd: HWND) of object;
procedure EnumerateChildWindows(wnd: HWND; consumer: TWndConsumer);
implementation
type
TWindowEnumerator = class
private
wnd: HWND;
consumer: TWndConsumer;
class function MyEnumChildrenProc(wnd: HWND; lp: LPARAM): BOOL; static; stdcall;
procedure Add(wnd: HWND);
public
constructor Create(wnd: HWND; consumer: TWndConsumer);
procedure Run;
end;
procedure EnumerateChildWindows(wnd: HWND; consumer: TWndConsumer);
var
enumerator: TWindowEnumerator;
begin
enumerator := TWindowEnumerator.Create(wnd, consumer);
try
enumerator.Run;
finally
enumerator.Free;
end;
end;
constructor TWindowEnumerator.Create(wnd: HWND; consumer: TWndConsumer);
begin
Self.wnd := wnd;
Self.consumer := consumer;
end;
procedure TWindowEnumerator.Run;
begin
EnumChildWindows(wnd, @TWindowEnumerator.MyEnumChildrenProc, LPARAM(Self));
end;
class function TWindowEnumerator.MyEnumChildrenProc(wnd: HWND; lp: LPARAM): BOOL; static; stdcall;
var
me: TWindowEnumerator;
begin
me := TWindowEnumerator(lp);
me.Add(wnd);
Result := True;
end;
procedure TWindowEnumerator.Add(wnd: HWND);
begin
consumer(wnd);
end;
end.

View File

@ -32,7 +32,7 @@ var
implementation implementation
uses DfmEngine, StyleNames; uses StyleNames, WindowEnumerator;
{$R *.lfm} {$R *.lfm}
@ -208,33 +208,44 @@ begin
end; end;
end; end;
type
TTreeNodeChildConsumer = class
private
ParentNode: TTreeNode;
ChildrenRootNode: TTreeNode;
ChildCount: Integer;
Form: TResults;
public
constructor Create(Form: TResults; ParentNode: TTreeNode);
procedure Consume(wnd: HWND);
end;
constructor TTreeNodeChildConsumer.Create(Form: TResults; ParentNode: TTreeNode);
begin
Self.Form := Form;
Self.ParentNode := ParentNode;
Self.ChildrenRootNode := nil;
Self.ChildCount := 0;
end;
procedure TTreeNodeChildConsumer.Consume(wnd: HWND);
var
node2: TTreeNode;
begin
if not Assigned(ChildrenRootNode) then
ChildrenRootNode := Form.TreeView1.Items.AddChild(ParentNode, 'Children information');
Inc(ChildCount);
node2 := Form.TreeView1.Items.AddChild(ChildrenRootNode, 'Child #' + IntToStr(ChildCount));
Form.GetWinInfo(integer(wnd), node2);
end;
procedure TResults.GetWinInfoChildren(wnd: HWND; ParentNode: TTreeNode); procedure TResults.GetWinInfoChildren(wnd: HWND; ParentNode: TTreeNode);
var var
i: integer; consumer: TTreeNodeChildConsumer;
node1, node2: TTreeNode;
childlist: TList;
EnumParams: TEnumParams;
class_name: String;
begin begin
childlist := TList.Create; consumer := TTreeNodeChildConsumer.Create(Self, ParentNode);
EnumerateChildWindows(wnd, consumer.Consume);
EnumParams.List := childlist; consumer.Free;
EnumParams.ParentWnd := wnd;
EnumChildWindows(wnd, @EnumChildrenProc, integer(@EnumParams));
with TreeView1.Items do
begin
if childlist.Count > 0 then
begin
node1 := AddChild(ParentNode, 'Children information');
for i := 1 to childlist.Count do
begin
node2 := AddChild(node1, 'Child #' + IntToStr(i));
GetWinInfo(integer(childlist[i - 1]), node2);
end;
end;
end;
childlist.Free;
end; end;
end. end.