首页 > 智能影音 >

说说模态化2:关于WM_QUIT消息

经过一些对模态化的简要介绍之后,今天我们来深入研究研究。

模态化的诀窍在于,当调用一个模态函数时,消息调度的责任由该函数处理,而不是由主程序处理。因此,如果你自定义了主程序的消息循环,那么一旦你失去对模态循环的控制,这些自定义的部分就会丢失。

关于模态的另一个重要的事情是:WM_QUIT消息总是会打破模态循环。

在你自己的模态循环中一定要记住这一点! 如果你调用 PeekMessage 函数GetMessage 函数并取到了一条WM_QUIT消息,则不仅必须退出模态循环,而且还必须重新生成 WM_QUIT消息(通过PostQuitMessage消息),这样,下一个外层循环将看到 WM_QUIT 消息并进行清理。 如果你未能传播消息,下一个外层将不知道它需要退出,并且程序似乎会”卡在”其关闭代码中,从而迫使用户以艰难的方式终止进程。

在后面的系列中,我们将看到这个围绕WM_QUIT消息的约定是如何工作的。 但是现在,先牢记:模态循环应该如何将WM_QUIT消息重新发布到下一个外层。

下面我们来看一个例子:

假设你的程序开始了一些操作,然后调用了WaitForSomething。在等待某事完成时,程序的其他部分决定是时候退出了。 (也许用户单击了“退出”按钮。)程序的其他部分将调用 PostQuitMessage(wParam) 来指示消息循环应该终止。

投递的WM_QUIT消息将首先由WaitForSomething函数中的GetMessage检索。 如果检索到的消息是 WM_QUIT 消息,GetMessage 函数将返回 FALSE。 在这种情况下,条件的“else”分支会被执行,它会取消正在进行的“Something”操作,然后将退出消息发送回消息队列以供下一个外部消息循环处理。

当 WaitForSomething 返回时,控制可能会退回到程序的主消息循环中。 然后主消息循环将检索 WM_QUIT 消息并在最终退出程序之前进行退出处理。

如果在 WaitForSomething 和程序的主消息循环之间有额外的模态层,每个层都会检索 WM_QUIT 消息,进行清理,然后在退出循环之前重新发布 WM_QUIT 消息(再次通过 PostQuitMessage)。

以这种方式,WM_QUIT 消息从一个模态循环传递到另一个模态循环,直到它到达最外层的循环,从而终止程序。

“但是等等,”我听到你说。 “为什么我必须做所有这些花哨的 WM_QUIT 步法? 我可以只拥有一个名为 g_fQuitting 的私有小全局变量。 当我想让程序退出时,我只是设置了这个变量,我所有的模态循环都会检查这个变量,如果它被设置了就提前退出。 像这样的东西:

所以我可以解决嵌套退出的问题,而无需执行所有这些 PostQuitMessage 繁琐的操作。”

你是对的,如果你控制了程序中的每一个模态循环。

但你没有。

例如,当你调用 DialogBox 函数时,对话框代码会运行自己的私有模式循环来执行对话框 UI,直到你开始调用 EndDialog 函数。 并且每当用户单击你的任何菜单时,Windows 都会运行自己的私有模式循环来执行菜单 UI。 事实上,即使是应用程序窗口的大小调整也是由 Windows 模态循环处理的。

当然,Windows 不知道你的小 g_fQuitting 变量,因此它不知道你要退出。 正是 WM_QUIT消息来负责系统的不同部分之间退出的协调工作。

请注意,这个关于 WM_QUIT 消息的约定是双向的。 你可以使用这个约定来退出模态循环(我们稍后会看到更多),但它也要求你遵守这个约定,以便其他组件(包括窗口管理器本身)可以让你的模态循环退出。

总结

试着增加这些Windows消息循环的底层知识,有助于你比其他程序员”更懂”。

其他人教你做事的机会,也相对少。

最后

Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。

本文来自:《Modality, part 3: The WM_QUIT message》

责任编辑:Rex_08

关键词: Windows Chen
推荐阅读