EnumWindows 和 EnumChildWindows 使我的 Treeview 保持更新

发布于 2024-11-07 17:11:50 字数 1761 浏览 5 评论 0原文

我正在尝试制作一个类似于 Winspector Spy 的程序。我的问题是我希望我的虚拟树视图始终更新 - 也就是说,在创建窗口、销毁窗口等时更新它。当然,所有外部 HWND。

为此,我正在考虑编写一个包含所有句柄+信息的数据容器,并在单独的线程中执行 EnumWindows 和 EnumChildWindows ,在其中我将用所述信息填充我的数据容器。

您会建议我这样做,还是有其他解决方案?如果我这样做,那么我应该让我的线程在整个程序生命周期内运行,然后在执行中进行无限循环,以清除我的数据容器,并每秒再次填充它,或者什么?

这是我的数据容器:

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.

I am trying to make a program similar to Winspector Spy. My problem is that I would like my Virtual Treeview to be updated at all times - that is, update it when a window is created, when a window is destroyed, etc. Of course, all external HWND's.

For that, I was thinking of writing a data container that contained all the Handles + information, and do the EnumWindows and EnumChildWindows in a seperate Thread, where I would fill my data container with said information.

Would you recommend I do it that way, or do you have another solution? If I do it this way, then should I make my Thread run during the whole Program Lifetime, and then just have an infinite loop within the Execute that would clear my datacontainer, and fill it again, every second, or something?

Here is my Data Container:

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

记忆で 2024-11-14 17:11:50

您可以挂钩WH_CBT 并检查 HCBT_CREATEWND/HCBT_DESTROYWND

系统调用WH_CBT钩子
激活、创建之前的过程,
破坏、最小化、最大化、
移动窗口或调整窗口大小...

另请参阅 我需要做什么才能让我的 WH_SHELL 或 WH_CBT 挂钩过程接收来自其他进程的事件?

You could hook for WH_CBT and examine HCBT_CREATEWND/HCBT_DESTROYWND

The system calls a WH_CBT hook
procedure before activating, creating,
destroying, minimizing, maximizing,
moving, or sizing a window ...

Also take a look at What do I have to do to make my WH_SHELL or WH_CBT hook procedure receive events from other processes?

一桥轻雨一伞开 2024-11-14 17:11:50

这确实应该是一个注释,但是注释中的代码看起来不太好。

您的代码中有一些奇怪的地方:

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

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

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

TWindow 继承自 TObject,因此在此代码中无关紧要,但如果更改继承,您的代码将中断,因此切勿在析构函数inherited >。

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

将其更改

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 。

最后是关于风格的注释

您的大写风格也很难阅读并分散对问题的注意力。
而且你的缩进不稳定且不寻常。
缩进对于遵循程序的逻辑很重要。
经常使用它来扫描程序结构的人会因为不寻常的缩进而分心。

与关键字相同。在我的代码中,我知道保留字总是以小写字母开头,而我给变量和例程指定的名称总是以大写字母开头。
这使我能够快速扫描程序的结构。
在保留字中使用大写会破坏扫描流程(就像阅读上一句时一样),因此不建议这样做。

特别是对于那些对草率缩进和在保留字中使用大写字母过敏的人。

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

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

Steve McConnel 他的优秀代码完整在第 399 至 452 页的布局和风格上进行了说明,使其成为本书中最大的一章。

This should really be a comment, but the code doesn't look OK in comments.

There are a few oddities in your code:

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

There's no need to empty strings in a destructor, but you need to call inherited Destroy.
Change it to:

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

TWindow inherits from TObject, so it doesn't matter in this code, but if you change the inheritance your code will break, so never omit inherited in a destructor.

In a constructor you need to call the inherited constructor:

Change this:

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;

To this:

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;

Because TWindow inherits from TObject, it does not matter that you ommited inherited Create here, but if you decide to change the code and inherit from something else, than your constructor will break.

There's no need to set anything to 0, nil or '' in a constructor, all class member are automatically set to 0 before create is called.

Finally a note on style

YoUr Capitalization style Is Hard too Read and distracts from the issue.
Also your indentation is inconstant and unusual.
Indentation is important to follow the logic of a program.
People who use it to scan program structure a lot get very distracted by unusual indentation.

Same with the keywords. In my code I know that reserved words always start with a lower case and names I gave to vars and routines always start with a capital.
This enables me to scan the structure of a program quickly.
Use of Capitals In Reserved words Breaks the FloW of scanning (like it does when reading the previous sentence) and is not recommended for that reason.

Especially for people who are allergic to sloppy indentation and Use Of Capitals In reserved words.

See: http://en.wikipedia.org/wiki/Indent_style

I'd recommend using the same style that is used in the VCL source.
It's not my personal favourite, but it is a clean style used by a lot of people.

Steve McConnel his excellent book code complete denotes pages 399 to 452 to layout and style, making it the largest chapter of the book.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文