结合前段时间经历,整理相关问题,绝大部分抄自《Windows核心编程》第26章
消息队列是在什么时候创建的?
当一个线程第一次被建立时,系统假定线程不会被用于任何与用户界面相关的任务,这样可以减少线程对系统资源的要求。但是,一旦这个线程调用一个与图形用户界面有关的函数(例如检查它的消息队列或建立一个窗口),系统就会为该线程分配一些另外的资源,以便它能够执行与用户界面有关的任务。
GetMessage与PeekMessage的区别
GetMessage从消息队列取出消息(WM_PAINT除外),PeekMessage可以取出消息也可以不取出消息;
如果GetMessage从消息队列取不到消息,会一直等待;而PeekMessage会立即返回;
返回值不一样,GetMessage在获取到WM_QUIT时返回false;(为什么不能SendMessage(hwnd, WM_QUIT?
SendMessage的实现
如果调用SendMessage的线程与窗口所属线程相同,则直接调用消息处理函数;
如果向其他线程的窗口发送消息,会将消息追加到接收线程的发送消息队列,并为接收线程设定QS_SENDMESSAGE标志;当接收线程等待消息时,如果有QS_SENDMESSAGE标志,系统会扫描发送消息队列并找到第一个发送的消息;发送线程会设置成idle状态,并等待应答消息队列;
一个线程等待SendMessage返回时处于idle状态,但可以执行一个任务:如果系统中另外一个线程向一个窗口发送消息,这个窗口是由这个等待SendMessage返回的线程建立的,则系统要立即处理发送的消息。这种情况下,系统不必等待线程去调用Getmessage等函数。
防止SendMessage导致停止响应
SendMessageTimeout、SendMessageCallback、SendNotifyMessage、ReplyMessage
PostQuitMessage
PostQuitMessage并不实际登记一个消息到线程的消息队列,只是设置了线程的QS_QUIT标志位与THREADINFO的nExitCode成员。因为这些操作永远不会失败,所以PostQuitMessage的原型被定义为返回VOID
从消息队列中提取消息的算法
1)如果有QS_SENDMESSAGE,GetMessage或PeekMessage在处理其他线程发送的消息之后不返回到线程,它们等待其他要处理的消息;
2)如果消息在线程的登记消息队列中,GetMessage或PeekMessage填充MSG结构并返回,此时一般会调用DispatchMessage让相应的窗口过程来处理消息;
3)如果有QS_QUIT;
4)如果消息在线程的虚拟输入队列,GetMessage或PeekMessage返回硬件输入消息;
5)如果有QS_PAINT,返回WM_PAINT;
6)如果有QS_TIMER,返回WM_TIMER;
(WM_PAINT与WM_TIMER的优先级低)
队列消息与非队列消息
队列化的消息是由Windows放入程序消息队列中的。在程序的消息循环中,重新传回并分配给窗口消息处理程序。非队列化的消息在Windows呼叫窗口时直接送给窗口消息处理程序。也就是说,队列化的消息被「发送」给消息队列,而非队列化的消息则「发送」给窗口消息处理程序。
队列化消息基本上是使用者输入的结果,以击键(如WM_KEYDOWN和WM_KEYUP消息)、击键产生的字符(WM_CHAR)、鼠标移动(WM_MOUSEMOVE)和鼠标按钮(WM_LBUTTONDOWN)的形式给出。队列化消息还包含时钟消息(WM_TIMER)、更新消息(WM_PAINT)和退出消息(WM_QUIT)。
非队列化消息则是其它消息。在许多情况下,非队列化消息来自呼叫特定的Windows函数。例如,当WinMain呼叫CreateWindow时,Windows将建立窗口并在处理中给窗口消息处理程序发送一个WM_CREATE消息。当WinMain呼叫ShowWindow时,Windows将给窗口消息处理程序发送WM_SIZE和WM_SHOWWINDOW消息。当WinMain呼叫UpdateWindow时,Windows将给窗口消息处理程序发送WM_PAINT消息。键盘或鼠标输入时发出的队列化消息信号,也能在非队列化消息中出现。例如,用键盘或鼠标选择了一个菜单项时,键盘或鼠标消息就是队列化的,而说明菜单项已选中的WM_COMMAND消息则可能就是非队列化的。