EnumWindows返回句柄的顺序是否有意义?

时间:2008-11-17 16:09:55

标签: windows winapi enumeration hwnd

从几个初步测试看来,EnumWindows总是以反向实例化顺序返回窗口,即最近实例化的窗口。这是一个有效的观察吗?如果是这样,在所有版本的Windows中都是如此吗?这是一个可靠的假设,即某种行为记录在某个地方吗?


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

5 个答案:

答案 0 :(得分:25)

以Z顺序返回它们。首先设置WS_EX_TOPMOST的最顶层窗口,直到最下面的窗口WS_EX_TOPMOST set,然后是最顶层的窗口没有WS_EX_TOPMOST,但是最下面的窗口没有WS_EX_TOPMOST 1}}。请注意,可见性不是一个决定因素,因此Z序中比可见窗口更高的不可见窗口仍然会出现在它之前。

修改

你不太可能按照自己的意愿使用它,只需从EnumWindows获得第一次回报。您的新窗口不仅不是第一次返回,而且您还有一个竞争条件,在此期间可以打开其他窗口。但是,您可以为应用程序保留所有已知窗口的列表,当您需要查找新打开的窗口时,请调用EnumWindows并将窗口句柄与列表中的窗口句柄进行比较。当你找到一个具有正确的类和标题(你甚至可以检查它属于GetWindowThreadProcessID的正确进程)并且列表中不是的那个时,你就找到了新窗口。

但是,出于您的目的,您可以通过安装CBT挂钩并观察HCBT_CREATEWND通知来获得更好的服务。有关详细信息,请参阅SetWindowsHookEx()the CBTProc callback上的MSDN帮助。

关于枚举顺序的确定程度

此问题的一些评论和其他答案提到MSDN中缺少关于EnumWindows返回窗口句柄的顺序的精确文档。事实上,EnumWindowsthe EnumWindowsProc callback上的网页在这个问题上都非常沉默。我提供以下证据:

  1. C++ Q&A article in MSDN magazine具体说明:

      

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

  2. EnumChildWindows上的页面提到了备注部分中的订单:

      

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

    这意味着订单依赖于Z顺序。因为,在 hWndParent 参数的描述中,它说:

      

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

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

  3. 这是此函数的可观察行为,这使得它可以改变它。总的来说,微软一直非常善于不对可观察行为进行重大改变。这不是保证,但这是一个非常安全的赌注。您更有可能发现在下一个版本中,您正在使用的函数已被弃用 - 并被另一个“Ex”版本替换 - 而不是发现其可观察行为已发生变化。
  4. 当然,这一点都是学术性的,因为EnumWindows可能不是OP问题的最佳解决方案 - 至少EnumThreadWindows可能更适合 - 但我我认为值得一提的是其他可能会遇到这篇文章的人。

答案 1 :(得分:2)

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

答案 2 :(得分:1)

订单未在API(MSDN link)中指定,因此无法保证其具体 - 如果有保证,则会在API中明确指定。例如,如果在枚举的中途创建了一个窗口会发生什么 - 它是否包含在枚举中?这使得窗口管理器可以自由地更改其实现,如果它变得更有效的话。

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

答案 3 :(得分:0)

如果您控制两个进程,您可以从第一个进程发送一个SendMessage,其中包含“HWND_BROADCAST”作为第一个参数。

然后另一个程序在收到msg时,可以对他的子窗口执行SendMessage。

答案 4 :(得分:0)

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

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