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 CODE_SEG("INIT") 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\n"); 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 PTHREADINFO ptiSender; 1025 PUSER_SENT_MESSAGE Message; 1026 1027 if(!(Message = AllocateUserMessage(FALSE))) 1028 { 1029 ERR("MsqSendMessageAsync(): Not enough memory to allocate a message\n"); 1030 return FALSE; 1031 } 1032 1033 ptiSender = PsGetCurrentThreadWin32Thread(); 1034 1035 Message->Msg.hwnd = hwnd; 1036 Message->Msg.message = Msg; 1037 Message->Msg.wParam = wParam; 1038 Message->Msg.lParam = lParam; 1039 Message->pkCompletionEvent = NULL; // No event needed. 1040 Message->ptiReceiver = ptiReceiver; 1041 Message->ptiCallBackSender = ptiSender; 1042 Message->CompletionCallback = CompletionCallback; 1043 Message->CompletionCallbackContext = CompletionCallbackContext; 1044 Message->HookMessage = HookMessage; 1045 Message->HasPackedLParam = HasPackedLParam; 1046 Message->QS_Flags = QS_SENDMESSAGE; 1047 Message->flags = SMF_RECEIVERFREE; 1048 1049 InsertTailList(&ptiReceiver->SentMessagesListHead, &Message->ListEntry); 1050 MsqWakeQueue(ptiReceiver, QS_SENDMESSAGE, TRUE); 1051 1052 return TRUE; 1053 } 1054 1055 NTSTATUS FASTCALL 1056 co_MsqSendMessage(PTHREADINFO ptirec, 1057 HWND Wnd, 1058 UINT Msg, 1059 WPARAM wParam, 1060 LPARAM lParam, 1061 UINT uTimeout, 1062 BOOL Block, 1063 INT HookMessage, 1064 ULONG_PTR *uResult) 1065 { 1066 PTHREADINFO pti; 1067 PUSER_SENT_MESSAGE SaveMsg, Message; 1068 NTSTATUS WaitStatus; 1069 LARGE_INTEGER Timeout; 1070 PLIST_ENTRY Entry; 1071 PWND pWnd; 1072 BOOLEAN SwapStateEnabled; 1073 LRESULT Result = 0; //// Result could be trashed. //// 1074 1075 pti = PsGetCurrentThreadWin32Thread(); 1076 ASSERT(pti != ptirec); 1077 ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!! 1078 1079 /* Don't send from or to a dying thread */ 1080 if (pti->TIF_flags & TIF_INCLEANUP || ptirec->TIF_flags & TIF_INCLEANUP) 1081 { 1082 // Unless we are dying and need to tell our parents. 1083 if (pti->TIF_flags & TIF_INCLEANUP && !(ptirec->TIF_flags & TIF_INCLEANUP)) 1084 { 1085 // Parent notify is the big one. Fire and forget! 1086 TRACE("Send message from dying thread %u\n", Msg); 1087 co_MsqSendMessageAsync(ptirec, Wnd, Msg, wParam, lParam, NULL, 0, FALSE, HookMessage); 1088 } 1089 if (uResult) *uResult = -1; 1090 TRACE("MsqSM: Msg %u Current pti %lu or Rec pti %lu\n", Msg, pti->TIF_flags & TIF_INCLEANUP, ptirec->TIF_flags & TIF_INCLEANUP); 1091 return STATUS_UNSUCCESSFUL; 1092 } 1093 1094 if (IsThreadSuspended(ptirec)) 1095 { 1096 ERR("Sending to Suspended Thread Msg %lx\n",Msg); 1097 if (uResult) *uResult = -1; 1098 return STATUS_UNSUCCESSFUL; 1099 } 1100 1101 // Should we do the same for No Wait? 1102 if ( HookMessage == MSQ_NORMAL ) 1103 { 1104 pWnd = ValidateHwndNoErr(Wnd); 1105 1106 // These can not cross International Border lines! 1107 if ( pti->ppi != ptirec->ppi && pWnd ) 1108 { 1109 switch(Msg) 1110 { 1111 // Handle the special case when working with password transfers across bordering processes. 1112 case EM_GETLINE: 1113 case EM_SETPASSWORDCHAR: 1114 case WM_GETTEXT: 1115 // Look for edit controls setup for passwords. 1116 if ( gpsi->atomSysClass[ICLS_EDIT] == pWnd->pcls->atomClassName && // Use atomNVClassName. 1117 pWnd->style & ES_PASSWORD ) 1118 { 1119 if (uResult) *uResult = -1; 1120 ERR("Running across the border without a passport!\n"); 1121 EngSetLastError(ERROR_ACCESS_DENIED); 1122 return STATUS_UNSUCCESSFUL; 1123 } 1124 break; 1125 case WM_NOTIFY: 1126 if (uResult) *uResult = -1; 1127 ERR("Running across the border without a passport!\n"); 1128 return STATUS_UNSUCCESSFUL; 1129 } 1130 } 1131 1132 // These can not cross State lines! 1133 if ( Msg == WM_CREATE || Msg == WM_NCCREATE ) 1134 { 1135 if (uResult) *uResult = -1; 1136 ERR("Can not tell the other State we have Create!\n"); 1137 return STATUS_UNSUCCESSFUL; 1138 } 1139 } 1140 1141 if(!(Message = AllocateUserMessage(TRUE))) 1142 { 1143 ERR("MsqSendMessage(): Not enough memory to allocate a message\n"); 1144 if (uResult) *uResult = -1; 1145 return STATUS_INSUFFICIENT_RESOURCES; 1146 } 1147 1148 Timeout.QuadPart = Int32x32To64(-10000,uTimeout); // Pass SMTO test with a TO of 0x80000000. 1149 TRACE("Timeout val %lld\n",Timeout.QuadPart); 1150 1151 Message->Msg.hwnd = Wnd; 1152 Message->Msg.message = Msg; 1153 Message->Msg.wParam = wParam; 1154 Message->Msg.lParam = lParam; 1155 Message->ptiReceiver = ptirec; 1156 Message->ptiSender = pti; 1157 Message->HookMessage = HookMessage; 1158 Message->QS_Flags = QS_SENDMESSAGE; 1159 1160 SaveMsg = pti->pusmSent; 1161 pti->pusmSent = Message; 1162 1163 /* Queue it in the destination's message queue */ 1164 InsertTailList(&ptirec->SentMessagesListHead, &Message->ListEntry); 1165 1166 MsqWakeQueue(ptirec, QS_SENDMESSAGE, TRUE); 1167 1168 // First time in, turn off swapping of the stack. 1169 if (pti->cEnterCount == 0) 1170 { 1171 SwapStateEnabled = KeSetKernelStackSwapEnable(FALSE); 1172 } 1173 pti->cEnterCount++; 1174 1175 if (Block) 1176 { 1177 PVOID WaitObjects[2]; 1178 1179 WaitObjects[0] = Message->pkCompletionEvent; // Wait 0 1180 WaitObjects[1] = ptirec->pEThread; // Wait 1 1181 1182 UserLeaveCo(); 1183 1184 WaitStatus = KeWaitForMultipleObjects( 2, 1185 WaitObjects, 1186 WaitAny, 1187 UserRequest, 1188 UserMode, 1189 FALSE, 1190 (uTimeout ? &Timeout : NULL), 1191 NULL ); 1192 1193 UserEnterCo(); 1194 1195 if (WaitStatus == STATUS_TIMEOUT) 1196 { 1197 /* Look up if the message has not yet dispatched, if so 1198 make sure it can't pass a result and it must not set the completion event anymore */ 1199 Entry = ptirec->SentMessagesListHead.Flink; 1200 while (Entry != &ptirec->SentMessagesListHead) 1201 { 1202 if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message) 1203 { 1204 Message->pkCompletionEvent = NULL; 1205 RemoveEntryList(&Message->ListEntry); 1206 ClearMsgBitsMask(ptirec, Message->QS_Flags); 1207 InsertTailList(&usmList, &Message->ListEntry); 1208 break; 1209 } 1210 Entry = Entry->Flink; 1211 } 1212 1213 ERR("MsqSendMessage (blocked) timed out 1 Status %lx\n", WaitStatus); 1214 } 1215 // Receiving thread passed on and left us hanging with issues still pending. 1216 else if (WaitStatus == STATUS_WAIT_1) 1217 { 1218 ERR("Bk Receiving Thread woken up dead!\n"); 1219 Message->flags |= SMF_RECEIVERDIED; 1220 } 1221 1222 while (co_MsqDispatchOneSentMessage(pti)) 1223 ; 1224 } 1225 else 1226 { 1227 PVOID WaitObjects[3]; 1228 1229 WaitObjects[0] = Message->pkCompletionEvent; // Wait 0 1230 WaitObjects[1] = pti->pEventQueueServer; // Wait 1 1231 WaitObjects[2] = ptirec->pEThread; // Wait 2 1232 1233 do 1234 { 1235 UserLeaveCo(); 1236 1237 WaitStatus = KeWaitForMultipleObjects( 3, 1238 WaitObjects, 1239 WaitAny, 1240 UserRequest, 1241 UserMode, 1242 FALSE, 1243 (uTimeout ? &Timeout : NULL), 1244 NULL); 1245 1246 UserEnterCo(); 1247 1248 if (WaitStatus == STATUS_TIMEOUT) 1249 { 1250 /* Look up if the message has not yet been dispatched, if so 1251 make sure it can't pass a result and it must not set the completion event anymore */ 1252 Entry = ptirec->SentMessagesListHead.Flink; 1253 while (Entry != &ptirec->SentMessagesListHead) 1254 { 1255 if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message) 1256 { 1257 Message->pkCompletionEvent = NULL; 1258 RemoveEntryList(&Message->ListEntry); 1259 ClearMsgBitsMask(ptirec, Message->QS_Flags); 1260 InsertTailList(&usmList, &Message->ListEntry); 1261 break; 1262 } 1263 Entry = Entry->Flink; 1264 } 1265 1266 ERR("MsqSendMessage timed out 2 Status %lx\n", WaitStatus); 1267 break; 1268 } 1269 // Receiving thread passed on and left us hanging with issues still pending. 1270 else if (WaitStatus == STATUS_WAIT_2) 1271 { 1272 ERR("NB Receiving Thread woken up dead!\n"); 1273 Message->flags |= SMF_RECEIVERDIED; 1274 break; 1275 } 1276 1277 if (WaitStatus == STATUS_USER_APC) break; 1278 1279 while (co_MsqDispatchOneSentMessage(pti)) 1280 ; 1281 } while (WaitStatus == STATUS_WAIT_1); 1282 } 1283 1284 // Count is nil, restore swapping of the stack. 1285 if (--pti->cEnterCount == 0 ) 1286 { 1287 KeSetKernelStackSwapEnable(SwapStateEnabled); 1288 } 1289 1290 // Handle User APC 1291 if (WaitStatus == STATUS_USER_APC) 1292 { 1293 // The current thread is dying! 1294 TRACE("User APC\n"); 1295 1296 // The Message will be on the Trouble list until Thread cleanup. 1297 Message->flags |= SMF_SENDERDIED; 1298 1299 co_IntDeliverUserAPC(); 1300 ERR("User APC Returned\n"); // Should not see this message. 1301 } 1302 1303 // Force this thread to wake up for the next go around. 1304 KeSetEvent(pti->pEventQueueServer, IO_NO_INCREMENT, FALSE); 1305 1306 Result = Message->lResult; 1307 1308 // Determine whether this message is being processed or not. 1309 if ((Message->flags & (SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE) 1310 { 1311 Message->flags |= SMF_RECEIVERFREE; 1312 } 1313 1314 if (!(Message->flags & SMF_RECEIVERFREE)) 1315 { 1316 TRACE("Sender Freeing Message %p ptirec %p bit %d list empty %d\n",Message,ptirec,!!(ptirec->pcti->fsChangeBits & QS_SENDMESSAGE),IsListEmpty(&ptirec->SentMessagesListHead)); 1317 // Make it to this point, the message was received. 1318 FreeUserMessage(Message); 1319 } 1320 1321 pti->pusmSent = SaveMsg; 1322 1323 TRACE("MSM Allocation Count %d Status %lx Result %d\n",SendMsgCount,WaitStatus,Result); 1324 1325 if (WaitStatus != STATUS_TIMEOUT) 1326 { 1327 if (uResult) 1328 { 1329 *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : 0); 1330 } 1331 } 1332 1333 return WaitStatus; 1334 } 1335 1336 VOID FASTCALL 1337 MsqPostMessage(PTHREADINFO pti, 1338 MSG* Msg, 1339 BOOLEAN HardwareMessage, 1340 DWORD MessageBits, 1341 DWORD dwQEvent, 1342 LONG_PTR ExtraInfo) 1343 { 1344 PUSER_MESSAGE Message; 1345 PUSER_MESSAGE_QUEUE MessageQueue; 1346 1347 MessageQueue = pti->MessageQueue; 1348 1349 if ((pti->TIF_flags & TIF_INCLEANUP) || (MessageQueue->QF_flags & QF_INDESTROY)) 1350 { 1351 ERR("Post Msg; Thread or Q is Dead!\n"); 1352 return; 1353 } 1354 1355 Message = MsqCreateMessage(Msg); 1356 if (!Message) 1357 return; 1358 1359 if (Msg->message == WM_HOTKEY) 1360 MessageBits |= QS_HOTKEY; 1361 1362 Message->dwQEvent = dwQEvent; 1363 Message->ExtraInfo = ExtraInfo; 1364 Message->QS_Flags = MessageBits; 1365 Message->pti = pti; 1366 1367 if (!HardwareMessage) 1368 { 1369 InsertTailList(&pti->PostedMessagesListHead, &Message->ListEntry); 1370 } 1371 else 1372 { 1373 InsertTailList(&MessageQueue->HardwareMessagesListHead, &Message->ListEntry); 1374 } 1375 1376 MsqWakeQueue(pti, MessageBits, TRUE); 1377 TRACE("Post Message %d\n", PostMsgCount); 1378 } 1379 1380 VOID FASTCALL 1381 MsqPostQuitMessage(PTHREADINFO pti, ULONG ExitCode) 1382 { 1383 pti->QuitPosted = TRUE; 1384 pti->exitCode = ExitCode; 1385 MsqWakeQueue(pti, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE); 1386 } 1387 1388 /*********************************************************************** 1389 * MsqSendParentNotify 1390 * 1391 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless 1392 * the window has the WS_EX_NOPARENTNOTIFY style. 1393 */ 1394 static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt ) 1395 { 1396 PWND pwndDesktop = UserGetDesktopWindow(); 1397 1398 /* pt has to be in the client coordinates of the parent window */ 1399 pt.x += pwndDesktop->rcClient.left - pwnd->rcClient.left; 1400 pt.y += pwndDesktop->rcClient.top - pwnd->rcClient.top; 1401 1402 for (;;) 1403 { 1404 PWND pwndParent; 1405 1406 if (!(pwnd->style & WS_CHILD)) break; 1407 if (pwnd->ExStyle & WS_EX_NOPARENTNOTIFY) break; 1408 if (!(pwndParent = IntGetParent(pwnd))) break; 1409 if (pwndParent == pwndDesktop) break; 1410 pt.x += pwnd->rcClient.left - pwndParent->rcClient.left; 1411 pt.y += pwnd->rcClient.top - pwndParent->rcClient.top; 1412 1413 pwnd = pwndParent; 1414 co_IntSendMessage( UserHMGetHandle(pwnd), WM_PARENTNOTIFY, 1415 MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) ); 1416 } 1417 } 1418 1419 VOID 1420 FASTCALL 1421 IntTrackMouseMove(PWND pwndTrack, PDESKTOP pDesk, PMSG msg, USHORT hittest) 1422 { 1423 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y); 1424 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this??? 1425 1426 if ( pDesk->spwndTrack != pwndTrack || // Change with tracking window or 1427 msg->message != WM_MOUSEMOVE || // Mouse click changes or 1428 pDesk->htEx != hittest) // Change in current hit test states. 1429 { 1430 TRACE("ITMM: Track Mouse Move!\n"); 1431 1432 /* Handle only the changing window track and mouse move across a border. */ 1433 if ( pDesk->spwndTrack != pwndTrack || 1434 (pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT) ) 1435 { 1436 TRACE("ITMM: Another Wnd %d or Across Border %d\n", 1437 pDesk->spwndTrack != pwndTrack,(pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT)); 1438 1439 if ( pDesk->dwDTFlags & DF_TME_LEAVE ) 1440 UserPostMessage( UserHMGetHandle(pDesk->spwndTrack), 1441 (pDesk->htEx != HTCLIENT) ? WM_NCMOUSELEAVE : WM_MOUSELEAVE, 1442 0, 0); 1443 1444 if ( pDesk->dwDTFlags & DF_TME_HOVER ) 1445 IntKillTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE); 1446 1447 /* Clear the flags to sign a change. */ 1448 pDesk->dwDTFlags &= ~(DF_TME_LEAVE|DF_TME_HOVER); 1449 } 1450 /* Set the Track window and hit test. */ 1451 pDesk->spwndTrack = pwndTrack; 1452 pDesk->htEx = hittest; 1453 } 1454 1455 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */ 1456 if ( pDesk->spwndTrack == pwndTrack && 1457 ( msg->message != WM_MOUSEMOVE || !RECTL_bPointInRect(&pDesk->rcMouseHover, msg->pt.x, msg->pt.y)) && 1458 pDesk->dwDTFlags & DF_TME_HOVER ) 1459 { 1460 TRACE("ITMM: Reset Hover points!\n"); 1461 // Restart timer for the hover period. 1462 IntSetTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM); 1463 // Reset desktop mouse hover from the system default hover rectangle. 1464 RECTL_vSetRect(&pDesk->rcMouseHover, 1465 msg->pt.x - gspv.iMouseHoverWidth / 2, 1466 msg->pt.y - gspv.iMouseHoverHeight / 2, 1467 msg->pt.x + gspv.iMouseHoverWidth / 2, 1468 msg->pt.y + gspv.iMouseHoverHeight / 2); 1469 } 1470 } 1471 1472 BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, BOOL* NotForUs, LONG_PTR ExtraInfo, UINT first, UINT last) 1473 { 1474 MSG clk_msg; 1475 POINT pt; 1476 UINT message; 1477 USHORT hittest; 1478 EVENTMSG event; 1479 MOUSEHOOKSTRUCT hook; 1480 BOOL eatMsg = FALSE; 1481 1482 PWND pwndMsg, pwndDesktop; 1483 PUSER_MESSAGE_QUEUE MessageQueue; 1484 PTHREADINFO pti; 1485 PSYSTEM_CURSORINFO CurInfo; 1486 PDESKTOP pDesk; 1487 1488 pti = PsGetCurrentThreadWin32Thread(); 1489 pwndDesktop = UserGetDesktopWindow(); 1490 MessageQueue = pti->MessageQueue; 1491 CurInfo = IntGetSysCursorInfo(); 1492 pwndMsg = ValidateHwndNoErr(msg->hwnd); 1493 clk_msg = MessageQueue->msgDblClk; 1494 pDesk = pwndDesktop->head.rpdesk; 1495 1496 /* find the window to dispatch this mouse message to */ 1497 if (MessageQueue->spwndCapture) 1498 { 1499 hittest = HTCLIENT; 1500 pwndMsg = MessageQueue->spwndCapture; 1501 } 1502 else 1503 { 1504 /* 1505 Start with null window. See wine win.c:test_mouse_input:WM_COMMAND tests. 1506 */ 1507 pwndMsg = co_WinPosWindowFromPoint( NULL, &msg->pt, &hittest, FALSE); 1508 } 1509 1510 TRACE("Got mouse message for %p, hittest: 0x%x\n", msg->hwnd, hittest); 1511 1512 // Null window or not the same "Hardware" message queue. 1513 if (pwndMsg == NULL || pwndMsg->head.pti->MessageQueue != MessageQueue) 1514 { 1515 // Crossing a boundary, so set cursor. See default message queue cursor. 1516 IntSystemSetCursor(SYSTEMCUR(ARROW)); 1517 /* Remove and ignore the message */ 1518 *RemoveMessages = TRUE; 1519 return FALSE; 1520 } 1521 1522 // Check to see if this is attached, 1523 if ( pwndMsg->head.pti != pti && // window thread is not current, 1524 MessageQueue->cThreads > 1 ) // and is attached... 1525 { 1526 // This is not for us and we should leave so the other thread can check for messages!!! 1527 *NotForUs = TRUE; 1528 *RemoveMessages = FALSE; 1529 return FALSE; 1530 } 1531 1532 if ( MessageQueue == gpqCursor ) // Cursor must use the same Queue! 1533 { 1534 IntTrackMouseMove(pwndMsg, pDesk, msg, hittest); 1535 } 1536 else 1537 { 1538 ERR("Not the same cursor!\n"); 1539 } 1540 1541 msg->hwnd = UserHMGetHandle(pwndMsg); 1542 1543 pt = msg->pt; 1544 message = msg->message; 1545 1546 /* Note: windows has no concept of a non-client wheel message */ 1547 if (message != WM_MOUSEWHEEL) 1548 { 1549 if (hittest != HTCLIENT) 1550 { 1551 message += WM_NCMOUSEMOVE - WM_MOUSEMOVE; 1552 msg->wParam = hittest; // Caution! This might break wParam check in DblClk. 1553 } 1554 else 1555 { 1556 /* coordinates don't get translated while tracking a menu */ 1557 /* FIXME: should differentiate popups and top-level menus */ 1558 if (!(MessageQueue->MenuOwner)) 1559 { 1560 pt.x += pwndDesktop->rcClient.left - pwndMsg->rcClient.left; 1561 pt.y += pwndDesktop->rcClient.top - pwndMsg->rcClient.top; 1562 } 1563 } 1564 } 1565 msg->lParam = MAKELONG( pt.x, pt.y ); 1566 1567 /* translate double clicks */ 1568 1569 if ((msg->message == WM_LBUTTONDOWN) || 1570 (msg->message == WM_RBUTTONDOWN) || 1571 (msg->message == WM_MBUTTONDOWN) || 1572 (msg->message == WM_XBUTTONDOWN)) 1573 { 1574 BOOL update = *RemoveMessages; 1575 1576 /* translate double clicks - 1577 * note that ...MOUSEMOVEs can slip in between 1578 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */ 1579 1580 if ((MessageQueue->MenuOwner || MessageQueue->MoveSize) || 1581 hittest != HTCLIENT || 1582 (pwndMsg->pcls->style & CS_DBLCLKS)) 1583 { 1584 if ((msg->message == clk_msg.message) && 1585 (msg->hwnd == clk_msg.hwnd) && 1586 // Only worry about XButton wParam. 1587 (msg->message != WM_XBUTTONDOWN || GET_XBUTTON_WPARAM(msg->wParam) == GET_XBUTTON_WPARAM(clk_msg.wParam)) && 1588 ((msg->time - clk_msg.time) < (ULONG)gspv.iDblClickTime) && 1589 (abs(msg->pt.x - clk_msg.pt.x) < UserGetSystemMetrics(SM_CXDOUBLECLK)/2) && 1590 (abs(msg->pt.y - clk_msg.pt.y) < UserGetSystemMetrics(SM_CYDOUBLECLK)/2)) 1591 { 1592 message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN); 1593 if (update) 1594 { 1595 MessageQueue->msgDblClk.message = 0; /* clear the double click conditions */ 1596 update = FALSE; 1597 } 1598 } 1599 } 1600 1601 if (!((first == 0 && last == 0) || (message >= first || message <= last))) 1602 { 1603 TRACE("Message out of range!!!\n"); 1604 return FALSE; 1605 } 1606 1607 /* update static double click conditions */ 1608 if (update) MessageQueue->msgDblClk = *msg; 1609 } 1610 else 1611 { 1612 if (!((first == 0 && last == 0) || (message >= first || message <= last))) 1613 { 1614 TRACE("Message out of range!!!\n"); 1615 return FALSE; 1616 } 1617 1618 // Update mouse move down keys. 1619 if (message == WM_MOUSEMOVE) 1620 { 1621 msg->wParam = MsqGetDownKeyState(MessageQueue); 1622 } 1623 } 1624 1625 if (gspv.bMouseClickLock) 1626 { 1627 BOOL IsClkLck = FALSE; 1628 1629 if(msg->message == WM_LBUTTONUP) 1630 { 1631 IsClkLck = ((msg->time - CurInfo->ClickLockTime) >= gspv.dwMouseClickLockTime); 1632 if (IsClkLck && (!CurInfo->ClickLockActive)) 1633 { 1634 CurInfo->ClickLockActive = TRUE; 1635 } 1636 } 1637 else if (msg->message == WM_LBUTTONDOWN) 1638 { 1639 if (CurInfo->ClickLockActive) 1640 { 1641 IsClkLck = TRUE; 1642 CurInfo->ClickLockActive = FALSE; 1643 } 1644 1645 CurInfo->ClickLockTime = msg->time; 1646 } 1647 1648 if(IsClkLck) 1649 { 1650 /* Remove and ignore the message */ 1651 *RemoveMessages = TRUE; 1652 TRACE("Remove and ignore the message\n"); 1653 return FALSE; 1654 } 1655 } 1656 1657 if (pti->TIF_flags & TIF_MSGPOSCHANGED) 1658 { 1659 pti->TIF_flags &= ~TIF_MSGPOSCHANGED; 1660 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, NULL, OBJID_CLIENT, CHILDID_SELF, 0); 1661 } 1662 1663 /* message is accepted now (but still get dropped) */ 1664 1665 event.message = msg->message; 1666 event.time = msg->time; 1667 event.hwnd = msg->hwnd; 1668 event.paramL = msg->pt.x; 1669 event.paramH = msg->pt.y; 1670 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event ); 1671 1672 hook.pt = msg->pt; 1673 hook.hwnd = msg->hwnd; 1674 hook.wHitTestCode = hittest; 1675 hook.dwExtraInfo = ExtraInfo; 1676 if (co_HOOK_CallHooks( WH_MOUSE, *RemoveMessages ? HC_ACTION : HC_NOREMOVE, 1677 message, (LPARAM)&hook )) 1678 { 1679 hook.pt = msg->pt; 1680 hook.hwnd = msg->hwnd; 1681 hook.wHitTestCode = hittest; 1682 hook.dwExtraInfo = ExtraInfo; 1683 co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook ); 1684 1685 ERR("WH_MOUSE dropped mouse message!\n"); 1686 1687 /* Remove and skip message */ 1688 *RemoveMessages = TRUE; 1689 return FALSE; 1690 } 1691 1692 if ((hittest == (USHORT)HTERROR) || (hittest == (USHORT)HTNOWHERE)) 1693 { 1694 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message )); 1695 1696 /* Remove and skip message */ 1697 *RemoveMessages = TRUE; 1698 return FALSE; 1699 } 1700 1701 if ((*RemoveMessages == FALSE) || MessageQueue->spwndCapture) 1702 { 1703 /* Accept the message */ 1704 msg->message = message; 1705 return TRUE; 1706 } 1707 1708 if ((msg->message == WM_LBUTTONDOWN) || 1709 (msg->message == WM_RBUTTONDOWN) || 1710 (msg->message == WM_MBUTTONDOWN) || 1711 (msg->message == WM_XBUTTONDOWN)) 1712 { 1713 /* Send the WM_PARENTNOTIFY, 1714 * note that even for double/nonclient clicks 1715 * notification message is still WM_L/M/RBUTTONDOWN. 1716 */ 1717 MsqSendParentNotify(pwndMsg, msg->message, 0, msg->pt ); 1718 1719 /* Activate the window if needed */ 1720 1721 if (pwndMsg != MessageQueue->spwndActive) 1722 { 1723 PWND pwndTop = pwndMsg; 1724 pwndTop = IntGetNonChildAncestor(pwndTop); 1725 1726 TRACE("Mouse pti %p pwndMsg pti %p pwndTop pti %p\n",MessageQueue->ptiMouse,pwndMsg->head.pti,pwndTop->head.pti); 1727 1728 if (pwndTop && pwndTop != pwndDesktop) 1729 { 1730 LONG ret = co_IntSendMessage( msg->hwnd, 1731 WM_MOUSEACTIVATE, 1732 (WPARAM)UserHMGetHandle(pwndTop), 1733 MAKELONG( hittest, msg->message)); 1734 switch(ret) 1735 { 1736 case MA_NOACTIVATEANDEAT: 1737 eatMsg = TRUE; 1738 /* fall through */ 1739 case MA_NOACTIVATE: 1740 break; 1741 case MA_ACTIVATEANDEAT: 1742 eatMsg = TRUE; 1743 /* fall through */ 1744 case MA_ACTIVATE: 1745 case 0: 1746 if (!co_IntMouseActivateWindow( pwndTop )) eatMsg = TRUE; 1747 break; 1748 default: 1749 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret ); 1750 break; 1751 } 1752 } 1753 } 1754 } 1755 1756 /* send the WM_SETCURSOR message */ 1757 1758 /* Windows sends the normal mouse message as the message parameter 1759 in the WM_SETCURSOR message even if it's non-client mouse message */ 1760 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message )); 1761 1762 msg->message = message; 1763 return !eatMsg; 1764 } 1765 1766 BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages) 1767 { 1768 EVENTMSG Event; 1769 USER_REFERENCE_ENTRY Ref; 1770 PWND pWnd; 1771 UINT ImmRet; 1772 BOOL Ret = TRUE; 1773 WPARAM wParam = Msg->wParam; 1774 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1775 1776 if (Msg->message == VK_PACKET) 1777 { 1778 pti->wchInjected = HIWORD(Msg->wParam); 1779 } 1780 1781 if (Msg->message == WM_KEYDOWN || Msg->message == WM_SYSKEYDOWN || 1782 Msg->message == WM_KEYUP || Msg->message == WM_SYSKEYUP) 1783 { 1784 switch (Msg->wParam) 1785 { 1786 case VK_LSHIFT: case VK_RSHIFT: 1787 Msg->wParam = VK_SHIFT; 1788 break; 1789 case VK_LCONTROL: case VK_RCONTROL: 1790 Msg->wParam = VK_CONTROL; 1791 break; 1792 case VK_LMENU: case VK_RMENU: 1793 Msg->wParam = VK_MENU; 1794 break; 1795 } 1796 } 1797 1798 pWnd = ValidateHwndNoErr(Msg->hwnd); 1799 if (pWnd) UserRefObjectCo(pWnd, &Ref); 1800 1801 Event.message = Msg->message; 1802 Event.hwnd = Msg->hwnd; 1803 Event.time = Msg->time; 1804 Event.paramL = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8); 1805 Event.paramH = Msg->lParam & 0x7FFF; 1806 if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000; 1807 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event); 1808 1809 if (*RemoveMessages) 1810 { 1811 if ((Msg->message == WM_KEYDOWN) && 1812 (Msg->hwnd != IntGetDesktopWindow())) 1813 { 1814 /* Handle F1 key by sending out WM_HELP message */ 1815 if (Msg->wParam == VK_F1) 1816 { 1817 UserPostMessage( Msg->hwnd, WM_KEYF1, 0, 0 ); 1818 } 1819 else if (Msg->wParam >= VK_BROWSER_BACK && 1820 Msg->wParam <= VK_LAUNCH_APP2) 1821 { 1822 /* FIXME: Process keystate */ 1823 co_IntSendMessage(Msg->hwnd, WM_APPCOMMAND, (WPARAM)Msg->hwnd, MAKELPARAM(0, (FAPPCOMMAND_KEY | (Msg->wParam - VK_BROWSER_BACK + 1)))); 1824 } 1825 } 1826 else if (Msg->message == WM_KEYUP) 1827 { 1828 /* Handle VK_APPS key by posting a WM_CONTEXTMENU message */ 1829 if (Msg->wParam == VK_APPS && pti->MessageQueue->MenuOwner == NULL) 1830 UserPostMessage( Msg->hwnd, WM_CONTEXTMENU, (WPARAM)Msg->hwnd, -1 ); 1831 } 1832 } 1833 1834 //// Key Down! 1835 if ( *RemoveMessages && Msg->message == WM_SYSKEYDOWN ) 1836 { 1837 if ( HIWORD(Msg->lParam) & KF_ALTDOWN ) 1838 { 1839 if ( Msg->wParam == VK_ESCAPE || Msg->wParam == VK_TAB ) // Alt-Tab/ESC Alt-Shift-Tab/ESC 1840 { 1841 WPARAM wParamTmp; 1842 1843 wParamTmp = UserGetKeyState(VK_SHIFT) & 0x8000 ? SC_PREVWINDOW : SC_NEXTWINDOW; 1844 TRACE("Send WM_SYSCOMMAND Alt-Tab/ESC Alt-Shift-Tab/ESC\n"); 1845 co_IntSendMessage( Msg->hwnd, WM_SYSCOMMAND, wParamTmp, Msg->wParam ); 1846 1847 //// Keep looping. 1848 Ret = FALSE; 1849 //// Skip the rest. 1850 goto Exit; 1851 } 1852 } 1853 } 1854 1855 if ( *RemoveMessages && (Msg->message == WM_SYSKEYDOWN || Msg->message == WM_KEYDOWN) ) 1856 { 1857 if (gdwLanguageToggleKey < 3) 1858 { 1859 if (IS_KEY_DOWN(gafAsyncKeyState, gdwLanguageToggleKey == 1 ? VK_LMENU : VK_CONTROL)) // L Alt 1 or Ctrl 2 . 1860 { 1861 if ( wParam == VK_LSHIFT ) gLanguageToggleKeyState = INPUTLANGCHANGE_FORWARD; // Left Alt - Left Shift, Next 1862 //// FIXME : It seems to always be VK_LSHIFT. 1863 if ( wParam == VK_RSHIFT ) gLanguageToggleKeyState = INPUTLANGCHANGE_BACKWARD; // Left Alt - Right Shift, Previous 1864 } 1865 } 1866 } 1867 1868 //// Key Up! Alt Key Ctrl Key 1869 if ( *RemoveMessages && (Msg->message == WM_SYSKEYUP || Msg->message == WM_KEYUP) ) 1870 { 1871 // When initializing win32k: Reading from the registry hotkey combination 1872 // to switch the keyboard layout and store it to global variable. 1873 // Using this combination of hotkeys in this function 1874 1875 if ( gdwLanguageToggleKey < 3 && 1876 IS_KEY_DOWN(gafAsyncKeyState, gdwLanguageToggleKey == 1 ? VK_LMENU : VK_CONTROL) ) 1877 { 1878 if ( Msg->wParam == VK_SHIFT && !(IS_KEY_DOWN(gafAsyncKeyState, VK_SHIFT))) 1879 { 1880 WPARAM wParamILR; 1881 PKL pkl = pti->KeyboardLayout; 1882 1883 if (pWnd) UserDerefObjectCo(pWnd); 1884 1885 //// Seems to override message window. 1886 if (!(pWnd = pti->MessageQueue->spwndFocus)) 1887 { 1888 pWnd = pti->MessageQueue->spwndActive; 1889 } 1890 if (pWnd) UserRefObjectCo(pWnd, &Ref); 1891 1892 if (pkl != NULL && gLanguageToggleKeyState) 1893 { 1894 TRACE("Posting WM_INPUTLANGCHANGEREQUEST KeyState %d\n", gLanguageToggleKeyState ); 1895 1896 wParamILR = gLanguageToggleKeyState; 1897 // If system character set and font signature send flag. 1898 if ( gSystemFS & pkl->dwFontSigs ) 1899 { 1900 wParamILR |= INPUTLANGCHANGE_SYSCHARSET; 1901 } 1902 1903 UserPostMessage( UserHMGetHandle(pWnd), 1904 WM_INPUTLANGCHANGEREQUEST, 1905 wParamILR, 1906 (LPARAM)pkl->hkl ); 1907 1908 gLanguageToggleKeyState = 0; 1909 //// Keep looping. 1910 Ret = FALSE; 1911 //// Skip the rest. 1912 goto Exit; 1913 } 1914 } 1915 } 1916 } 1917 1918 if (co_HOOK_CallHooks( WH_KEYBOARD, 1919 *RemoveMessages ? HC_ACTION : HC_NOREMOVE, 1920 LOWORD(Msg->wParam), 1921 Msg->lParam)) 1922 { 1923 /* skip this message */ 1924 co_HOOK_CallHooks( WH_CBT, 1925 HCBT_KEYSKIPPED, 1926 LOWORD(Msg->wParam), 1927 Msg->lParam ); 1928 1929 ERR("KeyboardMessage WH_KEYBOARD Call Hook return!\n"); 1930 1931 *RemoveMessages = TRUE; 1932 1933 Ret = FALSE; 1934 } 1935 1936 if ( pWnd && Ret && *RemoveMessages && Msg->message == WM_KEYDOWN && !(pti->TIF_flags & TIF_DISABLEIME)) 1937 { 1938 if ( (ImmRet = IntImmProcessKey(pti->MessageQueue, pWnd, Msg->message, Msg->wParam, Msg->lParam)) ) 1939 { 1940 if ( ImmRet & (IPHK_HOTKEY|IPHK_SKIPTHISKEY) ) 1941 { 1942 ImmRet = 0; 1943 } 1944 if ( ImmRet & IPHK_PROCESSBYIME ) 1945 { 1946 Msg->wParam = VK_PROCESSKEY; 1947 } 1948 } 1949 } 1950 Exit: 1951 if (pWnd) UserDerefObjectCo(pWnd); 1952 return Ret; 1953 } 1954 1955 BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, BOOL* NotForUs, LONG_PTR ExtraInfo, UINT first, UINT last) 1956 { 1957 if ( IS_MOUSE_MESSAGE(Msg->message)) 1958 { 1959 return co_IntProcessMouseMessage(Msg, RemoveMessages, NotForUs, ExtraInfo, first, last); 1960 } 1961 else if ( IS_KBD_MESSAGE(Msg->message)) 1962 { 1963 return co_IntProcessKeyboardMessage(Msg, RemoveMessages); 1964 } 1965 1966 return TRUE; 1967 } 1968 1969 /* check whether a message filter contains at least one potential hardware message */ 1970 static INT FASTCALL 1971 filter_contains_hw_range( UINT first, UINT last ) 1972 { 1973 /* hardware message ranges are (in numerical order): 1974 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST 1975 * WM_KEYFIRST .. WM_KEYLAST 1976 * WM_MOUSEFIRST .. WM_MOUSELAST 1977 */ 1978 if (!last) --last; 1979 if (last < WM_NCMOUSEFIRST) return 0; 1980 if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0; 1981 if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0; 1982 if (first > WM_MOUSELAST) return 0; 1983 return 1; 1984 } 1985 1986 /* check whether message is in the range of mouse messages */ 1987 static inline BOOL is_mouse_message( UINT message ) 1988 { 1989 return ( //( message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST ) || This seems to break tests... 1990 ( message >= WM_MOUSEFIRST && message <= WM_MOUSELAST ) || 1991 ( message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK ) || 1992 ( message >= WM_MBUTTONDOWN && message <= WM_MBUTTONDBLCLK ) || 1993 ( message >= WM_LBUTTONDOWN && message <= WM_RBUTTONDBLCLK ) ); 1994 } 1995 1996 BOOL APIENTRY 1997 co_MsqPeekHardwareMessage(IN PTHREADINFO pti, 1998 IN BOOL Remove, 1999 IN PWND Window, 2000 IN UINT MsgFilterLow, 2001 IN UINT MsgFilterHigh, 2002 IN UINT QSflags, 2003 OUT MSG* pMsg) 2004 { 2005 BOOL AcceptMessage, NotForUs; 2006 PUSER_MESSAGE CurrentMessage; 2007 PLIST_ENTRY ListHead; 2008 MSG msg; 2009 ULONG_PTR idSave; 2010 DWORD QS_Flags; 2011 LONG_PTR ExtraInfo; 2012 BOOL Ret = FALSE; 2013 PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue; 2014 2015 if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE; 2016 2017 ListHead = MessageQueue->HardwareMessagesListHead.Flink; 2018 2019 if (IsListEmpty(ListHead)) return FALSE; 2020 2021 if (!MessageQueue->ptiSysLock) 2022 { 2023 MessageQueue->ptiSysLock = pti; 2024 pti->pcti->CTI_flags |= CTI_THREADSYSLOCK; 2025 } 2026 2027 if (MessageQueue->ptiSysLock != pti) 2028 { 2029 ERR("Thread Q is locked to ptiSysLock 0x%p pti 0x%p\n",MessageQueue->ptiSysLock,pti); 2030 return FALSE; 2031 } 2032 2033 while (ListHead != &MessageQueue->HardwareMessagesListHead) 2034 { 2035 CurrentMessage = CONTAINING_RECORD(ListHead, USER_MESSAGE, ListEntry); 2036 ListHead = ListHead->Flink; 2037 2038 if (MessageQueue->idSysPeek == (ULONG_PTR)CurrentMessage) 2039 { 2040 TRACE("Skip this message due to it is in play!\n"); 2041 continue; 2042 } 2043 /* 2044 MSDN: 2045 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL. 2046 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL. 2047 3: handle to the window whose messages are to be retrieved. 2048 */ 2049 if ( ( !Window || // 1 2050 ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2 2051 ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) || // 3 2052 ( is_mouse_message(CurrentMessage->Msg.message) ) ) && // Null window for anything mouse. 2053 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) || 2054 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) ) 2055 { 2056 idSave = MessageQueue->idSysPeek; 2057 MessageQueue->idSysPeek = (ULONG_PTR)CurrentMessage; 2058 2059 msg = CurrentMessage->Msg; 2060 ExtraInfo = CurrentMessage->ExtraInfo; 2061 QS_Flags = CurrentMessage->QS_Flags; 2062 2063 NotForUs = FALSE; 2064 2065 UpdateKeyStateFromMsg(MessageQueue, &msg); 2066 AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, &NotForUs, ExtraInfo, MsgFilterLow, MsgFilterHigh); 2067 2068 if (Remove) 2069 { 2070 if (CurrentMessage->pti != NULL && (MessageQueue->idSysPeek == (ULONG_PTR)CurrentMessage)) 2071 { 2072 MsqDestroyMessage(CurrentMessage); 2073 } 2074 ClearMsgBitsMask(pti, QS_Flags); 2075 } 2076 2077 MessageQueue->idSysPeek = idSave; 2078 2079 if (NotForUs) 2080 { 2081 Ret = FALSE; 2082 break; 2083 } 2084 2085 if (AcceptMessage) 2086 { 2087 *pMsg = msg; 2088 // Fix all but one wine win:test_GetMessagePos WM_TIMER tests. See PostTimerMessages. 2089 if (!RtlEqualMemory(&pti->ptLast, &msg.pt, sizeof(POINT))) 2090 { 2091 pti->TIF_flags |= TIF_MSGPOSCHANGED; 2092 } 2093 pti->timeLast = msg.time; 2094 pti->ptLast = msg.pt; 2095 MessageQueue->ExtraInfo = ExtraInfo; 2096 Ret = TRUE; 2097 break; 2098 } 2099 } 2100 } 2101 2102 MessageQueue->ptiSysLock = NULL; 2103 pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK; 2104 return Ret; 2105 } 2106 2107 BOOLEAN APIENTRY 2108 MsqPeekMessage(IN PTHREADINFO pti, 2109 IN BOOLEAN Remove, 2110 IN PWND Window, 2111 IN UINT MsgFilterLow, 2112 IN UINT MsgFilterHigh, 2113 IN UINT QSflags, 2114 OUT LONG_PTR *ExtraInfo, 2115 OUT DWORD *dwQEvent, 2116 OUT PMSG Message) 2117 { 2118 PUSER_MESSAGE CurrentMessage; 2119 PLIST_ENTRY ListHead; 2120 DWORD QS_Flags; 2121 BOOL Ret = FALSE; 2122 2123 ListHead = pti->PostedMessagesListHead.Flink; 2124 2125 if (IsListEmpty(ListHead)) return FALSE; 2126 2127 while(ListHead != &pti->PostedMessagesListHead) 2128 { 2129 CurrentMessage = CONTAINING_RECORD(ListHead, USER_MESSAGE, ListEntry); 2130 ListHead = ListHead->Flink; 2131 /* 2132 MSDN: 2133 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL. 2134 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL. 2135 3: handle to the window whose messages are to be retrieved. 2136 */ 2137 if ( ( !Window || // 1 2138 ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2 2139 ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3 2140 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) || 2141 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) ) 2142 { 2143 *Message = CurrentMessage->Msg; 2144 *ExtraInfo = CurrentMessage->ExtraInfo; 2145 QS_Flags = CurrentMessage->QS_Flags; 2146 if (dwQEvent) *dwQEvent = CurrentMessage->dwQEvent; 2147 2148 if (Remove) 2149 { 2150 if (CurrentMessage->pti != NULL) 2151 { 2152 MsqDestroyMessage(CurrentMessage); 2153 } 2154 ClearMsgBitsMask(pti, QS_Flags); 2155 } 2156 Ret = TRUE; 2157 break; 2158 } 2159 } 2160 2161 return Ret; 2162 } 2163 2164 NTSTATUS FASTCALL 2165 co_MsqWaitForNewMessages(PTHREADINFO pti, PWND WndFilter, 2166 UINT MsgFilterMin, UINT MsgFilterMax) 2167 { 2168 NTSTATUS ret = STATUS_SUCCESS; 2169 2170 // Post mouse moves before waiting for messages. 2171 if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED) 2172 { 2173 IntCoalesceMouseMove(pti); 2174 } 2175 2176 UserLeaveCo(); 2177 2178 ZwYieldExecution(); // Let someone else run! 2179 2180 ret = KeWaitForSingleObject( pti->pEventQueueServer, 2181 UserRequest, 2182 UserMode, 2183 FALSE, 2184 NULL ); 2185 UserEnterCo(); 2186 if ( ret == STATUS_USER_APC ) 2187 { 2188 TRACE("MWFNW User APC\n"); 2189 co_IntDeliverUserAPC(); 2190 } 2191 return ret; 2192 } 2193 2194 BOOL FASTCALL 2195 MsqIsHung(PTHREADINFO pti, DWORD TimeOut) 2196 { 2197 DWORD dwTimeStamp = EngGetTickCount32(); 2198 if (dwTimeStamp - pti->pcti->timeLastRead > TimeOut && 2199 !(pti->pcti->fsWakeMask & QS_INPUT) && 2200 !PsGetThreadFreezeCount(pti->pEThread) && 2201 !(pti->ppi->W32PF_flags & W32PF_APPSTARTING)) 2202 { 2203 TRACE("\nMsqIsHung(pti %p, TimeOut %lu)\n" 2204 "pEThread %p, ThreadsProcess %p, ImageFileName '%s'\n" 2205 "dwTimeStamp = %lu\n" 2206 "pti->pcti->timeLastRead = %lu\n" 2207 "pti->timeLast = %lu\n" 2208 "PsGetThreadFreezeCount(pti->pEThread) = %lu\n", 2209 pti, TimeOut, 2210 pti->pEThread, 2211 pti->pEThread ? pti->pEThread->ThreadsProcess : NULL, 2212 (pti->pEThread && pti->pEThread->ThreadsProcess) 2213 ? pti->pEThread->ThreadsProcess->ImageFileName : "(None)", 2214 dwTimeStamp, 2215 pti->pcti->timeLastRead, 2216 pti->timeLast, 2217 PsGetThreadFreezeCount(pti->pEThread)); 2218 2219 return TRUE; 2220 } 2221 2222 return FALSE; 2223 } 2224 2225 BOOL FASTCALL 2226 IsThreadSuspended(PTHREADINFO pti) 2227 { 2228 if (pti->pEThread) 2229 { 2230 BOOL Ret = TRUE; 2231 if (!(pti->pEThread->Tcb.SuspendCount) && !PsGetThreadFreezeCount(pti->pEThread)) Ret = FALSE; 2232 return Ret; 2233 } 2234 return FALSE; 2235 } 2236 2237 VOID 2238 CALLBACK 2239 HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) 2240 { 2241 DoTheScreenSaver(); 2242 TRACE("HungAppSysTimerProc\n"); 2243 // Process list of windows that are hung and waiting. 2244 } 2245 2246 BOOLEAN FASTCALL 2247 MsqInitializeMessageQueue(PTHREADINFO pti, PUSER_MESSAGE_QUEUE MessageQueue) 2248 { 2249 InitializeListHead(&MessageQueue->HardwareMessagesListHead); // Keep here! 2250 MessageQueue->spwndFocus = NULL; 2251 MessageQueue->iCursorLevel = 0; 2252 MessageQueue->CursorObject = SYSTEMCUR(WAIT); // See test_initial_cursor. 2253 if (MessageQueue->CursorObject) 2254 { 2255 TRACE("Default cursor hcur %p\n",UserHMGetHandle(MessageQueue->CursorObject)); 2256 UserReferenceObject(MessageQueue->CursorObject); 2257 } 2258 RtlCopyMemory(MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState)); 2259 MessageQueue->ptiMouse = pti; 2260 MessageQueue->ptiKeyboard = pti; 2261 MessageQueue->cThreads++; 2262 2263 return TRUE; 2264 } 2265 2266 VOID FASTCALL 2267 MsqCleanupThreadMsgs(PTHREADINFO pti) 2268 { 2269 PLIST_ENTRY CurrentEntry; 2270 PUSER_MESSAGE CurrentMessage; 2271 PUSER_SENT_MESSAGE CurrentSentMessage; 2272 2273 TRACE("MsqCleanupThreadMsgs %p\n",pti); 2274 2275 // Clear it all out. 2276 if (pti->pcti) 2277 { 2278 pti->pcti->fsWakeBits = 0; 2279 pti->pcti->fsChangeBits = 0; 2280 } 2281 2282 pti->nCntsQBits[QSRosKey] = 0; 2283 pti->nCntsQBits[QSRosMouseMove] = 0; 2284 pti->nCntsQBits[QSRosMouseButton] = 0; 2285 pti->nCntsQBits[QSRosPostMessage] = 0; 2286 pti->nCntsQBits[QSRosSendMessage] = 0; 2287 pti->nCntsQBits[QSRosHotKey] = 0; 2288 pti->nCntsQBits[QSRosEvent] = 0; 2289 2290 /* cleanup posted messages */ 2291 while (!IsListEmpty(&pti->PostedMessagesListHead)) 2292 { 2293 CurrentEntry = pti->PostedMessagesListHead.Flink; 2294 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry); 2295 ERR("Thread Cleanup Post Messages %p\n",CurrentMessage); 2296 if (CurrentMessage->dwQEvent) 2297 { 2298 if (CurrentMessage->dwQEvent == POSTEVENT_NWE) 2299 { 2300 ExFreePoolWithTag( (PVOID)CurrentMessage->ExtraInfo, TAG_HOOK); 2301 } 2302 } 2303 MsqDestroyMessage(CurrentMessage); 2304 } 2305 2306 /* remove the messages that have not yet been dispatched */ 2307 while (!IsListEmpty(&pti->SentMessagesListHead)) 2308 { 2309 CurrentEntry = pti->SentMessagesListHead.Flink; 2310 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry); 2311 2312 ERR("Thread Cleanup Sent Messages %p\n",CurrentSentMessage); 2313 2314 /* wake the sender's thread */ 2315 if (CurrentSentMessage->pkCompletionEvent != NULL) 2316 { 2317 KeSetEvent(CurrentSentMessage->pkCompletionEvent, IO_NO_INCREMENT, FALSE); 2318 } 2319 2320 if (CurrentSentMessage->HasPackedLParam) 2321 { 2322 if (CurrentSentMessage->Msg.lParam) 2323 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam); 2324 } 2325 2326 /* free the message */ 2327 FreeUserMessage(CurrentSentMessage); 2328 } 2329 2330 // Process Trouble Message List 2331 if (!IsListEmpty(&usmList)) 2332 { 2333 CurrentEntry = usmList.Flink; 2334 while (CurrentEntry != &usmList) 2335 { 2336 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry); 2337 CurrentEntry = CurrentEntry->Flink; 2338 2339 TRACE("Found troubled messages %p on the list\n",CurrentSentMessage); 2340 2341 if ( pti == CurrentSentMessage->ptiReceiver ) 2342 { 2343 if (CurrentSentMessage->HasPackedLParam) 2344 { 2345 if (CurrentSentMessage->Msg.lParam) 2346 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam); 2347 } 2348 2349 /* free the message */ 2350 FreeUserMessage(CurrentSentMessage); 2351 } 2352 else if ( pti == CurrentSentMessage->ptiSender || 2353 pti == CurrentSentMessage->ptiCallBackSender ) 2354 { 2355 // Determine whether this message is being processed or not. 2356 if ((CurrentSentMessage->flags & (SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE) 2357 { 2358 CurrentSentMessage->flags |= SMF_RECEIVERFREE; 2359 } 2360 2361 if (!(CurrentSentMessage->flags & SMF_RECEIVERFREE)) 2362 { 2363 2364 if (CurrentSentMessage->HasPackedLParam) 2365 { 2366 if (CurrentSentMessage->Msg.lParam) 2367 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam); 2368 } 2369 2370 /* free the message */ 2371 FreeUserMessage(CurrentSentMessage); 2372 } 2373 } 2374 } 2375 } 2376 } 2377 2378 VOID FASTCALL 2379 MsqCleanupMessageQueue(PTHREADINFO pti) 2380 { 2381 PUSER_MESSAGE_QUEUE MessageQueue; 2382 PLIST_ENTRY CurrentEntry; 2383 PUSER_MESSAGE CurrentMessage; 2384 2385 MessageQueue = pti->MessageQueue; 2386 MessageQueue->cThreads--; 2387 2388 if (MessageQueue->cThreads) 2389 { 2390 if (MessageQueue->ptiSysLock == pti) MessageQueue->ptiSysLock = NULL; 2391 } 2392 2393 if (MessageQueue->cThreads == 0) //// Fix a crash related to CORE-10471 testing. 2394 { 2395 /* cleanup posted messages */ 2396 while (!IsListEmpty(&MessageQueue->HardwareMessagesListHead)) 2397 { 2398 CurrentEntry = MessageQueue->HardwareMessagesListHead.Flink; 2399 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry); 2400 ERR("MQ Cleanup Post Messages %p\n",CurrentMessage); 2401 MsqDestroyMessage(CurrentMessage); 2402 } 2403 } //// 2404 2405 if (MessageQueue->CursorObject) 2406 { 2407 PCURICON_OBJECT pCursor = MessageQueue->CursorObject; 2408 2409 /* Change to another cursor if we going to dereference current one 2410 Note: we can't use UserSetCursor because it uses current thread 2411 message queue instead of queue given for cleanup */ 2412 if (IntGetSysCursorInfo()->CurrentCursorObject == pCursor) 2413 { 2414 HDC hdcScreen; 2415 2416 /* Get the screen DC */ 2417 hdcScreen = IntGetScreenDC(); 2418 if (hdcScreen) 2419 GreMovePointer(hdcScreen, -1, -1); 2420 IntGetSysCursorInfo()->CurrentCursorObject = NULL; 2421 } 2422 2423 TRACE("DereferenceObject pCursor\n"); 2424 UserDereferenceObject(pCursor); 2425 } 2426 2427 if (gpqForeground == MessageQueue) 2428 { 2429 IntSetFocusMessageQueue(NULL); 2430 } 2431 if (gpqForegroundPrev == MessageQueue) 2432 { 2433 gpqForegroundPrev = NULL; 2434 } 2435 if (gpqCursor == MessageQueue) 2436 { 2437 gpqCursor = NULL; 2438 } 2439 } 2440 2441 PUSER_MESSAGE_QUEUE FASTCALL 2442 MsqCreateMessageQueue(PTHREADINFO pti) 2443 { 2444 PUSER_MESSAGE_QUEUE MessageQueue; 2445 2446 MessageQueue = ExAllocatePoolWithTag(NonPagedPool, 2447 sizeof(*MessageQueue), 2448 USERTAG_Q); 2449 2450 if (!MessageQueue) 2451 { 2452 return NULL; 2453 } 2454 2455 RtlZeroMemory(MessageQueue, sizeof(*MessageQueue)); 2456 /* hold at least one reference until it'll be destroyed */ 2457 IntReferenceMessageQueue(MessageQueue); 2458 /* initialize the queue */ 2459 if (!MsqInitializeMessageQueue(pti, MessageQueue)) 2460 { 2461 IntDereferenceMessageQueue(MessageQueue); 2462 return NULL; 2463 } 2464 2465 return MessageQueue; 2466 } 2467 2468 VOID FASTCALL 2469 MsqDestroyMessageQueue(_In_ PTHREADINFO pti) 2470 { 2471 PDESKTOP desk; 2472 PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue; 2473 2474 NT_ASSERT(MessageQueue != NULL); 2475 MessageQueue->QF_flags |= QF_INDESTROY; 2476 2477 /* remove the message queue from any desktops */ 2478 if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0))) 2479 { 2480 (void)InterlockedExchangePointer((PVOID*)&desk->ActiveMessageQueue, 0); 2481 IntDereferenceMessageQueue(MessageQueue); 2482 } 2483 2484 /* clean it up */ 2485 MsqCleanupMessageQueue(pti); 2486 2487 /* decrease the reference counter, if it hits zero, the queue will be freed */ 2488 _PRAGMA_WARNING_SUPPRESS(__WARNING_USING_UNINIT_VAR); 2489 IntDereferenceMessageQueue(MessageQueue); 2490 } 2491 2492 LPARAM FASTCALL 2493 MsqSetMessageExtraInfo(LPARAM lParam) 2494 { 2495 LPARAM Ret; 2496 PTHREADINFO pti; 2497 PUSER_MESSAGE_QUEUE MessageQueue; 2498 2499 pti = PsGetCurrentThreadWin32Thread(); 2500 MessageQueue = pti->MessageQueue; 2501 if(!MessageQueue) 2502 { 2503 return 0; 2504 } 2505 2506 Ret = MessageQueue->ExtraInfo; 2507 MessageQueue->ExtraInfo = lParam; 2508 2509 return Ret; 2510 } 2511 2512 LPARAM FASTCALL 2513 MsqGetMessageExtraInfo(VOID) 2514 { 2515 PTHREADINFO pti; 2516 PUSER_MESSAGE_QUEUE MessageQueue; 2517 2518 pti = PsGetCurrentThreadWin32Thread(); 2519 MessageQueue = pti->MessageQueue; 2520 if(!MessageQueue) 2521 { 2522 return 0; 2523 } 2524 2525 return MessageQueue->ExtraInfo; 2526 } 2527 2528 // ReplyMessage is called by the thread receiving the window message. 2529 BOOL FASTCALL 2530 co_MsqReplyMessage( LRESULT lResult ) 2531 { 2532 PUSER_SENT_MESSAGE Message; 2533 PTHREADINFO pti; 2534 2535 pti = PsGetCurrentThreadWin32Thread(); 2536 Message = pti->pusmCurrent; 2537 2538 if (!Message) return FALSE; 2539 2540 if (Message->QS_Flags & QS_SMRESULT) return FALSE; 2541 2542 // SendMessageXxx || Callback msg and not a notify msg 2543 if (Message->ptiSender || Message->CompletionCallback) 2544 { 2545 Message->lResult = lResult; 2546 Message->QS_Flags |= QS_SMRESULT; 2547 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away.. 2548 } 2549 return TRUE; 2550 } 2551 2552 HWND FASTCALL 2553 MsqSetStateWindow(PTHREADINFO pti, ULONG Type, HWND hWnd) 2554 { 2555 HWND Prev; 2556 PUSER_MESSAGE_QUEUE MessageQueue; 2557 2558 MessageQueue = pti->MessageQueue; 2559 2560 switch(Type) 2561 { 2562 case MSQ_STATE_CAPTURE: 2563 Prev = MessageQueue->spwndCapture ? UserHMGetHandle(MessageQueue->spwndCapture) : 0; 2564 MessageQueue->spwndCapture = ValidateHwndNoErr(hWnd); 2565 return Prev; 2566 case MSQ_STATE_ACTIVE: 2567 Prev = MessageQueue->spwndActive ? UserHMGetHandle(MessageQueue->spwndActive) : 0; 2568 MessageQueue->spwndActive = ValidateHwndNoErr(hWnd); 2569 return Prev; 2570 case MSQ_STATE_FOCUS: 2571 Prev = MessageQueue->spwndFocus ? UserHMGetHandle(MessageQueue->spwndFocus) : 0; 2572 MessageQueue->spwndFocus = ValidateHwndNoErr(hWnd); 2573 return Prev; 2574 case MSQ_STATE_MENUOWNER: 2575 Prev = MessageQueue->MenuOwner; 2576 MessageQueue->MenuOwner = hWnd; 2577 return Prev; 2578 case MSQ_STATE_MOVESIZE: 2579 Prev = MessageQueue->MoveSize; 2580 MessageQueue->MoveSize = hWnd; 2581 return Prev; 2582 case MSQ_STATE_CARET: 2583 Prev = MessageQueue->CaretInfo.hWnd; 2584 MessageQueue->CaretInfo.hWnd = hWnd; 2585 return Prev; 2586 } 2587 2588 return NULL; 2589 } 2590 2591 SHORT 2592 APIENTRY 2593 NtUserGetKeyState(INT key) 2594 { 2595 DWORD Ret; 2596 2597 UserEnterShared(); 2598 2599 Ret = UserGetKeyState(key); 2600 2601 UserLeave(); 2602 2603 return (SHORT)Ret; 2604 } 2605 2606 2607 DWORD 2608 APIENTRY 2609 NtUserGetKeyboardState(LPBYTE lpKeyState) 2610 { 2611 DWORD i, ret = TRUE; 2612 PTHREADINFO pti; 2613 PUSER_MESSAGE_QUEUE MessageQueue; 2614 2615 UserEnterShared(); 2616 2617 pti = PsGetCurrentThreadWin32Thread(); 2618 MessageQueue = pti->MessageQueue; 2619 2620 _SEH2_TRY 2621 { 2622 /* Probe and copy key state to an array */ 2623 ProbeForWrite(lpKeyState, 256 * sizeof(BYTE), 1); 2624 for (i = 0; i < 256; ++i) 2625 { 2626 lpKeyState[i] = 0; 2627 if (IS_KEY_DOWN(MessageQueue->afKeyState, i)) 2628 lpKeyState[i] |= KS_DOWN_BIT; 2629 if (IS_KEY_LOCKED(MessageQueue->afKeyState, i)) 2630 lpKeyState[i] |= KS_LOCK_BIT; 2631 } 2632 } 2633 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2634 { 2635 SetLastNtError(_SEH2_GetExceptionCode()); 2636 ret = FALSE; 2637 } 2638 _SEH2_END; 2639 2640 UserLeave(); 2641 2642 return ret; 2643 } 2644 2645 BOOL 2646 APIENTRY 2647 NtUserSetKeyboardState(LPBYTE pKeyState) 2648 { 2649 UINT i; 2650 BOOL bRet = TRUE; 2651 PTHREADINFO pti; 2652 PUSER_MESSAGE_QUEUE MessageQueue; 2653 2654 UserEnterExclusive(); 2655 2656 pti = PsGetCurrentThreadWin32Thread(); 2657 MessageQueue = pti->MessageQueue; 2658 2659 _SEH2_TRY 2660 { 2661 ProbeForRead(pKeyState, 256 * sizeof(BYTE), 1); 2662 for (i = 0; i < 256; ++i) 2663 { 2664 SET_KEY_DOWN(MessageQueue->afKeyState, i, pKeyState[i] & KS_DOWN_BIT); 2665 SET_KEY_LOCKED(MessageQueue->afKeyState, i, pKeyState[i] & KS_LOCK_BIT); 2666 } 2667 } 2668 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2669 { 2670 SetLastNtError(_SEH2_GetExceptionCode()); 2671 bRet = FALSE; 2672 } 2673 _SEH2_END; 2674 2675 UserLeave(); 2676 2677 return bRet; 2678 } 2679 2680 /* EOF */ 2681