EnumWindows和EnumChildWindows保持我的Treeview更新

时间:2011-05-14 13:15:45

标签: multithreading delphi windows-messages virtualtreeview window-handles

我正在尝试制作类似于Winspector Spy的程序。我的问题是我希望我的Virtual Treeview能够随时更新 - 也就是说,在创建窗口时,窗口被破坏时更新它等等。当然,所有外部HWND都是。

为此,我正在考虑编写一个包含所有Handles +信息的数据容器,并在一个单独的Thread中执行EnumWindows和EnumChildWindows,在那里我将使用所述信息填充我的数据容器。

你会建议我这样做,还是你有另一种解决方案?如果我这样做,那么我应该在整个程序生命周期内运行我的线程,然后在Execute内只有一个无限循环,它将清除我的datacontainer,并再次填充,每秒,或某事?

这是我的数据容器:

unit WindowList;

interface

Uses
  Windows, SysUtils, Classes, VirtualTrees, WinHandles, Messages,
  Generics.Collections;


type
  TWindow = class;
  TWindowList = class(TObjectList<TWindow>)
  public
    constructor Create;
    function AddWindow(Wnd : HWND):TWindow;
  end;

  ///////////////////////////////////////

  TWindow = class
  public
    Node         : PVirtualNode;
    Children     : TObjectList<TWindow>;
    Handle       : HWND;
    Icon         : HICON;
    ClassName    : string;
    Text         : string;
    constructor Create(Wnd : HWND);
    destructor Destroy;
    function AddWindow(Wnd : HWND):TWindow;
  end;


implementation

{ TWindowList }

function TWindowList.AddWindow(Wnd: HWND): TWindow;
var
  Window : TWindow;
begin
  Window := TWindow.Create(Wnd);
  Add(Window);
  Result := Window;
end;

constructor TWindowList.Create;
begin
  inherited Create(True);
end;

{ TWindow }

function TWindow.AddWindow(Wnd: HWND): TWindow;
var
  Window : TWindow;
begin
  Window := TWindow.Create(Wnd);
  Children.Add(Window);
  Result := Window;
end;

constructor TWindow.Create(Wnd: HWND);
begin
  Handle := Wnd;
  if Handle = 0 then Exit;
  ClassName := GetClassName(Handle);
  Text := GetHandleText(Handle);
  Node := Nil;
  Children := TObjectList<TWindow>.Create(True);
end;

destructor TWindow.Destroy;
begin
  ClassName := '';
  Text := '';
  Children.Free;
end;

end.

2 个答案:

答案 0 :(得分:3)

hook WH_CBT可以检查HCBT_CREATEWND / HCBT_DESTROYWND

  

系统调用WH_CBT挂钩   激活,创建之前的程序,   摧毁,最小化,最大化,   移动或调整窗口大小...

另请查看What do I have to do to make my WH_SHELL or WH_CBT hook procedure receive events from other processes?

答案 1 :(得分:1)

这应该是一个评论,但代码在评论中看起来不行。

您的代码中有一些奇怪之处:<​​/ p>

destructor TWindow.Destroy;
begin
  ClassName := '';
  Text := '';
  Children.Free;
end;

不需要在析构函数中清空字符串,但是你需要调用继承的Destroy 将其更改为:

destructor TWindow.Destroy;
begin
  Children.Free;
  inherited Destroy;
end;

TWindow继承自TObject,因此在此代码中无关紧要,但如果更改继承,则代码将中断,因此永远不要在inherited中省略destructor

在构造函数中,您需要调用继承的构造函数:

改变这个:

constructor TWindow.Create(Wnd: HWND);
begin
  Handle := Wnd;
  if Handle = 0 then Exit;
  ClassName := GetClassName(Handle);
  Text := GetHandleText(Handle);
  Node := Nil;
  Children := TObjectList<TWindow>.Create(True);
end;

对此:

constructor TWindow.Create(Wnd: HWND);
begin
  inherited Create;
  Handle := Wnd;
  if Handle = 0 then Exit;
  ClassName := GetClassName(Handle);
  Text := GetHandleText(Handle);
  Children := TObjectList<TWindow>.Create(True);
end;

因为TWindow继承自TObject,所以你在这里省略了inherited Create并不重要,但是如果你决定改变代码并继承其他东西,那么你的构造函数就会破坏。

无需在构造函数中为0nil''设置任何内容,在调用create之前,所有类成员都会自动设置为0。

最后关于风格的说明

YoUr资本化风格难以阅读并分散注意力。

与关键字相同。在我的代码中,我知道保留字总是以小写字母开头,而我给vars和例程的名字总是以大写字母开头。
这使我能够快速扫描程序的结构 在保留字中使用Capitals打破扫描的FloW(就像读取前一句时一样),因此不建议使用。

尤其适用于对草率压痕过度过敏和使用大写字母的人。保留字。

请参阅:http://en.wikipedia.org/wiki/Indent_style

我建议使用VCL源中使用的相同样式。 这不是我个人的最爱,但它是很多人使用的干净风格。

Steve McConnel他的优秀书籍code complete表示第399至452页的布局和风格,使其成为本书的最大篇章。