窗口管理器功能的递归调用可能会意外地失败

症状

递归调用导出 USER32 的窗口管理器功能。DLL 可能会返回不执行请求的操作,也不设置错误代码。这通常发生在应用程序中与深层嵌套的窗口层次结构。在症状之间可能会出现:

  • 与深层嵌套的窗口层次结构的应用程序无法正确调整子窗口框架窗口调整大小时。Windows 将移动和/或调整通过调用 MoveWindow、 SetWindowPos 或 DeferWindowPos。

  • 窗口消息不会传播到父窗口或子窗口按预期的方式。DefWindowProc 可能无法成功地传播到接收消息的窗口的子窗口的父窗口的消息。

  • 窗口消息发送到窗口是通过调用发送消息,由指定的窗口不收到 SendMessageTimeout 或 SendMessageCallback。

此外,又能正常的应用程序也可能会遇到以上所述,如果在应用程序窗口中的线程上设置 WH_CALLWNDPROC 或 WH_CALLWNDPROCRET 窗口挂钩的现象。挂钩窗口可以通过调用 SetWindowsHookEx 函数在特定的线程上或在所有 UI 线程上设置。

原因

这种现象是 Windows 无法增长调用线程的内核堆栈才能执行请求的操作的结果。由于其他内核堆栈处理过程有必要在 x64 Windows 环境中,内核堆栈可由快的速度比在 Windows 环境窗口管理器功能进行递归调用时导出 x86 USER32。DLL。 尽管本文中描述的症状是更可能发生在 x64 Windows 平台,可能会占用线程的内核堆栈上 x86 的递归调用 Windows 平台。

解决方案

下面的解决方案可用来变通解决此问题

  1. 调整子窗口的大小,而将该消息传递给 DefWindowProc 的 WM_WINDOWPOSCHANGED 窗口消息进行处理时。

  2. 而不是在处理 WM_WINDOWPOSCHANGED 或 WM_SIZE 窗口消息时调整子窗口的父窗口调整大小时以异步方式调整子窗口的大小。

  3. 重新设计应用程序用户界面,以减少嵌套的窗口深度。

更多信息

Win32 子系统部分采用内核模式设备驱动程序 (WIN32K。SYS)。对由 USER32 中导出的函数的调用。WIN32K 将调用 DLL 的一个窗口,其大小和位置,包括状态更改。若要执行所请求的操作的系统。通常修改窗口的状态的函数会导致窗口消息发送到窗口中进行修改,其中 WIN32K。系统可使用户模式标注来调用正在修改窗口的窗口过程。例如,WIN32K。系统将发送一个窗口 WM_WINDOWPOSCHANGING 窗口消息及 WM_WINDOWPOSCHANGED 窗口消息时通过调用 SetWindowPos 函数来修改大小和/或窗口的位置。DefWindowProc 会将指定的窗口发送 WM_SIZE 消息调用 WM_WINDOWPOSCHANGED 消息时,窗口的大小发生了变化。当父窗口接收到 WM_WINDOWPOSCHANGED 或 WM_SIZE 窗口消息,这会导致递归调用到 WIN32K,应用程序通常调整子窗口。SYS 中深层嵌套的窗口层次结构。否则正常的应用程序也可能会遇到在进程中的线程上设置 WH_CALLWNDPROC 或 WH_CALLWNDPROCRET 挂钩时,本文中描述的症状。这是由于为其他内核堆栈空间消耗时 WIN32K。SYS 处理调用挂接过程。调用发送消息发送到窗口由调用线程所有窗口消息通常会调用而无需调入 WIN32K 接收消息的窗口的窗口过程。SYS。但是,发送消息将调用 WIN32K。系统如果有 WH_CALLWNDPROC 挂钩或 WH_CALLWNDPROCRET WIN32K 为调用线程上挂钩集。系统管理挂钩和句柄调用挂接过程。如上文所述,DefWindowProc 将指定的窗口 WM_SIZE 消息调用 WM_WINDOWPOSCHANGED 消息时,窗口的大小发生了变化。WH_CALLWNDPROC 挂钩或 WH_CALLWNDPROCRET 将导致发送消息调用转换为内核模式的 DefWindowProc 使为了调用挂接过程。调整子窗口处理而不是 WM_SIZE 窗口消息的 WM_WINDOWPOSCHANGED 窗口消息将减少内核堆栈的使用不再需要转换到内核模式,按顺序发送消息时调用挂接过程。遇到此问题的 Windows 窗体应用程序的开发人员应请参阅 KB 文章的其他信息。

需要更多帮助?

扩展你的技能
了解培训
抢先获得新功能
加入 Microsoft 内部人员

此信息是否有帮助?

谢谢您的反馈意见!

谢谢你的反馈! 可能需要转接到 Office 支持专员。

×