MsgWaitForMultipleObjects Function
MSDN: Waits until one or all of the specified objects are in the signaled state or the time-out interval elapses. The objects can include input event objects, which you specify using the dwWakeMask parameter.
To enter an alertable wait state, use the MsgWaitForMultipleObjectsEx function.微软提供了一个MsgWaitForMultipleObjects函数,该函数的特点是它不但可以等待内核对象,还可以等消息。也就是当有消息到来时,该函数也一样可以返回,并处理消息。
一般用法如下:
while (TRUE){
dRet = ::MsgWaitForMultipleObjects(1, m_hThread, FALSE, INFINITE, QS_ALLINPUT);
if (dRet == WAIT_OBJECT_0 + 1)
{
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
break;
}
}
SendMessage,SendMessageTimeout,SendMessageCallback,SendNotifyMessage和ReplyMessage
1. SendMessage未返回后,发送消息的线程是否可以处理其他的消息?
程例01
创建一个窗口,再创建两个Work Thread。第一个Thread先SendMessage给主窗口,主窗口弹出MessageBox即可(阻塞)。第二个之后SendMessage给主窗口,主窗口依然可以处理消息(例如再次弹出一个MessageBox)。
程例02
创建一个窗口,再创建两个Work Thread。第一个Thread先SendMessage给主窗口,主窗口while(1) ::Sleep(0);。第二个之后SendMessage给主窗口,主窗口无法处理消息。
程序例子3
程序例子4
消息循环全过程
GetMessage(PeekMessage)会检查消息队列状态标志,首先检查QS_SENDMESSAGE(或许由DWORD GetQueueStatus(UINT)来获取这个状态标志是否被设置),GetMessage会在函数内部处理(或许是主动CallWindowProc罢),而不返回,向相应的窗口过程发送消息后,继续等待其他要处理的消息。
然后检查QS_POSTMESSAGE标志,如果被设置,函数(/*GetMessage*/)返回TRUE,通常是DispatchMessage去分发消息。
接下去检测QS_QUIT设置,如果有则关闭QS_QUIT,GetMessage返回FALSE。
再接下去是检测QS_INPUT,包括键盘和鼠标消息,如果队列中没有键盘消息了,则关闭QS_KEY,没有鼠标按键消息了,就关闭QS_MOUSEBUTTON,最后没有鼠标移动消息了,则关闭QS_MOUSEMOVE标志,而GetMessage返回TRUE。
最后分别是处理QS_PAINT和QS_TIMER,这两种消息处理的逻辑相对复杂。
QS_PAINT标志的处理与此不同。如果线程建立的一个窗口有无效的区域,QS_PAINT标志被设置。当这个线程建立的所有窗口所占据的区域变成无效 时(通常由于对ValidateRect、ValidateRegion或BeginPaint的调用而引起),QS_PAINT标志就被关闭。只有当线 程建立的所有窗口都无效时,这个标志才关闭。调用GetMessage或PeekMessage对这个唤醒标志没有影响。【《Windows核心编程》】
该线程建立的定时器报时的时候,QS_TIMER会被设置,GetMessage和PeekMessage返回TRUE,产生WM_TIMER消息,直到下一次定时器报时。
非Active窗口点击失效
如果有一个窗口,它并没有Active,你想关闭它,直接点击右上角的x即可。但是有时候,我们会模拟按钮,例如用几张位图模拟一个Button,当窗口非Active的状态时,你直接点击它,它就收不到LBUTTONDOWN的消息。可以这么解决这个问题。
简单说来就是利用MouseMove消息,来进行SetCapture/ReleaseCapture。
(完 )
消息队列消息和窗口过程消息
消息有两种,一种投递到消息队列,你可以用GetMessage/PeekMessage来获取到,另外一种是直接发送到窗口过程的,比如WM_ACTIVATEAPP。
MSDN会这样写: A window receives this message through its WindowProc function。
事情是这样的:
我想手工处理 WM_LBUTTONDOWN,WM_LBUTTONUP,和WM_LBUTTONDBLCLK,于是在处理UP消息后,PeekMessage(, NULL),但是根本获取不到(注意我第二个参数为NULL)
于是我下了结论是 WM_LBUTTONDBLCLK 走窗口过程,而不是消息队列。【MSDN里面也是这么说的哦】
但是 PeekMessage的第二个参数改为当前窗口的句柄,就可以获得了。这怎么解释呢?
----嗯,貌似还是走窗口过程的,因为我注释了DispatchMessage( &msg );... 难道发现个技巧(怎么Peek到窗口过程消息)?。。。 。。。