co_IntPeekMessage主要实现内核里获取窗口消息,具体实现代码如下:
#001 BOOL FASTCALL
#002 co_IntPeekMessage(PUSER_MESSAGE Msg,
#003 HWND hWnd,
#004 UINT MsgFilterMin,
#005 UINT MsgFilterMax,
#006 UINT RemoveMsg)
#007 {
#008 PTHREADINFO pti;
#009 LARGE_INTEGER LargeTickCount;
#010 PUSER_MESSAGE_QUEUE ThreadQueue;
#011 PUSER_MESSAGE Message;
#012 BOOL Present, RemoveMessages;
#013 USER_REFERENCE_ENTRY Ref;
#014 USHORT HitTest;
#015 MOUSEHOOKSTRUCT MHook;
#016
#017 /* The queues and order in which they are checked are documented in the MSDN
#018 article on GetMessage() */
#019
获取当前线程信息。
#020 pti = PsGetCurrentThreadWin32Thread();
取得线程的消息队列。
#021 ThreadQueue = pti->MessageQueue;
#022
#023 /* Inspect RemoveMsg flags */
#024 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
消息是否删除的标志。
#025 RemoveMessages = RemoveMsg & PM_REMOVE;
#026
#027 CheckMessages:
#028
#029 Present = FALSE;
#030
获取内核计数。
#031 KeQueryTickCount(&LargeTickCount);
设置线程最后读取消息的时间。
#032 ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
#033
分发线程的消息。
#034 /* Dispatch sent messages here. */
#035 while (co_MsqDispatchOneSentMessage(ThreadQueue))
#036 ;
#037
#038 /* Now look for a quit message. */
#039
是否退出标志,如果是就构造退出消息。
#040 if (ThreadQueue->QuitPosted)
#041 {
#042 /* According to the PSDK, WM_QUIT messages are always returned, regardless
#043 of the filter specified */
构造退出消息。
#044 Msg->Msg.hwnd = NULL;
#045 Msg->Msg.message = WM_QUIT;
#046 Msg->Msg.wParam = ThreadQueue->QuitExitCode;
#047 Msg->Msg.lParam = 0;
#048 Msg->FreeLParam = FALSE;
#049 if (RemoveMessages)
#050 {
#051 ThreadQueue->QuitPosted = FALSE;
#052 }
#053 goto MsgExit;
#054 }
#055
查找一般的消息是否出现。
#056 /* Now check for normal messages. */
#057 Present = co_MsqFindMessage(ThreadQueue,
#058 FALSE,
#059 RemoveMessages,
#060 hWnd,
#061 MsgFilterMin,
#062 MsgFilterMax,
#063 &Message);
如果找到消息,就拷贝消息到用户结构里。
#064 if (Present)
#065 {
#066 RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
#067 if (RemoveMessages)
#068 {
删除内核里的消息结构。
#069 MsqDestroyMessage(Message);
#070 }
#071 goto MessageFound;
#072 }
#073
检查是否硬件的事件消息。
#074 /* Check for hardware events. */
#075 Present = co_MsqFindMessage(ThreadQueue,
#076 TRUE,
#077 RemoveMessages,
#078 hWnd,
#079 MsgFilterMin,
#080 MsgFilterMax,
#081 &Message);
#082 if (Present)
#083 {
#084 RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
#085 if (RemoveMessages)
#086 {
#087 MsqDestroyMessage(Message);
#088 }
#089 goto MessageFound;
#090 }
#091
重复分发消息。
#092 /* Check for sent messages again. */
#093 while (co_MsqDispatchOneSentMessage(ThreadQueue))
#094 ;
#095
检查是否窗口绘制的消息。
#096 /* Check for paint messages. */
#097 if (IntGetPaintMessage(hWnd, MsgFilterMin, MsgFilterMax, pti, &Msg->Msg, RemoveMessages))
#098 {
#099 Msg->FreeLParam = FALSE;
#100 goto MsgExit;
#101 }
#102
定时器消息,再回去检查消息。
#103 if (ThreadQueue->WakeMask & QS_TIMER)
#104 if (PostTimerMessages(hWnd)) // If there are timers ready,
#105 goto CheckMessages; // go back and process them.
#106
检查系统定时器消息是否出现。
#107 // LOL! Polling Timer Queue? How much time is spent doing this?
#108 /* Check for WM_(SYS)TIMER messages */
#109 Present = MsqGetTimerMessage(ThreadQueue, hWnd, MsgFilterMin, MsgFilterMax,
#110 &Msg->Msg, RemoveMessages);
#111 if (Present)
#112 {
#113 Msg->FreeLParam = FALSE;
#114 goto MessageFound;
#115 }
#116
如果有消息出现,就进入下面处理。
#117 if(Present)
#118 {
#119 MessageFound:
#120
如果要删除消息,就进入处理。
#121 if(RemoveMessages)
#122 {
#123 PWINDOW_OBJECT MsgWindow = NULL;
#124
获取消息的窗口。
#125 if(Msg->Msg.hwnd && (MsgWindow = UserGetWindowObject(Msg->Msg.hwnd)) &&
#126 Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST)
#127 {
#128 USHORT HitTest;
#129
#130 UserRefObjectCo(MsgWindow, &Ref);
#131
转换鼠标的消息。
#132 if(co_IntTranslateMouseMessage(ThreadQueue, &Msg->Msg, &HitTest, TRUE))
#133 /* FIXME - check message filter again, if the message doesn't match anymore,
#134 search again */
#135 {
#136 UserDerefObjectCo(MsgWindow);
#137 /* eat the message, search again */
#138 goto CheckMessages;
#139 }
#140
如果接收消息的队列窗口为空,就发送到当前活动的窗口。
#141 if(ThreadQueue->CaptureWindow == NULL)
#142 {
#143 co_IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
#144 if((Msg->Msg.message != WM_MOUSEMOVE && Msg->Msg.message != WM_NCMOUSEMOVE) &&
#145 IS_BTN_MESSAGE(Msg->Msg.message, DOWN) &&
#146 co_IntActivateWindowMouse(ThreadQueue, &Msg->Msg, MsgWindow, &HitTest))
#147 {
#148 UserDerefObjectCo(MsgWindow);
#149 /* eat the message, search again */
#150 goto CheckMessages;
#151 }
#152 }
#153
#154 UserDerefObjectCo(MsgWindow);
#155 }
#156 else
#157 {
#158 co_IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
#159 }
#160
#161 // if(MsgWindow)
#162 // {
#163 // UserDereferenceObject(MsgWindow);
#164 // }
#165
#166 goto MsgExit;
#167 }
#168
#169 if((Msg->Msg.hwnd && Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST) &&
#170 co_IntTranslateMouseMessage(ThreadQueue, &Msg->Msg, &HitTest, FALSE))
#171 /* FIXME - check message filter again, if the message doesn't match anymore,
#172 search again */
#173 {
#174 /* eat the message, search again */
#175 goto CheckMessages;
#176 }
下面开始处理鼠标消息的功能函数。
#177 MsgExit:
#178 if ( ISITHOOKED(WH_MOUSE) &&
#179 Msg->Msg.message >= WM_MOUSEFIRST &&
#180 Msg->Msg.message <= WM_MOUSELAST )
#181 {
#182 MHook.pt = Msg->Msg.pt;
#183 MHook.hwnd = Msg->Msg.hwnd;
#184 MHook.wHitTestCode = HitTest;
#185 MHook.dwExtraInfo = 0;
#186 if (co_HOOK_CallHooks( WH_MOUSE,
#187 RemoveMsg ? HC_ACTION : HC_NOREMOVE,
#188 Msg->Msg.message,
#189 (LPARAM)&MHook ))
#190 {
#191 if (ISITHOOKED(WH_CBT))
#192 {
#193 MHook.pt = Msg->Msg.pt;
#194 MHook.hwnd = Msg->Msg.hwnd;
#195 MHook.wHitTestCode = HitTest;
#196 MHook.dwExtraInfo = 0;
#197 co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED,
#198 Msg->Msg.message, (LPARAM)&MHook);
#199 }
#200 return FALSE;
#201 }
#202 }
键盘的消息过滤功能函数。
#203 if ( ISITHOOKED(WH_KEYBOARD) &&
#204 (Msg->Msg.message == WM_KEYDOWN || Msg->Msg.message == WM_KEYUP) )
#205 {
#206 if (co_HOOK_CallHooks( WH_KEYBOARD,
#207 RemoveMsg ? HC_ACTION : HC_NOREMOVE,
#208 LOWORD(Msg->Msg.wParam),
#209 Msg->Msg.lParam))
#210 {
#211 if (ISITHOOKED(WH_CBT))
#212 {
#213 /* skip this message */
#214 co_HOOK_CallHooks( WH_CBT, HCBT_KEYSKIPPED,
#215 LOWORD(Msg->Msg.wParam), Msg->Msg.lParam );
#216 }
#217 return FALSE;
#218 }
#219 }
#220 // The WH_GETMESSAGE hook enables an application to monitor messages about to
#221 // be returned by the GetMessage or PeekMessage function.
#222 if (ISITHOOKED(WH_GETMESSAGE))
#223 {
#224 //DPRINT1("Peek WH_GETMESSAGE -> %x/n",&Msg);
#225 co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)&Msg->Msg);
#226 }
#227 return TRUE;
#228 }
#229
#230 return Present;
#231 }