正如我们在第3篇文章的结尾所提到的,既然你已经知道了关于 WM_QUIT 消息的使用技巧,那么,你就可以大胆地使用它们。

如果你希望 TimedMessageBox 函数越健壮,那么需要做的工作就越多。本篇将介绍一个基于知识库中一个示例程序的简单版本,我们只是添加了一些额外的错误修复。

请看代码:

模态弹窗和非模态弹窗区别(一个基础版本的超时关闭对话框)(1)

我们所实现的 CheapTimedMessageBox 函数,和 MessageBox 十分类似,只是我们添加了这样一个小功能:如果用户没有在 dwTimeout 时间内做出响应,则函数将会返回-1。有一个使用限制是:在同一时刻,只会有一个超时消息框是激活的。如果你的程序是单线程的,则这并不是一个很大的问题,但是如果你的程序是一个多线程程序,则这将会是一个问题。

你能看明白它是如何工作的吗?请听我来慢慢道来。

程序中的全局静态变量 s_fTimedOut 指示是否在超时的时候生成一个假的 WM_QUIT 消息。当MessageBox函数返回的时候,我们的确是超时了,这个时候,我们会使用 PeekMessage 函数来从消息队列中移除假的 WM_QUIT 消息。

需要注意的一点是,我们只会移除我们自己生成的 WM_QUIT 消息。也就是在这种情况下,程序的其他部分所生成的 WM_QUIT 消息,我们不会移除它们。

另外请注意,当我们确定发生超时的时候,我们会在通过发送 WM_QUIT 消息使消息框退出其消息循环之前,重新启用所有者窗口。这里我们遵循了之前文章中所提到的关于禁用和启用窗口的正确顺序的原则。

另外还要注意,我们使用了线程计时器而不是窗口计时器。 那是因为,我们不拥有传入的窗口,因此不知道哪些计时器 ID 可以安全使用。 我们选择的任何计时器 ID 都可能碰巧与该窗口正在使用的计时器 ID 发生冲突,从而导致行为不稳定。

让我们回想一下,当你将 NULL 作为 hwnd 参数传递给 SetTimer 函数并同时将零作为 nIDEvent 参数传递时,SetTimer 函数会创建一个全新的计时器,为其分配一个唯一 ID,然后返回该 ID。 大多数人在阅读 SetTimer 规范的那一部分时,都会挠头并问自己:“为什么有人要使用它?”

接下来,我们将会构建一个更加强壮的版本,请拭目以待。

总结

我的经验是,对于自动关闭的窗口,应该仅适用于那些对用户不那么重要的消息提示。如果一个消息提示比较重要,则只能由用户来决定是否关闭它。用户,是上帝。我们需要确保用户不漏过他/她不应该漏过的所有消息。TopomelBox目前还没有使用到自动关闭窗口,不清楚以后会不会有。

最后

Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。本文来自:《Modality, part 7: A timed MessageBox, the cheap version》

模态弹窗和非模态弹窗区别(一个基础版本的超时关闭对话框)(2)

,