19

从几个初步测试看来,EnumWindows总是以反向实例化顺序返回窗口,即最先实例化的窗口。这是一个有效的观察吗?如果是这样,是否适用于所有版本的 Windows?这是一个可靠的假设吗,即该行为是否记录在某处?


上下文:我正在处理一种情况,我正在触发第三方应用程序打开几个非模态窗口,一旦它们打开,我需要向这些窗口发送一些窗口消息,但我没有万无一失的方法将它们标识为它们的窗口类和它们的标题都会有所不同,我也不知道它们的预期坐标。但是,如果我可以依赖上述行为,EnumWindows我可以简单地使用EnumWindows其类和标题符合我期望的返回的第一个句柄。这仍然会留下一些假设的漏洞,但我认为这已经足够好了。不过,欢迎提供替代建议。

4

5 回答 5

28

它按 Z 顺序返回它们。首先是带有WS_EX_TOPMOSTset 的最顶部的窗口,直到带有 的最底部的窗口WS_EX_TOPMOST set,然后是没有 的最顶部的窗口WS_EX_TOPMOST,尽管是没有 的最底部的窗口WS_EX_TOPMOST。请注意,可见性不是决定因素,因此在 Z 顺序中高于可见窗口的不可见窗口仍将出现在其之前。

编辑

您不太可能随心所欲地使用它,只需从EnumWindows. 不仅您的新窗口不太可能是第一次返回,而且您还会遇到其他窗口可以同时打开的竞争条件。但是,您可以保留应用程序所有已知窗口的列表,当您需要查找新打开的窗口时,调用EnumWindows窗口句柄并将其与列表中的句柄进行比较。当您找到一个没有在您的列表中的具有正确类和标题(您甚至可以使用 来检查它是否属于正确的进程GetWindowThreadProcessID)时,您就找到了新窗口。

但是,出于您的目的,安装 CBT 挂钩并注意 HCBT_CREATEWND 通知可能会更好地为您服务。有关详细信息,请参阅 MSDN 帮助SetWindowsHookEx()回调CBTProc

枚举顺序的确定程度

对此问题的许多评论和其他答案都提到了 MSDN 中缺乏关于EnumWindows返回窗口句柄顺序的精确文档。事实上,页面EnumWindows回调都对这个问题保持沉默EnumWindowsProc我提供以下证据:

  1. MSDN 杂志中的一篇 C++ Q&A 文章确实明确指出:

    EnumWindows 以自上而下的 Z 顺序枚举窗口

  2. 页面上EnumChildWindows暗指备注部分的订单:

    在枚举过程中按 Z 顺序移动或重新定位的子窗口将被正确枚举。

    这意味着顺序是 Z 顺序相关的。因为,在hWndParent参数的描述中,它说:

    如果此参数为 NULL,则此函数等效于 EnumWindows。

    可以假设相同的逻辑和顺序适用于EnumWindows.

  3. 这是此函数的可观察行为,这使得对其进行更改是一项重大更改。总的来说,微软在不对可观察行为进行重大更改方面做得很好。这不是保证,但这是一个非常安全的赌注。您更有可能发现在下一个版本中您正在使用的功能已被弃用——并被另一个“Ex”版本取代——而不是发现它的可观察行为发生了变化。

当然,在这一点上这都是非常学术的,因为EnumWindows可能不是解决 OP 问题的最佳解决方案——至少EnumThreadWindows可能更合适——但我认为对于可能遇到这个问题的其他人来说值得一提邮政。

于 2008-11-17T16:15:31.913 回答
2

以前的答案需要相当大的改进。Enum-order = Z-order 仅当 GetSystemMetrics(SM_IMMENABLED)=0 时,即禁用输入法管理器/输入法编辑器功能。因为所有窗口类“IME”(标题“Default IME”)和“MSCTFIME UI”都在窗口“Progman”(“程序管理器”)之后枚举,即不是Z 顺序。

于 2014-02-15T10:02:02.103 回答
1

该顺序未在 API(MSDN 链接)中指定,因此不能保证它是特别的 - 如果有保证,它将在 API 中明确指定。例如,如果在枚举的中途创建了一个窗口,会发生什么 - 它是否包含在枚举中?如果这样做变得更有效率,这允许窗口管理器自由地更改其实现。

但是,有一个独特的值可以用来区分窗口 - 窗口句柄本身。在您的EnumWindowProc方法中,保存每个匹配窗口的窗口句柄 - 无论如何您都需要它来向窗口发送消息。

于 2008-11-17T16:24:32.847 回答
0

如果您控制这两个进程,您可以从第一个进程发送一个带有“HWND_BROADCAST”作为第一个参数的 SendMessage。

然后其他程序在收到消息时,可以向他的子窗口发送一个 SendMessage。

于 2008-11-17T16:40:30.007 回答
0

如果文档没有说明枚举顺序,我强烈建议您远离任何假设。Raymond Chen 的博客 (blogs.msdn.com/oldnewthing) 上的几篇文章会告诉您有多少应用程序依赖于所有这些未记录的内容/观察结果,并且当新版本的 Windows 出现时会出现严重错误(除非MS 开发人员为另一个表现不佳的应用程序引入了另一个 shim)。

至于您的目的,有几个函数可以帮助您完成任务,例如 GetWindowThreadProcessID、GetParent、EnumThreadWindows 和 EnumWindows。

于 2008-11-17T16:42:49.423 回答