消息队列在Win32中如何工作?

时间:2012-02-11 07:21:18

标签: windows winapi windows-messages

我在Win32上阅读了一些内容以及消息循环是如何工作的,而且还有一些东西对我来说还不清楚:消息队列中究竟存储了什么?对应于消息(WM_COMMANDWM_CREATE等)的整数值或指向包含消息整数值的MSG结构的指针以及wParam等其他内容,{ {1}}等等?

3 个答案:

答案 0 :(得分:11)

要简单地回答您的问题,队列中的每条消息至少都会存储

  • 消息所针对的窗口句柄
  • 消息代码,wParam和lParam,正如您已经正确指出的那样,
  • 发布邮件的时间,您使用GetMessageTime()
  • 检索
  • 用于UI消息,消息发布时光标的位置(参见GetMessagePos())。

请注意,并非所有邮件都实际存储在队列中。永远不会存储使用SendMessage()从拥有该窗口的线程发送到窗口的消息;相反,直接调用接收器窗口的消息功能。从其他线程发送的消息将被存储,直到被处理,并且发送线程将阻塞,直到消息被回复,退出窗口函数或显式调用ReplyMessage()。 API函数InSendMessage()有助于确定windows函数是否正在处理从另一个线程发送的消息。

您或系统发布的消息存储在队列中,但有一些例外。

  • WM_TIMER消息实际上从未存储;相反,如果队列中没有其他消息并且计时器已经成熟,则GetMessage()构造一个计时器消息。这意味着,首先,定时器消息具有最低的出队优先级,其次,来自短周期定时器的多个消息永远不会溢出队列,即使GetMessage()未被调用一段时间。因此,即使自上次处理来自该计时器的WM_TIMER消息后计时器已多次触发,也会为给定的计时器发送 WM_TIMER消息。

  • 同样,WM_QUIT也不存储,而只是标记。 GetMessage()假装在队列耗尽后检索到WM_QUIT,这是它检索的最后一条消息。

  • 另一个例子是WM_PAINT消息(帽子提示为@cody-grey以提醒这个)。当窗口1的任何部分标记为“脏”并需要重新绘制时,也会模拟此消息。这也是一个低优先级消息,使得当队列变空时,窗口中的多个无效区域一次全部重新绘制,以降低GUI的响应性并减少闪烁。您可以通过调用UpdateWindow()强制立即重新绘制。此函数的作用类似于SendMessage(),因为在窗口的外露部分实际重绘之前它不会返回。如果该窗口的无效区域为空,则该函数向窗口发送WM_PAINT,这是一种明显的优化。

可能还有其他例外和内部优化。

PostMessage()发布的消息最终会出现在拥有发布消息的窗口的线程的队列中。

消息以什么形式存储在内部,我们不知道,我们也不在乎。 Windows API完全抽象出来。 MSG结构填充在您传递给GetMessage()PeekMessage()的内存中。除了Windows SDK指南中记录的内容之外,您无需了解或担心内部实现的详细信息。


¹我不知道WM_PAINT和WM_TIMER是如何相互优先排序的。我假设WM_PAINT的优先级较低,但我可能错了。

答案 1 :(得分:9)

Windows中的消息队列是抽象。将它想象成一个队列非常有帮助,但它的实际实现要详细得多。 Windows中有四种不同的消息来源:

  • SendMessage()传递的消息。 Windows直接调用窗口过程,Peek / GetMessage()不返回消息,但需要调用该函数才能调度。到目前为止,大多数消息都以这种方式传递。 WM_COMMAND就是这样,它直接由转换关键事件的代码发送,比如TranslateAccelerator()。没有类似队列的行为。

  • 从窗口状态合成的消息。最好的例子是WM_PAINT,当“窗口有一个脏矩形”状态标志被设置时传递。并且,当“定时器已到期”状态标志被设置时传送WM_TIMER。这些是“低优先级”消息,仅在消息队列为空时传递。它们由GetMessage()提供,但不以其他方式存在于队列中。

  • 输入键盘和鼠标的事件消息。这些是真正具有类似队列行为的消息。对于键盘,这确保了预先输入,当程序未准备好接受击键时,没有键击丢失。一堆状态与它相关联,例如,键盘的整个状态被复制。除了状态较少外,鼠标大致相同。 WM_MOUSEMOVE消息是一个有趣的角落情况,队列存储光标遍历的每个像素。职位变更会累积到一条消息中,并在必要时存储或传递。

  • 通过显式PostMessage()调用存储在队列中的消息。这完全取决于程序代码,显然它只需要存储调用的参数加上调用的时间,这样就可以在GetMessage()时准确地重放它。

答案 2 :(得分:0)

MSDN有一篇很好的文章here,解释了有关消息和消息队列的所有内容。

但是为了回答你的问题,每个窗口都存在队列,它会临时存储消息及其关联参数,不管它是MSG的队列是否是实现定义的,但它很可能是(或类似的东西)。还应注意,并非所有消息都将进入队列,有些消息需要立即处理。

相关问题