基本概念
首先介绍一些相关的基本概念,这些概念来自微软MSDN中的关于windows api编程的部分章节。
窗口(window)
一个窗口(window)是位于屏幕上的长方形区域,用于接收用户输入并展示输出。用户可以通过鼠标或键盘与窗口交互。窗口会接收用户的输入,并通过消息(message)与其他窗口通信。
消息(message)
在Windows消息循环中,消息(message)是指一种用于传递和处理不同类型的信息的数据结构。系统使用消息将输入传递给window procedure。每个消息都有一个唯一的标识符,因此消息循环能够识别不同类型的消息,并将消息分发给相应的窗口所在线程处理。
-
消息的来源
消息可以是来自用户的输入,比如鼠标点击、键盘输入等。对于每个输入事件,系统都会生成一条消息。
当应用程序引起系统变更(例如改变窗口大小、重绘窗口内容、创建或者关闭窗口等)时,系统会生成消息通知相关窗口。
应用程序可以主动生成消息,以便执行特定的任务(例如更新显示内容)或与其他应用程序的窗口通信。 -
消息的四个参数
-
window handle
- 标识这条消息将发往哪个窗口
-
message identifier
- 标识消息的目的,window procedure根据message identifier确认如何处理这条消息
-
两个message parameters
- 指定window procedure处理这条消息时用到的数据或数据的位置。如果不需要message parameter,那么这两个参数将被置为null。
-
-
消息的分类
3.1 根据由谁定义分类
-
系统定义的消息
- 系统向应用程序通信时,系统会send或post系统定义的消息。
- 系统通过这些消息控制应用程序的操作,并提供输入或者其他信息给应用程序。
- 应用程序也可以使用这些消息来控制通过使用预先注册(register)的窗口类创建的控件窗口(control window)的操作
-
应用程序定义的消息
- 如果应用程序创建自己的消息,那么接收这些消息的窗口必须解释这些消息并提供适当的处理。
3.2 根据route方式分类
-
queued message
- 被发送到消息队列中的消息。
-
nonqueued message
- 被直接发送到window procedure的消息。
-
窗口过程(window procedure)
系统调用窗口的一个函数来与之通信,这个函数被称为“window procedure”。
Window procedure是一个接收并处理所有发往本窗口的消息的函数。
Windows-based 的应用程序的每个窗口都有一个名为window procedure的函数,系统会调用window procedure函数来处理消息。
在收到消息后,window procedure将会根据消息的标识符(message identifier)和消息参数(message parameters)来执行适当的操作处理该消息。
典型的window procedure通常包含一个大的switch语句,用于根据消息的类型(message code)选择适当的处理操作。
window procedure中的switch语句是用于消息的分发和处理的关键部分,它使得窗口可以正确地响应不同类型的消息。
消息队列(Message Queue)
消息队列(Message Queue)是一个用于存储消息的数据结构,是一种先进先出(FIFO)的队列。当一个窗口收到一个属于queued message的消息时,这个消息会被放入该窗口的消息队列中等待被处理。消息队列按照消息被接收的顺序排列消息。
在消息循环中,系统会不断地检查消息队列,如果消息队列中有待处理的消息,系统就会从队列中取出一条消息,并将其分发到相应的window procedure。
系统包含一个独立的消息队列,并为每个GUI线程维护一个消息队列。
当用户通过鼠标或键盘输入时,鼠标或键盘的设备驱动将输入转换为消息,并将这些消息放入系统消息队列(system message queue)中。
系统从系统消息队列中逐个删除消息,并检查消息以确定其目标窗口。然后,系统将消息发送到创建该目标窗口的线程的消息队列(message queue)中。
一个线程的消息队列接收该线程创建的所有窗口来自鼠标和键盘的消息。线程从其消息队列中删除消息,并指示系统将消息发送到特定的window procedure处理。
消息循环(Message Loop)
消息循环调用 GetMessage、TranslateMessage、DispatchMessage 这三个函数数。(出处:https://learn.microsoft.com/en-us/windows/win32/winmsg/about-messages-and-message-queues)
GetMessage
GetMessage函数从队列中检索消息,并将消息复制到MSG类型的结构。
GetMessage会一直block,直到有消息返回。
TranslateMessage
TranslateMessage将键盘驱动程序映射到 ASCII 字符的键消息映射成字符消息( character messages)。字符消息将被post到调用线程的消息队列,以便下次线程调用GetMessage或PeekMessage函数时读取。
DispatchMessage
DispatchMessage将消息分发给相应的目标窗口或消息处理函数。
消息循环的过程
消息循环的基本流程如下。
- 获取下一个消息(GetMessage)
从消息队列中获取下一个待处理的消息。 - 分发消息(DispatchMessage)
将消息分发给目标窗口或其他消息处理函数。 - 处理消息
根据消息类型和内容,window procedure会执行适当的的操作。
消息循环开始后,它会持续从线程的消息队列中检索消息,并将消息分发给对应的窗口。当GetMessage函数从消息队列中取出WM_QUIT消息时,消息循环才结束。