6

我阅读了一些关于 Win32 以及消息循环如何工作的内容,但我仍然不清楚:消息队列中究竟存储了什么?对应于消息( , 等)的WM_COMMAND整数值WM_CREATE或指向MSG包含消息整数值和其他内容(如wParam,等)的结构的指针lParam

4

3 回答 3

14

为了狭隘地回答您的问题,队列中的每条消息至少存储,

  • 消息指向的窗口句柄,
  • 正如您已经正确指出的,消息代码 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-gray 致敬以提醒这一点)。当窗口¹的任何部分被标记为“脏”并需要重新绘制时,也会模拟此消息。这也是一个低优先级的消息,当队列为空时,窗口中的多个无效区域会立即重新绘制,以降低 GUI 的响应性并减少闪烁。您可以通过调用强制立即重新绘制UpdateWindow()。这个函数的行为类似于SendMessage(),在某种意义上它不会返回,直到窗口的暴露部分被重绘。如果窗口的无效区域为空,则此函数不会向窗口发送 WM_PAINT,这是一种明显的优化。

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

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

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


¹我不知道 WM_PAINT 和 WM_TIMER 相对于彼此的优先级如何。我假设 WM_PAINT 的优先级较低,但我可能错了。

于 2012-02-11T09:50:51.500 回答
9

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

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

  • 从窗口状态合成的消息。最好的例子是 WM_PAINT,当设置了“窗口有脏矩形”状态标志时交付。和 WM_TIMER,在设置“定时器已过期”状态标志时交付。这些是“低优先级”消息,仅在消息队列为空时传递。它们由 GetMessage() 传递,但不存在于队列中。

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

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

于 2012-02-11T13:30:45.990 回答
0

MSDN 有一篇很好的文章在这里解释了关于消息和消息队列的所有内容。

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

于 2012-02-11T07:45:23.057 回答