众所周知,我们可以使用 SendMessage 或者 PostMessage 来发送消息,那为什么在 Win32 API 中,会单独设计一个 PostQuitMessage 呢?
有一位读者 A. Skrobov 问我,”PostQuitMessage 和 PostThreadMessage(GetCurrentThreadId, WM_QUIT) 到底有什么区别,我怎么看起来是一样的效果?”
它们并不等同,尽管乍一看它们可能看起来是这样。差异是微妙的,但很重要。
与 WM_PAINT, WM_MOUSEMOVE 和 WM_TIMER 消息一样,WM_QUIT 消息不是 “真的” 投递的消息。相反,它是系统生成的消息之一,就好像它被投递一样,即使它不是。与其他消息一样,WM_QUIT消息是”低优先级”消息,仅在消息队列为空时才会生成。
当线程调用 PostQuitMessage 时,系统在消息队列中设置一个标志,该标志表示: “如果有人请求获取消息并且队列中没有消息,则创建一条 WM_QUIT 消息。” 这就像其他“虚拟发布”的消息一样。
如果存在任何无效区域,则 WM_PAINT 按需生成消息,如果鼠标自上次检查以来移动,则按需生成WM_MOUSEMOVE 消息,如果有任何到期计时器,则会按需生成 WM_TIMER 消息。
由于消息是“虚拟发布的”,因此多个调用会合并,就像多个绘制消息、多个鼠标移动和多个计时器消息也会合并一样。
为什么 WM_QUIT 被设计为低优先级消息呢?
因为系统尽量不在”糟糕的时间”注入 WM_QUIT 消息,相反,它在生成 WM_QUIT 消息之前等待事情”安定下来”,从而减少了程序可能处于由一系列已发布消息触发的多步骤过程中的可能性。
比如,如果 PeekMessage(…, PM_NOREMOVE) 获取到了 WM_QUIT 消息,这将返回一条 WM_QUIT 消息,但不会清除该标志。WM_QUIT消息实际上“保留在队列中”。
作为另一种特殊行为,生成的 WM_QUIT 消息会绕过传递给 GetMessage 和 PeekMessage 函数的消息筛选器。如果设置了内部”退出消息挂起”标志,则一旦队列为空,无论你通过什么过滤器,你都会收到一条WM_QUIT 消息。
相比之下,PostThreadMessage 只是将消息放在线程队列中(真实,而不是虚拟),因此它不会像 PostQuitMessage 那样会附带一些其他的特殊效果。
总结
根据上文的描述,PostQuitMessage 系统为我们创建的一个 WM_QUIT 消息,不是真实的,只是设置了一个标志位。
PostThreadMessage 则是实实在在的在线程消息队列中放置了一条 WM_QUIT 消息。
最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《Why is there a special PostQuitMessage function?》