【问题标题】:EnumWindows and EnumChildWindows to keep my Treeview updatedEnumWindows 和 EnumChildWindows 让我的 Treeview 保持更新
【发布时间】:2011-05-14 13:15:44
【问题描述】:

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

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

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

这是我的数据容器:

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.

【问题讨论】:

  • 在 windows 事件上做一个全局钩子不是更容易吗?

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


【解决方案1】:

您可以将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?

【讨论】:

  • @Alex - 那么,我需要为此创建一个 DLL 吗?有没有办法避免这种情况?
  • 我不相信,SetWindowsHookEx 要求将代码托管在 dll 中,iirc 您还需要 32/64 位挂钩 dll,因此需要从相应位数的进程中调用它们跨度>
  • @Alex 我的方法不会更简单吗?
  • 将您的实例作为lParam 参数传递给EnumWindows,然后您就可以在回调过程中访问它。但我真的不认为你想从枚举器中调用 Synchronize !首先构建窗口句柄列表,然后再处理它们。
  • @Jeff 为什么你还需要在一个单独的线程中完成所有这些工作?
【解决方案2】:

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

您的代码中有一些奇怪之处:

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

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

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

TWindow 继承自 TObject,因此在此代码中无关紧要,但如果您更改继承,您的代码将中断,因此切勿在 destructor 中省略 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 他的优秀code complete 表示第 399 至 452 页的布局和样式,使其成为本书最大的章节。

【讨论】:

  • 我看不出我的代码有什么问题 - 对我来说非常易读。缩进让我更容易将变量与值分开。
  • @Jeff:就像你说的:关键字是for me,你在贴代码给别人看。
  • @Johan - 同意,但是我没有这种类型的.. 让我们称它们为关于我的代码格式的“提示”,我总是这样做。 :)
  • @Bruce - 那么,我这样做的方式到底有什么问题? :)
  • @Jeff,这就是所谓的religious issue,如果只是你在看代码,那很好,但是人们加入宗教是有原因的,不要只是开始自己的宗教。它提供了一种标准的做事方式,并为您的世界增添了结构,因此您可以使用共享的参考框架与人们交流。这些东西非常重要,一点也不小。
猜你喜欢
  • 2014-07-23
  • 1970-01-01
  • 2012-02-15
  • 1970-01-01
  • 2012-05-11
  • 2021-05-24
  • 1970-01-01
  • 1970-01-01
  • 2015-06-19
相关资源
最近更新 更多