Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmsgqueue.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS Win32k subsystem 00004 * PURPOSE: Message queues 00005 * FILE: subsystems/win32/win32k/ntuser/msgqueue.c 00006 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) 00007 Alexandre Julliard 00008 Maarten Lankhorst 00009 */ 00010 00011 #include <win32k.h> 00012 DBG_DEFAULT_CHANNEL(UserMsgQ); 00013 00014 /* GLOBALS *******************************************************************/ 00015 00016 static PPAGED_LOOKASIDE_LIST pgMessageLookasideList; 00017 PUSER_MESSAGE_QUEUE gpqCursor; 00018 00019 /* FUNCTIONS *****************************************************************/ 00020 00021 INIT_FUNCTION 00022 NTSTATUS 00023 NTAPI 00024 MsqInitializeImpl(VOID) 00025 { 00026 pgMessageLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG); 00027 if(!pgMessageLookasideList) 00028 return STATUS_NO_MEMORY; 00029 ExInitializePagedLookasideList(pgMessageLookasideList, 00030 NULL, 00031 NULL, 00032 0, 00033 sizeof(USER_MESSAGE), 00034 TAG_USRMSG, 00035 256); 00036 00037 return(STATUS_SUCCESS); 00038 } 00039 00040 PWND FASTCALL 00041 IntChildrenWindowFromPoint(PWND pWndTop, INT x, INT y) 00042 { 00043 PWND pWnd, pWndChild; 00044 00045 if (!(pWndTop->style & WS_VISIBLE)) return NULL; 00046 if ((pWndTop->style & WS_DISABLED)) return NULL; 00047 if (!IntPtInWindow(pWndTop, x, y)) return NULL; 00048 00049 if (x - pWndTop->rcClient.left < pWndTop->rcClient.right && 00050 y - pWndTop->rcClient.top < pWndTop->rcClient.bottom ) 00051 { 00052 for (pWnd = pWndTop->spwndChild; 00053 pWnd != NULL; 00054 pWnd = pWnd->spwndNext) 00055 { 00056 if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED ) 00057 { 00058 TRACE("The Window is in DESTROY!\n"); 00059 continue; 00060 } 00061 00062 pWndChild = IntChildrenWindowFromPoint(pWnd, x, y); 00063 00064 if (pWndChild) 00065 { 00066 return pWndChild; 00067 } 00068 } 00069 } 00070 return pWndTop; 00071 } 00072 00073 PWND FASTCALL 00074 IntTopLevelWindowFromPoint(INT x, INT y) 00075 { 00076 PWND pWnd, pwndDesktop; 00077 00078 /* Get the desktop window */ 00079 pwndDesktop = UserGetDesktopWindow(); 00080 if (!pwndDesktop) 00081 return NULL; 00082 00083 /* Loop all top level windows */ 00084 for (pWnd = pwndDesktop->spwndChild; 00085 pWnd != NULL; 00086 pWnd = pWnd->spwndNext) 00087 { 00088 if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED) 00089 { 00090 TRACE("The Window is in DESTROY!\n"); 00091 continue; 00092 } 00093 00094 if ((pWnd->style & WS_VISIBLE) && IntPtInWindow(pWnd, x, y)) 00095 return pWnd; 00096 } 00097 00098 /* Window has not been found */ 00099 return NULL; 00100 } 00101 00102 PCURICON_OBJECT 00103 FASTCALL 00104 UserSetCursor( 00105 PCURICON_OBJECT NewCursor, 00106 BOOL ForceChange) 00107 { 00108 PCURICON_OBJECT OldCursor; 00109 HDC hdcScreen; 00110 PTHREADINFO pti; 00111 PUSER_MESSAGE_QUEUE MessageQueue; 00112 PWND pWnd; 00113 00114 pti = PsGetCurrentThreadWin32Thread(); 00115 MessageQueue = pti->MessageQueue; 00116 00117 /* Get the screen DC */ 00118 if(!(hdcScreen = IntGetScreenDC())) 00119 { 00120 return NULL; 00121 } 00122 00123 OldCursor = MessageQueue->CursorObject; 00124 00125 /* Check if cursors are different */ 00126 if (OldCursor == NewCursor) 00127 return OldCursor; 00128 00129 /* Update cursor for this message queue */ 00130 MessageQueue->CursorObject = NewCursor; 00131 00132 /* If cursor is not visible we have nothing to do */ 00133 if (MessageQueue->ShowingCursor < 0) 00134 return OldCursor; 00135 00136 /* Update cursor if this message queue controls it */ 00137 pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y); 00138 if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue) 00139 { 00140 if (NewCursor) 00141 { 00142 /* Call GDI to set the new screen cursor */ 00143 GreSetPointerShape(hdcScreen, 00144 NewCursor->IconInfo.hbmMask, 00145 NewCursor->IconInfo.hbmColor, 00146 NewCursor->IconInfo.xHotspot, 00147 NewCursor->IconInfo.yHotspot, 00148 gpsi->ptCursor.x, 00149 gpsi->ptCursor.y); 00150 } 00151 else /* Note: OldCursor != NewCursor so we have to hide cursor */ 00152 { 00153 /* Remove the cursor */ 00154 GreMovePointer(hdcScreen, -1, -1); 00155 TRACE("Removing pointer!\n"); 00156 } 00157 IntGetSysCursorInfo()->CurrentCursorObject = NewCursor; 00158 } 00159 00160 /* Return the old cursor */ 00161 return OldCursor; 00162 } 00163 00164 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR 00165 * User32 macro NtUserShowCursor */ 00166 int UserShowCursor(BOOL bShow) 00167 { 00168 HDC hdcScreen; 00169 PTHREADINFO pti; 00170 PUSER_MESSAGE_QUEUE MessageQueue; 00171 PWND pWnd; 00172 00173 if (!(hdcScreen = IntGetScreenDC())) 00174 { 00175 return -1; /* No mouse */ 00176 } 00177 00178 pti = PsGetCurrentThreadWin32Thread(); 00179 MessageQueue = pti->MessageQueue; 00180 00181 /* Update counter */ 00182 MessageQueue->ShowingCursor += bShow ? 1 : -1; 00183 00184 /* Check for trivial cases */ 00185 if ((bShow && MessageQueue->ShowingCursor != 0) || 00186 (!bShow && MessageQueue->ShowingCursor != -1)) 00187 { 00188 /* Note: w don't update global info here because it is used only 00189 internally to check if cursor is visible */ 00190 return MessageQueue->ShowingCursor; 00191 } 00192 00193 /* Check if cursor is above window owned by this MessageQueue */ 00194 pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y); 00195 if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue) 00196 { 00197 if (bShow) 00198 { 00199 /* Show the pointer */ 00200 GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y); 00201 TRACE("Showing pointer!\n"); 00202 } 00203 else 00204 { 00205 /* Remove the pointer */ 00206 GreMovePointer(hdcScreen, -1, -1); 00207 TRACE("Removing pointer!\n"); 00208 } 00209 00210 /* Update global info */ 00211 IntGetSysCursorInfo()->ShowingCursor = MessageQueue->ShowingCursor; 00212 } 00213 00214 return MessageQueue->ShowingCursor; 00215 } 00216 00217 DWORD FASTCALL 00218 UserGetKeyState(DWORD dwKey) 00219 { 00220 DWORD dwRet = 0; 00221 PTHREADINFO pti; 00222 PUSER_MESSAGE_QUEUE MessageQueue; 00223 00224 pti = PsGetCurrentThreadWin32Thread(); 00225 MessageQueue = pti->MessageQueue; 00226 00227 if (dwKey < 0x100) 00228 { 00229 if (IS_KEY_DOWN(MessageQueue->afKeyState, dwKey)) 00230 dwRet |= 0xFF80; // If down, windows returns 0xFF80. 00231 if (IS_KEY_LOCKED(MessageQueue->afKeyState, dwKey)) 00232 dwRet |= 0x1; 00233 } 00234 else 00235 { 00236 EngSetLastError(ERROR_INVALID_PARAMETER); 00237 } 00238 return dwRet; 00239 } 00240 00241 /* change the input key state for a given key */ 00242 static VOID 00243 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue, WORD wVk, BOOL bIsDown) 00244 { 00245 TRACE("UpdateKeyState wVk: %d, bIsDown: %d\n", wVk, bIsDown); 00246 00247 if (bIsDown) 00248 { 00249 /* If it's first key down event, xor lock bit */ 00250 if (!IS_KEY_DOWN(MessageQueue->afKeyState, wVk)) 00251 SET_KEY_LOCKED(MessageQueue->afKeyState, wVk, !IS_KEY_LOCKED(MessageQueue->afKeyState, wVk)); 00252 00253 SET_KEY_DOWN(MessageQueue->afKeyState, wVk, TRUE); 00254 MessageQueue->afKeyRecentDown[wVk / 8] |= (1 << (wVk % 8)); 00255 } 00256 else 00257 SET_KEY_DOWN(MessageQueue->afKeyState, wVk, FALSE); 00258 } 00259 00260 /* update the input key state for a keyboard message */ 00261 static VOID 00262 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue, MSG* msg) 00263 { 00264 UCHAR key; 00265 BOOL down = FALSE; 00266 00267 TRACE("UpdateKeyStateFromMsg message:%d\n", msg->message); 00268 00269 switch (msg->message) 00270 { 00271 case WM_LBUTTONDOWN: 00272 down = TRUE; 00273 /* fall through */ 00274 case WM_LBUTTONUP: 00275 UpdateKeyState(MessageQueue, VK_LBUTTON, down); 00276 break; 00277 case WM_MBUTTONDOWN: 00278 down = TRUE; 00279 /* fall through */ 00280 case WM_MBUTTONUP: 00281 UpdateKeyState(MessageQueue, VK_MBUTTON, down); 00282 break; 00283 case WM_RBUTTONDOWN: 00284 down = TRUE; 00285 /* fall through */ 00286 case WM_RBUTTONUP: 00287 UpdateKeyState(MessageQueue, VK_RBUTTON, down); 00288 break; 00289 case WM_XBUTTONDOWN: 00290 down = TRUE; 00291 /* fall through */ 00292 case WM_XBUTTONUP: 00293 if (msg->wParam == XBUTTON1) 00294 UpdateKeyState(MessageQueue, VK_XBUTTON1, down); 00295 else if (msg->wParam == XBUTTON2) 00296 UpdateKeyState(MessageQueue, VK_XBUTTON2, down); 00297 break; 00298 case WM_KEYDOWN: 00299 case WM_SYSKEYDOWN: 00300 down = TRUE; 00301 /* fall through */ 00302 case WM_KEYUP: 00303 case WM_SYSKEYUP: 00304 key = (UCHAR)msg->wParam; 00305 UpdateKeyState(MessageQueue, key, down); 00306 switch(key) 00307 { 00308 case VK_LCONTROL: 00309 case VK_RCONTROL: 00310 down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LCONTROL) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RCONTROL); 00311 UpdateKeyState(MessageQueue, VK_CONTROL, down); 00312 break; 00313 case VK_LMENU: 00314 case VK_RMENU: 00315 down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LMENU) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RMENU); 00316 UpdateKeyState(MessageQueue, VK_MENU, down); 00317 break; 00318 case VK_LSHIFT: 00319 case VK_RSHIFT: 00320 down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LSHIFT) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RSHIFT); 00321 UpdateKeyState(MessageQueue, VK_SHIFT, down); 00322 break; 00323 } 00324 break; 00325 } 00326 } 00327 00328 HANDLE FASTCALL 00329 IntMsqSetWakeMask(DWORD WakeMask) 00330 { 00331 PTHREADINFO Win32Thread; 00332 PUSER_MESSAGE_QUEUE MessageQueue; 00333 HANDLE MessageEventHandle; 00334 DWORD dwFlags = HIWORD(WakeMask); 00335 00336 Win32Thread = PsGetCurrentThreadWin32Thread(); 00337 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL) 00338 return 0; 00339 00340 MessageQueue = Win32Thread->MessageQueue; 00341 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient 00342 MessageEventHandle = MessageQueue->NewMessagesHandle; 00343 00344 if (Win32Thread->pcti) 00345 { 00346 if ( (Win32Thread->pcti->fsChangeBits & LOWORD(WakeMask)) || 00347 ( (dwFlags & MWMO_INPUTAVAILABLE) && (Win32Thread->pcti->fsWakeBits & LOWORD(WakeMask)) ) ) 00348 { 00349 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread->pcti->fsChangeBits, Win32Thread->pcti->fsWakeBits, WakeMask); 00350 KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE); // Wake it up! 00351 return MessageEventHandle; 00352 } 00353 } 00354 00355 IdlePing(); 00356 00357 return MessageEventHandle; 00358 } 00359 00360 BOOL FASTCALL 00361 IntMsqClearWakeMask(VOID) 00362 { 00363 PTHREADINFO Win32Thread; 00364 00365 Win32Thread = PsGetCurrentThreadWin32Thread(); 00366 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL) 00367 return FALSE; 00368 // Very hacky, but that is what they do. 00369 Win32Thread->pcti->fsWakeBits = 0; 00370 00371 IdlePong(); 00372 00373 return TRUE; 00374 } 00375 00376 /* 00377 Due to the uncertainty of knowing what was set in our multilevel message queue, 00378 and even if the bits are all cleared. The same as cTimers/cPaintsReady. 00379 I think this is the best solution... (jt) */ 00380 VOID FASTCALL 00381 MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue, DWORD MessageBits, BOOL KeyEvent) 00382 { 00383 PTHREADINFO pti; 00384 00385 pti = Queue->Thread->Tcb.Win32Thread; 00386 pti->pcti->fsWakeBits |= MessageBits; 00387 pti->pcti->fsChangeBits |= MessageBits; 00388 00389 // Start bit accounting to help clear the main set of bits. 00390 if (MessageBits & QS_KEY) Queue->nCntsQBits[QSRosKey]++; 00391 if (MessageBits & QS_MOUSEMOVE) Queue->nCntsQBits[QSRosMouseMove]++; 00392 if (MessageBits & QS_MOUSEBUTTON) Queue->nCntsQBits[QSRosMouseButton]++; 00393 if (MessageBits & QS_POSTMESSAGE) Queue->nCntsQBits[QSRosPostMessage]++; 00394 if (MessageBits & QS_SENDMESSAGE) Queue->nCntsQBits[QSRosSendMessage]++; 00395 if (MessageBits & QS_HOTKEY) Queue->nCntsQBits[QSRosHotKey]++; 00396 00397 if (KeyEvent) 00398 KeSetEvent(Queue->NewMessages, IO_NO_INCREMENT, FALSE); 00399 } 00400 00401 VOID FASTCALL 00402 ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue, UINT MessageBits) 00403 { 00404 PTHREADINFO pti; 00405 UINT ClrMask = 0; 00406 00407 pti = Queue->Thread->Tcb.Win32Thread; 00408 00409 if (MessageBits & QS_KEY) 00410 { 00411 if (--Queue->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY; 00412 } 00413 if (MessageBits & QS_MOUSEMOVE) // ReactOS hard coded. 00414 { // Account for tracking mouse moves.. 00415 if (--Queue->nCntsQBits[QSRosMouseMove] == 0) ClrMask |= QS_MOUSEMOVE; 00416 // Handle mouse move bits here. 00417 if (Queue->MouseMoved) ClrMask |= QS_MOUSEMOVE; 00418 } 00419 if (MessageBits & QS_MOUSEBUTTON) 00420 { 00421 if (--Queue->nCntsQBits[QSRosMouseButton] == 0) ClrMask |= QS_MOUSEBUTTON; 00422 } 00423 if (MessageBits & QS_POSTMESSAGE) 00424 { 00425 if (--Queue->nCntsQBits[QSRosPostMessage] == 0) ClrMask |= QS_POSTMESSAGE; 00426 } 00427 if (MessageBits & QS_TIMER) // ReactOS hard coded. 00428 { // Handle timer bits here. 00429 if ( pti->cTimersReady ) 00430 { 00431 if (--pti->cTimersReady == 0) ClrMask |= QS_TIMER; 00432 } 00433 } 00434 if (MessageBits & QS_PAINT) // ReactOS hard coded. 00435 { // Handle paint bits here. 00436 if ( pti->cPaintsReady ) 00437 { 00438 if (--pti->cPaintsReady == 0) ClrMask |= QS_PAINT; 00439 } 00440 } 00441 if (MessageBits & QS_SENDMESSAGE) 00442 { 00443 if (--Queue->nCntsQBits[QSRosSendMessage] == 0) ClrMask |= QS_SENDMESSAGE; 00444 } 00445 if (MessageBits & QS_HOTKEY) 00446 { 00447 if (--Queue->nCntsQBits[QSRosHotKey] == 0) ClrMask |= QS_HOTKEY; 00448 } 00449 00450 pti->pcti->fsWakeBits &= ~ClrMask; 00451 pti->pcti->fsChangeBits &= ~ClrMask; 00452 } 00453 00454 VOID FASTCALL 00455 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue) 00456 { 00457 PTHREADINFO pti; 00458 pti = Queue->Thread->Tcb.Win32Thread; 00459 pti->cPaintsReady++; 00460 MsqWakeQueue(Queue, QS_PAINT, TRUE); 00461 } 00462 00463 VOID FASTCALL 00464 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue) 00465 { 00466 ClearMsgBitsMask(Queue, QS_PAINT); 00467 } 00468 00469 VOID FASTCALL 00470 MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg) 00471 { 00472 MessageQueue->MouseMoveMsg = *Msg; 00473 MessageQueue->MouseMoved = TRUE; 00474 MsqWakeQueue(MessageQueue, QS_MOUSEMOVE, TRUE); 00475 } 00476 00477 VOID FASTCALL 00478 co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook) 00479 { 00480 LARGE_INTEGER LargeTickCount; 00481 MSLLHOOKSTRUCT MouseHookData; 00482 PDESKTOP pDesk; 00483 PWND pwnd, pwndDesktop; 00484 HDC hdcScreen; 00485 PSYSTEM_CURSORINFO CurInfo; 00486 00487 KeQueryTickCount(&LargeTickCount); 00488 Msg->time = MsqCalculateMessageTime(&LargeTickCount); 00489 00490 MouseHookData.pt.x = LOWORD(Msg->lParam); 00491 MouseHookData.pt.y = HIWORD(Msg->lParam); 00492 switch (Msg->message) 00493 { 00494 case WM_MOUSEWHEEL: 00495 MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg->wParam)); 00496 break; 00497 case WM_XBUTTONDOWN: 00498 case WM_XBUTTONUP: 00499 case WM_XBUTTONDBLCLK: 00500 case WM_NCXBUTTONDOWN: 00501 case WM_NCXBUTTONUP: 00502 case WM_NCXBUTTONDBLCLK: 00503 MouseHookData.mouseData = MAKELONG(0, HIWORD(Msg->wParam)); 00504 break; 00505 default: 00506 MouseHookData.mouseData = 0; 00507 break; 00508 } 00509 00510 MouseHookData.flags = flags; // LLMHF_INJECTED 00511 MouseHookData.time = Msg->time; 00512 MouseHookData.dwExtraInfo = dwExtraInfo; 00513 00514 /* If the hook procedure returned non zero, dont send the message */ 00515 if (Hook) 00516 { 00517 if (co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION, Msg->message, (LPARAM) &MouseHookData)) 00518 return; 00519 } 00520 00521 /* Get the desktop window */ 00522 pwndDesktop = UserGetDesktopWindow(); 00523 if (!pwndDesktop) return; 00524 pDesk = pwndDesktop->head.rpdesk; 00525 00526 /* Check if the mouse is captured */ 00527 Msg->hwnd = IntGetCaptureWindow(); 00528 if (Msg->hwnd != NULL) 00529 { 00530 pwnd = UserGetWindowObject(Msg->hwnd); 00531 } 00532 else 00533 { 00534 pwnd = IntTopLevelWindowFromPoint(Msg->pt.x, Msg->pt.y); 00535 if (pwnd) Msg->hwnd = pwnd->head.h; 00536 } 00537 00538 hdcScreen = IntGetScreenDC(); 00539 CurInfo = IntGetSysCursorInfo(); 00540 00541 /* Check if we found a window */ 00542 if (Msg->hwnd != NULL && pwnd != NULL) 00543 { 00544 if (Msg->message == WM_MOUSEMOVE) 00545 { 00546 PUSER_MESSAGE_QUEUE MessageQueue = pwnd->head.pti->MessageQueue; 00547 00548 /* Check if cursor should be visible */ 00549 if(hdcScreen && 00550 MessageQueue->CursorObject && 00551 MessageQueue->ShowingCursor >= 0) 00552 { 00553 /* Check if shape has changed */ 00554 if(CurInfo->CurrentCursorObject != MessageQueue->CursorObject) 00555 { 00556 /* Call GDI to set the new screen cursor */ 00557 GreSetPointerShape(hdcScreen, 00558 MessageQueue->CursorObject->IconInfo.hbmMask, 00559 MessageQueue->CursorObject->IconInfo.hbmColor, 00560 MessageQueue->CursorObject->IconInfo.xHotspot, 00561 MessageQueue->CursorObject->IconInfo.yHotspot, 00562 gpsi->ptCursor.x, 00563 gpsi->ptCursor.y); 00564 } else 00565 GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y); 00566 } 00567 /* Check if w have to hide cursor */ 00568 else if (CurInfo->ShowingCursor >= 0) 00569 GreMovePointer(hdcScreen, -1, -1); 00570 00571 /* Update global cursor info */ 00572 CurInfo->ShowingCursor = MessageQueue->ShowingCursor; 00573 CurInfo->CurrentCursorObject = MessageQueue->CursorObject; 00574 gpqCursor = MessageQueue; 00575 00576 /* Mouse move is a special case */ 00577 MsqPostMouseMove(MessageQueue, Msg); 00578 } 00579 else 00580 { 00581 TRACE("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd)); 00582 MsqPostMessage(pwnd->head.pti->MessageQueue, Msg, TRUE, QS_MOUSEBUTTON); 00583 } 00584 } 00585 else if (hdcScreen) 00586 { 00587 /* always show cursor on background; FIXME: set default pointer */ 00588 GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y); 00589 CurInfo->ShowingCursor = 0; 00590 } 00591 } 00592 00593 VOID FASTCALL 00594 MsqPostHotKeyMessage(PVOID Thread, HWND hWnd, WPARAM wParam, LPARAM lParam) 00595 { 00596 PWND Window; 00597 PTHREADINFO Win32Thread; 00598 MSG Mesg; 00599 LARGE_INTEGER LargeTickCount; 00600 NTSTATUS Status; 00601 INT id; 00602 DWORD Type; 00603 00604 Status = ObReferenceObjectByPointer (Thread, 00605 THREAD_ALL_ACCESS, 00606 PsThreadType, 00607 KernelMode); 00608 if (!NT_SUCCESS(Status)) 00609 return; 00610 00611 Win32Thread = ((PETHREAD)Thread)->Tcb.Win32Thread; 00612 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL) 00613 { 00614 ObDereferenceObject ((PETHREAD)Thread); 00615 return; 00616 } 00617 00618 Window = IntGetWindowObject(hWnd); 00619 if (!Window) 00620 { 00621 ObDereferenceObject ((PETHREAD)Thread); 00622 return; 00623 } 00624 00625 id = wParam; // Check for hot keys unrelated to the hot keys set by RegisterHotKey. 00626 00627 Mesg.hwnd = hWnd; 00628 Mesg.message = id != IDHK_REACTOS ? WM_HOTKEY : WM_SYSCOMMAND; 00629 Mesg.wParam = id != IDHK_REACTOS ? wParam : SC_HOTKEY; 00630 Mesg.lParam = id != IDHK_REACTOS ? lParam : (LPARAM)hWnd; 00631 Type = id != IDHK_REACTOS ? QS_HOTKEY : QS_POSTMESSAGE; 00632 KeQueryTickCount(&LargeTickCount); 00633 Mesg.time = MsqCalculateMessageTime(&LargeTickCount); 00634 Mesg.pt = gpsi->ptCursor; 00635 MsqPostMessage(Window->head.pti->MessageQueue, &Mesg, FALSE, Type); 00636 UserDereferenceObject(Window); 00637 ObDereferenceObject (Thread); 00638 00639 } 00640 00641 PUSER_MESSAGE FASTCALL 00642 MsqCreateMessage(LPMSG Msg) 00643 { 00644 PUSER_MESSAGE Message; 00645 00646 Message = ExAllocateFromPagedLookasideList(pgMessageLookasideList); 00647 if (!Message) 00648 { 00649 return NULL; 00650 } 00651 00652 RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG)); 00653 00654 return Message; 00655 } 00656 00657 VOID FASTCALL 00658 MsqDestroyMessage(PUSER_MESSAGE Message) 00659 { 00660 ExFreeToPagedLookasideList(pgMessageLookasideList, Message); 00661 } 00662 00663 BOOLEAN FASTCALL 00664 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue) 00665 { 00666 PUSER_SENT_MESSAGE SaveMsg, Message; 00667 PLIST_ENTRY Entry; 00668 PTHREADINFO pti; 00669 BOOL Ret; 00670 LRESULT Result = 0; 00671 00672 if (IsListEmpty(&MessageQueue->SentMessagesListHead)) 00673 { 00674 return(FALSE); 00675 } 00676 00677 /* remove it from the list of pending messages */ 00678 Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead); 00679 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry); 00680 00681 pti = MessageQueue->Thread->Tcb.Win32Thread; 00682 00683 SaveMsg = pti->pusmCurrent; 00684 pti->pusmCurrent = Message; 00685 00686 // Processing a message sent to it from another thread. 00687 if ( ( Message->SenderQueue && MessageQueue != Message->SenderQueue) || 00688 ( Message->CallBackSenderQueue && MessageQueue != Message->CallBackSenderQueue )) 00689 { // most likely, but, to be sure. 00690 pti->pcti->CTI_flags |= CTI_INSENDMESSAGE; // Let the user know... 00691 } 00692 00693 /* insert it to the list of messages that are currently dispatched by this 00694 message queue */ 00695 InsertTailList(&MessageQueue->LocalDispatchingMessagesHead, 00696 &Message->ListEntry); 00697 00698 ClearMsgBitsMask(MessageQueue, Message->QS_Flags); 00699 00700 if (Message->HookMessage == MSQ_ISHOOK) 00701 { // Direct Hook Call processor 00702 Result = co_CallHook( Message->Msg.message, // HookId 00703 (INT)(INT_PTR)Message->Msg.hwnd, // Code 00704 Message->Msg.wParam, 00705 Message->Msg.lParam); 00706 } 00707 else if (Message->HookMessage == MSQ_ISEVENT) 00708 { // Direct Event Call processor 00709 Result = co_EVENT_CallEvents( Message->Msg.message, 00710 Message->Msg.hwnd, 00711 Message->Msg.wParam, 00712 Message->Msg.lParam); 00713 } 00714 else if(Message->HookMessage == MSQ_INJECTMODULE) 00715 { 00716 Result = IntLoadHookModule(Message->Msg.message, 00717 (HHOOK)Message->Msg.lParam, 00718 Message->Msg.wParam); 00719 } 00720 else if ((Message->CompletionCallback) && 00721 (Message->CallBackSenderQueue == MessageQueue)) 00722 { /* Call the callback routine */ 00723 if (Message->QS_Flags & QS_SMRESULT) 00724 { 00725 co_IntCallSentMessageCallback(Message->CompletionCallback, 00726 Message->Msg.hwnd, 00727 Message->Msg.message, 00728 Message->CompletionCallbackContext, 00729 Message->lResult); 00730 /* Set callback to NULL to prevent reentry */ 00731 Message->CompletionCallback = NULL; 00732 } 00733 else 00734 { 00735 /* The message has not been processed yet, reinsert it. */ 00736 RemoveEntryList(&Message->ListEntry); 00737 InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead, &Message->ListEntry); 00738 TRACE("Callback Message not processed yet. Requeuing the message\n"); 00739 Ret = FALSE; 00740 goto Exit; 00741 } 00742 } 00743 else 00744 { /* Call the window procedure. */ 00745 Result = co_IntSendMessage( Message->Msg.hwnd, 00746 Message->Msg.message, 00747 Message->Msg.wParam, 00748 Message->Msg.lParam); 00749 } 00750 00751 /* remove the message from the local dispatching list, because it doesn't need 00752 to be cleaned up on thread termination anymore */ 00753 RemoveEntryList(&Message->ListEntry); 00754 00755 /* If the message is a callback, insert it in the callback senders MessageQueue */ 00756 if (Message->CompletionCallback) 00757 { 00758 if (Message->CallBackSenderQueue) 00759 { 00760 Message->lResult = Result; 00761 Message->QS_Flags |= QS_SMRESULT; 00762 00763 /* insert it in the callers message queue */ 00764 InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead, &Message->ListEntry); 00765 MsqWakeQueue(Message->CallBackSenderQueue, QS_SENDMESSAGE, TRUE); 00766 IntDereferenceMessageQueue(Message->CallBackSenderQueue); 00767 } 00768 Ret = TRUE; 00769 goto Exit; 00770 } 00771 00772 /* remove the message from the dispatching list if needed, so lock the sender's message queue */ 00773 if (Message->SenderQueue) 00774 { 00775 if (Message->DispatchingListEntry.Flink != NULL) 00776 { 00777 /* only remove it from the dispatching list if not already removed by a timeout */ 00778 RemoveEntryList(&Message->DispatchingListEntry); 00779 } 00780 } 00781 /* still keep the sender's message queue locked, so the sender can't exit the 00782 MsqSendMessage() function (if timed out) */ 00783 00784 if (Message->QS_Flags & QS_SMRESULT) 00785 { 00786 Result = Message->lResult; 00787 } 00788 00789 /* Let the sender know the result. */ 00790 if (Message->Result != NULL) 00791 { 00792 *Message->Result = Result; 00793 } 00794 00795 if (Message->HasPackedLParam == TRUE) 00796 { 00797 if (Message->Msg.lParam) 00798 ExFreePool((PVOID)Message->Msg.lParam); 00799 } 00800 00801 /* Notify the sender. */ 00802 if (Message->CompletionEvent != NULL) 00803 { 00804 KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE); 00805 } 00806 00807 /* if the message has a sender */ 00808 if (Message->SenderQueue) 00809 { 00810 /* dereference our and the sender's message queue */ 00811 IntDereferenceMessageQueue(Message->SenderQueue); 00812 IntDereferenceMessageQueue(MessageQueue); 00813 } 00814 00815 /* free the message */ 00816 ExFreePoolWithTag(Message, TAG_USRMSG); 00817 Ret = TRUE; 00818 Exit: 00819 /* do not hangup on the user if this is reentering */ 00820 if (!SaveMsg) pti->pcti->CTI_flags &= ~CTI_INSENDMESSAGE; 00821 pti->pusmCurrent = SaveMsg; 00822 00823 return Ret; 00824 } 00825 00826 VOID APIENTRY 00827 MsqRemoveWindowMessagesFromQueue(PVOID pWindow) 00828 { 00829 PUSER_SENT_MESSAGE SentMessage; 00830 PUSER_MESSAGE PostedMessage; 00831 PUSER_MESSAGE_QUEUE MessageQueue; 00832 PLIST_ENTRY CurrentEntry, ListHead; 00833 PWND Window = pWindow; 00834 00835 ASSERT(Window); 00836 00837 MessageQueue = Window->head.pti->MessageQueue; 00838 ASSERT(MessageQueue); 00839 00840 /* remove the posted messages for this window */ 00841 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink; 00842 ListHead = &MessageQueue->PostedMessagesListHead; 00843 while (CurrentEntry != ListHead) 00844 { 00845 PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, 00846 ListEntry); 00847 if (PostedMessage->Msg.hwnd == Window->head.h) 00848 { 00849 RemoveEntryList(&PostedMessage->ListEntry); 00850 ClearMsgBitsMask(MessageQueue, PostedMessage->QS_Flags); 00851 MsqDestroyMessage(PostedMessage); 00852 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink; 00853 } 00854 else 00855 { 00856 CurrentEntry = CurrentEntry->Flink; 00857 } 00858 } 00859 00860 /* remove the sent messages for this window */ 00861 CurrentEntry = MessageQueue->SentMessagesListHead.Flink; 00862 ListHead = &MessageQueue->SentMessagesListHead; 00863 while (CurrentEntry != ListHead) 00864 { 00865 SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, 00866 ListEntry); 00867 if(SentMessage->Msg.hwnd == Window->head.h) 00868 { 00869 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n"); 00870 00871 RemoveEntryList(&SentMessage->ListEntry); 00872 ClearMsgBitsMask(MessageQueue, SentMessage->QS_Flags); 00873 00874 /* if it is a callback and this queue is not the sender queue, dereference queue */ 00875 if ((SentMessage->CompletionCallback) && (SentMessage->CallBackSenderQueue != MessageQueue)) 00876 { 00877 IntDereferenceMessageQueue(SentMessage->CallBackSenderQueue); 00878 } 00879 /* Only if the message has a sender was the queue referenced */ 00880 if ((SentMessage->SenderQueue) 00881 && (SentMessage->DispatchingListEntry.Flink != NULL)) 00882 { 00883 RemoveEntryList(&SentMessage->DispatchingListEntry); 00884 } 00885 00886 /* wake the sender's thread */ 00887 if (SentMessage->CompletionEvent != NULL) 00888 { 00889 KeSetEvent(SentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE); 00890 } 00891 00892 if (SentMessage->HasPackedLParam == TRUE) 00893 { 00894 if (SentMessage->Msg.lParam) 00895 ExFreePool((PVOID)SentMessage->Msg.lParam); 00896 } 00897 00898 /* if the message has a sender */ 00899 if (SentMessage->SenderQueue) 00900 { 00901 /* dereference our and the sender's message queue */ 00902 IntDereferenceMessageQueue(MessageQueue); 00903 IntDereferenceMessageQueue(SentMessage->SenderQueue); 00904 } 00905 00906 /* free the message */ 00907 ExFreePoolWithTag(SentMessage, TAG_USRMSG); 00908 00909 CurrentEntry = MessageQueue->SentMessagesListHead.Flink; 00910 } 00911 else 00912 { 00913 CurrentEntry = CurrentEntry->Flink; 00914 } 00915 } 00916 } 00917 00918 BOOL FASTCALL 00919 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver, 00920 HWND hwnd, 00921 UINT Msg, 00922 WPARAM wParam, 00923 LPARAM lParam, 00924 SENDASYNCPROC CompletionCallback, 00925 ULONG_PTR CompletionCallbackContext, 00926 BOOL HasPackedLParam, 00927 INT HookMessage) 00928 { 00929 00930 PTHREADINFO ptiSender; 00931 PUSER_SENT_MESSAGE Message; 00932 00933 if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG))) 00934 { 00935 ERR("MsqSendMessage(): Not enough memory to allocate a message"); 00936 return FALSE; 00937 } 00938 00939 ptiSender = PsGetCurrentThreadWin32Thread(); 00940 00941 IntReferenceMessageQueue(ptiReceiver->MessageQueue); 00942 /* Take reference on this MessageQueue if its a callback. It will be released 00943 when message is processed or removed from target hwnd MessageQueue */ 00944 if (CompletionCallback) 00945 IntReferenceMessageQueue(ptiSender->MessageQueue); 00946 00947 Message->Msg.hwnd = hwnd; 00948 Message->Msg.message = Msg; 00949 Message->Msg.wParam = wParam; 00950 Message->Msg.lParam = lParam; 00951 Message->CompletionEvent = NULL; 00952 Message->Result = 0; 00953 Message->lResult = 0; 00954 Message->SenderQueue = NULL; 00955 Message->CallBackSenderQueue = ptiSender->MessageQueue; 00956 Message->DispatchingListEntry.Flink = NULL; 00957 Message->CompletionCallback = CompletionCallback; 00958 Message->CompletionCallbackContext = CompletionCallbackContext; 00959 Message->HookMessage = HookMessage; 00960 Message->HasPackedLParam = HasPackedLParam; 00961 Message->QS_Flags = QS_SENDMESSAGE; 00962 00963 InsertTailList(&ptiReceiver->MessageQueue->SentMessagesListHead, &Message->ListEntry); 00964 MsqWakeQueue(ptiReceiver->MessageQueue, QS_SENDMESSAGE, TRUE); 00965 IntDereferenceMessageQueue(ptiReceiver->MessageQueue); 00966 00967 return TRUE; 00968 } 00969 00970 NTSTATUS FASTCALL 00971 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, 00972 HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, 00973 UINT uTimeout, BOOL Block, INT HookMessage, 00974 ULONG_PTR *uResult) 00975 { 00976 PTHREADINFO pti, ptirec; 00977 PUSER_SENT_MESSAGE Message; 00978 KEVENT CompletionEvent; 00979 NTSTATUS WaitStatus; 00980 PUSER_MESSAGE_QUEUE ThreadQueue; 00981 LARGE_INTEGER Timeout; 00982 PLIST_ENTRY Entry; 00983 LRESULT Result = 0; 00984 00985 pti = PsGetCurrentThreadWin32Thread(); 00986 ThreadQueue = pti->MessageQueue; 00987 ptirec = MessageQueue->Thread->Tcb.Win32Thread; 00988 ASSERT(ThreadQueue != MessageQueue); 00989 ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!! 00990 00991 /* Don't send from or to a dying thread */ 00992 if (pti->TIF_flags & TIF_INCLEANUP || ptirec->TIF_flags & TIF_INCLEANUP) 00993 { 00994 if (uResult) *uResult = -1; 00995 ERR("MsqSM: Current pti %d or Rec pti %d\n",pti->TIF_flags & TIF_INCLEANUP, ptirec->TIF_flags & TIF_INCLEANUP); 00996 return STATUS_UNSUCCESSFUL; 00997 } 00998 00999 if ( HookMessage == MSQ_NORMAL ) 01000 { 01001 // These can not cross International Border lines! 01002 if ( pti->ppi != ptirec->ppi ) 01003 { 01004 switch(Msg) 01005 { 01006 case EM_GETLINE: 01007 case EM_SETPASSWORDCHAR: 01008 case WM_GETTEXT: 01009 case WM_NOTIFY: 01010 if (uResult) *uResult = -1; 01011 ERR("Running across the border without a passport!\n"); 01012 return STATUS_UNSUCCESSFUL; 01013 } 01014 } 01015 01016 // These can not cross State lines! 01017 if ( Msg == WM_CREATE || Msg == WM_NCCREATE ) 01018 { 01019 if (uResult) *uResult = -1; 01020 ERR("Can not tell the other State we have Create!\n"); 01021 return STATUS_UNSUCCESSFUL; 01022 } 01023 } 01024 01025 if(!(Message = ExAllocatePoolWithTag(PagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG))) 01026 { 01027 ERR("MsqSendMessage(): Not enough memory to allocate a message"); 01028 return STATUS_INSUFFICIENT_RESOURCES; 01029 } 01030 01031 KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE); 01032 01033 Timeout.QuadPart = (LONGLONG) uTimeout * (LONGLONG) -10000; 01034 01035 /* FIXME: Increase reference counter of sender's message queue here */ 01036 01037 Message->Msg.hwnd = Wnd; 01038 Message->Msg.message = Msg; 01039 Message->Msg.wParam = wParam; 01040 Message->Msg.lParam = lParam; 01041 Message->CompletionEvent = &CompletionEvent; 01042 Message->Result = &Result; 01043 Message->lResult = 0; 01044 Message->QS_Flags = 0; 01045 Message->SenderQueue = ThreadQueue; 01046 Message->CallBackSenderQueue = NULL; 01047 IntReferenceMessageQueue(ThreadQueue); 01048 Message->CompletionCallback = NULL; 01049 Message->CompletionCallbackContext = 0; 01050 Message->HookMessage = HookMessage; 01051 Message->HasPackedLParam = FALSE; 01052 01053 IntReferenceMessageQueue(MessageQueue); 01054 01055 /* Add it to the list of pending messages */ 01056 InsertTailList(&ThreadQueue->DispatchingMessagesHead, &Message->DispatchingListEntry); 01057 01058 /* Queue it in the destination's message queue */ 01059 InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry); 01060 01061 Message->QS_Flags = QS_SENDMESSAGE; 01062 MsqWakeQueue(MessageQueue, QS_SENDMESSAGE, TRUE); 01063 01064 /* We can't access the Message anymore since it could have already been deleted! */ 01065 01066 if(Block) 01067 { 01068 UserLeaveCo(); 01069 01070 /* Don't process messages sent to the thread */ 01071 WaitStatus = KeWaitForSingleObject(&CompletionEvent, UserRequest, UserMode, 01072 FALSE, (uTimeout ? &Timeout : NULL)); 01073 01074 UserEnterCo(); 01075 01076 if(WaitStatus == STATUS_TIMEOUT) 01077 { 01078 /* Look up if the message has not yet dispatched, if so 01079 make sure it can't pass a result and it must not set the completion event anymore */ 01080 Entry = MessageQueue->SentMessagesListHead.Flink; 01081 while (Entry != &MessageQueue->SentMessagesListHead) 01082 { 01083 if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) 01084 == Message) 01085 { 01086 /* We can access Message here, it's secure because the message queue is locked 01087 and the message is still hasn't been dispatched */ 01088 Message->CompletionEvent = NULL; 01089 Message->Result = NULL; 01090 break; 01091 } 01092 Entry = Entry->Flink; 01093 } 01094 01095 /* Remove from the local dispatching list so the other thread knows, 01096 it can't pass a result and it must not set the completion event anymore */ 01097 Entry = ThreadQueue->DispatchingMessagesHead.Flink; 01098 while (Entry != &ThreadQueue->DispatchingMessagesHead) 01099 { 01100 if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry) 01101 == Message) 01102 { 01103 /* We can access Message here, it's secure because the sender's message is locked 01104 and the message has definitely not yet been destroyed, otherwise it would 01105 have been removed from this list by the dispatching routine right after 01106 dispatching the message */ 01107 Message->CompletionEvent = NULL; 01108 Message->Result = NULL; 01109 RemoveEntryList(&Message->DispatchingListEntry); 01110 Message->DispatchingListEntry.Flink = NULL; 01111 break; 01112 } 01113 Entry = Entry->Flink; 01114 } 01115 01116 TRACE("MsqSendMessage (blocked) timed out 1\n"); 01117 } 01118 while (co_MsqDispatchOneSentMessage(ThreadQueue)) 01119 ; 01120 } 01121 else 01122 { 01123 PVOID WaitObjects[2]; 01124 01125 WaitObjects[0] = &CompletionEvent; 01126 WaitObjects[1] = ThreadQueue->NewMessages; 01127 do 01128 { 01129 UserLeaveCo(); 01130 01131 WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest, 01132 UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL); 01133 01134 UserEnterCo(); 01135 01136 if(WaitStatus == STATUS_TIMEOUT) 01137 { 01138 /* Look up if the message has not yet been dispatched, if so 01139 make sure it can't pass a result and it must not set the completion event anymore */ 01140 Entry = MessageQueue->SentMessagesListHead.Flink; 01141 while (Entry != &MessageQueue->SentMessagesListHead) 01142 { 01143 if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) 01144 == Message) 01145 { 01146 /* We can access Message here, it's secure because the message queue is locked 01147 and the message is still hasn't been dispatched */ 01148 Message->CompletionEvent = NULL; 01149 Message->Result = NULL; 01150 break; 01151 } 01152 Entry = Entry->Flink; 01153 } 01154 01155 /* Remove from the local dispatching list so the other thread knows, 01156 it can't pass a result and it must not set the completion event anymore */ 01157 Entry = ThreadQueue->DispatchingMessagesHead.Flink; 01158 while (Entry != &ThreadQueue->DispatchingMessagesHead) 01159 { 01160 if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry) 01161 == Message) 01162 { 01163 /* We can access Message here, it's secure because the sender's message is locked 01164 and the message has definitely not yet been destroyed, otherwise it would 01165 have been removed from this list by the dispatching routine right after 01166 dispatching the message */ 01167 Message->CompletionEvent = NULL; 01168 Message->Result = NULL; 01169 RemoveEntryList(&Message->DispatchingListEntry); 01170 Message->DispatchingListEntry.Flink = NULL; 01171 break; 01172 } 01173 Entry = Entry->Flink; 01174 } 01175 01176 TRACE("MsqSendMessage timed out 2\n"); 01177 break; 01178 } 01179 while (co_MsqDispatchOneSentMessage(ThreadQueue)) 01180 ; 01181 } 01182 while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus); 01183 } 01184 01185 if(WaitStatus != STATUS_TIMEOUT) 01186 *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1); 01187 01188 return WaitStatus; 01189 } 01190 01191 VOID FASTCALL 01192 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg, BOOLEAN HardwareMessage, 01193 DWORD MessageBits) 01194 { 01195 PUSER_MESSAGE Message; 01196 01197 if(!(Message = MsqCreateMessage(Msg))) 01198 { 01199 return; 01200 } 01201 01202 if(!HardwareMessage) 01203 { 01204 InsertTailList(&MessageQueue->PostedMessagesListHead, 01205 &Message->ListEntry); 01206 } 01207 else 01208 { 01209 InsertTailList(&MessageQueue->HardwareMessagesListHead, 01210 &Message->ListEntry); 01211 } 01212 01213 Message->QS_Flags = MessageBits; 01214 MsqWakeQueue(MessageQueue, MessageBits, (MessageBits & QS_TIMER ? FALSE : TRUE)); 01215 } 01216 01217 VOID FASTCALL 01218 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode) 01219 { 01220 MessageQueue->QuitPosted = TRUE; 01221 MessageQueue->QuitExitCode = ExitCode; 01222 MsqWakeQueue(MessageQueue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE); 01223 } 01224 01225 /*********************************************************************** 01226 * MsqSendParentNotify 01227 * 01228 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless 01229 * the window has the WS_EX_NOPARENTNOTIFY style. 01230 */ 01231 static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt ) 01232 { 01233 PWND pwndDesktop = UserGetDesktopWindow(); 01234 01235 /* pt has to be in the client coordinates of the parent window */ 01236 pt.x += pwndDesktop->rcClient.left - pwnd->rcClient.left; 01237 pt.y += pwndDesktop->rcClient.top - pwnd->rcClient.top; 01238 01239 for (;;) 01240 { 01241 PWND pwndParent; 01242 01243 if (!(pwnd->style & WS_CHILD)) break; 01244 if (pwnd->ExStyle & WS_EX_NOPARENTNOTIFY) break; 01245 if (!(pwndParent = IntGetParent(pwnd))) break; 01246 if (pwndParent == pwndDesktop) break; 01247 pt.x += pwnd->rcClient.left - pwndParent->rcClient.left; 01248 pt.y += pwnd->rcClient.top - pwndParent->rcClient.top; 01249 01250 pwnd = pwndParent; 01251 co_IntSendMessage( UserHMGetHandle(pwnd), WM_PARENTNOTIFY, 01252 MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) ); 01253 } 01254 } 01255 01256 VOID 01257 FASTCALL 01258 IntTrackMouseMove(PWND pwndTrack, PDESKTOP pDesk, PMSG msg, USHORT hittest) 01259 { 01260 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y); 01261 hittest = GetNCHitEx(pwndTrack, msg->pt); 01262 01263 if ( pDesk->spwndTrack != pwndTrack || // Change with tracking window or 01264 msg->message != WM_MOUSEMOVE || // Mouse click changes or 01265 pDesk->htEx != hittest) // Change in current hit test states. 01266 { 01267 TRACE("ITMM: Track Mouse Move!\n"); 01268 01269 /* Handle only the changing window track and mouse move across a border. */ 01270 if ( pDesk->spwndTrack != pwndTrack || 01271 (pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT) ) 01272 { 01273 TRACE("ITMM: Another Wnd %d or Across Border %d\n", 01274 pDesk->spwndTrack != pwndTrack,(pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT)); 01275 01276 if ( pDesk->dwDTFlags & DF_TME_LEAVE ) 01277 UserPostMessage( UserHMGetHandle(pDesk->spwndTrack), 01278 (pDesk->htEx != HTCLIENT) ? WM_NCMOUSELEAVE : WM_MOUSELEAVE, 01279 0, 0); 01280 01281 if ( pDesk->dwDTFlags & DF_TME_HOVER ) 01282 IntKillTimer(UserHMGetHandle(pDesk->spwndTrack), ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE); 01283 01284 /* Clear the flags to sign a change. */ 01285 pDesk->dwDTFlags &= ~(DF_TME_LEAVE|DF_TME_HOVER); 01286 } 01287 /* Set the Track window and hit test. */ 01288 pDesk->spwndTrack = pwndTrack; 01289 pDesk->htEx = hittest; 01290 } 01291 01292 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */ 01293 if ( pDesk->spwndTrack == pwndTrack && 01294 ( msg->message != WM_MOUSEMOVE || !RECTL_bPointInRect(&pDesk->rcMouseHover, msg->pt.x, msg->pt.y)) && 01295 pDesk->dwDTFlags & DF_TME_HOVER ) 01296 { 01297 TRACE("ITMM: Reset Hover points!\n"); 01298 // Restart timer for the hover period. 01299 IntSetTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM); 01300 // Reset desktop mouse hover from the system default hover rectangle. 01301 RECTL_vSetRect(&pDesk->rcMouseHover, 01302 msg->pt.x - gspv.iMouseHoverWidth / 2, 01303 msg->pt.y - gspv.iMouseHoverHeight / 2, 01304 msg->pt.x + gspv.iMouseHoverWidth / 2, 01305 msg->pt.y + gspv.iMouseHoverHeight / 2); 01306 } 01307 } 01308 01309 BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT last) 01310 { 01311 MSG clk_msg; 01312 POINT pt; 01313 UINT message; 01314 USHORT hittest; 01315 EVENTMSG event; 01316 MOUSEHOOKSTRUCT hook; 01317 BOOL eatMsg; 01318 01319 PWND pwndMsg, pwndDesktop; 01320 PUSER_MESSAGE_QUEUE MessageQueue; 01321 PTHREADINFO pti; 01322 PSYSTEM_CURSORINFO CurInfo; 01323 PDESKTOP pDesk; 01324 DECLARE_RETURN(BOOL); 01325 01326 pti = PsGetCurrentThreadWin32Thread(); 01327 pwndDesktop = UserGetDesktopWindow(); 01328 MessageQueue = pti->MessageQueue; 01329 CurInfo = IntGetSysCursorInfo(); 01330 pwndMsg = UserGetWindowObject(msg->hwnd); 01331 clk_msg = MessageQueue->msgDblClk; 01332 pDesk = pwndDesktop->head.rpdesk; 01333 01334 /* find the window to dispatch this mouse message to */ 01335 if (MessageQueue->CaptureWindow) 01336 { 01337 hittest = HTCLIENT; 01338 pwndMsg = IntGetWindowObject(MessageQueue->CaptureWindow); 01339 } 01340 else 01341 { 01342 pwndMsg = co_WinPosWindowFromPoint(pwndMsg, &msg->pt, &hittest); 01343 } 01344 01345 TRACE("Got mouse message for 0x%x, hittest: 0x%x\n", msg->hwnd, hittest ); 01346 01347 if (pwndMsg == NULL || pwndMsg->head.pti != pti) 01348 { 01349 /* Remove and ignore the message */ 01350 *RemoveMessages = TRUE; 01351 RETURN(FALSE); 01352 } 01353 01354 if ( MessageQueue == gpqCursor ) // Cursor must use the same Queue! 01355 { 01356 IntTrackMouseMove(pwndMsg, pDesk, msg, hittest); 01357 } 01358 else 01359 { 01360 ERR("Not the same cursor!\n"); 01361 } 01362 01363 msg->hwnd = UserHMGetHandle(pwndMsg); 01364 01365 #if 0 01366 if (!check_hwnd_filter( msg, hwnd_filter )) RETURN(FALSE); 01367 #endif 01368 01369 pt = msg->pt; 01370 message = msg->message; 01371 /* Note: windows has no concept of a non-client wheel message */ 01372 if (message != WM_MOUSEWHEEL) 01373 { 01374 if (hittest != HTCLIENT) 01375 { 01376 message += WM_NCMOUSEMOVE - WM_MOUSEMOVE; 01377 msg->wParam = hittest; 01378 } 01379 else 01380 { 01381 /* coordinates don't get translated while tracking a menu */ 01382 /* FIXME: should differentiate popups and top-level menus */ 01383 if (!(MessageQueue->MenuOwner)) 01384 { 01385 pt.x += pwndDesktop->rcClient.left - pwndMsg->rcClient.left; 01386 pt.y += pwndDesktop->rcClient.top - pwndMsg->rcClient.top; 01387 } 01388 } 01389 } 01390 msg->lParam = MAKELONG( pt.x, pt.y ); 01391 01392 /* translate double clicks */ 01393 01394 if ((msg->message == WM_LBUTTONDOWN) || 01395 (msg->message == WM_RBUTTONDOWN) || 01396 (msg->message == WM_MBUTTONDOWN) || 01397 (msg->message == WM_XBUTTONDOWN)) 01398 { 01399 BOOL update = *RemoveMessages; 01400 01401 /* translate double clicks - 01402 * note that ...MOUSEMOVEs can slip in between 01403 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */ 01404 01405 if ((MessageQueue->MenuOwner || MessageQueue->MoveSize) || 01406 hittest != HTCLIENT || 01407 (pwndMsg->pcls->style & CS_DBLCLKS)) 01408 { 01409 if ((msg->message == clk_msg.message) && 01410 (msg->hwnd == clk_msg.hwnd) && 01411 (msg->wParam == clk_msg.wParam) && 01412 ((msg->time - clk_msg.time) < (ULONG)gspv.iDblClickTime) && 01413 (abs(msg->pt.x - clk_msg.pt.x) < UserGetSystemMetrics(SM_CXDOUBLECLK)/2) && 01414 (abs(msg->pt.y - clk_msg.pt.y) < UserGetSystemMetrics(SM_CYDOUBLECLK)/2)) 01415 { 01416 message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN); 01417 if (update) 01418 { 01419 MessageQueue->msgDblClk.message = 0; /* clear the double click conditions */ 01420 update = FALSE; 01421 } 01422 } 01423 } 01424 01425 if (!((first == 0 && last == 0) || (message >= first || message <= last))) 01426 { 01427 TRACE("Message out of range!!!\n"); 01428 RETURN(FALSE); 01429 } 01430 01431 /* update static double click conditions */ 01432 if (update) MessageQueue->msgDblClk = *msg; 01433 } 01434 else 01435 { 01436 if (!((first == 0 && last == 0) || (message >= first || message <= last))) 01437 { 01438 TRACE("Message out of range!!!\n"); 01439 RETURN(FALSE); 01440 } 01441 } 01442 01443 if(gspv.bMouseClickLock) 01444 { 01445 BOOL IsClkLck = FALSE; 01446 01447 if(msg->message == WM_LBUTTONUP) 01448 { 01449 IsClkLck = ((msg->time - CurInfo->ClickLockTime) >= gspv.dwMouseClickLockTime); 01450 if (IsClkLck && (!CurInfo->ClickLockActive)) 01451 { 01452 CurInfo->ClickLockActive = TRUE; 01453 } 01454 } 01455 else if (msg->message == WM_LBUTTONDOWN) 01456 { 01457 if (CurInfo->ClickLockActive) 01458 { 01459 IsClkLck = TRUE; 01460 CurInfo->ClickLockActive = FALSE; 01461 } 01462 01463 CurInfo->ClickLockTime = msg->time; 01464 } 01465 01466 if(IsClkLck) 01467 { 01468 /* Remove and ignore the message */ 01469 *RemoveMessages = TRUE; 01470 RETURN(FALSE); 01471 } 01472 } 01473 01474 /* message is accepted now (but may still get dropped) */ 01475 01476 event.message = msg->message; 01477 event.time = msg->time; 01478 event.hwnd = msg->hwnd; 01479 event.paramL = msg->pt.x; 01480 event.paramH = msg->pt.y; 01481 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event ); 01482 01483 hook.pt = msg->pt; 01484 hook.hwnd = msg->hwnd; 01485 hook.wHitTestCode = hittest; 01486 hook.dwExtraInfo = 0 /* extra_info */ ; 01487 if (co_HOOK_CallHooks( WH_MOUSE, *RemoveMessages ? HC_ACTION : HC_NOREMOVE, 01488 message, (LPARAM)&hook )) 01489 { 01490 hook.pt = msg->pt; 01491 hook.hwnd = msg->hwnd; 01492 hook.wHitTestCode = hittest; 01493 hook.dwExtraInfo = 0 /* extra_info */ ; 01494 co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook ); 01495 01496 ERR("WH_MOUSE dorpped mouse message!\n"); 01497 01498 /* Remove and skip message */ 01499 *RemoveMessages = TRUE; 01500 RETURN(FALSE); 01501 } 01502 01503 if ((hittest == HTERROR) || (hittest == HTNOWHERE)) 01504 { 01505 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, 01506 MAKELONG( hittest, msg->message )); 01507 01508 /* Remove and skip message */ 01509 *RemoveMessages = TRUE; 01510 RETURN(FALSE); 01511 } 01512 01513 if ((*RemoveMessages == FALSE) || MessageQueue->CaptureWindow) 01514 { 01515 /* Accept the message */ 01516 msg->message = message; 01517 RETURN(TRUE); 01518 } 01519 01520 eatMsg = FALSE; 01521 01522 if ((msg->message == WM_LBUTTONDOWN) || 01523 (msg->message == WM_RBUTTONDOWN) || 01524 (msg->message == WM_MBUTTONDOWN) || 01525 (msg->message == WM_XBUTTONDOWN)) 01526 { 01527 /* Send the WM_PARENTNOTIFY, 01528 * note that even for double/nonclient clicks 01529 * notification message is still WM_L/M/RBUTTONDOWN. 01530 */ 01531 MsqSendParentNotify(pwndMsg, msg->message, 0, msg->pt ); 01532 01533 /* Activate the window if needed */ 01534 01535 if (msg->hwnd != UserGetForegroundWindow()) 01536 { 01537 PWND pwndTop = pwndMsg; 01538 while (pwndTop) 01539 { 01540 if ((pwndTop->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) break; 01541 pwndTop = IntGetParent( pwndTop ); 01542 } 01543 01544 if (pwndTop && pwndTop != pwndDesktop) 01545 { 01546 LONG ret = co_IntSendMessage( msg->hwnd, 01547 WM_MOUSEACTIVATE, 01548 (WPARAM)UserHMGetHandle(pwndTop), 01549 MAKELONG( hittest, msg->message)); 01550 switch(ret) 01551 { 01552 case MA_NOACTIVATEANDEAT: 01553 eatMsg = TRUE; 01554 /* fall through */ 01555 case MA_NOACTIVATE: 01556 break; 01557 case MA_ACTIVATEANDEAT: 01558 eatMsg = TRUE; 01559 /* fall through */ 01560 case MA_ACTIVATE: 01561 case 0: 01562 if(!co_IntMouseActivateWindow(pwndMsg)) eatMsg = TRUE; 01563 break; 01564 default: 01565 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret ); 01566 break; 01567 } 01568 } 01569 } 01570 } 01571 01572 /* send the WM_SETCURSOR message */ 01573 01574 /* Windows sends the normal mouse message as the message parameter 01575 in the WM_SETCURSOR message even if it's non-client mouse message */ 01576 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message )); 01577 01578 msg->message = message; 01579 RETURN(!eatMsg); 01580 01581 CLEANUP: 01582 if(pwndMsg) 01583 UserDereferenceObject(pwndMsg); 01584 01585 END_CLEANUP; 01586 } 01587 01588 BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages) 01589 { 01590 EVENTMSG Event; 01591 01592 if (Msg->message == WM_KEYDOWN || Msg->message == WM_SYSKEYDOWN || 01593 Msg->message == WM_KEYUP || Msg->message == WM_SYSKEYUP) 01594 { 01595 switch (Msg->wParam) 01596 { 01597 case VK_LSHIFT: case VK_RSHIFT: 01598 Msg->wParam = VK_SHIFT; 01599 break; 01600 case VK_LCONTROL: case VK_RCONTROL: 01601 Msg->wParam = VK_CONTROL; 01602 break; 01603 case VK_LMENU: case VK_RMENU: 01604 Msg->wParam = VK_MENU; 01605 break; 01606 } 01607 } 01608 01609 Event.message = Msg->message; 01610 Event.hwnd = Msg->hwnd; 01611 Event.time = Msg->time; 01612 Event.paramL = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8); 01613 Event.paramH = Msg->lParam & 0x7FFF; 01614 if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000; 01615 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event); 01616 01617 if (co_HOOK_CallHooks( WH_KEYBOARD, 01618 *RemoveMessages ? HC_ACTION : HC_NOREMOVE, 01619 LOWORD(Msg->wParam), 01620 Msg->lParam)) 01621 { 01622 /* skip this message */ 01623 co_HOOK_CallHooks( WH_CBT, 01624 HCBT_KEYSKIPPED, 01625 LOWORD(Msg->wParam), 01626 Msg->lParam ); 01627 ERR("KeyboardMessage WH_CBT Call Hook return!\n"); 01628 return FALSE; 01629 } 01630 return TRUE; 01631 } 01632 01633 BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, UINT first, UINT last) 01634 { 01635 if ( IS_MOUSE_MESSAGE(Msg->message)) 01636 { 01637 return co_IntProcessMouseMessage(Msg, RemoveMessages, first, last); 01638 } 01639 else if ( IS_KBD_MESSAGE(Msg->message)) 01640 { 01641 return co_IntProcessKeyboardMessage(Msg, RemoveMessages); 01642 } 01643 01644 return TRUE; 01645 } 01646 01647 BOOL APIENTRY 01648 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue, 01649 IN BOOL Remove, 01650 IN PWND Window, 01651 IN UINT MsgFilterLow, 01652 IN UINT MsgFilterHigh, 01653 OUT MSG* pMsg) 01654 { 01655 BOOL AcceptMessage; 01656 MSG msg; 01657 01658 if(!(MessageQueue->MouseMoved)) 01659 return FALSE; 01660 01661 msg = MessageQueue->MouseMoveMsg; 01662 01663 AcceptMessage = co_IntProcessMouseMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh); 01664 01665 if(AcceptMessage) 01666 *pMsg = msg; 01667 01668 if(Remove) 01669 { 01670 ClearMsgBitsMask(MessageQueue, QS_MOUSEMOVE); 01671 MessageQueue->MouseMoved = FALSE; 01672 } 01673 01674 return AcceptMessage; 01675 } 01676 01677 /* check whether a message filter contains at least one potential hardware message */ 01678 static INT FASTCALL 01679 filter_contains_hw_range( UINT first, UINT last ) 01680 { 01681 /* hardware message ranges are (in numerical order): 01682 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST 01683 * WM_KEYFIRST .. WM_KEYLAST 01684 * WM_MOUSEFIRST .. WM_MOUSELAST 01685 */ 01686 if (!last) --last; 01687 if (last < WM_NCMOUSEFIRST) return 0; 01688 if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0; 01689 if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0; 01690 if (first > WM_MOUSELAST) return 0; 01691 return 1; 01692 } 01693 01694 BOOL APIENTRY 01695 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, 01696 IN BOOL Remove, 01697 IN PWND Window, 01698 IN UINT MsgFilterLow, 01699 IN UINT MsgFilterHigh, 01700 IN UINT QSflags, 01701 OUT MSG* pMsg) 01702 { 01703 01704 BOOL AcceptMessage; 01705 PUSER_MESSAGE CurrentMessage; 01706 PLIST_ENTRY ListHead, CurrentEntry = NULL; 01707 MSG msg; 01708 01709 if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE; 01710 01711 ListHead = &MessageQueue->HardwareMessagesListHead; 01712 CurrentEntry = ListHead->Flink; 01713 01714 if (IsListEmpty(CurrentEntry)) return FALSE; 01715 01716 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, 01717 ListEntry); 01718 do 01719 { 01720 if (IsListEmpty(CurrentEntry)) break; 01721 if (!CurrentMessage) break; 01722 CurrentEntry = CurrentMessage->ListEntry.Flink; 01723 /* 01724 MSDN: 01725 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL. 01726 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL. 01727 3: handle to the window whose messages are to be retrieved. 01728 */ 01729 if ( ( !Window || // 1 01730 ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2 01731 ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3 01732 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) || 01733 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) ) 01734 { 01735 msg = CurrentMessage->Msg; 01736 01737 UpdateKeyStateFromMsg(MessageQueue, &msg); 01738 AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh); 01739 01740 if (Remove) 01741 { 01742 RemoveEntryList(&CurrentMessage->ListEntry); 01743 ClearMsgBitsMask(MessageQueue, CurrentMessage->QS_Flags); 01744 MsqDestroyMessage(CurrentMessage); 01745 } 01746 01747 if (AcceptMessage) 01748 { 01749 *pMsg = msg; 01750 return TRUE; 01751 } 01752 } 01753 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, 01754 ListEntry); 01755 } 01756 while(CurrentEntry != ListHead); 01757 01758 return FALSE; 01759 } 01760 01761 BOOLEAN APIENTRY 01762 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, 01763 IN BOOLEAN Remove, 01764 IN PWND Window, 01765 IN UINT MsgFilterLow, 01766 IN UINT MsgFilterHigh, 01767 IN UINT QSflags, 01768 OUT PMSG Message) 01769 { 01770 PLIST_ENTRY CurrentEntry; 01771 PUSER_MESSAGE CurrentMessage; 01772 PLIST_ENTRY ListHead; 01773 01774 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink; 01775 ListHead = &MessageQueue->PostedMessagesListHead; 01776 01777 if (IsListEmpty(CurrentEntry)) return FALSE; 01778 01779 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, 01780 ListEntry); 01781 do 01782 { 01783 if (IsListEmpty(CurrentEntry)) break; 01784 if (!CurrentMessage) break; 01785 CurrentEntry = CurrentEntry->Flink; 01786 /* 01787 MSDN: 01788 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL. 01789 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL. 01790 3: handle to the window whose messages are to be retrieved. 01791 */ 01792 if ( ( !Window || // 1 01793 ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2 01794 ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3 01795 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) || 01796 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) ) 01797 { 01798 *Message = CurrentMessage->Msg; 01799 01800 if (Remove) 01801 { 01802 RemoveEntryList(&CurrentMessage->ListEntry); 01803 ClearMsgBitsMask(MessageQueue, CurrentMessage->QS_Flags); 01804 MsqDestroyMessage(CurrentMessage); 01805 } 01806 return(TRUE); 01807 } 01808 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, 01809 ListEntry); 01810 } 01811 while (CurrentEntry != ListHead); 01812 01813 return(FALSE); 01814 } 01815 01816 NTSTATUS FASTCALL 01817 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, PWND WndFilter, 01818 UINT MsgFilterMin, UINT MsgFilterMax) 01819 { 01820 NTSTATUS ret; 01821 UserLeaveCo(); 01822 ret = KeWaitForSingleObject( MessageQueue->NewMessages, 01823 UserRequest, 01824 UserMode, 01825 FALSE, 01826 NULL ); 01827 UserEnterCo(); 01828 return ret; 01829 } 01830 01831 BOOL FASTCALL 01832 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue) 01833 { 01834 LARGE_INTEGER LargeTickCount; 01835 01836 KeQueryTickCount(&LargeTickCount); 01837 return ((LargeTickCount.u.LowPart - MessageQueue->LastMsgRead) > MSQ_HUNG); 01838 } 01839 01840 VOID 01841 CALLBACK 01842 HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) 01843 { 01844 DoTheScreenSaver(); 01845 TRACE("HungAppSysTimerProc\n"); 01846 // Process list of windows that are hung and waiting. 01847 } 01848 01849 BOOLEAN FASTCALL 01850 MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQueue) 01851 { 01852 LARGE_INTEGER LargeTickCount; 01853 NTSTATUS Status; 01854 01855 MessageQueue->Thread = Thread; 01856 MessageQueue->CaretInfo = (PTHRDCARETINFO)(MessageQueue + 1); 01857 InitializeListHead(&MessageQueue->PostedMessagesListHead); 01858 InitializeListHead(&MessageQueue->SentMessagesListHead); 01859 InitializeListHead(&MessageQueue->HardwareMessagesListHead); 01860 InitializeListHead(&MessageQueue->DispatchingMessagesHead); 01861 InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead); 01862 MessageQueue->QuitPosted = FALSE; 01863 MessageQueue->QuitExitCode = 0; 01864 KeQueryTickCount(&LargeTickCount); 01865 MessageQueue->LastMsgRead = LargeTickCount.u.LowPart; 01866 MessageQueue->spwndFocus = NULL; 01867 MessageQueue->NewMessagesHandle = NULL; 01868 MessageQueue->ShowingCursor = 0; 01869 MessageQueue->CursorObject = NULL; 01870 RtlCopyMemory(MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState)); 01871 01872 Status = ZwCreateEvent(&MessageQueue->NewMessagesHandle, EVENT_ALL_ACCESS, 01873 NULL, SynchronizationEvent, FALSE); 01874 if (!NT_SUCCESS(Status)) 01875 { 01876 return FALSE; 01877 } 01878 01879 Status = ObReferenceObjectByHandle(MessageQueue->NewMessagesHandle, 0, 01880 ExEventObjectType, KernelMode, 01881 (PVOID*)&MessageQueue->NewMessages, NULL); 01882 if (!NT_SUCCESS(Status)) 01883 { 01884 ZwClose(MessageQueue->NewMessagesHandle); 01885 MessageQueue->NewMessagesHandle = NULL; 01886 return FALSE; 01887 } 01888 01889 return TRUE; 01890 } 01891 01892 VOID FASTCALL 01893 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue) 01894 { 01895 PLIST_ENTRY CurrentEntry; 01896 PUSER_MESSAGE CurrentMessage; 01897 PUSER_SENT_MESSAGE CurrentSentMessage; 01898 PTHREADINFO pti; 01899 01900 pti = MessageQueue->Thread->Tcb.Win32Thread; 01901 01902 01903 /* cleanup posted messages */ 01904 while (!IsListEmpty(&MessageQueue->PostedMessagesListHead)) 01905 { 01906 CurrentEntry = RemoveHeadList(&MessageQueue->PostedMessagesListHead); 01907 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, 01908 ListEntry); 01909 MsqDestroyMessage(CurrentMessage); 01910 } 01911 01912 /* remove the messages that have not yet been dispatched */ 01913 while (!IsListEmpty(&MessageQueue->SentMessagesListHead)) 01914 { 01915 CurrentEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead); 01916 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, 01917 ListEntry); 01918 01919 /* if it is a callback and this queue is not the sender queue, dereference queue */ 01920 if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue)) 01921 { 01922 IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue); 01923 } 01924 01925 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n"); 01926 /* Only if the message has a sender was the message in the DispatchingList */ 01927 if ((CurrentSentMessage->SenderQueue) 01928 && (CurrentSentMessage->DispatchingListEntry.Flink != NULL)) 01929 { 01930 RemoveEntryList(&CurrentSentMessage->DispatchingListEntry); 01931 } 01932 01933 /* wake the sender's thread */ 01934 if (CurrentSentMessage->CompletionEvent != NULL) 01935 { 01936 KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE); 01937 } 01938 01939 if (CurrentSentMessage->HasPackedLParam == TRUE) 01940 { 01941 if (CurrentSentMessage->Msg.lParam) 01942 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam); 01943 } 01944 01945 /* if the message has a sender */ 01946 if (CurrentSentMessage->SenderQueue) 01947 { 01948 /* dereference our and the sender's message queue */ 01949 IntDereferenceMessageQueue(MessageQueue); 01950 IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue); 01951 } 01952 01953 /* free the message */ 01954 ExFreePool(CurrentSentMessage); 01955 } 01956 01957 /* notify senders of dispatching messages. This needs to be cleaned up if e.g. 01958 ExitThread() was called in a SendMessage() umode callback */ 01959 while (!IsListEmpty(&MessageQueue->LocalDispatchingMessagesHead)) 01960 { 01961 CurrentEntry = RemoveHeadList(&MessageQueue->LocalDispatchingMessagesHead); 01962 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, 01963 ListEntry); 01964 01965 /* if it is a callback and this queue is not the sender queue, dereference queue */ 01966 if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue)) 01967 { 01968 IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue); 01969 } 01970 01971 /* remove the message from the dispatching list */ 01972 if(CurrentSentMessage->DispatchingListEntry.Flink != NULL) 01973 { 01974 RemoveEntryList(&CurrentSentMessage->DispatchingListEntry); 01975 } 01976 01977 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n"); 01978 01979 /* wake the sender's thread */ 01980 if (CurrentSentMessage->CompletionEvent != NULL) 01981 { 01982 KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE); 01983 } 01984 01985 if (CurrentSentMessage->HasPackedLParam == TRUE) 01986 { 01987 if (CurrentSentMessage->Msg.lParam) 01988 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam); 01989 } 01990 01991 /* if the message has a sender */ 01992 if (CurrentSentMessage->SenderQueue) 01993 { 01994 /* dereference our and the sender's message queue */ 01995 IntDereferenceMessageQueue(MessageQueue); 01996 IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue); 01997 } 01998 01999 /* free the message */ 02000 ExFreePool(CurrentSentMessage); 02001 } 02002 02003 /* tell other threads not to bother returning any info to us */ 02004 while (! IsListEmpty(&MessageQueue->DispatchingMessagesHead)) 02005 { 02006 CurrentEntry = RemoveHeadList(&MessageQueue->DispatchingMessagesHead); 02007 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, 02008 DispatchingListEntry); 02009 CurrentSentMessage->CompletionEvent = NULL; 02010 CurrentSentMessage->Result = NULL; 02011 02012 /* do NOT dereference our message queue as it might get attempted to be 02013 locked later */ 02014 } 02015 02016 // Clear it all out. 02017 if(pti->pcti) 02018 { 02019 pti->pcti->fsWakeBits = 0; 02020 pti->pcti->fsChangeBits = 0; 02021 } 02022 02023 MessageQueue->nCntsQBits[QSRosKey] = 0; 02024 MessageQueue->nCntsQBits[QSRosMouseMove] = 0; 02025 MessageQueue->nCntsQBits[QSRosMouseButton] = 0; 02026 MessageQueue->nCntsQBits[QSRosPostMessage] = 0; 02027 MessageQueue->nCntsQBits[QSRosSendMessage] = 0; 02028 MessageQueue->nCntsQBits[QSRosHotKey] = 0; 02029 02030 if (MessageQueue->CursorObject) 02031 { 02032 PCURICON_OBJECT pCursor = MessageQueue->CursorObject; 02033 02034 /* Change to another cursor if we going to dereference current one 02035 Note: we can't use UserSetCursor because it uses current thread 02036 message queue instead of queue given for cleanup */ 02037 if (IntGetSysCursorInfo()->CurrentCursorObject == pCursor) 02038 { 02039 HDC hdcScreen; 02040 02041 /* Get the screen DC */ 02042 hdcScreen = IntGetScreenDC(); 02043 if (hdcScreen) 02044 GreMovePointer(hdcScreen, -1, -1); 02045 IntGetSysCursorInfo()->CurrentCursorObject = NULL; 02046 } 02047 02048 UserDereferenceObject(pCursor); 02049 } 02050 02051 } 02052 02053 PUSER_MESSAGE_QUEUE FASTCALL 02054 MsqCreateMessageQueue(struct _ETHREAD *Thread) 02055 { 02056 PUSER_MESSAGE_QUEUE MessageQueue; 02057 02058 MessageQueue = (PUSER_MESSAGE_QUEUE)ExAllocatePoolWithTag(NonPagedPool, 02059 sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO), 02060 USERTAG_Q); 02061 02062 if (!MessageQueue) 02063 { 02064 return NULL; 02065 } 02066 02067 RtlZeroMemory(MessageQueue, sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO)); 02068 /* hold at least one reference until it'll be destroyed */ 02069 IntReferenceMessageQueue(MessageQueue); 02070 /* initialize the queue */ 02071 if (!MsqInitializeMessageQueue(Thread, MessageQueue)) 02072 { 02073 IntDereferenceMessageQueue(MessageQueue); 02074 return NULL; 02075 } 02076 02077 return MessageQueue; 02078 } 02079 02080 VOID FASTCALL 02081 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue) 02082 { 02083 PDESKTOP desk; 02084 02085 MessageQueue->QF_flags |= QF_INDESTROY; 02086 02087 /* remove the message queue from any desktops */ 02088 if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0))) 02089 { 02090 (void)InterlockedExchangePointer((PVOID*)&desk->ActiveMessageQueue, 0); 02091 IntDereferenceMessageQueue(MessageQueue); 02092 } 02093 02094 /* clean it up */ 02095 MsqCleanupMessageQueue(MessageQueue); 02096 02097 if (MessageQueue->NewMessagesHandle != NULL) 02098 ZwClose(MessageQueue->NewMessagesHandle); 02099 MessageQueue->NewMessagesHandle = NULL; 02100 /* decrease the reference counter, if it hits zero, the queue will be freed */ 02101 IntDereferenceMessageQueue(MessageQueue); 02102 } 02103 02104 LPARAM FASTCALL 02105 MsqSetMessageExtraInfo(LPARAM lParam) 02106 { 02107 LPARAM Ret; 02108 PTHREADINFO pti; 02109 PUSER_MESSAGE_QUEUE MessageQueue; 02110 02111 pti = PsGetCurrentThreadWin32Thread(); 02112 MessageQueue = pti->MessageQueue; 02113 if(!MessageQueue) 02114 { 02115 return 0; 02116 } 02117 02118 Ret = MessageQueue->ExtraInfo; 02119 MessageQueue->ExtraInfo = lParam; 02120 02121 return Ret; 02122 } 02123 02124 LPARAM FASTCALL 02125 MsqGetMessageExtraInfo(VOID) 02126 { 02127 PTHREADINFO pti; 02128 PUSER_MESSAGE_QUEUE MessageQueue; 02129 02130 pti = PsGetCurrentThreadWin32Thread(); 02131 MessageQueue = pti->MessageQueue; 02132 if(!MessageQueue) 02133 { 02134 return 0; 02135 } 02136 02137 return MessageQueue->ExtraInfo; 02138 } 02139 02140 // ReplyMessage is called by the thread receiving the window message. 02141 BOOL FASTCALL 02142 co_MsqReplyMessage( LRESULT lResult ) 02143 { 02144 PUSER_SENT_MESSAGE Message; 02145 PTHREADINFO pti; 02146 02147 pti = PsGetCurrentThreadWin32Thread(); 02148 Message = pti->pusmCurrent; 02149 02150 if (!Message) return FALSE; 02151 02152 if (Message->QS_Flags & QS_SMRESULT) return FALSE; 02153 02154 // SendMessageXxx || Callback msg and not a notify msg 02155 if (Message->SenderQueue || Message->CompletionCallback) 02156 { 02157 Message->lResult = lResult; 02158 Message->QS_Flags |= QS_SMRESULT; 02159 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away.. 02160 } 02161 return TRUE; 02162 } 02163 02164 HWND FASTCALL 02165 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd) 02166 { 02167 HWND Prev; 02168 02169 switch(Type) 02170 { 02171 case MSQ_STATE_CAPTURE: 02172 Prev = MessageQueue->CaptureWindow; 02173 MessageQueue->CaptureWindow = hWnd; 02174 return Prev; 02175 case MSQ_STATE_ACTIVE: 02176 Prev = MessageQueue->spwndActive ? UserHMGetHandle(MessageQueue->spwndActive) : 0; 02177 MessageQueue->spwndActive = UserGetWindowObject(hWnd); 02178 return Prev; 02179 case MSQ_STATE_FOCUS: 02180 Prev = MessageQueue->spwndFocus ? UserHMGetHandle(MessageQueue->spwndFocus) : 0; 02181 MessageQueue->spwndFocus = UserGetWindowObject(hWnd); 02182 return Prev; 02183 case MSQ_STATE_MENUOWNER: 02184 Prev = MessageQueue->MenuOwner; 02185 MessageQueue->MenuOwner = hWnd; 02186 return Prev; 02187 case MSQ_STATE_MOVESIZE: 02188 Prev = MessageQueue->MoveSize; 02189 MessageQueue->MoveSize = hWnd; 02190 return Prev; 02191 case MSQ_STATE_CARET: 02192 ASSERT(MessageQueue->CaretInfo); 02193 Prev = MessageQueue->CaretInfo->hWnd; 02194 MessageQueue->CaretInfo->hWnd = hWnd; 02195 return Prev; 02196 } 02197 02198 return NULL; 02199 } 02200 02201 SHORT 02202 APIENTRY 02203 NtUserGetKeyState(INT key) 02204 { 02205 DWORD Ret; 02206 02207 UserEnterShared(); 02208 02209 Ret = UserGetKeyState(key); 02210 02211 UserLeave(); 02212 02213 return (SHORT)Ret; 02214 } 02215 02216 02217 DWORD 02218 APIENTRY 02219 NtUserGetKeyboardState(LPBYTE lpKeyState) 02220 { 02221 DWORD i, ret = TRUE; 02222 PTHREADINFO pti; 02223 PUSER_MESSAGE_QUEUE MessageQueue; 02224 02225 UserEnterShared(); 02226 02227 pti = PsGetCurrentThreadWin32Thread(); 02228 MessageQueue = pti->MessageQueue; 02229 02230 _SEH2_TRY 02231 { 02232 /* Probe and copy key state to an array */ 02233 ProbeForWrite(lpKeyState, 256 * sizeof(BYTE), 1); 02234 for (i = 0; i < 256; ++i) 02235 { 02236 lpKeyState[i] = 0; 02237 if (IS_KEY_DOWN(MessageQueue->afKeyState, i)) 02238 lpKeyState[i] |= KS_DOWN_BIT; 02239 if (IS_KEY_LOCKED(MessageQueue->afKeyState, i)) 02240 lpKeyState[i] |= KS_LOCK_BIT; 02241 } 02242 } 02243 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 02244 { 02245 SetLastNtError(_SEH2_GetExceptionCode()); 02246 ret = FALSE; 02247 } 02248 _SEH2_END; 02249 02250 UserLeave(); 02251 02252 return ret; 02253 } 02254 02255 BOOL 02256 APIENTRY 02257 NtUserSetKeyboardState(LPBYTE pKeyState) 02258 { 02259 UINT i; 02260 BOOL bRet = TRUE; 02261 PTHREADINFO pti; 02262 PUSER_MESSAGE_QUEUE MessageQueue; 02263 02264 UserEnterExclusive(); 02265 02266 pti = PsGetCurrentThreadWin32Thread(); 02267 MessageQueue = pti->MessageQueue; 02268 02269 _SEH2_TRY 02270 { 02271 ProbeForRead(pKeyState, 256 * sizeof(BYTE), 1); 02272 for (i = 0; i < 256; ++i) 02273 { 02274 SET_KEY_DOWN(MessageQueue->afKeyState, i, pKeyState[i] & KS_DOWN_BIT); 02275 SET_KEY_LOCKED(MessageQueue->afKeyState, i, pKeyState[i] & KS_LOCK_BIT); 02276 } 02277 } 02278 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 02279 { 02280 SetLastNtError(_SEH2_GetExceptionCode()); 02281 bRet = FALSE; 02282 } 02283 _SEH2_END; 02284 02285 UserLeave(); 02286 02287 return bRet; 02288 } 02289 02290 /* EOF */ Generated on Sun May 27 2012 04:38:34 for ReactOS by
1.7.6.1
|