设置WH_CALLWNDPROC挂钩可防止深层次结构中的WM_HELP传播

时间:2015-08-19 14:16:26

标签: delphi winapi

当按下F1键时,win32 API首先发送相应的密钥消息,然后向具有焦点的控件发送WM_HELP消息。 由于它不处理它,它会一直发送到父母链到表单,该表单对消息作出反应。 在Delphi(XE7)中,这是因为调用CallWindowProc

内的Vcl.Controls.TWinControl.DefaultHandler而发生的

虽然这在我的应用程序中的几乎所有位置都能正常工作,但有一个地方WM_HELP永远不会到达顶层。 试图重现它,我想出了一个测试应用程序,你可以在这里找到:

http://obones.free.fr/wm_help.zip

在构建应用程序并启动它之后,将焦点放在In SubLevelLevel 1编辑内,然后按F1。 您将看到表单已捕获WM_HELP

现在,如果你在In SubLevel2Level 15内进行相同操作,你会看到没有记录任何内容,表单永远不会看到WM_HELP

在VCL中进行跟踪我发现对于那些深层次,CallWindowProcVcl.Controls.TWinControl.DefaultHandler的调用会立即返回层次结构中的一个控件,从而阻止表单接收消息

但是,我无法弄清楚为什么Win32 API代码认为它不应再传播消息,除了一件事:如果我删除WH_CALLWNDPROC挂钩,那么一切都恢复正常。 如果取消选中Use hook复选框,则可以看到禁用它的效果。

现在,人们会争辩说我不应该拥有如此深层次的组成部分,我同意。然而,中心的两个框架内部的结构直接受到我注意到这个问题的应用程序的启发。

这意味着在没有实际注意到问题的情况下触发问题非常容易。希望在我的情况下,我可以移除一些面板并回到限制之下。

但有没有人遇到过这种情况?如果是的话,你能解决它吗?或者这是Win32 API的已知行为吗?

1 个答案:

答案 0 :(得分:2)

这是由Windows内核堆栈溢出引起的。如果您递归发送窗口消息会发生这种情况。在64位Windows上,内核堆栈溢出的速度比在32位Windows上快得多。

此错误还导致VCL在通过将递归AlignControls代码更改为(my)迭代版本(更多关于堆栈溢出:http://news.jrsoftware.org/news/toolbar2000/msg07779.html

之前,在修复之前未正确调整深度嵌套控件的大小