1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: Message queues 5 * FILE: win32ss/user/ntuser/msgqueue.c 6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) 7 Alexandre Julliard 8 Maarten Lankhorst 9 */ 10 11 #include <win32k.h> 12 DBG_DEFAULT_CHANNEL(UserMsgQ); 13 14 /* GLOBALS *******************************************************************/ 15 16 static PPAGED_LOOKASIDE_LIST pgMessageLookasideList; 17 static PPAGED_LOOKASIDE_LIST pgSendMsgLookasideList; 18 INT PostMsgCount = 0; 19 INT SendMsgCount = 0; 20 PUSER_MESSAGE_QUEUE gpqCursor; 21 ULONG_PTR gdwMouseMoveExtraInfo = 0; 22 DWORD gdwMouseMoveTimeStamp = 0; 23 LIST_ENTRY usmList; 24 25 /* FUNCTIONS *****************************************************************/ 26 27 INIT_FUNCTION 28 NTSTATUS 29 NTAPI 30 MsqInitializeImpl(VOID) 31 { 32 // Setup Post Messages 33 pgMessageLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG); 34 if (!pgMessageLookasideList) 35 return STATUS_NO_MEMORY; 36 ExInitializePagedLookasideList(pgMessageLookasideList, 37 NULL, 38 NULL, 39 0, 40 sizeof(USER_MESSAGE), 41 TAG_USRMSG, 42 256); 43 // Setup Send Messages 44 pgSendMsgLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG); 45 if (!pgSendMsgLookasideList) 46 return STATUS_NO_MEMORY; 47 ExInitializePagedLookasideList(pgSendMsgLookasideList, 48 NULL, 49 NULL, 50 0, 51 sizeof(USER_SENT_MESSAGE), 52 TAG_USRMSG, 53 16); 54 55 InitializeListHead(&usmList); 56 57 return(STATUS_SUCCESS); 58 } 59 60 PWND FASTCALL 61 IntTopLevelWindowFromPoint(INT x, INT y) 62 { 63 PWND pWnd, pwndDesktop; 64 65 /* Get the desktop window */ 66 pwndDesktop = UserGetDesktopWindow(); 67 if (!pwndDesktop) 68 return NULL; 69 70 /* Loop all top level windows */ 71 for (pWnd = pwndDesktop->spwndChild; 72 pWnd != NULL; 73 pWnd = pWnd->spwndNext) 74 { 75 if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED) 76 { 77 TRACE("The Window is in DESTROY!\n"); 78 continue; 79 } 80 81 if ((pWnd->style & WS_VISIBLE) && 82 (pWnd->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) != (WS_EX_LAYERED|WS_EX_TRANSPARENT) && 83 IntPtInWindow(pWnd, x, y)) 84 return pWnd; 85 } 86 87 /* Window has not been found */ 88 return pwndDesktop; 89 } 90 91 PCURICON_OBJECT 92 FASTCALL 93 UserSetCursor( 94 PCURICON_OBJECT NewCursor, 95 BOOL ForceChange) 96 { 97 PCURICON_OBJECT OldCursor; 98 HDC hdcScreen; 99 PTHREADINFO pti; 100 PUSER_MESSAGE_QUEUE MessageQueue; 101 PWND pWnd; 102 103 pti = PsGetCurrentThreadWin32Thread(); 104 MessageQueue = pti->MessageQueue; 105 106 OldCursor = MessageQueue->CursorObject; 107 108 /* Check if cursors are different */ 109 if (OldCursor == NewCursor) 110 return OldCursor; 111 112 /* Update cursor for this message queue */ 113 MessageQueue->CursorObject = NewCursor; 114 115 /* If cursor is not visible we have nothing to do */ 116 if (MessageQueue->iCursorLevel < 0) 117 return OldCursor; 118 119 // Fixes the error message "Not the same cursor!". 120 if (gpqCursor == NULL) 121 { 122 gpqCursor = MessageQueue; 123 } 124 125 /* Update cursor if this message queue controls it */ 126 pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y); 127 if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue) 128 { 129 /* Get the screen DC */ 130 if (!(hdcScreen = IntGetScreenDC())) 131 { 132 return NULL; 133 } 134 135 if (NewCursor) 136 { 137 /* Call GDI to set the new screen cursor */ 138 PCURICON_OBJECT CursorFrame = NewCursor; 139 if(NewCursor->CURSORF_flags & CURSORF_ACON) 140 { 141 FIXME("Should animate the cursor, using only the first frame now.\n"); 142 CursorFrame = ((PACON)NewCursor)->aspcur[0]; 143 } 144 GreSetPointerShape(hdcScreen, 145 CursorFrame->hbmAlpha ? NULL : NewCursor->hbmMask, 146 CursorFrame->hbmAlpha ? NewCursor->hbmAlpha : NewCursor->hbmColor, 147 CursorFrame->xHotspot, 148 CursorFrame->yHotspot, 149 gpsi->ptCursor.x, 150 gpsi->ptCursor.y, 151 CursorFrame->hbmAlpha ? SPS_ALPHA : 0); 152 } 153 else /* Note: OldCursor != NewCursor so we have to hide cursor */ 154 { 155 /* Remove the cursor */ 156 GreMovePointer(hdcScreen, -1, -1); 157 TRACE("Removing pointer!\n"); 158 } 159 IntGetSysCursorInfo()->CurrentCursorObject = NewCursor; 160 } 161 162 /* Return the old cursor */ 163 return OldCursor; 164 } 165 166 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR 167 * User32 macro NtUserShowCursor */ 168 int UserShowCursor(BOOL bShow) 169 { 170 HDC hdcScreen; 171 PTHREADINFO pti; 172 PUSER_MESSAGE_QUEUE MessageQueue; 173 PWND pWnd; 174 175 if (!(hdcScreen = IntGetScreenDC())) 176 { 177 return -1; /* No mouse */ 178 } 179 180 pti = PsGetCurrentThreadWin32Thread(); 181 MessageQueue = pti->MessageQueue; 182 183 /* Update counter */ 184 MessageQueue->iCursorLevel += bShow ? 1 : -1; 185 pti->iCursorLevel += bShow ? 1 : -1; 186 187 /* Check for trivial cases */ 188 if ((bShow && MessageQueue->iCursorLevel != 0) || 189 (!bShow && MessageQueue->iCursorLevel != -1)) 190 { 191 /* Note: w don't update global info here because it is used only 192 internally to check if cursor is visible */ 193 return MessageQueue->iCursorLevel; 194 } 195 196 /* Check if cursor is above window owned by this MessageQueue */ 197 pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y); 198 if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue) 199 { 200 if (bShow) 201 { 202 /* Show the pointer */ 203 GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y); 204 TRACE("Showing pointer!\n"); 205 } 206 else 207 { 208 /* Remove the pointer */ 209 GreMovePointer(hdcScreen, -1, -1); 210 TRACE("Removing pointer!\n"); 211 } 212 213 /* Update global info */ 214 IntGetSysCursorInfo()->ShowingCursor = MessageQueue->iCursorLevel; 215 } 216 217 return MessageQueue->iCursorLevel; 218 } 219 220 DWORD FASTCALL 221 UserGetKeyState(DWORD dwKey) 222 { 223 DWORD dwRet = 0; 224 PTHREADINFO pti; 225 PUSER_MESSAGE_QUEUE MessageQueue; 226 227 pti = PsGetCurrentThreadWin32Thread(); 228 MessageQueue = pti->MessageQueue; 229 230 if (dwKey < 0x100) 231 { 232 if (IS_KEY_DOWN(MessageQueue->afKeyState, dwKey)) 233 dwRet |= 0xFF80; // If down, windows returns 0xFF80. 234 if (IS_KEY_LOCKED(MessageQueue->afKeyState, dwKey)) 235 dwRet |= 0x1; 236 } 237 else 238 { 239 EngSetLastError(ERROR_INVALID_PARAMETER); 240 } 241 return dwRet; 242 } 243 244 /* change the input key state for a given key */ 245 static VOID 246 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue, WORD wVk, BOOL bIsDown) 247 { 248 TRACE("UpdateKeyState wVk: %u, bIsDown: %d\n", wVk, bIsDown); 249 250 if (bIsDown) 251 { 252 /* If it's first key down event, xor lock bit */ 253 if (!IS_KEY_DOWN(MessageQueue->afKeyState, wVk)) 254 SET_KEY_LOCKED(MessageQueue->afKeyState, wVk, !IS_KEY_LOCKED(MessageQueue->afKeyState, wVk)); 255 256 SET_KEY_DOWN(MessageQueue->afKeyState, wVk, TRUE); 257 MessageQueue->afKeyRecentDown[wVk / 8] |= (1 << (wVk % 8)); 258 } 259 else 260 SET_KEY_DOWN(MessageQueue->afKeyState, wVk, FALSE); 261 } 262 263 /* update the input key state for a keyboard message */ 264 static VOID 265 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue, MSG* msg) 266 { 267 UCHAR key; 268 BOOL down = FALSE; 269 270 TRACE("UpdateKeyStateFromMsg message:%u\n", msg->message); 271 272 switch (msg->message) 273 { 274 case WM_LBUTTONDOWN: 275 down = TRUE; 276 /* fall through */ 277 case WM_LBUTTONUP: 278 UpdateKeyState(MessageQueue, VK_LBUTTON, down); 279 break; 280 case WM_MBUTTONDOWN: 281 down = TRUE; 282 /* fall through */ 283 case WM_MBUTTONUP: 284 UpdateKeyState(MessageQueue, VK_MBUTTON, down); 285 break; 286 case WM_RBUTTONDOWN: 287 down = TRUE; 288 /* fall through */ 289 case WM_RBUTTONUP: 290 UpdateKeyState(MessageQueue, VK_RBUTTON, down); 291 break; 292 case WM_XBUTTONDOWN: 293 down = TRUE; 294 /* fall through */ 295 case WM_XBUTTONUP: 296 if (msg->wParam == XBUTTON1) 297 UpdateKeyState(MessageQueue, VK_XBUTTON1, down); 298 else if (msg->wParam == XBUTTON2) 299 UpdateKeyState(MessageQueue, VK_XBUTTON2, down); 300 break; 301 case WM_KEYDOWN: 302 case WM_SYSKEYDOWN: 303 down = TRUE; 304 /* fall through */ 305 case WM_KEYUP: 306 case WM_SYSKEYUP: 307 key = (UCHAR)msg->wParam; 308 UpdateKeyState(MessageQueue, key, down); 309 switch(key) 310 { 311 case VK_LCONTROL: 312 case VK_RCONTROL: 313 down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LCONTROL) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RCONTROL); 314 UpdateKeyState(MessageQueue, VK_CONTROL, down); 315 break; 316 case VK_LMENU: 317 case VK_RMENU: 318 down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LMENU) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RMENU); 319 UpdateKeyState(MessageQueue, VK_MENU, down); 320 break; 321 case VK_LSHIFT: 322 case VK_RSHIFT: 323 down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LSHIFT) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RSHIFT); 324 UpdateKeyState(MessageQueue, VK_SHIFT, down); 325 break; 326 } 327 break; 328 } 329 } 330 331 /* 332 Get down key states from the queue of prior processed input message key states. 333 334 This fixes the left button dragging on the desktop and release sticking outline issue. 335 USB Tablet pointer seems to stick the most and leaves the box outline displayed. 336 */ 337 WPARAM FASTCALL 338 MsqGetDownKeyState(PUSER_MESSAGE_QUEUE MessageQueue) 339 { 340 WPARAM ret = 0; 341 342 if (gspv.bMouseBtnSwap) 343 { 344 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_RBUTTON)) ret |= MK_LBUTTON; 345 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_LBUTTON)) ret |= MK_RBUTTON; 346 } 347 else 348 { 349 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_LBUTTON)) ret |= MK_LBUTTON; 350 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_RBUTTON)) ret |= MK_RBUTTON; 351 } 352 353 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_MBUTTON)) ret |= MK_MBUTTON; 354 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_SHIFT)) ret |= MK_SHIFT; 355 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_CONTROL)) ret |= MK_CONTROL; 356 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_XBUTTON1)) ret |= MK_XBUTTON1; 357 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_XBUTTON2)) ret |= MK_XBUTTON2; 358 return ret; 359 } 360 361 HANDLE FASTCALL 362 IntMsqSetWakeMask(DWORD WakeMask) 363 { 364 PTHREADINFO Win32Thread; 365 HANDLE MessageEventHandle; 366 DWORD dwFlags = HIWORD(WakeMask); 367 368 Win32Thread = PsGetCurrentThreadWin32Thread(); 369 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL) 370 return 0; 371 372 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient 373 MessageEventHandle = Win32Thread->hEventQueueClient; 374 375 if (Win32Thread->pcti) 376 { 377 if ( (Win32Thread->pcti->fsChangeBits & LOWORD(WakeMask)) || 378 ( (dwFlags & MWMO_INPUTAVAILABLE) && (Win32Thread->pcti->fsWakeBits & LOWORD(WakeMask)) ) ) 379 { 380 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread->pcti->fsChangeBits, Win32Thread->pcti->fsWakeBits, WakeMask); 381 KeSetEvent(Win32Thread->pEventQueueServer, IO_NO_INCREMENT, FALSE); // Wake it up! 382 return MessageEventHandle; 383 } 384 } 385 386 IdlePing(); 387 388 return MessageEventHandle; 389 } 390 391 BOOL FASTCALL 392 IntMsqClearWakeMask(VOID) 393 { 394 PTHREADINFO Win32Thread; 395 396 Win32Thread = PsGetCurrentThreadWin32Thread(); 397 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL) 398 return FALSE; 399 // Very hacky, but that is what they do. 400 Win32Thread->pcti->fsWakeBits = 0; 401 402 IdlePong(); 403 404 return TRUE; 405 } 406 407 /* 408 Due to the uncertainty of knowing what was set in our multilevel message queue, 409 and even if the bits are all cleared. The same as cTimers/cPaintsReady. 410 I think this is the best solution... (jt) */ 411 VOID FASTCALL 412 MsqWakeQueue(PTHREADINFO pti, DWORD MessageBits, BOOL KeyEvent) 413 { 414 PUSER_MESSAGE_QUEUE Queue; 415 416 Queue = pti->MessageQueue; 417 418 if (Queue->QF_flags & QF_INDESTROY) 419 { 420 ERR("This Message Queue is in Destroy!\n"); 421 } 422 pti->pcti->fsWakeBits |= MessageBits; 423 pti->pcti->fsChangeBits |= MessageBits; 424 425 // Start bit accounting to help clear the main set of bits. 426 if (MessageBits & QS_KEY) 427 { 428 pti->nCntsQBits[QSRosKey]++; 429 } 430 if (MessageBits & QS_MOUSE) 431 { 432 if (MessageBits & QS_MOUSEMOVE) pti->nCntsQBits[QSRosMouseMove]++; 433 if (MessageBits & QS_MOUSEBUTTON) pti->nCntsQBits[QSRosMouseButton]++; 434 } 435 if (MessageBits & QS_POSTMESSAGE) pti->nCntsQBits[QSRosPostMessage]++; 436 if (MessageBits & QS_SENDMESSAGE) pti->nCntsQBits[QSRosSendMessage]++; 437 if (MessageBits & QS_HOTKEY) pti->nCntsQBits[QSRosHotKey]++; 438 if (MessageBits & QS_EVENT) pti->nCntsQBits[QSRosEvent]++; 439 440 if (KeyEvent) 441 KeSetEvent(pti->pEventQueueServer, IO_NO_INCREMENT, FALSE); 442 } 443 444 VOID FASTCALL 445 ClearMsgBitsMask(PTHREADINFO pti, UINT MessageBits) 446 { 447 UINT ClrMask = 0; 448 449 if (MessageBits & QS_KEY) 450 { 451 if (--pti->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY; 452 } 453 if (MessageBits & QS_MOUSEMOVE) 454 { // Account for tracking mouse moves.. 455 if (pti->nCntsQBits[QSRosMouseMove]) 456 { 457 pti->nCntsQBits[QSRosMouseMove] = 0; // Throttle down count. Up to > 3:1 entries are ignored. 458 ClrMask |= QS_MOUSEMOVE; 459 } 460 } 461 if (MessageBits & QS_MOUSEBUTTON) 462 { 463 if (--pti->nCntsQBits[QSRosMouseButton] == 0) ClrMask |= QS_MOUSEBUTTON; 464 } 465 if (MessageBits & QS_POSTMESSAGE) 466 { 467 if (--pti->nCntsQBits[QSRosPostMessage] == 0) ClrMask |= QS_POSTMESSAGE; 468 } 469 if (MessageBits & QS_TIMER) // ReactOS hard coded. 470 { // Handle timer bits here. 471 if ( pti->cTimersReady ) 472 { 473 if (--pti->cTimersReady == 0) ClrMask |= QS_TIMER; 474 } 475 } 476 if (MessageBits & QS_PAINT) // ReactOS hard coded. 477 { // Handle paint bits here. 478 if ( pti->cPaintsReady ) 479 { 480 if (--pti->cPaintsReady == 0) ClrMask |= QS_PAINT; 481 } 482 } 483 if (MessageBits & QS_SENDMESSAGE) 484 { 485 if (--pti->nCntsQBits[QSRosSendMessage] == 0) ClrMask |= QS_SENDMESSAGE; 486 } 487 if (MessageBits & QS_HOTKEY) 488 { 489 if (--pti->nCntsQBits[QSRosHotKey] == 0) ClrMask |= QS_HOTKEY; 490 } 491 if (MessageBits & QS_EVENT) 492 { 493 if (--pti->nCntsQBits[QSRosEvent] == 0) ClrMask |= QS_EVENT; 494 } 495 496 pti->pcti->fsWakeBits &= ~ClrMask; 497 pti->pcti->fsChangeBits &= ~ClrMask; 498 } 499 500 VOID FASTCALL 501 MsqIncPaintCountQueue(PTHREADINFO pti) 502 { 503 pti->cPaintsReady++; 504 MsqWakeQueue(pti, QS_PAINT, TRUE); 505 } 506 507 VOID FASTCALL 508 MsqDecPaintCountQueue(PTHREADINFO pti) 509 { 510 ClearMsgBitsMask(pti, QS_PAINT); 511 } 512 513 /* 514 Post the move or update the message still pending to be processed. 515 Do not overload the queue with mouse move messages. 516 */ 517 VOID FASTCALL 518 MsqPostMouseMove(PTHREADINFO pti, MSG* Msg, LONG_PTR ExtraInfo) 519 { 520 PUSER_MESSAGE Message; 521 PLIST_ENTRY ListHead; 522 PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue; 523 524 ListHead = &MessageQueue->HardwareMessagesListHead; 525 526 // Do nothing if empty. 527 if (!IsListEmpty(ListHead->Flink)) 528 { 529 // Look at the end of the list, 530 Message = CONTAINING_RECORD(ListHead->Blink, USER_MESSAGE, ListEntry); 531 532 // If the mouse move message is existing on the list, 533 if (Message->Msg.message == WM_MOUSEMOVE) 534 { 535 // Overwrite the message with updated data! 536 Message->Msg = *Msg; 537 538 MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE); 539 return; 540 } 541 } 542 543 MsqPostMessage(pti, Msg, TRUE, QS_MOUSEMOVE, 0, ExtraInfo); 544 } 545 546 /* 547 Bring together the mouse move message. 548 Named "Coalesce" from Amine email ;^) (jt). 549 */ 550 VOID FASTCALL 551 IntCoalesceMouseMove(PTHREADINFO pti) 552 { 553 MSG Msg; 554 555 // Force time stamp to update, keeping message time in sync. 556 if (gdwMouseMoveTimeStamp == 0) 557 { 558 gdwMouseMoveTimeStamp = EngGetTickCount32(); 559 } 560 561 // Build mouse move message. 562 Msg.hwnd = NULL; 563 Msg.message = WM_MOUSEMOVE; 564 Msg.wParam = 0; 565 Msg.lParam = MAKELONG(gpsi->ptCursor.x, gpsi->ptCursor.y); 566 Msg.time = gdwMouseMoveTimeStamp; 567 Msg.pt = gpsi->ptCursor; 568 569 // Post the move. 570 MsqPostMouseMove(pti, &Msg, gdwMouseMoveExtraInfo); 571 572 // Zero the time stamp. 573 gdwMouseMoveTimeStamp = 0; 574 575 // Clear flag since the move was posted. 576 pti->MessageQueue->QF_flags &= ~QF_MOUSEMOVED; 577 } 578 579 VOID FASTCALL 580 co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook) 581 { 582 MSLLHOOKSTRUCT MouseHookData; 583 // PDESKTOP pDesk; 584 PWND pwnd, pwndDesktop; 585 HDC hdcScreen; 586 PTHREADINFO pti; 587 PUSER_MESSAGE_QUEUE MessageQueue; 588 PSYSTEM_CURSORINFO CurInfo; 589 590 Msg->time = EngGetTickCount32(); 591 592 MouseHookData.pt.x = LOWORD(Msg->lParam); 593 MouseHookData.pt.y = HIWORD(Msg->lParam); 594 switch (Msg->message) 595 { 596 case WM_MOUSEWHEEL: 597 MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg->wParam)); 598 break; 599 case WM_XBUTTONDOWN: 600 case WM_XBUTTONUP: 601 case WM_XBUTTONDBLCLK: 602 case WM_NCXBUTTONDOWN: 603 case WM_NCXBUTTONUP: 604 case WM_NCXBUTTONDBLCLK: 605 MouseHookData.mouseData = MAKELONG(0, HIWORD(Msg->wParam)); 606 break; 607 default: 608 MouseHookData.mouseData = 0; 609 break; 610 } 611 612 MouseHookData.flags = flags; // LLMHF_INJECTED 613 MouseHookData.time = Msg->time; 614 MouseHookData.dwExtraInfo = dwExtraInfo; 615 616 /* If the hook procedure returned non zero, dont send the message */ 617 if (Hook) 618 { 619 if (co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION, Msg->message, (LPARAM) &MouseHookData)) 620 return; 621 } 622 623 /* Get the desktop window */ 624 pwndDesktop = UserGetDesktopWindow(); 625 if (!pwndDesktop) return; 626 // pDesk = pwndDesktop->head.rpdesk; 627 628 /* Check if the mouse is captured */ 629 Msg->hwnd = IntGetCaptureWindow(); 630 if (Msg->hwnd != NULL) 631 { 632 pwnd = UserGetWindowObject(Msg->hwnd); 633 } 634 else 635 { 636 pwnd = IntTopLevelWindowFromPoint(Msg->pt.x, Msg->pt.y); 637 if (pwnd) Msg->hwnd = pwnd->head.h; 638 } 639 640 hdcScreen = IntGetScreenDC(); 641 CurInfo = IntGetSysCursorInfo(); 642 643 /* Check if we found a window */ 644 if (Msg->hwnd != NULL && pwnd != NULL) 645 { 646 pti = pwnd->head.pti; 647 MessageQueue = pti->MessageQueue; 648 649 if (MessageQueue->QF_flags & QF_INDESTROY) 650 { 651 ERR("Mouse is over a Window with a Dead Message Queue!\n"); 652 return; 653 } 654 655 // Check to see if this is attached. 656 if ( pti != MessageQueue->ptiMouse && 657 MessageQueue->cThreads > 1 ) 658 { 659 // Set the send pti to the message queue mouse pti. 660 pti = MessageQueue->ptiMouse; 661 } 662 663 if (Msg->message == WM_MOUSEMOVE) 664 { 665 /* Check if cursor should be visible */ 666 if(hdcScreen && 667 MessageQueue->CursorObject && 668 MessageQueue->iCursorLevel >= 0) 669 { 670 /* Check if shape has changed */ 671 if(CurInfo->CurrentCursorObject != MessageQueue->CursorObject) 672 { 673 /* Call GDI to set the new screen cursor */ 674 GreSetPointerShape(hdcScreen, 675 MessageQueue->CursorObject->hbmAlpha ? 676 NULL : MessageQueue->CursorObject->hbmMask, 677 MessageQueue->CursorObject->hbmAlpha ? 678 MessageQueue->CursorObject->hbmAlpha : MessageQueue->CursorObject->hbmColor, 679 MessageQueue->CursorObject->xHotspot, 680 MessageQueue->CursorObject->yHotspot, 681 gpsi->ptCursor.x, 682 gpsi->ptCursor.y, 683 MessageQueue->CursorObject->hbmAlpha ? SPS_ALPHA : 0); 684 685 } else 686 GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y); 687 } 688 /* Check if we have to hide cursor */ 689 else if (CurInfo->ShowingCursor >= 0) 690 GreMovePointer(hdcScreen, -1, -1); 691 692 /* Update global cursor info */ 693 CurInfo->ShowingCursor = MessageQueue->iCursorLevel; 694 CurInfo->CurrentCursorObject = MessageQueue->CursorObject; 695 gpqCursor = MessageQueue; 696 697 /* Mouse move is a special case */ 698 MessageQueue->QF_flags |= QF_MOUSEMOVED; 699 gdwMouseMoveExtraInfo = dwExtraInfo; 700 gdwMouseMoveTimeStamp = Msg->time; 701 MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE); 702 } 703 else 704 { 705 if (!IntGetCaptureWindow()) 706 { 707 // ERR("ptiLastInput is set\n"); 708 // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground. 709 // Find all the Move Mouse calls and fix mouse set active focus issues...... 710 } 711 712 // Post mouse move before posting mouse buttons, keep it in sync. 713 if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED) 714 { 715 IntCoalesceMouseMove(pti); 716 } 717 718 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd)); 719 MsqPostMessage(pti, Msg, TRUE, QS_MOUSEBUTTON, 0, dwExtraInfo); 720 } 721 } 722 else if (hdcScreen) 723 { 724 /* always show cursor on background; FIXME: set default pointer */ 725 GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y); 726 CurInfo->ShowingCursor = 0; 727 } 728 } 729 730 PUSER_MESSAGE FASTCALL 731 MsqCreateMessage(LPMSG Msg) 732 { 733 PUSER_MESSAGE Message; 734 735 Message = ExAllocateFromPagedLookasideList(pgMessageLookasideList); 736 if (!Message) 737 { 738 return NULL; 739 } 740 741 RtlZeroMemory(Message, sizeof(*Message)); 742 RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG)); 743 PostMsgCount++; 744 return Message; 745 } 746 747 VOID FASTCALL 748 MsqDestroyMessage(PUSER_MESSAGE Message) 749 { 750 TRACE("Post Destroy %d\n",PostMsgCount); 751 if (Message->pti == NULL) 752 { 753 ERR("Double Free Message\n"); 754 return; 755 } 756 RemoveEntryList(&Message->ListEntry); 757 Message->pti = NULL; 758 ExFreeToPagedLookasideList(pgMessageLookasideList, Message); 759 PostMsgCount--; 760 } 761 762 PUSER_SENT_MESSAGE FASTCALL 763 AllocateUserMessage(BOOL KEvent) 764 { 765 PUSER_SENT_MESSAGE Message; 766 767 if(!(Message = ExAllocateFromPagedLookasideList(pgSendMsgLookasideList))) 768 { 769 ERR("AllocateUserMessage(): Not enough memory to allocate a message"); 770 return NULL; 771 } 772 RtlZeroMemory(Message, sizeof(USER_SENT_MESSAGE)); 773 774 if (KEvent) 775 { 776 Message->pkCompletionEvent = &Message->CompletionEvent; 777 778 KeInitializeEvent(Message->pkCompletionEvent, NotificationEvent, FALSE); 779 } 780 SendMsgCount++; 781 TRACE("AUM pti %p msg %p\n",PsGetCurrentThreadWin32Thread(),Message); 782 return Message; 783 } 784 785 VOID FASTCALL 786 FreeUserMessage(PUSER_SENT_MESSAGE Message) 787 { 788 Message->pkCompletionEvent = NULL; 789 790 /* Remove it from the list */ 791 RemoveEntryList(&Message->ListEntry); 792 793 ExFreeToPagedLookasideList(pgSendMsgLookasideList, Message); 794 SendMsgCount--; 795 } 796 797 VOID APIENTRY 798 MsqRemoveWindowMessagesFromQueue(PWND Window) 799 { 800 PTHREADINFO pti; 801 PUSER_SENT_MESSAGE SentMessage; 802 PUSER_MESSAGE PostedMessage; 803 PLIST_ENTRY CurrentEntry, ListHead; 804 805 ASSERT(Window); 806 807 pti = Window->head.pti; 808 809 /* remove the posted messages for this window */ 810 CurrentEntry = pti->PostedMessagesListHead.Flink; 811 ListHead = &pti->PostedMessagesListHead; 812 while (CurrentEntry != ListHead) 813 { 814 PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry); 815 816 if (PostedMessage->Msg.hwnd == Window->head.h) 817 { 818 if (PostedMessage->Msg.message == WM_QUIT && pti->QuitPosted == 0) 819 { 820 pti->QuitPosted = 1; 821 pti->exitCode = PostedMessage->Msg.wParam; 822 } 823 ClearMsgBitsMask(pti, PostedMessage->QS_Flags); 824 MsqDestroyMessage(PostedMessage); 825 CurrentEntry = pti->PostedMessagesListHead.Flink; 826 } 827 else 828 { 829 CurrentEntry = CurrentEntry->Flink; 830 } 831 } 832 833 /* remove the sent messages for this window */ 834 CurrentEntry = pti->SentMessagesListHead.Flink; 835 ListHead = &pti->SentMessagesListHead; 836 while (CurrentEntry != ListHead) 837 { 838 SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry); 839 840 if(SentMessage->Msg.hwnd == Window->head.h) 841 { 842 ERR("Remove Window Messages %p From Sent Queue\n",SentMessage); 843 #if 0 // Should mark these as invalid and allow the rest clean up, so far no harm by just commenting out. See CORE-9210. 844 ClearMsgBitsMask(pti, SentMessage->QS_Flags); 845 846 /* wake the sender's thread */ 847 if (SentMessage->pkCompletionEvent != NULL) 848 { 849 KeSetEvent(SentMessage->pkCompletionEvent, IO_NO_INCREMENT, FALSE); 850 } 851 852 if (SentMessage->HasPackedLParam) 853 { 854 if (SentMessage->Msg.lParam) 855 ExFreePool((PVOID)SentMessage->Msg.lParam); 856 } 857 858 /* free the message */ 859 FreeUserMessage(SentMessage); 860 861 CurrentEntry = pti->SentMessagesListHead.Flink; 862 #endif 863 CurrentEntry = CurrentEntry->Flink; 864 } 865 else 866 { 867 CurrentEntry = CurrentEntry->Flink; 868 } 869 } 870 } 871 872 BOOLEAN FASTCALL 873 co_MsqDispatchOneSentMessage( 874 _In_ PTHREADINFO pti) 875 { 876 PUSER_SENT_MESSAGE SaveMsg, Message; 877 PLIST_ENTRY Entry; 878 BOOL Ret; 879 LRESULT Result = 0; 880 881 ASSERT(pti == PsGetCurrentThreadWin32Thread()); 882 883 if (IsListEmpty(&pti->SentMessagesListHead)) 884 { 885 return(FALSE); 886 } 887 888 /* remove it from the list of pending messages */ 889 Entry = RemoveHeadList(&pti->SentMessagesListHead); 890 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry); 891 892 // Signal this message is being processed. 893 Message->flags |= SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE; 894 895 SaveMsg = pti->pusmCurrent; 896 pti->pusmCurrent = Message; 897 898 // Processing a message sent to it from another thread. 899 if ( ( Message->ptiSender && pti != Message->ptiSender) || 900 ( Message->ptiCallBackSender && pti != Message->ptiCallBackSender )) 901 { // most likely, but, to be sure. 902 pti->pcti->CTI_flags |= CTI_INSENDMESSAGE; // Let the user know... 903 } 904 905 /* Now insert it to the global list of messages that can be removed Justin Case there's Trouble */ 906 InsertTailList(&usmList, &Message->ListEntry); 907 908 ClearMsgBitsMask(pti, Message->QS_Flags); 909 910 if (Message->HookMessage == MSQ_ISHOOK) 911 { // Direct Hook Call processor 912 Result = co_CallHook( Message->Msg.message, // HookId 913 (INT)(INT_PTR)Message->Msg.hwnd, // Code 914 Message->Msg.wParam, 915 Message->Msg.lParam); 916 } 917 else if(Message->HookMessage == MSQ_INJECTMODULE) 918 { 919 Result = IntLoadHookModule(Message->Msg.message, 920 (HHOOK)Message->Msg.lParam, 921 Message->Msg.wParam); 922 } 923 else if ((Message->CompletionCallback) && 924 (Message->ptiCallBackSender == pti)) 925 { /* Call the callback routine */ 926 if (Message->QS_Flags & QS_SMRESULT) 927 { 928 co_IntCallSentMessageCallback(Message->CompletionCallback, 929 Message->Msg.hwnd, 930 Message->Msg.message, 931 Message->CompletionCallbackContext, 932 Message->lResult); 933 /* Set callback to NULL to prevent reentry */ 934 Message->CompletionCallback = NULL; 935 } 936 else 937 { 938 /* The message has not been processed yet, reinsert it. */ 939 RemoveEntryList(&Message->ListEntry); 940 InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry); 941 // List is occupied need to set the bit. 942 MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE); 943 ERR("Callback Message not processed yet. Requeuing the message\n"); //// <---- Need to see if this happens. 944 Ret = FALSE; 945 goto Exit; 946 } 947 } 948 else 949 { /* Call the window procedure. */ 950 Result = co_IntSendMessage( Message->Msg.hwnd, 951 Message->Msg.message, 952 Message->Msg.wParam, 953 Message->Msg.lParam); 954 } 955 956 /* If the message is a callback, insert it in the callback senders MessageQueue */ 957 if (Message->CompletionCallback) 958 { 959 if (Message->ptiCallBackSender) 960 { 961 Message->lResult = Result; 962 Message->QS_Flags |= QS_SMRESULT; 963 964 /* insert it in the callers message queue */ 965 RemoveEntryList(&Message->ListEntry); 966 InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry); 967 MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE); 968 } 969 Ret = TRUE; 970 goto Exit; 971 } 972 973 // Retrieve the result from callback. 974 if (Message->QS_Flags & QS_SMRESULT) 975 { 976 Result = Message->lResult; 977 } 978 979 /* Let the sender know the result. */ 980 Message->lResult = Result; 981 982 if (Message->HasPackedLParam) 983 { 984 if (Message->Msg.lParam) 985 ExFreePool((PVOID)Message->Msg.lParam); 986 } 987 988 // Clear busy signal. 989 Message->flags &= ~SMF_RECEIVERBUSY; 990 991 /* Notify the sender. */ 992 if (Message->pkCompletionEvent != NULL) 993 { 994 KeSetEvent(Message->pkCompletionEvent, IO_NO_INCREMENT, FALSE); 995 } 996 997 /* free the message */ 998 if (Message->flags & SMF_RECEIVERFREE) 999 { 1000 TRACE("Receiver Freeing Message %p\n",Message); 1001 FreeUserMessage(Message); 1002 } 1003 1004 Ret = TRUE; 1005 Exit: 1006 /* do not hangup on the user if this is reentering */ 1007 if (!SaveMsg) pti->pcti->CTI_flags &= ~CTI_INSENDMESSAGE; 1008 pti->pusmCurrent = SaveMsg; 1009 1010 return Ret; 1011 } 1012 1013 BOOL FASTCALL 1014 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver, 1015 HWND hwnd, 1016 UINT Msg, 1017 WPARAM wParam, 1018 LPARAM lParam, 1019 SENDASYNCPROC CompletionCallback, 1020 ULONG_PTR CompletionCallbackContext, 1021 BOOL HasPackedLParam, 1022 INT HookMessage) 1023 { 1024 1025 PTHREADINFO ptiSender; 1026 PUSER_SENT_MESSAGE Message; 1027 1028 if(!(Message = AllocateUserMessage(FALSE))) 1029 { 1030 ERR("MsqSendMessageAsync(): Not enough memory to allocate a message"); 1031 return FALSE; 1032 } 1033 1034 ptiSender = PsGetCurrentThreadWin32Thread(); 1035 1036 Message->Msg.hwnd = hwnd; 1037 Message->Msg.message = Msg; 1038 Message->Msg.wParam = wParam; 1039 Message->Msg.lParam = lParam; 1040 Message->pkCompletionEvent = NULL; // No event needed. 1041 Message->ptiReceiver = ptiReceiver; 1042 Message->ptiCallBackSender = ptiSender; 1043 Message->CompletionCallback = CompletionCallback; 1044 Message->CompletionCallbackContext = CompletionCallbackContext; 1045 Message->HookMessage = HookMessage; 1046 Message->HasPackedLParam = HasPackedLParam; 1047 Message->QS_Flags = QS_SENDMESSAGE; 1048 Message->flags = SMF_RECEIVERFREE; 1049 1050 InsertTailList(&ptiReceiver->SentMessagesListHead, &Message->ListEntry); 1051 MsqWakeQueue(ptiReceiver, QS_SENDMESSAGE, TRUE); 1052 1053 return TRUE; 1054 } 1055 1056 NTSTATUS FASTCALL 1057 co_MsqSendMessage(PTHREADINFO ptirec, 1058 HWND Wnd, 1059 UINT Msg, 1060 WPARAM wParam, 1061 LPARAM lParam, 1062 UINT uTimeout, 1063 BOOL Block, 1064 INT HookMessage, 1065 ULONG_PTR *uResult) 1066 { 1067 PTHREADINFO pti; 1068 PUSER_SENT_MESSAGE SaveMsg, Message; 1069 NTSTATUS WaitStatus; 1070 LARGE_INTEGER Timeout; 1071 PLIST_ENTRY Entry; 1072 PWND pWnd; 1073 BOOLEAN SwapStateEnabled; 1074 LRESULT Result = 0; //// Result could be trashed. //// 1075 1076 pti = PsGetCurrentThreadWin32Thread(); 1077 ASSERT(pti != ptirec); 1078 ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!! 1079 1080 /* Don't send from or to a dying thread */ 1081 if (pti->TIF_flags & TIF_INCLEANUP || ptirec->TIF_flags & TIF_INCLEANUP) 1082 { 1083 // Unless we are dying and need to tell our parents. 1084 if (pti->TIF_flags & TIF_INCLEANUP && !(ptirec->TIF_flags & TIF_INCLEANUP)) 1085 { 1086 // Parent notify is the big one. Fire and forget! 1087 TRACE("Send message from dying thread %u\n", Msg); 1088 co_MsqSendMessageAsync(ptirec, Wnd, Msg, wParam, lParam, NULL, 0, FALSE, HookMessage); 1089 } 1090 if (uResult) *uResult = -1; 1091 TRACE("MsqSM: Msg %u Current pti %lu or Rec pti %lu\n", Msg, pti->TIF_flags & TIF_INCLEANUP, ptirec->TIF_flags & TIF_INCLEANUP); 1092 return STATUS_UNSUCCESSFUL; 1093 } 1094 1095 if (IsThreadSuspended(ptirec)) 1096 { 1097 ERR("Sending to Suspended Thread Msg %lx\n",Msg); 1098 if (uResult) *uResult = -1; 1099 return STATUS_UNSUCCESSFUL; 1100 } 1101 1102 // Should we do the same for No Wait? 1103 if ( HookMessage == MSQ_NORMAL ) 1104 { 1105 pWnd = ValidateHwndNoErr(Wnd); 1106 1107 // These can not cross International Border lines! 1108 if ( pti->ppi != ptirec->ppi && pWnd ) 1109 { 1110 switch(Msg) 1111 { 1112 // Handle the special case when working with password transfers across bordering processes. 1113 case EM_GETLINE: 1114 case EM_SETPASSWORDCHAR: 1115 case WM_GETTEXT: 1116 // Look for edit controls setup for passwords. 1117 if ( gpsi->atomSysClass[ICLS_EDIT] == pWnd->pcls->atomClassName && // Use atomNVClassName. 1118 pWnd->style & ES_PASSWORD ) 1119 { 1120 if (uResult) *uResult = -1; 1121 ERR("Running across the border without a passport!\n"); 1122 EngSetLastError(ERROR_ACCESS_DENIED); 1123 return STATUS_UNSUCCESSFUL; 1124 } 1125 break; 1126 case WM_NOTIFY: 1127 if (uResult) *uResult = -1; 1128 ERR("Running across the border without a passport!\n"); 1129 return STATUS_UNSUCCESSFUL; 1130 } 1131 } 1132 1133 // These can not cross State lines! 1134 if ( Msg == WM_CREATE || Msg == WM_NCCREATE ) 1135 { 1136 if (uResult) *uResult = -1; 1137 ERR("Can not tell the other State we have Create!\n"); 1138 return STATUS_UNSUCCESSFUL; 1139 } 1140 } 1141 1142 if(!(Message = AllocateUserMessage(TRUE))) 1143 { 1144 ERR("MsqSendMessage(): Not enough memory to allocate a message\n"); 1145 if (uResult) *uResult = -1; 1146 return STATUS_INSUFFICIENT_RESOURCES; 1147 } 1148 1149 Timeout.QuadPart = Int32x32To64(-10000,uTimeout); // Pass SMTO test with a TO of 0x80000000. 1150 TRACE("Timeout val %lld\n",Timeout.QuadPart); 1151 1152 Message->Msg.hwnd = Wnd; 1153 Message->Msg.message = Msg; 1154 Message->Msg.wParam = wParam; 1155 Message->Msg.lParam = lParam; 1156 Message->ptiReceiver = ptirec; 1157 Message->ptiSender = pti; 1158 Message->HookMessage = HookMessage; 1159 Message->QS_Flags = QS_SENDMESSAGE; 1160 1161 SaveMsg = pti->pusmSent; 1162 pti->pusmSent = Message; 1163 1164 /* Queue it in the destination's message queue */ 1165 InsertTailList(&ptirec->SentMessagesListHead, &Message->ListEntry); 1166 1167 MsqWakeQueue(ptirec, QS_SENDMESSAGE, TRUE); 1168 1169 // First time in, turn off swapping of the stack. 1170 if (pti->cEnterCount == 0) 1171 { 1172 SwapStateEnabled = KeSetKernelStackSwapEnable(FALSE); 1173 } 1174 pti->cEnterCount++; 1175 1176 if (Block) 1177 { 1178 PVOID WaitObjects[2]; 1179 1180 WaitObjects[0] = Message->pkCompletionEvent; // Wait 0 1181 WaitObjects[1] = ptirec->pEThread; // Wait 1 1182 1183 UserLeaveCo(); 1184 1185 WaitStatus = KeWaitForMultipleObjects( 2, 1186 WaitObjects, 1187 WaitAny, 1188 UserRequest, 1189 UserMode, 1190 FALSE, 1191 (uTimeout ? &Timeout : NULL), 1192 NULL ); 1193 1194 UserEnterCo(); 1195 1196 if (WaitStatus == STATUS_TIMEOUT) 1197 { 1198 /* Look up if the message has not yet dispatched, if so 1199 make sure it can't pass a result and it must not set the completion event anymore */ 1200 Entry = ptirec->SentMessagesListHead.Flink; 1201 while (Entry != &ptirec->SentMessagesListHead) 1202 { 1203 if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message) 1204 { 1205 Message->pkCompletionEvent = NULL; 1206 RemoveEntryList(&Message->ListEntry); 1207 ClearMsgBitsMask(ptirec, Message->QS_Flags); 1208 InsertTailList(&usmList, &Message->ListEntry); 1209 break; 1210 } 1211 Entry = Entry->Flink; 1212 } 1213 1214 ERR("MsqSendMessage (blocked) timed out 1 Status %lx\n", WaitStatus); 1215 } 1216 // Receiving thread passed on and left us hanging with issues still pending. 1217 else if (WaitStatus == STATUS_WAIT_1) 1218 { 1219 ERR("Bk Receiving Thread woken up dead!\n"); 1220 Message->flags |= SMF_RECEIVERDIED; 1221 } 1222 1223 while (co_MsqDispatchOneSentMessage(pti)) 1224 ; 1225 } 1226 else 1227 { 1228 PVOID WaitObjects[3]; 1229 1230 WaitObjects[0] = Message->pkCompletionEvent; // Wait 0 1231 WaitObjects[1] = pti->pEventQueueServer; // Wait 1 1232 WaitObjects[2] = ptirec->pEThread; // Wait 2 1233 1234 do 1235 { 1236 UserLeaveCo(); 1237 1238 WaitStatus = KeWaitForMultipleObjects( 3, 1239 WaitObjects, 1240 WaitAny, 1241 UserRequest, 1242 UserMode, 1243 FALSE, 1244 (uTimeout ? &Timeout : NULL), 1245 NULL); 1246 1247 UserEnterCo(); 1248 1249 if (WaitStatus == STATUS_TIMEOUT) 1250 { 1251 /* Look up if the message has not yet been dispatched, if so 1252 make sure it can't pass a result and it must not set the completion event anymore */ 1253 Entry = ptirec->SentMessagesListHead.Flink; 1254 while (Entry != &ptirec->SentMessagesListHead) 1255 { 1256 if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message) 1257 { 1258 Message->pkCompletionEvent = NULL; 1259 RemoveEntryList(&Message->ListEntry); 1260 ClearMsgBitsMask(ptirec, Message->QS_Flags); 1261 InsertTailList(&usmList, &Message->ListEntry); 1262 break; 1263 } 1264 Entry = Entry->Flink; 1265 } 1266 1267 ERR("MsqSendMessage timed out 2 Status %lx\n", WaitStatus); 1268 break; 1269 } 1270 // Receiving thread passed on and left us hanging with issues still pending. 1271 else if (WaitStatus == STATUS_WAIT_2) 1272 { 1273 ERR("NB Receiving Thread woken up dead!\n"); 1274 Message->flags |= SMF_RECEIVERDIED; 1275 break; 1276 } 1277 1278 if (WaitStatus == STATUS_USER_APC) break; 1279 1280 while (co_MsqDispatchOneSentMessage(pti)) 1281 ; 1282 } while (WaitStatus == STATUS_WAIT_1); 1283 } 1284 1285 // Count is nil, restore swapping of the stack. 1286 if (--pti->cEnterCount == 0 ) 1287 { 1288 KeSetKernelStackSwapEnable(SwapStateEnabled); 1289 } 1290 1291 // Handle User APC 1292 if (WaitStatus == STATUS_USER_APC) 1293 { 1294 // The current thread is dying! 1295 TRACE("User APC\n"); 1296 1297 // The Message will be on the Trouble list until Thread cleanup. 1298 Message->flags |= SMF_SENDERDIED; 1299 1300 co_IntDeliverUserAPC(); 1301 ERR("User APC Returned\n"); // Should not see this message. 1302 } 1303 1304 // Force this thread to wake up for the next go around. 1305 KeSetEvent(pti->pEventQueueServer, IO_NO_INCREMENT, FALSE); 1306 1307 Result = Message->lResult; 1308 1309 // Determine whether this message is being processed or not. 1310 if ((Message->flags & (SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE) 1311 { 1312 Message->flags |= SMF_RECEIVERFREE; 1313 } 1314 1315 if (!(Message->flags & SMF_RECEIVERFREE)) 1316 { 1317 TRACE("Sender Freeing Message %p ptirec %p bit %d list empty %d\n",Message,ptirec,!!(ptirec->pcti->fsChangeBits & QS_SENDMESSAGE),IsListEmpty(&ptirec->SentMessagesListHead)); 1318 // Make it to this point, the message was received. 1319 FreeUserMessage(Message); 1320 } 1321 1322 pti->pusmSent = SaveMsg; 1323 1324 TRACE("MSM Allocation Count %d Status %lx Result %d\n",SendMsgCount,WaitStatus,Result); 1325 1326 if (WaitStatus != STATUS_TIMEOUT) 1327 { 1328 if (uResult) 1329 { 1330 *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : 0); 1331 } 1332 } 1333 1334 return WaitStatus; 1335 } 1336 1337 VOID FASTCALL 1338 MsqPostMessage(PTHREADINFO pti, 1339 MSG* Msg, 1340 BOOLEAN HardwareMessage, 1341 DWORD MessageBits, 1342 DWORD dwQEvent, 1343 LONG_PTR ExtraInfo) 1344 { 1345 PUSER_MESSAGE Message; 1346 PUSER_MESSAGE_QUEUE MessageQueue; 1347 1348 if ( pti->TIF_flags & TIF_INCLEANUP || pti->MessageQueue->QF_flags & QF_INDESTROY ) 1349 { 1350 ERR("Post Msg; Thread or Q is Dead!\n"); 1351 return; 1352 } 1353 1354 if(!(Message = MsqCreateMessage(Msg))) 1355 { 1356 return; 1357 } 1358 1359 MessageQueue = pti->MessageQueue; 1360 1361 if (!HardwareMessage) 1362 { 1363 InsertTailList(&pti->PostedMessagesListHead, &Message->ListEntry); 1364 } 1365 else 1366 { 1367 InsertTailList(&MessageQueue->HardwareMessagesListHead, &Message->ListEntry); 1368 } 1369 1370 if (Msg->message == WM_HOTKEY) MessageBits |= QS_HOTKEY; // Justin Case, just set it. 1371 Message->dwQEvent = dwQEvent; 1372 Message->ExtraInfo = ExtraInfo; 1373 Message->QS_Flags = MessageBits; 1374 Message->pti = pti; 1375 MsqWakeQueue(pti, MessageBits, TRUE); 1376 TRACE("Post Message %d\n",PostMsgCount); 1377 } 1378 1379 VOID FASTCALL 1380 MsqPostQuitMessage(PTHREADINFO pti, ULONG ExitCode) 1381 { 1382 pti->QuitPosted = TRUE; 1383 pti->exitCode = ExitCode; 1384 MsqWakeQueue(pti, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE); 1385 } 1386 1387 /*********************************************************************** 1388 * MsqSendParentNotify 1389 * 1390 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless 1391 * the window has the WS_EX_NOPARENTNOTIFY style. 1392 */ 1393 static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt ) 1394 { 1395 PWND pwndDesktop = UserGetDesktopWindow(); 1396 1397 /* pt has to be in the client coordinates of the parent window */ 1398 pt.x += pwndDesktop->rcClient.left - pwnd->rcClient.left; 1399 pt.y += pwndDesktop->rcClient.top - pwnd->rcClient.top; 1400 1401 for (;;) 1402 { 1403 PWND pwndParent; 1404 1405 if (!(pwnd->style & WS_CHILD)) break; 1406 if (pwnd->ExStyle & WS_EX_NOPARENTNOTIFY) break; 1407 if (!(pwndParent = IntGetParent(pwnd))) break; 1408 if (pwndParent == pwndDesktop) break; 1409 pt.x += pwnd->rcClient.left - pwndParent->rcClient.left; 1410 pt.y += pwnd->rcClient.top - pwndParent->rcClient.top; 1411 1412 pwnd = pwndParent; 1413 co_IntSendMessage( UserHMGetHandle(pwnd), WM_PARENTNOTIFY, 1414 MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) ); 1415 } 1416 } 1417 1418 VOID 1419 FASTCALL 1420 IntTrackMouseMove(PWND pwndTrack, PDESKTOP pDesk, PMSG msg, USHORT hittest) 1421 { 1422 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y); 1423 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this??? 1424 1425 if ( pDesk->spwndTrack != pwndTrack || // Change with tracking window or 1426 msg->message != WM_MOUSEMOVE || // Mouse click changes or 1427 pDesk->htEx != hittest) // Change in current hit test states. 1428 { 1429 TRACE("ITMM: Track Mouse Move!\n"); 1430 1431 /* Handle only the changing window track and mouse move across a border. */ 1432 if ( pDesk->spwndTrack != pwndTrack || 1433 (pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT) ) 1434 { 1435 TRACE("ITMM: Another Wnd %d or Across Border %d\n", 1436 pDesk->spwndTrack != pwndTrack,(pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT)); 1437 1438 if ( pDesk->dwDTFlags & DF_TME_LEAVE ) 1439 UserPostMessage( UserHMGetHandle(pDesk->spwndTrack), 1440 (pDesk->htEx != HTCLIENT) ? WM_NCMOUSELEAVE : WM_MOUSELEAVE, 1441 0, 0); 1442 1443 if ( pDesk->dwDTFlags & DF_TME_HOVER ) 1444 IntKillTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE); 1445 1446 /* Clear the flags to sign a change. */ 1447 pDesk->dwDTFlags &= ~(DF_TME_LEAVE|DF_TME_HOVER); 1448 } 1449 /* Set the Track window and hit test. */ 1450 pDesk->spwndTrack = pwndTrack; 1451 pDesk->htEx = hittest; 1452 } 1453 1454 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */ 1455 if ( pDesk->spwndTrack == pwndTrack && 1456 ( msg->message != WM_MOUSEMOVE || !RECTL_bPointInRect(&pDesk->rcMouseHover, msg->pt.x, msg->pt.y)) && 1457 pDesk->dwDTFlags & DF_TME_HOVER ) 1458 { 1459 TRACE("ITMM: Reset Hover points!\n"); 1460 // Restart timer for the hover period. 1461 IntSetTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM); 1462 // Reset desktop mouse hover from the system default hover rectangle. 1463 RECTL_vSetRect(&pDesk->rcMouseHover, 1464 msg->pt.x - gspv.iMouseHoverWidth / 2, 1465 msg->pt.y - gspv.iMouseHoverHeight / 2, 1466 msg->pt.x + gspv.iMouseHoverWidth / 2, 1467 msg->pt.y + gspv.iMouseHoverHeight / 2); 1468 } 1469 } 1470 1471 BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, BOOL* NotForUs, LONG_PTR ExtraInfo, UINT first, UINT last) 1472 { 1473 MSG clk_msg; 1474 POINT pt; 1475 UINT message; 1476 USHORT hittest; 1477 EVENTMSG event; 1478 MOUSEHOOKSTRUCT hook; 1479 BOOL eatMsg = FALSE; 1480 1481 PWND pwndMsg, pwndDesktop; 1482 PUSER_MESSAGE_QUEUE MessageQueue; 1483 PTHREADINFO pti; 1484 PSYSTEM_CURSORINFO CurInfo; 1485 PDESKTOP pDesk; 1486 1487 pti = PsGetCurrentThreadWin32Thread(); 1488 pwndDesktop = UserGetDesktopWindow(); 1489 MessageQueue = pti->MessageQueue; 1490 CurInfo = IntGetSysCursorInfo(); 1491 pwndMsg = ValidateHwndNoErr(msg->hwnd); 1492 clk_msg = MessageQueue->msgDblClk; 1493 pDesk = pwndDesktop->head.rpdesk; 1494 1495 /* find the window to dispatch this mouse message to */ 1496 if (MessageQueue->spwndCapture) 1497 { 1498 hittest = HTCLIENT; 1499 pwndMsg = MessageQueue->spwndCapture; 1500 } 1501 else 1502 { 1503 /* 1504 Start with null window. See wine win.c:test_mouse_input:WM_COMMAND tests. 1505 */ 1506 pwndMsg = co_WinPosWindowFromPoint( NULL, &msg->pt, &hittest, FALSE); 1507 } 1508 1509 TRACE("Got mouse message for %p, hittest: 0x%x\n", msg->hwnd, hittest); 1510 1511 // Null window or not the same "Hardware" message queue. 1512 if (pwndMsg == NULL || pwndMsg->head.pti->MessageQueue != MessageQueue) 1513 { 1514 // Crossing a boundary, so set cursor. See default message queue cursor. 1515 IntSystemSetCursor(SYSTEMCUR(ARROW)); 1516 /* Remove and ignore the message */ 1517 *RemoveMessages = TRUE; 1518 return FALSE; 1519 } 1520 1521 // Check to see if this is attached, 1522 if ( pwndMsg->head.pti != pti && // window thread is not current, 1523 MessageQueue->cThreads > 1 ) // and is attached... 1524 { 1525 // This is not for us and we should leave so the other thread can check for messages!!! 1526 *NotForUs = TRUE; 1527 *RemoveMessages = TRUE; 1528 return FALSE; 1529 } 1530 1531 if ( MessageQueue == gpqCursor ) // Cursor must use the same Queue! 1532 { 1533 IntTrackMouseMove(pwndMsg, pDesk, msg, hittest); 1534 } 1535 else 1536 { 1537 ERR("Not the same cursor!\n"); 1538 } 1539 1540 msg->hwnd = UserHMGetHandle(pwndMsg); 1541 1542 pt = msg->pt; 1543 message = msg->message; 1544 1545 /* Note: windows has no concept of a non-client wheel message */ 1546 if (message != WM_MOUSEWHEEL) 1547 { 1548 if (hittest != HTCLIENT) 1549 { 1550 message += WM_NCMOUSEMOVE - WM_MOUSEMOVE; 1551 msg->wParam = hittest; // Caution! This might break wParam check in DblClk. 1552 } 1553 else 1554 { 1555 /* coordinates don't get translated while tracking a menu */ 1556 /* FIXME: should differentiate popups and top-level menus */ 1557 if (!(MessageQueue->MenuOwner)) 1558 { 1559 pt.x += pwndDesktop->rcClient.left - pwndMsg->rcClient.left; 1560 pt.y += pwndDesktop->rcClient.top - pwndMsg->rcClient.top; 1561 } 1562 } 1563 } 1564 msg->lParam = MAKELONG( pt.x, pt.y ); 1565 1566 /* translate double clicks */ 1567 1568 if ((msg->message == WM_LBUTTONDOWN) || 1569 (msg->message == WM_RBUTTONDOWN) || 1570 (msg->message == WM_MBUTTONDOWN) || 1571 (msg->message == WM_XBUTTONDOWN)) 1572 { 1573 BOOL update = *RemoveMessages; 1574 1575 /* translate double clicks - 1576 * note that ...MOUSEMOVEs can slip in between 1577 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */ 1578 1579 if ((MessageQueue->MenuOwner || MessageQueue->MoveSize) || 1580 hittest != HTCLIENT || 1581 (pwndMsg->pcls->style & CS_DBLCLKS)) 1582 { 1583 if ((msg->message == clk_msg.message) && 1584 (msg->hwnd == clk_msg.hwnd) && 1585 // Only worry about XButton wParam. 1586 (msg->message != WM_XBUTTONDOWN || GET_XBUTTON_WPARAM(msg->wParam) == GET_XBUTTON_WPARAM(clk_msg.wParam)) && 1587 ((msg->time - clk_msg.time) < (ULONG)gspv.iDblClickTime) && 1588 (abs(msg->pt.x - clk_msg.pt.x) < UserGetSystemMetrics(SM_CXDOUBLECLK)/2) && 1589 (abs(msg->pt.y - clk_msg.pt.y) < UserGetSystemMetrics(SM_CYDOUBLECLK)/2)) 1590 { 1591 message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN); 1592 if (update) 1593 { 1594 MessageQueue->msgDblClk.message = 0; /* clear the double click conditions */ 1595 update = FALSE; 1596 } 1597 } 1598 } 1599 1600 if (!((first == 0 && last == 0) || (message >= first || message <= last))) 1601 { 1602 TRACE("Message out of range!!!\n"); 1603 return FALSE; 1604 } 1605 1606 /* update static double click conditions */ 1607 if (update) MessageQueue->msgDblClk = *msg; 1608 } 1609 else 1610 { 1611 if (!((first == 0 && last == 0) || (message >= first || message <= last))) 1612 { 1613 TRACE("Message out of range!!!\n"); 1614 return FALSE; 1615 } 1616 1617 // Update mouse move down keys. 1618 if (message == WM_MOUSEMOVE) 1619 { 1620 msg->wParam = MsqGetDownKeyState(MessageQueue); 1621 } 1622 } 1623 1624 if (gspv.bMouseClickLock) 1625 { 1626 BOOL IsClkLck = FALSE; 1627 1628 if(msg->message == WM_LBUTTONUP) 1629 { 1630 IsClkLck = ((msg->time - CurInfo->ClickLockTime) >= gspv.dwMouseClickLockTime); 1631 if (IsClkLck && (!CurInfo->ClickLockActive)) 1632 { 1633 CurInfo->ClickLockActive = TRUE; 1634 } 1635 } 1636 else if (msg->message == WM_LBUTTONDOWN) 1637 { 1638 if (CurInfo->ClickLockActive) 1639 { 1640 IsClkLck = TRUE; 1641 CurInfo->ClickLockActive = FALSE; 1642 } 1643 1644 CurInfo->ClickLockTime = msg->time; 1645 } 1646 1647 if(IsClkLck) 1648 { 1649 /* Remove and ignore the message */ 1650 *RemoveMessages = TRUE; 1651 TRACE("Remove and ignore the message\n"); 1652 return FALSE; 1653 } 1654 } 1655 1656 if (pti->TIF_flags & TIF_MSGPOSCHANGED) 1657 { 1658 pti->TIF_flags &= ~TIF_MSGPOSCHANGED; 1659 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, NULL, OBJID_CLIENT, CHILDID_SELF, 0); 1660 } 1661 1662 /* message is accepted now (but still get dropped) */ 1663 1664 event.message = msg->message; 1665 event.time = msg->time; 1666 event.hwnd = msg->hwnd; 1667 event.paramL = msg->pt.x; 1668 event.paramH = msg->pt.y; 1669 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event ); 1670 1671 hook.pt = msg->pt; 1672 hook.hwnd = msg->hwnd; 1673 hook.wHitTestCode = hittest; 1674 hook.dwExtraInfo = ExtraInfo; 1675 if (co_HOOK_CallHooks( WH_MOUSE, *RemoveMessages ? HC_ACTION : HC_NOREMOVE, 1676 message, (LPARAM)&hook )) 1677 { 1678 hook.pt = msg->pt; 1679 hook.hwnd = msg->hwnd; 1680 hook.wHitTestCode = hittest; 1681 hook.dwExtraInfo = ExtraInfo; 1682 co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook ); 1683 1684 ERR("WH_MOUSE dropped mouse message!\n"); 1685 1686 /* Remove and skip message */ 1687 *RemoveMessages = TRUE; 1688 return FALSE; 1689 } 1690 1691 if ((hittest == (USHORT)HTERROR) || (hittest == (USHORT)HTNOWHERE)) 1692 { 1693 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message )); 1694 1695 /* Remove and skip message */ 1696 *RemoveMessages = TRUE; 1697 return FALSE; 1698 } 1699 1700 if ((*RemoveMessages == FALSE) || MessageQueue->spwndCapture) 1701 { 1702 /* Accept the message */ 1703 msg->message = message; 1704 return TRUE; 1705 } 1706 1707 if ((msg->message == WM_LBUTTONDOWN) || 1708 (msg->message == WM_RBUTTONDOWN) || 1709 (msg->message == WM_MBUTTONDOWN) || 1710 (msg->message == WM_XBUTTONDOWN)) 1711 { 1712 /* Send the WM_PARENTNOTIFY, 1713 * note that even for double/nonclient clicks 1714 * notification message is still WM_L/M/RBUTTONDOWN. 1715 */ 1716 MsqSendParentNotify(pwndMsg, msg->message, 0, msg->pt ); 1717 1718 /* Activate the window if needed */ 1719 1720 if (pwndMsg != MessageQueue->spwndActive) 1721 { 1722 PWND pwndTop = pwndMsg; 1723 pwndTop = IntGetNonChildAncestor(pwndTop); 1724 1725 TRACE("Mouse pti %p pwndMsg pti %p pwndTop pti %p\n",MessageQueue->ptiMouse,pwndMsg->head.pti,pwndTop->head.pti); 1726 1727 if (pwndTop && pwndTop != pwndDesktop) 1728 { 1729 LONG ret = co_IntSendMessage( msg->hwnd, 1730 WM_MOUSEACTIVATE, 1731 (WPARAM)UserHMGetHandle(pwndTop), 1732 MAKELONG( hittest, msg->message)); 1733 switch(ret) 1734 { 1735 case MA_NOACTIVATEANDEAT: 1736 eatMsg = TRUE; 1737 /* fall through */ 1738 case MA_NOACTIVATE: 1739 break; 1740 case MA_ACTIVATEANDEAT: 1741 eatMsg = TRUE; 1742 /* fall through */ 1743 case MA_ACTIVATE: 1744 case 0: 1745 if (!co_IntMouseActivateWindow( pwndTop )) eatMsg = TRUE; 1746 break; 1747 default: 1748 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret ); 1749 break; 1750 } 1751 } 1752 } 1753 } 1754 1755 /* send the WM_SETCURSOR message */ 1756 1757 /* Windows sends the normal mouse message as the message parameter 1758 in the WM_SETCURSOR message even if it's non-client mouse message */ 1759 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message )); 1760 1761 msg->message = message; 1762 return !eatMsg; 1763 } 1764 1765 BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages) 1766 { 1767 EVENTMSG Event; 1768 USER_REFERENCE_ENTRY Ref; 1769 PWND pWnd; 1770 UINT ImmRet; 1771 BOOL Ret = TRUE; 1772 WPARAM wParam = Msg->wParam; 1773 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1774 1775 if (Msg->message == VK_PACKET) 1776 { 1777 pti->wchInjected = HIWORD(Msg->wParam); 1778 } 1779 1780 if (Msg->message == WM_KEYDOWN || Msg->message == WM_SYSKEYDOWN || 1781 Msg->message == WM_KEYUP || Msg->message == WM_SYSKEYUP) 1782 { 1783 switch (Msg->wParam) 1784 { 1785 case VK_LSHIFT: case VK_RSHIFT: 1786 Msg->wParam = VK_SHIFT; 1787 break; 1788 case VK_LCONTROL: case VK_RCONTROL: 1789 Msg->wParam = VK_CONTROL; 1790 break; 1791 case VK_LMENU: case VK_RMENU: 1792 Msg->wParam = VK_MENU; 1793 break; 1794 } 1795 } 1796 1797 pWnd = ValidateHwndNoErr(Msg->hwnd); 1798 if (pWnd) UserRefObjectCo(pWnd, &Ref); 1799 1800 Event.message = Msg->message; 1801 Event.hwnd = Msg->hwnd; 1802 Event.time = Msg->time; 1803 Event.paramL = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8); 1804 Event.paramH = Msg->lParam & 0x7FFF; 1805 if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000; 1806 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event); 1807 1808 if (*RemoveMessages) 1809 { 1810 if ((Msg->message == WM_KEYDOWN) && 1811 (Msg->hwnd != IntGetDesktopWindow())) 1812 { 1813 /* Handle F1 key by sending out WM_HELP message */ 1814 if (Msg->wParam == VK_F1) 1815 { 1816 UserPostMessage( Msg->hwnd, WM_KEYF1, 0, 0 ); 1817 } 1818 else if (Msg->wParam >= VK_BROWSER_BACK && 1819 Msg->wParam <= VK_LAUNCH_APP2) 1820 { 1821 /* FIXME: Process keystate */ 1822 co_IntSendMessage(Msg->hwnd, WM_APPCOMMAND, (WPARAM)Msg->hwnd, MAKELPARAM(0, (FAPPCOMMAND_KEY | (Msg->wParam - VK_BROWSER_BACK + 1)))); 1823 } 1824 } 1825 else if (Msg->message == WM_KEYUP) 1826 { 1827 /* Handle VK_APPS key by posting a WM_CONTEXTMENU message */ 1828 if (Msg->wParam == VK_APPS && pti->MessageQueue->MenuOwner == NULL) 1829 UserPostMessage( Msg->hwnd, WM_CONTEXTMENU, (WPARAM)Msg->hwnd, -1 ); 1830 } 1831 } 1832 1833 //// Key Down! 1834 if ( *RemoveMessages && Msg->message == WM_SYSKEYDOWN ) 1835 { 1836 if ( HIWORD(Msg->lParam) & KF_ALTDOWN ) 1837 { 1838 if ( Msg->wParam == VK_ESCAPE || Msg->wParam == VK_TAB ) // Alt-Tab/ESC Alt-Shift-Tab/ESC 1839 { 1840 WPARAM wParamTmp; 1841 1842 wParamTmp = UserGetKeyState(VK_SHIFT) & 0x8000 ? SC_PREVWINDOW : SC_NEXTWINDOW; 1843 TRACE("Send WM_SYSCOMMAND Alt-Tab/ESC Alt-Shift-Tab/ESC\n"); 1844 co_IntSendMessage( Msg->hwnd, WM_SYSCOMMAND, wParamTmp, Msg->wParam ); 1845 1846 //// Keep looping. 1847 Ret = FALSE; 1848 //// Skip the rest. 1849 goto Exit; 1850 } 1851 } 1852 } 1853 1854 if ( *RemoveMessages && (Msg->message == WM_SYSKEYDOWN || Msg->message == WM_KEYDOWN) ) 1855 { 1856 if (gdwLanguageToggleKey < 3) 1857 { 1858 if (IS_KEY_DOWN(gafAsyncKeyState, gdwLanguageToggleKey == 1 ? VK_LMENU : VK_CONTROL)) // L Alt 1 or Ctrl 2 . 1859 { 1860 if ( wParam == VK_LSHIFT ) gLanguageToggleKeyState = INPUTLANGCHANGE_FORWARD; // Left Alt - Left Shift, Next 1861 //// FIXME : It seems to always be VK_LSHIFT. 1862 if ( wParam == VK_RSHIFT ) gLanguageToggleKeyState = INPUTLANGCHANGE_BACKWARD; // Left Alt - Right Shift, Previous 1863 } 1864 } 1865 } 1866 1867 //// Key Up! Alt Key Ctrl Key 1868 if ( *RemoveMessages && (Msg->message == WM_SYSKEYUP || Msg->message == WM_KEYUP) ) 1869 { 1870 // When initializing win32k: Reading from the registry hotkey combination 1871 // to switch the keyboard layout and store it to global variable. 1872 // Using this combination of hotkeys in this function 1873 1874 if ( gdwLanguageToggleKey < 3 && 1875 IS_KEY_DOWN(gafAsyncKeyState, gdwLanguageToggleKey == 1 ? VK_LMENU : VK_CONTROL) ) 1876 { 1877 if ( Msg->wParam == VK_SHIFT && !(IS_KEY_DOWN(gafAsyncKeyState, VK_SHIFT))) 1878 { 1879 WPARAM wParamILR; 1880 PKL pkl = pti->KeyboardLayout; 1881 1882 if (pWnd) UserDerefObjectCo(pWnd); 1883 1884 //// Seems to override message window. 1885 if (!(pWnd = pti->MessageQueue->spwndFocus)) 1886 { 1887 pWnd = pti->MessageQueue->spwndActive; 1888 } 1889 if (pWnd) UserRefObjectCo(pWnd, &Ref); 1890 1891 if (pkl != NULL && gLanguageToggleKeyState) 1892 { 1893 TRACE("Posting WM_INPUTLANGCHANGEREQUEST KeyState %d\n", gLanguageToggleKeyState ); 1894 1895 wParamILR = gLanguageToggleKeyState; 1896 // If system character set and font signature send flag. 1897 if ( gSystemFS & pkl->dwFontSigs ) 1898 { 1899 wParamILR |= INPUTLANGCHANGE_SYSCHARSET; 1900 } 1901 1902 UserPostMessage( UserHMGetHandle(pWnd), 1903 WM_INPUTLANGCHANGEREQUEST, 1904 wParamILR, 1905 (LPARAM)pkl->hkl ); 1906 1907 gLanguageToggleKeyState = 0; 1908 //// Keep looping. 1909 Ret = FALSE; 1910 //// Skip the rest. 1911 goto Exit; 1912 } 1913 } 1914 } 1915 } 1916 1917 if (co_HOOK_CallHooks( WH_KEYBOARD, 1918 *RemoveMessages ? HC_ACTION : HC_NOREMOVE, 1919 LOWORD(Msg->wParam), 1920 Msg->lParam)) 1921 { 1922 /* skip this message */ 1923 co_HOOK_CallHooks( WH_CBT, 1924 HCBT_KEYSKIPPED, 1925 LOWORD(Msg->wParam), 1926 Msg->lParam ); 1927 1928 ERR("KeyboardMessage WH_KEYBOARD Call Hook return!\n"); 1929 1930 *RemoveMessages = TRUE; 1931 1932 Ret = FALSE; 1933 } 1934 1935 if ( pWnd && Ret && *RemoveMessages && Msg->message == WM_KEYDOWN && !(pti->TIF_flags & TIF_DISABLEIME)) 1936 { 1937 if ( (ImmRet = IntImmProcessKey(pti->MessageQueue, pWnd, Msg->message, Msg->wParam, Msg->lParam)) ) 1938 { 1939 if ( ImmRet & (IPHK_HOTKEY|IPHK_SKIPTHISKEY) ) 1940 { 1941 ImmRet = 0; 1942 } 1943 if ( ImmRet & IPHK_PROCESSBYIME ) 1944 { 1945 Msg->wParam = VK_PROCESSKEY; 1946 } 1947 } 1948 } 1949 Exit: 1950 if (pWnd) UserDerefObjectCo(pWnd); 1951 return Ret; 1952 } 1953 1954 BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, BOOL* NotForUs, LONG_PTR ExtraInfo, UINT first, UINT last) 1955 { 1956 if ( IS_MOUSE_MESSAGE(Msg->message)) 1957 { 1958 return co_IntProcessMouseMessage(Msg, RemoveMessages, NotForUs, ExtraInfo, first, last); 1959 } 1960 else if ( IS_KBD_MESSAGE(Msg->message)) 1961 { 1962 return co_IntProcessKeyboardMessage(Msg, RemoveMessages); 1963 } 1964 1965 return TRUE; 1966 } 1967 1968 /* check whether a message filter contains at least one potential hardware message */ 1969 static INT FASTCALL 1970 filter_contains_hw_range( UINT first, UINT last ) 1971 { 1972 /* hardware message ranges are (in numerical order): 1973 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST 1974 * WM_KEYFIRST .. WM_KEYLAST 1975 * WM_MOUSEFIRST .. WM_MOUSELAST 1976 */ 1977 if (!last) --last; 1978 if (last < WM_NCMOUSEFIRST) return 0; 1979 if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0; 1980 if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0; 1981 if (first > WM_MOUSELAST) return 0; 1982 return 1; 1983 } 1984 1985 /* check whether message is in the range of mouse messages */ 1986 static inline BOOL is_mouse_message( UINT message ) 1987 { 1988 return ( //( message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST ) || This seems to break tests... 1989 ( message >= WM_MOUSEFIRST && message <= WM_MOUSELAST ) || 1990 ( message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK ) || 1991 ( message >= WM_MBUTTONDOWN && message <= WM_MBUTTONDBLCLK ) || 1992 ( message >= WM_LBUTTONDOWN && message <= WM_RBUTTONDBLCLK ) ); 1993 } 1994 1995 BOOL APIENTRY 1996 co_MsqPeekHardwareMessage(IN PTHREADINFO pti, 1997 IN BOOL Remove, 1998 IN PWND Window, 1999 IN UINT MsgFilterLow, 2000 IN UINT MsgFilterHigh, 2001 IN UINT QSflags, 2002 OUT MSG* pMsg) 2003 { 2004 BOOL AcceptMessage, NotForUs; 2005 PUSER_MESSAGE CurrentMessage; 2006 PLIST_ENTRY ListHead; 2007 MSG msg; 2008 ULONG_PTR idSave; 2009 DWORD QS_Flags; 2010 LONG_PTR ExtraInfo; 2011 BOOL Ret = FALSE; 2012 PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue; 2013 2014 if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE; 2015 2016 ListHead = MessageQueue->HardwareMessagesListHead.Flink; 2017 2018 if (IsListEmpty(ListHead)) return FALSE; 2019 2020 if (!MessageQueue->ptiSysLock) 2021 { 2022 MessageQueue->ptiSysLock = pti; 2023 pti->pcti->CTI_flags |= CTI_THREADSYSLOCK; 2024 } 2025 2026 if (MessageQueue->ptiSysLock != pti) 2027 { 2028 ERR("Thread Q is locked to ptiSysLock 0x%p pti 0x%p\n",MessageQueue->ptiSysLock,pti); 2029 return FALSE; 2030 } 2031 2032 while (ListHead != &MessageQueue->HardwareMessagesListHead) 2033 { 2034 CurrentMessage = CONTAINING_RECORD(ListHead, USER_MESSAGE, ListEntry); 2035 ListHead = ListHead->Flink; 2036 2037 if (MessageQueue->idSysPeek == (ULONG_PTR)CurrentMessage) 2038 { 2039 TRACE("Skip this message due to it is in play!\n"); 2040 continue; 2041 } 2042 /* 2043 MSDN: 2044 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL. 2045 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL. 2046 3: handle to the window whose messages are to be retrieved. 2047 */ 2048 if ( ( !Window || // 1 2049 ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2 2050 ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) || // 3 2051 ( is_mouse_message(CurrentMessage->Msg.message) ) ) && // Null window for anything mouse. 2052 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) || 2053 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) ) 2054 { 2055 idSave = MessageQueue->idSysPeek; 2056 MessageQueue->idSysPeek = (ULONG_PTR)CurrentMessage; 2057 2058 msg = CurrentMessage->Msg; 2059 ExtraInfo = CurrentMessage->ExtraInfo; 2060 QS_Flags = CurrentMessage->QS_Flags; 2061 2062 NotForUs = FALSE; 2063 2064 UpdateKeyStateFromMsg(MessageQueue, &msg); 2065 AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, &NotForUs, ExtraInfo, MsgFilterLow, MsgFilterHigh); 2066 2067 if (Remove) 2068 { 2069 if (CurrentMessage->pti != NULL && (MessageQueue->idSysPeek == (ULONG_PTR)CurrentMessage)) 2070 { 2071 MsqDestroyMessage(CurrentMessage); 2072 } 2073 ClearMsgBitsMask(pti, QS_Flags); 2074 } 2075 2076 MessageQueue->idSysPeek = idSave; 2077 2078 if (NotForUs) 2079 { 2080 Ret = FALSE; 2081 break; 2082 } 2083 2084 if (AcceptMessage) 2085 { 2086 *pMsg = msg; 2087 // Fix all but one wine win:test_GetMessagePos WM_TIMER tests. See PostTimerMessages. 2088 if (!RtlEqualMemory(&pti->ptLast, &msg.pt, sizeof(POINT))) 2089 { 2090 pti->TIF_flags |= TIF_MSGPOSCHANGED; 2091 } 2092 pti->ptLast = msg.pt; 2093 pti->timeLast = msg.time; 2094 MessageQueue->ExtraInfo = ExtraInfo; 2095 Ret = TRUE; 2096 break; 2097 } 2098 } 2099 } 2100 2101 MessageQueue->ptiSysLock = NULL; 2102 pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK; 2103 return Ret; 2104 } 2105 2106 BOOLEAN APIENTRY 2107 MsqPeekMessage(IN PTHREADINFO pti, 2108 IN BOOLEAN Remove, 2109 IN PWND Window, 2110 IN UINT MsgFilterLow, 2111 IN UINT MsgFilterHigh, 2112 IN UINT QSflags, 2113 OUT LONG_PTR *ExtraInfo, 2114 OUT DWORD *dwQEvent, 2115 OUT PMSG Message) 2116 { 2117 PUSER_MESSAGE CurrentMessage; 2118 PLIST_ENTRY ListHead; 2119 DWORD QS_Flags; 2120 BOOL Ret = FALSE; 2121 2122 ListHead = pti->PostedMessagesListHead.Flink; 2123 2124 if (IsListEmpty(ListHead)) return FALSE; 2125 2126 while(ListHead != &pti->PostedMessagesListHead) 2127 { 2128 CurrentMessage = CONTAINING_RECORD(ListHead, USER_MESSAGE, ListEntry); 2129 ListHead = ListHead->Flink; 2130 /* 2131 MSDN: 2132 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL. 2133 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL. 2134 3: handle to the window whose messages are to be retrieved. 2135 */ 2136 if ( ( !Window || // 1 2137 ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2 2138 ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3 2139 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) || 2140 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) ) 2141 { 2142 *Message = CurrentMessage->Msg; 2143 *ExtraInfo = CurrentMessage->ExtraInfo; 2144 QS_Flags = CurrentMessage->QS_Flags; 2145 if (dwQEvent) *dwQEvent = CurrentMessage->dwQEvent; 2146 2147 if (Remove) 2148 { 2149 if (CurrentMessage->pti != NULL) 2150 { 2151 MsqDestroyMessage(CurrentMessage); 2152 } 2153 ClearMsgBitsMask(pti, QS_Flags); 2154 } 2155 Ret = TRUE; 2156 break; 2157 } 2158 } 2159 2160 return Ret; 2161 } 2162 2163 NTSTATUS FASTCALL 2164 co_MsqWaitForNewMessages(PTHREADINFO pti, PWND WndFilter, 2165 UINT MsgFilterMin, UINT MsgFilterMax) 2166 { 2167 NTSTATUS ret = STATUS_SUCCESS; 2168 2169 // Post mouse moves before waiting for messages. 2170 if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED) 2171 { 2172 IntCoalesceMouseMove(pti); 2173 } 2174 2175 UserLeaveCo(); 2176 2177 ZwYieldExecution(); // Let someone else run! 2178 2179 ret = KeWaitForSingleObject( pti->pEventQueueServer, 2180 UserRequest, 2181 UserMode, 2182 FALSE, 2183 NULL ); 2184 UserEnterCo(); 2185 if ( ret == STATUS_USER_APC ) 2186 { 2187 TRACE("MWFNW User APC\n"); 2188 co_IntDeliverUserAPC(); 2189 } 2190 return ret; 2191 } 2192 2193 BOOL FASTCALL 2194 MsqIsHung(PTHREADINFO pti) 2195 { 2196 if (EngGetTickCount32() - pti->timeLast > MSQ_HUNG && 2197 !(pti->pcti->fsWakeMask & QS_INPUT) && 2198 !PsGetThreadFreezeCount(pti->pEThread) && 2199 !(pti->ppi->W32PF_flags & W32PF_APPSTARTING)) 2200 return TRUE; 2201 2202 return FALSE; 2203 } 2204 2205 BOOL FASTCALL 2206 IsThreadSuspended(PTHREADINFO pti) 2207 { 2208 if (pti->pEThread) 2209 { 2210 BOOL Ret = TRUE; 2211 if (!(pti->pEThread->Tcb.SuspendCount) && !PsGetThreadFreezeCount(pti->pEThread)) Ret = FALSE; 2212 return Ret; 2213 } 2214 return FALSE; 2215 } 2216 2217 VOID 2218 CALLBACK 2219 HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) 2220 { 2221 DoTheScreenSaver(); 2222 TRACE("HungAppSysTimerProc\n"); 2223 // Process list of windows that are hung and waiting. 2224 } 2225 2226 BOOLEAN FASTCALL 2227 MsqInitializeMessageQueue(PTHREADINFO pti, PUSER_MESSAGE_QUEUE MessageQueue) 2228 { 2229 InitializeListHead(&MessageQueue->HardwareMessagesListHead); // Keep here! 2230 MessageQueue->spwndFocus = NULL; 2231 MessageQueue->iCursorLevel = 0; 2232 MessageQueue->CursorObject = SYSTEMCUR(WAIT); // See test_initial_cursor. 2233 if (MessageQueue->CursorObject) 2234 { 2235 TRACE("Default cursor hcur %p\n",UserHMGetHandle(MessageQueue->CursorObject)); 2236 UserReferenceObject(MessageQueue->CursorObject); 2237 } 2238 RtlCopyMemory(MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState)); 2239 MessageQueue->ptiMouse = pti; 2240 MessageQueue->ptiKeyboard = pti; 2241 MessageQueue->cThreads++; 2242 2243 return TRUE; 2244 } 2245 2246 VOID FASTCALL 2247 MsqCleanupThreadMsgs(PTHREADINFO pti) 2248 { 2249 PLIST_ENTRY CurrentEntry; 2250 PUSER_MESSAGE CurrentMessage; 2251 PUSER_SENT_MESSAGE CurrentSentMessage; 2252 2253 TRACE("MsqCleanupThreadMsgs %p\n",pti); 2254 2255 // Clear it all out. 2256 if (pti->pcti) 2257 { 2258 pti->pcti->fsWakeBits = 0; 2259 pti->pcti->fsChangeBits = 0; 2260 } 2261 2262 pti->nCntsQBits[QSRosKey] = 0; 2263 pti->nCntsQBits[QSRosMouseMove] = 0; 2264 pti->nCntsQBits[QSRosMouseButton] = 0; 2265 pti->nCntsQBits[QSRosPostMessage] = 0; 2266 pti->nCntsQBits[QSRosSendMessage] = 0; 2267 pti->nCntsQBits[QSRosHotKey] = 0; 2268 pti->nCntsQBits[QSRosEvent] = 0; 2269 2270 /* cleanup posted messages */ 2271 while (!IsListEmpty(&pti->PostedMessagesListHead)) 2272 { 2273 CurrentEntry = pti->PostedMessagesListHead.Flink; 2274 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry); 2275 ERR("Thread Cleanup Post Messages %p\n",CurrentMessage); 2276 if (CurrentMessage->dwQEvent) 2277 { 2278 if (CurrentMessage->dwQEvent == POSTEVENT_NWE) 2279 { 2280 ExFreePoolWithTag( (PVOID)CurrentMessage->ExtraInfo, TAG_HOOK); 2281 } 2282 } 2283 MsqDestroyMessage(CurrentMessage); 2284 } 2285 2286 /* remove the messages that have not yet been dispatched */ 2287 while (!IsListEmpty(&pti->SentMessagesListHead)) 2288 { 2289 CurrentEntry = pti->SentMessagesListHead.Flink; 2290 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry); 2291 2292 ERR("Thread Cleanup Sent Messages %p\n",CurrentSentMessage); 2293 2294 /* wake the sender's thread */ 2295 if (CurrentSentMessage->pkCompletionEvent != NULL) 2296 { 2297 KeSetEvent(CurrentSentMessage->pkCompletionEvent, IO_NO_INCREMENT, FALSE); 2298 } 2299 2300 if (CurrentSentMessage->HasPackedLParam) 2301 { 2302 if (CurrentSentMessage->Msg.lParam) 2303 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam); 2304 } 2305 2306 /* free the message */ 2307 FreeUserMessage(CurrentSentMessage); 2308 } 2309 2310 // Process Trouble Message List 2311 if (!IsListEmpty(&usmList)) 2312 { 2313 CurrentEntry = usmList.Flink; 2314 while (CurrentEntry != &usmList) 2315 { 2316 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry); 2317 CurrentEntry = CurrentEntry->Flink; 2318 2319 TRACE("Found troubled messages %p on the list\n",CurrentSentMessage); 2320 2321 if ( pti == CurrentSentMessage->ptiReceiver ) 2322 { 2323 if (CurrentSentMessage->HasPackedLParam) 2324 { 2325 if (CurrentSentMessage->Msg.lParam) 2326 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam); 2327 } 2328 2329 /* free the message */ 2330 FreeUserMessage(CurrentSentMessage); 2331 } 2332 else if ( pti == CurrentSentMessage->ptiSender || 2333 pti == CurrentSentMessage->ptiCallBackSender ) 2334 { 2335 // Determine whether this message is being processed or not. 2336 if ((CurrentSentMessage->flags & (SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE) 2337 { 2338 CurrentSentMessage->flags |= SMF_RECEIVERFREE; 2339 } 2340 2341 if (!(CurrentSentMessage->flags & SMF_RECEIVERFREE)) 2342 { 2343 2344 if (CurrentSentMessage->HasPackedLParam) 2345 { 2346 if (CurrentSentMessage->Msg.lParam) 2347 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam); 2348 } 2349 2350 /* free the message */ 2351 FreeUserMessage(CurrentSentMessage); 2352 } 2353 } 2354 } 2355 } 2356 } 2357 2358 VOID FASTCALL 2359 MsqCleanupMessageQueue(PTHREADINFO pti) 2360 { 2361 PUSER_MESSAGE_QUEUE MessageQueue; 2362 PLIST_ENTRY CurrentEntry; 2363 PUSER_MESSAGE CurrentMessage; 2364 2365 MessageQueue = pti->MessageQueue; 2366 MessageQueue->cThreads--; 2367 2368 if (MessageQueue->cThreads) 2369 { 2370 if (MessageQueue->ptiSysLock == pti) MessageQueue->ptiSysLock = NULL; 2371 } 2372 2373 if (MessageQueue->cThreads == 0) //// Fix a crash related to CORE-10471 testing. 2374 { 2375 /* cleanup posted messages */ 2376 while (!IsListEmpty(&MessageQueue->HardwareMessagesListHead)) 2377 { 2378 CurrentEntry = MessageQueue->HardwareMessagesListHead.Flink; 2379 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry); 2380 ERR("MQ Cleanup Post Messages %p\n",CurrentMessage); 2381 MsqDestroyMessage(CurrentMessage); 2382 } 2383 } //// 2384 2385 if (MessageQueue->CursorObject) 2386 { 2387 PCURICON_OBJECT pCursor = MessageQueue->CursorObject; 2388 2389 /* Change to another cursor if we going to dereference current one 2390 Note: we can't use UserSetCursor because it uses current thread 2391 message queue instead of queue given for cleanup */ 2392 if (IntGetSysCursorInfo()->CurrentCursorObject == pCursor) 2393 { 2394 HDC hdcScreen; 2395 2396 /* Get the screen DC */ 2397 hdcScreen = IntGetScreenDC(); 2398 if (hdcScreen) 2399 GreMovePointer(hdcScreen, -1, -1); 2400 IntGetSysCursorInfo()->CurrentCursorObject = NULL; 2401 } 2402 2403 TRACE("DereferenceObject pCursor\n"); 2404 UserDereferenceObject(pCursor); 2405 } 2406 2407 if (gpqForeground == MessageQueue) 2408 { 2409 IntSetFocusMessageQueue(NULL); 2410 } 2411 if (gpqForegroundPrev == MessageQueue) 2412 { 2413 gpqForegroundPrev = NULL; 2414 } 2415 if (gpqCursor == MessageQueue) 2416 { 2417 gpqCursor = NULL; 2418 } 2419 } 2420 2421 PUSER_MESSAGE_QUEUE FASTCALL 2422 MsqCreateMessageQueue(PTHREADINFO pti) 2423 { 2424 PUSER_MESSAGE_QUEUE MessageQueue; 2425 2426 MessageQueue = ExAllocatePoolWithTag(NonPagedPool, 2427 sizeof(*MessageQueue), 2428 USERTAG_Q); 2429 2430 if (!MessageQueue) 2431 { 2432 return NULL; 2433 } 2434 2435 RtlZeroMemory(MessageQueue, sizeof(*MessageQueue)); 2436 /* hold at least one reference until it'll be destroyed */ 2437 IntReferenceMessageQueue(MessageQueue); 2438 /* initialize the queue */ 2439 if (!MsqInitializeMessageQueue(pti, MessageQueue)) 2440 { 2441 IntDereferenceMessageQueue(MessageQueue); 2442 return NULL; 2443 } 2444 2445 return MessageQueue; 2446 } 2447 2448 VOID FASTCALL 2449 MsqDestroyMessageQueue(_In_ PTHREADINFO pti) 2450 { 2451 PDESKTOP desk; 2452 PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue; 2453 2454 NT_ASSERT(MessageQueue != NULL); 2455 MessageQueue->QF_flags |= QF_INDESTROY; 2456 2457 /* remove the message queue from any desktops */ 2458 if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0))) 2459 { 2460 (void)InterlockedExchangePointer((PVOID*)&desk->ActiveMessageQueue, 0); 2461 IntDereferenceMessageQueue(MessageQueue); 2462 } 2463 2464 /* clean it up */ 2465 MsqCleanupMessageQueue(pti); 2466 2467 /* decrease the reference counter, if it hits zero, the queue will be freed */ 2468 _PRAGMA_WARNING_SUPPRESS(__WARNING_USING_UNINIT_VAR); 2469 IntDereferenceMessageQueue(MessageQueue); 2470 } 2471 2472 LPARAM FASTCALL 2473 MsqSetMessageExtraInfo(LPARAM lParam) 2474 { 2475 LPARAM Ret; 2476 PTHREADINFO pti; 2477 PUSER_MESSAGE_QUEUE MessageQueue; 2478 2479 pti = PsGetCurrentThreadWin32Thread(); 2480 MessageQueue = pti->MessageQueue; 2481 if(!MessageQueue) 2482 { 2483 return 0; 2484 } 2485 2486 Ret = MessageQueue->ExtraInfo; 2487 MessageQueue->ExtraInfo = lParam; 2488 2489 return Ret; 2490 } 2491 2492 LPARAM FASTCALL 2493 MsqGetMessageExtraInfo(VOID) 2494 { 2495 PTHREADINFO pti; 2496 PUSER_MESSAGE_QUEUE MessageQueue; 2497 2498 pti = PsGetCurrentThreadWin32Thread(); 2499 MessageQueue = pti->MessageQueue; 2500 if(!MessageQueue) 2501 { 2502 return 0; 2503 } 2504 2505 return MessageQueue->ExtraInfo; 2506 } 2507 2508 // ReplyMessage is called by the thread receiving the window message. 2509 BOOL FASTCALL 2510 co_MsqReplyMessage( LRESULT lResult ) 2511 { 2512 PUSER_SENT_MESSAGE Message; 2513 PTHREADINFO pti; 2514 2515 pti = PsGetCurrentThreadWin32Thread(); 2516 Message = pti->pusmCurrent; 2517 2518 if (!Message) return FALSE; 2519 2520 if (Message->QS_Flags & QS_SMRESULT) return FALSE; 2521 2522 // SendMessageXxx || Callback msg and not a notify msg 2523 if (Message->ptiSender || Message->CompletionCallback) 2524 { 2525 Message->lResult = lResult; 2526 Message->QS_Flags |= QS_SMRESULT; 2527 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away.. 2528 } 2529 return TRUE; 2530 } 2531 2532 HWND FASTCALL 2533 MsqSetStateWindow(PTHREADINFO pti, ULONG Type, HWND hWnd) 2534 { 2535 HWND Prev; 2536 PUSER_MESSAGE_QUEUE MessageQueue; 2537 2538 MessageQueue = pti->MessageQueue; 2539 2540 switch(Type) 2541 { 2542 case MSQ_STATE_CAPTURE: 2543 Prev = MessageQueue->spwndCapture ? UserHMGetHandle(MessageQueue->spwndCapture) : 0; 2544 MessageQueue->spwndCapture = ValidateHwndNoErr(hWnd); 2545 return Prev; 2546 case MSQ_STATE_ACTIVE: 2547 Prev = MessageQueue->spwndActive ? UserHMGetHandle(MessageQueue->spwndActive) : 0; 2548 MessageQueue->spwndActive = ValidateHwndNoErr(hWnd); 2549 return Prev; 2550 case MSQ_STATE_FOCUS: 2551 Prev = MessageQueue->spwndFocus ? UserHMGetHandle(MessageQueue->spwndFocus) : 0; 2552 MessageQueue->spwndFocus = ValidateHwndNoErr(hWnd); 2553 return Prev; 2554 case MSQ_STATE_MENUOWNER: 2555 Prev = MessageQueue->MenuOwner; 2556 MessageQueue->MenuOwner = hWnd; 2557 return Prev; 2558 case MSQ_STATE_MOVESIZE: 2559 Prev = MessageQueue->MoveSize; 2560 MessageQueue->MoveSize = hWnd; 2561 return Prev; 2562 case MSQ_STATE_CARET: 2563 Prev = MessageQueue->CaretInfo.hWnd; 2564 MessageQueue->CaretInfo.hWnd = hWnd; 2565 return Prev; 2566 } 2567 2568 return NULL; 2569 } 2570 2571 SHORT 2572 APIENTRY 2573 NtUserGetKeyState(INT key) 2574 { 2575 DWORD Ret; 2576 2577 UserEnterShared(); 2578 2579 Ret = UserGetKeyState(key); 2580 2581 UserLeave(); 2582 2583 return (SHORT)Ret; 2584 } 2585 2586 2587 DWORD 2588 APIENTRY 2589 NtUserGetKeyboardState(LPBYTE lpKeyState) 2590 { 2591 DWORD i, ret = TRUE; 2592 PTHREADINFO pti; 2593 PUSER_MESSAGE_QUEUE MessageQueue; 2594 2595 UserEnterShared(); 2596 2597 pti = PsGetCurrentThreadWin32Thread(); 2598 MessageQueue = pti->MessageQueue; 2599 2600 _SEH2_TRY 2601 { 2602 /* Probe and copy key state to an array */ 2603 ProbeForWrite(lpKeyState, 256 * sizeof(BYTE), 1); 2604 for (i = 0; i < 256; ++i) 2605 { 2606 lpKeyState[i] = 0; 2607 if (IS_KEY_DOWN(MessageQueue->afKeyState, i)) 2608 lpKeyState[i] |= KS_DOWN_BIT; 2609 if (IS_KEY_LOCKED(MessageQueue->afKeyState, i)) 2610 lpKeyState[i] |= KS_LOCK_BIT; 2611 } 2612 } 2613 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2614 { 2615 SetLastNtError(_SEH2_GetExceptionCode()); 2616 ret = FALSE; 2617 } 2618 _SEH2_END; 2619 2620 UserLeave(); 2621 2622 return ret; 2623 } 2624 2625 BOOL 2626 APIENTRY 2627 NtUserSetKeyboardState(LPBYTE pKeyState) 2628 { 2629 UINT i; 2630 BOOL bRet = TRUE; 2631 PTHREADINFO pti; 2632 PUSER_MESSAGE_QUEUE MessageQueue; 2633 2634 UserEnterExclusive(); 2635 2636 pti = PsGetCurrentThreadWin32Thread(); 2637 MessageQueue = pti->MessageQueue; 2638 2639 _SEH2_TRY 2640 { 2641 ProbeForRead(pKeyState, 256 * sizeof(BYTE), 1); 2642 for (i = 0; i < 256; ++i) 2643 { 2644 SET_KEY_DOWN(MessageQueue->afKeyState, i, pKeyState[i] & KS_DOWN_BIT); 2645 SET_KEY_LOCKED(MessageQueue->afKeyState, i, pKeyState[i] & KS_LOCK_BIT); 2646 } 2647 } 2648 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2649 { 2650 SetLastNtError(_SEH2_GetExceptionCode()); 2651 bRet = FALSE; 2652 } 2653 _SEH2_END; 2654 2655 UserLeave(); 2656 2657 return bRet; 2658 } 2659 2660 /* EOF */ 2661