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

我在Win32上读了一些东西以及消息循环是如何工作的,还有一些东西还不清楚:什么存储在消息队列中? 与消息( WM_COMMANDWM_CREATE等)相对应的整数值,还是指向包含消息整数值和其他东西(如wParamlParam等)的MSG结构的指针?

为了回答你的问题,队列中的每条消息至少要存储一个消息,

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

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

您或系统发布的消息存储在队列中,但有一些例外情况。 WM_TIMER消息永远不会被实际存储 ; 相反,如果队列中没有其他消息并且定时器已经成熟, GetMessage()构造一个定时器消息。 这意味着,首先,定时器消息具有最低的出队优先级,并且秒,即使不调用GetMessage()一段时间,来自短周期定时器的多个消息也不会溢出队列。 同样,WM_QUIT也不存储,而只是标记。 在队列耗尽后, GetMessage()假装检索到WM_QUIT,这是它检索的最后一个消息。 可能还有其他例外和内部优化。

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

邮件以什么形式存储在内部,我们不知道,我们不在乎。 Windows API完全抽象化。 MSG结构填充到您传递给GetMessage()PeekMessage()内存中。 除了Windows SDK指南中介绍的内容之外,您不需要知道或担心内部实现的细节。

Windows中的消息队列是一个抽象概念 。 把它看成是一个队列是非常有用的,但是它的实际实现是非常详细的。 Windows中有四种不同的消息来源:

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

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

  • 输入键盘和鼠标的事件消息。 这些是真正具有队列式行为的消息。 对于键盘来说,这确保了提前输入工作,当程序没有准备好接受按键时,没有击键被丢失。 一堆状态与它关联,例如键盘的整个状态被复制。 对于鼠标大致相同,只是状态较少。 WM_MOUSEMOVE消息是一个有趣的角落情况,队列不会存储游标遍历的每个像素。 位置更改会累积到单个消息中,并在必要时进行存储或交付。

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

MSDN有一个很好的文章, 在这里解释消息和消息队列的所有内容。

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