Messages and Message Queues
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG, *PMSG, *LPMSG;
About Messages and Message Queues
Windows Messages
系统和窗口处理函数,通过message交流。
系统和应用程序都产生消息。
一个应用程序 可以直接发送消息 给他自己的窗口 去执行。或者和在其他应用程序中的窗口交流。
消息有四个函数:
a window handle, a message identifier, and two values called message parameters.
系统通过它决定,哪个窗口处理函数应该接收他。
Message的参数指定data or the location of data
integer, packed bit flags, a pointer to a structure containing additional data, and so on.
Message Types
System-Defined MessagesMessage Routing
队列消息:WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEY DOWN, 等用户输入信息。
非队列消息: WM_TIMER, WM_PAINT, WM_QUIT.
Queued Messages
系统可以在一个时刻,显示任意数量的窗口。 将 鼠标和键盘的输入 路由到适当的窗口, 系统使用消息队列。
系统持有一个单独的“系统队列”和一个“线程独有队列”为每个GUI线程。
Queued Messages
无论用户移动,单击鼠标,敲击键盘, 设备驱动都会将输入 放入“系统消息队列”. 系统队列 检查每一个消息 来决定目标窗口, 然后投递他们到“线程队列”。
一个“线程队列”接收所有 “窗口创建的” 鼠标键盘消息。 线程移除每一个消息 并 递交给系统去 运送他们到 适当的窗口函数和线程。
有三个例外的消息: WM_PAINT, WM_TIMER, WM_QUIT.
他们三个 只有在系统消息队列中 没有其他消息时,才被转发到 窗口。 另外 对于同一窗口的多个WM_PAINT被合并为一个WM_PAINT, 所有无效区域合并为一个总的无效区域。
系统投递消息到 线程消息队列,通过填充MSG结构包括: handle(目的地窗口的Handle), 消息定义,两个参数,时间,鼠标点。
一个线程可以 向自己的 “线程消息队列” 投递消息,或者其他线程, 通过PostMessage, PostThreadMessage.
一个应用程序可以用GetMessage去除自己队列中的一个消息. 检查但不去除消息,可以使用PeekMessage.
DispatchMessage驱动系统传送消息到 窗口处理过程。包括(handle, message_identifier, two message parameters)
对于投递时间和投递位置, 需要用GetMessageTime 和 GetMessagePos获取。
WaitMessage可以将当前进程挂起, 直到进程中收到消息。
Nonqueued Messages
非队列消息, 立即被传送到目标窗口过程, 跳过“系统队列”和“进程队列”。
有一些典型地发送非队列消息的情况,来直接影响窗口的状态。eg:
当用户激活一个新的应用程序窗口时, 系统发送一系列消息,包括WM_ACTIVATE,WM_SETFOCUS,WM_SETCURSOR.
一些系统函数会产生非队列消息, 例如, 系统调用SetWindowPos发送WM_WINDOWPOSCHANGED消息之后。
其他一些发送非队列消息的函数: BroadcastSystemMessage, BroadcastSystemMessageEx, SendMessage, SendMessageTimeout, SendNotifyMessage.
Message Handling
TranslateMessage:将键盘虚拟键,转换为可识别的字符码。
DispatchMessage: 发送Handle!=null的消息,到相应的Handle
如果线程使用了 非模态对话框, 消息循环必须判断 IsDialogMessage以至于对话框可以 收到键盘输入。
Window Procedure
对于用户不处理的消息,可以抛给DefWindowProc处理。
Message Filtering
GetMessage, PeekMessage最后一个参数,填写过滤范围。
WM_KEYFIRST, WM_KEYLAST,检索键盘消息
WM_MOUSEFIRST, WM_MOUSELAST, 检索鼠标消息
如果GetMessage(...,NUM)不存在,GetMessage则不返回,一直等待。
Posting and Sending Messages
SendMessageCallBack: 处理完这条消息, 就调用CallBack函数处理
SendMessageTimeOut: 超时作废
SendNotifyMessage: 如果是同线程, 则等处理完返回, 如果是异线程,则直接返回
SendDlgItemMessage: 向Dialog中控件发送消息
Posting Messages
PostMessage(NULL,..)送给当前线程的 Message Queue
HWND_TOPMOST all top window
满的时候,查看返回值。
SendMessage 调用的线程,要等处理完返回,才能继续工作。
Message Deadlocks
A线程发送给B线程时, 需要等SendMessage返回, 这时候可能造成 死锁。 如果对方暂停的时候。
小结:
1. “自己发的”消息PostMessage, PostThreadMessage,RedrawWindow “目的地”指定HWND窗口句柄。
2. “系统发的”键盘事件,焦点在哪个窗口,就发给哪个窗口。鼠标事件, desktop时鼠标在哪个窗口上, 就发送给哪个窗口。
3. GetMessage获取进程消息队列中的消息。 DispatchMessage将消息除时间坐标的内容发送到相应窗口函数处理。
浙公网安备 33010602011771号