int FirstTimerSlot; /* the first timer slot to be checked */第一个时间槽 DWORD TimerMask; /* timer slots mask */时间槽标记
int loop_depth; /* message loop depth, for dialog boxes. */消息循环深度, };
DWORD dwState可选的取值:
#define QS_NOTIFYMSG 0x10000000 //标志表示消息队列中有待处理的notify消息 #ifndef _LITE_VERSION
#define QS_SYNCMSG 0x20000000 //表示有待处理的同步消息 #else
#define QS_DESKTIMER 0x20000000 #endif
#define QS_POSTMSG 0x40000000 //表示有待处理的post消息 #define QS_QUIT 0x80000000 //对应MSG_QUIT #define QS_INPUT 0x01000000
#define QS_PAINT 0x02000000 //对应MSG_PAINT #define QS_TIMER 0x0000FFFF //对应MSG_TIMER #define QS_EMPTY 0x00000000
3、函数流程
fn BOOL PeekMessageEx (PMSG pMsg, HWND hWnd, \\ * int iMsgFilterMin, int iMsgFilterMax, \\ * BOOL bWait, UINT uRemoveMsg)
* \\brief Peeks a message from the message queue of a main window. *
* This functions peek a message from the message queue of the window \\a hWnd; * if \\a bWait is TRUE, it will wait for the message, else return immediatly. *
* \\param pMsg Pointer to the result message. * \\param hWnd The handle to the window.
* \\param iMsgFilterMin The min identifier of the message that should be peeked. * \\param iMsgFilterMax The max identifier of the message that should be peeked. * \\param bWait Whether to wait for a message.
* \\param uRemoveMsg Whether remove the message from the message queue. * Should be the following values: * - PM_NOREMOVE\\n
* Leave it in the message queue. * - PM_REMOVE
* Remove it from the message queue. * - PM_NOYIELD * Nouse now. *
* \\return TRUE if there is a message peeked, or FALSE. *
* \\sa GetMessage, PeekPostMessage, HavePendingMessage, PostMessage
BOOL PeekMessageEx (PMSG pMsg, HWND hWnd, int iMsgFilterMin, int iMsgFilterMax,
BOOL bWait, UINT uRemoveMsg)
{
PMSGQUEUE pMsgQueue; PQMSG phead;
//若pMsg不为空或者当前窗口不是桌面窗口且不是主窗口返回FALSE
if (!pMsg || (hWnd != HWND_DESKTOP && !MG_IS_MAIN_WINDOW(hWnd))) return FALSE;
pMsgQueue = __mg_dsk_msg_queue; //设置消息队列为默认消息队列 memset (pMsg, 0, sizeof(MSG)); //将pMsg指向的内存空间置为0 checkagain:
LOCK_MSGQ (pMsgQueue); //将消息队列上锁
if (pMsgQueue->dwState & QS_QUIT) { //如果消息队列的队首的消息类型为QS_QUIT pMsg->hwnd = hWnd; //设置pMsg的窗口句柄为当前窗口 pMsg->message = MSG_QUIT; //设置消息类型为MSG_QUIT pMsg->wParam = 0; //设置参数 pMsg->lParam = 0; SET_PADD (NULL);
if (uRemoveMsg == PM_REMOVE) { //如果参数uRemoveMsg为PM_REMOVE, pMsgQueue->loop_depth --; //消息队列的循环深度减一 if (pMsgQueue->loop_depth == 0) //如果消息队列的循环深度为0 pMsgQueue->dwState &= ~QS_QUIT; //设置消息队列的状态 }
UNLOCK_MSGQ (pMsgQueue);//解锁消息队列 return FALSE; //返回错误,表示获取消息失败 }
if (pMsgQueue->dwState & QS_NOTIFYMSG) {//如果消息队列类型为QS_NOTIFYMSG if (pMsgQueue->pFirstNotifyMsg) { //如果当前消息队列不为空
phead = pMsgQueue->pFirstNotifyMsg;//phead指向当前消息队列的队首
*pMsg = phead->Msg; //队首的消息信息赋给pMsg指向的消息 SET_PADD (NULL);
if (IS_MSG_WANTED(pMsg->message)) {//该消息是否是合适的消息 if (uRemoveMsg == PM_REMOVE) { // uRemoveMsg为PM_REMOVE pMsgQueue->pFirstNotifyMsg = phead->next; //消息头指向下一个消息 FreeQMSG (phead); //释放刚刚取出的消息所占的内存空间 }
UNLOCK_MSGQ (pMsgQueue); return TRUE; } }
else //如果当前消息队列为空
pMsgQueue->dwState &= ~QS_NOTIFYMSG; }
if (pMsgQueue->dwState & QS_POSTMSG) {//如果消息队列类型为QS_ POSTMSG if (pMsgQueue->readpos != pMsgQueue->writepos) { //读消息位置!=写消息位置 *pMsg = pMsgQueue->msg[pMsgQueue->readpos];//读第readpos条消息 SET_PADD (NULL);
if (IS_MSG_WANTED(pMsg->message)) { CheckCapturedMouseMessage (pMsg); if (uRemoveMsg == PM_REMOVE) {
pMsgQueue->readpos++;//读消息的位置指向下一条消息 if (pMsgQueue->readpos >= pMsgQueue->len) pMsgQueue->readpos = 0; }
UNLOCK_MSGQ (pMsgQueue); return TRUE; } } else
pMsgQueue->dwState &= ~QS_POSTMSG; } /*
* check invalidate region of the windows */
// MSG_PAINT消息,其重点是检查了QS_PAINT标志。当有QS_PAINT标志的时候,它实际上通过 msgCheckHostedTree函数,来检查那些窗口是需要重绘的。那些需要重绘的窗口,就会产生MSG_PAINT消息。
if (pMsgQueue->dwState & QS_PAINT && IS_MSG_WANTED(MSG_PAINT)) { PMAINWIN pHostingRoot; HWND hNeedPaint; PMAINWIN pWin;
pMsg->message = MSG_PAINT; //设置消息类型 pMsg->wParam = 0; pMsg->lParam = 0; SET_PADD (NULL);
pHostingRoot = __mg_dsk_win; //设置根窗口
if ( (hNeedPaint = msgCheckHostedTree (pHostingRoot)) ) {//获得无效区域的句柄 pMsg->hwnd = hNeedPaint; pWin = (PMAINWIN) hNeedPaint;
pMsg->lParam = (LPARAM)(&pWin->InvRgn.rgn); UNLOCK_MSGQ (pMsgQueue); return TRUE; }
/* no paint message */
pMsgQueue->dwState &= ~QS_PAINT; }
if (pMsgQueue->dwState & QS_DESKTIMER) { pMsg->hwnd = HWND_DESKTOP; pMsg->message = MSG_TIMER; pMsg->wParam = 0; pMsg->lParam = 0;
if (uRemoveMsg == PM_REMOVE) {
pMsgQueue->dwState &= ~QS_DESKTIMER; }
return TRUE; }
if (pMsgQueue->TimerMask && IS_MSG_WANTED(MSG_TIMER)) { int slot; TIMER* timer;
/* get the first expired timer slot */ slot = pMsgQueue->FirstTimerSlot; do {
if (pMsgQueue->TimerMask & (0x01 << slot)) break;
slot ++;
slot %= DEF_NR_TIMERS;
if (slot == pMsgQueue->FirstTimerSlot) { slot = -1; break; }
} while (TRUE);
pMsgQueue->FirstTimerSlot ++;
pMsgQueue->FirstTimerSlot %= DEF_NR_TIMERS;
if ((timer = __mg_get_timer (slot))) {
unsigned int tick_count = timer->tick_count;
timer->tick_count = 0;
pMsgQueue->TimerMask &= ~(0x01 << slot);
if (timer->proc) {
BOOL ret_timer_proc;
/* unlock the message queue when calling timer proc */ UNLOCK_MSGQ (pMsgQueue);
/* calling the timer callback procedure */ ret_timer_proc = timer->proc (timer->hWnd, timer->id, tick_count);
/* lock the message queue again */ LOCK_MSGQ (pMsgQueue);
if (!ret_timer_proc) { /* remove the timer */
__mg_remove_timer (timer, slot); } } else {
pMsg->message = MSG_TIMER; pMsg->hwnd = timer->hWnd; pMsg->wParam = timer->id; pMsg->lParam = tick_count; SET_PADD (NULL);
UNLOCK_MSGQ (pMsgQueue); return TRUE; } } }
UNLOCK_MSGQ (pMsgQueue); /* no message, idle */ if (bWait) {
int id=pMsgQueue->OnIdle (pMsgQueue); if(id==5) { idle=5; return TRUE; }
goto checkagain; }