2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Message queues
5 * FILE: subsystems/win32/win32k/ntuser/msgqueue.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
12 DBG_DEFAULT_CHANNEL(UserMsgQ
);
14 /* GLOBALS *******************************************************************/
16 static PPAGED_LOOKASIDE_LIST pgMessageLookasideList
;
17 PUSER_MESSAGE_QUEUE gpqCursor
;
18 ULONG_PTR gdwMouseMoveExtraInfo
= 0;
19 DWORD gdwMouseMoveTimeStamp
= 0;
22 /* FUNCTIONS *****************************************************************/
27 MsqInitializeImpl(VOID
)
29 pgMessageLookasideList
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(PAGED_LOOKASIDE_LIST
), TAG_USRMSG
);
30 if(!pgMessageLookasideList
)
31 return STATUS_NO_MEMORY
;
32 ExInitializePagedLookasideList(pgMessageLookasideList
,
40 return(STATUS_SUCCESS
);
44 IntTopLevelWindowFromPoint(INT x
, INT y
)
46 PWND pWnd
, pwndDesktop
;
48 /* Get the desktop window */
49 pwndDesktop
= UserGetDesktopWindow();
53 /* Loop all top level windows */
54 for (pWnd
= pwndDesktop
->spwndChild
;
56 pWnd
= pWnd
->spwndNext
)
58 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
60 TRACE("The Window is in DESTROY!\n");
64 if ((pWnd
->style
& WS_VISIBLE
) && IntPtInWindow(pWnd
, x
, y
))
68 /* Window has not been found */
75 PCURICON_OBJECT NewCursor
,
78 PCURICON_OBJECT OldCursor
;
81 PUSER_MESSAGE_QUEUE MessageQueue
;
84 pti
= PsGetCurrentThreadWin32Thread();
85 MessageQueue
= pti
->MessageQueue
;
87 /* Get the screen DC */
88 if(!(hdcScreen
= IntGetScreenDC()))
93 OldCursor
= MessageQueue
->CursorObject
;
95 /* Check if cursors are different */
96 if (OldCursor
== NewCursor
)
99 /* Update cursor for this message queue */
100 MessageQueue
->CursorObject
= NewCursor
;
102 /* If cursor is not visible we have nothing to do */
103 if (MessageQueue
->iCursorLevel
< 0)
106 /* Update cursor if this message queue controls it */
107 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
108 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
112 /* Call GDI to set the new screen cursor */
113 #ifdef NEW_CURSORICON
114 PCURICON_OBJECT CursorFrame
= NewCursor
;
115 if(NewCursor
->CURSORF_flags
& CURSORF_ACON
)
117 FIXME("Should animate the cursor, using only the first frame now.\n");
118 CursorFrame
= ((PACON
)NewCursor
)->aspcur
[0];
120 GreSetPointerShape(hdcScreen
,
121 CursorFrame
->hbmAlpha
? NULL
: NewCursor
->hbmMask
,
122 CursorFrame
->hbmAlpha
? NewCursor
->hbmAlpha
: NewCursor
->hbmColor
,
123 CursorFrame
->xHotspot
,
124 CursorFrame
->yHotspot
,
127 CursorFrame
->hbmAlpha
? SPS_ALPHA
: 0);
129 GreSetPointerShape(hdcScreen
,
130 NewCursor
->IconInfo
.hbmMask
,
131 NewCursor
->IconInfo
.hbmColor
,
132 NewCursor
->IconInfo
.xHotspot
,
133 NewCursor
->IconInfo
.yHotspot
,
139 else /* Note: OldCursor != NewCursor so we have to hide cursor */
141 /* Remove the cursor */
142 GreMovePointer(hdcScreen
, -1, -1);
143 TRACE("Removing pointer!\n");
145 IntGetSysCursorInfo()->CurrentCursorObject
= NewCursor
;
148 /* Return the old cursor */
152 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
153 * User32 macro NtUserShowCursor */
154 int UserShowCursor(BOOL bShow
)
158 PUSER_MESSAGE_QUEUE MessageQueue
;
161 if (!(hdcScreen
= IntGetScreenDC()))
163 return -1; /* No mouse */
166 pti
= PsGetCurrentThreadWin32Thread();
167 MessageQueue
= pti
->MessageQueue
;
170 MessageQueue
->iCursorLevel
+= bShow
? 1 : -1;
171 pti
->iCursorLevel
+= bShow
? 1 : -1;
173 /* Check for trivial cases */
174 if ((bShow
&& MessageQueue
->iCursorLevel
!= 0) ||
175 (!bShow
&& MessageQueue
->iCursorLevel
!= -1))
177 /* Note: w don't update global info here because it is used only
178 internally to check if cursor is visible */
179 return MessageQueue
->iCursorLevel
;
182 /* Check if cursor is above window owned by this MessageQueue */
183 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
184 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
188 /* Show the pointer */
189 GreMovePointer(hdcScreen
, gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
190 TRACE("Showing pointer!\n");
194 /* Remove the pointer */
195 GreMovePointer(hdcScreen
, -1, -1);
196 TRACE("Removing pointer!\n");
199 /* Update global info */
200 IntGetSysCursorInfo()->ShowingCursor
= MessageQueue
->iCursorLevel
;
203 return MessageQueue
->iCursorLevel
;
207 UserGetKeyState(DWORD dwKey
)
211 PUSER_MESSAGE_QUEUE MessageQueue
;
213 pti
= PsGetCurrentThreadWin32Thread();
214 MessageQueue
= pti
->MessageQueue
;
218 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, dwKey
))
219 dwRet
|= 0xFF80; // If down, windows returns 0xFF80.
220 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, dwKey
))
225 EngSetLastError(ERROR_INVALID_PARAMETER
);
230 /* change the input key state for a given key */
232 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue
, WORD wVk
, BOOL bIsDown
)
234 TRACE("UpdateKeyState wVk: %u, bIsDown: %d\n", wVk
, bIsDown
);
238 /* If it's first key down event, xor lock bit */
239 if (!IS_KEY_DOWN(MessageQueue
->afKeyState
, wVk
))
240 SET_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
, !IS_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
));
242 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, TRUE
);
243 MessageQueue
->afKeyRecentDown
[wVk
/ 8] |= (1 << (wVk
% 8));
246 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, FALSE
);
249 /* update the input key state for a keyboard message */
251 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
256 TRACE("UpdateKeyStateFromMsg message:%u\n", msg
->message
);
258 switch (msg
->message
)
264 UpdateKeyState(MessageQueue
, VK_LBUTTON
, down
);
270 UpdateKeyState(MessageQueue
, VK_MBUTTON
, down
);
276 UpdateKeyState(MessageQueue
, VK_RBUTTON
, down
);
282 if (msg
->wParam
== XBUTTON1
)
283 UpdateKeyState(MessageQueue
, VK_XBUTTON1
, down
);
284 else if (msg
->wParam
== XBUTTON2
)
285 UpdateKeyState(MessageQueue
, VK_XBUTTON2
, down
);
293 key
= (UCHAR
)msg
->wParam
;
294 UpdateKeyState(MessageQueue
, key
, down
);
299 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LCONTROL
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RCONTROL
);
300 UpdateKeyState(MessageQueue
, VK_CONTROL
, down
);
304 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LMENU
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RMENU
);
305 UpdateKeyState(MessageQueue
, VK_MENU
, down
);
309 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LSHIFT
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RSHIFT
);
310 UpdateKeyState(MessageQueue
, VK_SHIFT
, down
);
318 Get down key states from the queue of prior processed input message key states.
320 This fixes the left button dragging on the desktop and release sticking outline issue.
321 USB Tablet pointer seems to stick the most and leaves the box outline displayed.
324 MsqGetDownKeyState(PUSER_MESSAGE_QUEUE MessageQueue
)
328 if (gspv
.bMouseBtnSwap
)
330 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RBUTTON
)) ret
|= MK_LBUTTON
;
331 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LBUTTON
)) ret
|= MK_RBUTTON
;
335 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LBUTTON
)) ret
|= MK_LBUTTON
;
336 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RBUTTON
)) ret
|= MK_RBUTTON
;
339 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_MBUTTON
)) ret
|= MK_MBUTTON
;
340 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_SHIFT
)) ret
|= MK_SHIFT
;
341 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_CONTROL
)) ret
|= MK_CONTROL
;
342 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_XBUTTON1
)) ret
|= MK_XBUTTON1
;
343 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_XBUTTON2
)) ret
|= MK_XBUTTON2
;
348 IntMsqSetWakeMask(DWORD WakeMask
)
350 PTHREADINFO Win32Thread
;
351 HANDLE MessageEventHandle
;
352 DWORD dwFlags
= HIWORD(WakeMask
);
354 Win32Thread
= PsGetCurrentThreadWin32Thread();
355 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
358 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
359 MessageEventHandle
= Win32Thread
->hEventQueueClient
;
361 if (Win32Thread
->pcti
)
363 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
364 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
366 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
367 KeSetEvent(Win32Thread
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
368 return MessageEventHandle
;
374 return MessageEventHandle
;
378 IntMsqClearWakeMask(VOID
)
380 PTHREADINFO Win32Thread
;
382 Win32Thread
= PsGetCurrentThreadWin32Thread();
383 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
385 // Very hacky, but that is what they do.
386 Win32Thread
->pcti
->fsWakeBits
= 0;
394 Due to the uncertainty of knowing what was set in our multilevel message queue,
395 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
396 I think this is the best solution... (jt) */
398 MsqWakeQueue(PTHREADINFO pti
, DWORD MessageBits
, BOOL KeyEvent
)
400 PUSER_MESSAGE_QUEUE Queue
;
402 Queue
= pti
->MessageQueue
;
404 if (Queue
->QF_flags
& QF_INDESTROY
)
406 ERR("This Message Queue is in Destroy!\n");
408 pti
->pcti
->fsWakeBits
|= MessageBits
;
409 pti
->pcti
->fsChangeBits
|= MessageBits
;
411 // Start bit accounting to help clear the main set of bits.
412 if (MessageBits
& QS_KEY
)
414 pti
->nCntsQBits
[QSRosKey
]++;
416 if (MessageBits
& QS_MOUSE
)
418 if (MessageBits
& QS_MOUSEMOVE
) pti
->nCntsQBits
[QSRosMouseMove
]++;
419 if (MessageBits
& QS_MOUSEBUTTON
) pti
->nCntsQBits
[QSRosMouseButton
]++;
421 if (MessageBits
& QS_POSTMESSAGE
) pti
->nCntsQBits
[QSRosPostMessage
]++;
422 if (MessageBits
& QS_SENDMESSAGE
) pti
->nCntsQBits
[QSRosSendMessage
]++;
423 if (MessageBits
& QS_HOTKEY
) pti
->nCntsQBits
[QSRosHotKey
]++;
424 if (MessageBits
& QS_EVENT
) pti
->nCntsQBits
[QSRosEvent
]++;
427 KeSetEvent(pti
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
);
431 ClearMsgBitsMask(PTHREADINFO pti
, UINT MessageBits
)
435 if (MessageBits
& QS_KEY
)
437 if (--pti
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
439 if (MessageBits
& QS_MOUSEMOVE
)
440 { // Account for tracking mouse moves..
441 if (pti
->nCntsQBits
[QSRosMouseMove
])
443 pti
->nCntsQBits
[QSRosMouseMove
] = 0; // Throttle down count. Up to > 3:1 entries are ignored.
444 ClrMask
|= QS_MOUSEMOVE
;
447 if (MessageBits
& QS_MOUSEBUTTON
)
449 if (--pti
->nCntsQBits
[QSRosMouseButton
] == 0) ClrMask
|= QS_MOUSEBUTTON
;
451 if (MessageBits
& QS_POSTMESSAGE
)
453 if (--pti
->nCntsQBits
[QSRosPostMessage
] == 0) ClrMask
|= QS_POSTMESSAGE
;
455 if (MessageBits
& QS_TIMER
) // ReactOS hard coded.
456 { // Handle timer bits here.
457 if ( pti
->cTimersReady
)
459 if (--pti
->cTimersReady
== 0) ClrMask
|= QS_TIMER
;
462 if (MessageBits
& QS_PAINT
) // ReactOS hard coded.
463 { // Handle paint bits here.
464 if ( pti
->cPaintsReady
)
466 if (--pti
->cPaintsReady
== 0) ClrMask
|= QS_PAINT
;
469 if (MessageBits
& QS_SENDMESSAGE
)
471 if (--pti
->nCntsQBits
[QSRosSendMessage
] == 0) ClrMask
|= QS_SENDMESSAGE
;
473 if (MessageBits
& QS_HOTKEY
)
475 if (--pti
->nCntsQBits
[QSRosHotKey
] == 0) ClrMask
|= QS_HOTKEY
;
477 if (MessageBits
& QS_EVENT
)
479 if (--pti
->nCntsQBits
[QSRosEvent
] == 0) ClrMask
|= QS_EVENT
;
482 pti
->pcti
->fsWakeBits
&= ~ClrMask
;
483 pti
->pcti
->fsChangeBits
&= ~ClrMask
;
487 MsqIncPaintCountQueue(PTHREADINFO pti
)
490 MsqWakeQueue(pti
, QS_PAINT
, TRUE
);
494 MsqDecPaintCountQueue(PTHREADINFO pti
)
496 ClearMsgBitsMask(pti
, QS_PAINT
);
500 Post the move or update the message still pending to be processed.
501 Do not overload the queue with mouse move messages.
504 MsqPostMouseMove(PTHREADINFO pti
, MSG
* Msg
, LONG_PTR ExtraInfo
)
506 PUSER_MESSAGE Message
;
507 PLIST_ENTRY ListHead
;
508 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
510 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
512 // Do nothing if empty.
513 if (!IsListEmpty(ListHead
->Flink
))
515 // Look at the end of the list,
516 Message
= CONTAINING_RECORD(ListHead
->Blink
, USER_MESSAGE
, ListEntry
);
518 // If the mouse move message is existing on the list,
519 if (Message
->Msg
.message
== WM_MOUSEMOVE
)
521 // Overwrite the message with updated data!
524 MsqWakeQueue(pti
, QS_MOUSEMOVE
, TRUE
);
529 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEMOVE
, 0, ExtraInfo
);
533 Bring together the mouse move message.
534 Named "Coalesce" from Amine email ;^) (jt).
537 IntCoalesceMouseMove(PTHREADINFO pti
)
540 LARGE_INTEGER LargeTickCount
;
542 // Force time stamp to update, keeping message time in sync.
543 if (gdwMouseMoveTimeStamp
== 0)
545 KeQueryTickCount(&LargeTickCount
);
546 gdwMouseMoveTimeStamp
= MsqCalculateMessageTime(&LargeTickCount
);
549 // Build mouse move message.
551 Msg
.message
= WM_MOUSEMOVE
;
553 Msg
.lParam
= MAKELONG(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
554 Msg
.time
= gdwMouseMoveTimeStamp
;
555 Msg
.pt
= gpsi
->ptCursor
;
558 MsqPostMouseMove(pti
, &Msg
, gdwMouseMoveExtraInfo
);
560 // Zero the time stamp.
561 gdwMouseMoveTimeStamp
= 0;
563 // Clear flag since the move was posted.
564 pti
->MessageQueue
->QF_flags
&= ~QF_MOUSEMOVED
;
568 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
570 LARGE_INTEGER LargeTickCount
;
571 MSLLHOOKSTRUCT MouseHookData
;
573 PWND pwnd
, pwndDesktop
;
576 PUSER_MESSAGE_QUEUE MessageQueue
;
577 PSYSTEM_CURSORINFO CurInfo
;
579 KeQueryTickCount(&LargeTickCount
);
580 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
582 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
583 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
584 switch (Msg
->message
)
587 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
591 case WM_XBUTTONDBLCLK
:
592 case WM_NCXBUTTONDOWN
:
594 case WM_NCXBUTTONDBLCLK
:
595 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
598 MouseHookData
.mouseData
= 0;
602 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
603 MouseHookData
.time
= Msg
->time
;
604 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
606 /* If the hook procedure returned non zero, dont send the message */
609 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
613 /* Get the desktop window */
614 pwndDesktop
= UserGetDesktopWindow();
615 if (!pwndDesktop
) return;
616 // pDesk = pwndDesktop->head.rpdesk;
618 /* Check if the mouse is captured */
619 Msg
->hwnd
= IntGetCaptureWindow();
620 if (Msg
->hwnd
!= NULL
)
622 pwnd
= UserGetWindowObject(Msg
->hwnd
);
626 pwnd
= IntTopLevelWindowFromPoint(Msg
->pt
.x
, Msg
->pt
.y
);
627 if (pwnd
) Msg
->hwnd
= pwnd
->head
.h
;
630 hdcScreen
= IntGetScreenDC();
631 CurInfo
= IntGetSysCursorInfo();
633 /* Check if we found a window */
634 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
636 pti
= pwnd
->head
.pti
;
637 MessageQueue
= pti
->MessageQueue
;
639 if (MessageQueue
->QF_flags
& QF_INDESTROY
)
641 ERR("Mouse is over a Window with a Dead Message Queue!\n");
645 MessageQueue
->ptiMouse
= pti
;
647 if (Msg
->message
== WM_MOUSEMOVE
)
649 /* Check if cursor should be visible */
651 MessageQueue
->CursorObject
&&
652 MessageQueue
->iCursorLevel
>= 0)
654 /* Check if shape has changed */
655 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
657 /* Call GDI to set the new screen cursor */
658 #ifdef NEW_CURSORICON
659 GreSetPointerShape(hdcScreen
,
660 MessageQueue
->CursorObject
->hbmAlpha
?
661 NULL
: MessageQueue
->CursorObject
->hbmMask
,
662 MessageQueue
->CursorObject
->hbmAlpha
?
663 MessageQueue
->CursorObject
->hbmAlpha
: MessageQueue
->CursorObject
->hbmColor
,
664 MessageQueue
->CursorObject
->xHotspot
,
665 MessageQueue
->CursorObject
->yHotspot
,
668 MessageQueue
->CursorObject
->hbmAlpha
? SPS_ALPHA
: 0);
670 GreSetPointerShape(hdcScreen
,
671 MessageQueue
->CursorObject
->IconInfo
.hbmMask
,
672 MessageQueue
->CursorObject
->IconInfo
.hbmColor
,
673 MessageQueue
->CursorObject
->IconInfo
.xHotspot
,
674 MessageQueue
->CursorObject
->IconInfo
.yHotspot
,
680 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
682 /* Check if w have to hide cursor */
683 else if (CurInfo
->ShowingCursor
>= 0)
684 GreMovePointer(hdcScreen
, -1, -1);
686 /* Update global cursor info */
687 CurInfo
->ShowingCursor
= MessageQueue
->iCursorLevel
;
688 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
689 gpqCursor
= MessageQueue
;
691 /* Mouse move is a special case */
692 MessageQueue
->QF_flags
|= QF_MOUSEMOVED
;
693 gdwMouseMoveExtraInfo
= dwExtraInfo
;
694 gdwMouseMoveTimeStamp
= Msg
->time
;
695 MsqWakeQueue(pti
, QS_MOUSEMOVE
, TRUE
);
699 if (!IntGetCaptureWindow())
701 // ERR("ptiLastInput is set\n");
702 // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
703 // Find all the Move Mouse calls and fix mouse set active focus issues......
706 // Post mouse move before posting mouse buttons, keep it in sync.
707 if (pti
->MessageQueue
->QF_flags
& QF_MOUSEMOVED
)
709 IntCoalesceMouseMove(pti
);
712 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd
));
713 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEBUTTON
, 0, dwExtraInfo
);
718 /* always show cursor on background; FIXME: set default pointer */
719 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
720 CurInfo
->ShowingCursor
= 0;
724 PUSER_MESSAGE FASTCALL
725 MsqCreateMessage(LPMSG Msg
)
727 PUSER_MESSAGE Message
;
729 Message
= ExAllocateFromPagedLookasideList(pgMessageLookasideList
);
735 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
741 MsqDestroyMessage(PUSER_MESSAGE Message
)
743 ExFreeToPagedLookasideList(pgMessageLookasideList
, Message
);
747 co_MsqDispatchOneSentMessage(PTHREADINFO pti
)
749 PUSER_SENT_MESSAGE SaveMsg
, Message
;
754 if (IsListEmpty(&pti
->SentMessagesListHead
))
759 /* remove it from the list of pending messages */
760 Entry
= RemoveHeadList(&pti
->SentMessagesListHead
);
761 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
763 SaveMsg
= pti
->pusmCurrent
;
764 pti
->pusmCurrent
= Message
;
766 // Processing a message sent to it from another thread.
767 if ( ( Message
->ptiSender
&& pti
!= Message
->ptiSender
) ||
768 ( Message
->ptiCallBackSender
&& pti
!= Message
->ptiCallBackSender
))
769 { // most likely, but, to be sure.
770 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
773 /* insert it to the list of messages that are currently dispatched by this
775 InsertTailList(&pti
->LocalDispatchingMessagesHead
,
776 &Message
->ListEntry
);
778 ClearMsgBitsMask(pti
, Message
->QS_Flags
);
780 if (Message
->HookMessage
== MSQ_ISHOOK
)
781 { // Direct Hook Call processor
782 Result
= co_CallHook( Message
->Msg
.message
, // HookId
783 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
785 Message
->Msg
.lParam
);
787 else if (Message
->HookMessage
== MSQ_ISEVENT
)
788 { // Direct Event Call processor
789 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
792 Message
->Msg
.lParam
);
794 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
796 Result
= IntLoadHookModule(Message
->Msg
.message
,
797 (HHOOK
)Message
->Msg
.lParam
,
798 Message
->Msg
.wParam
);
800 else if ((Message
->CompletionCallback
) &&
801 (Message
->ptiCallBackSender
== pti
))
802 { /* Call the callback routine */
803 if (Message
->QS_Flags
& QS_SMRESULT
)
805 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
807 Message
->Msg
.message
,
808 Message
->CompletionCallbackContext
,
810 /* Set callback to NULL to prevent reentry */
811 Message
->CompletionCallback
= NULL
;
815 /* The message has not been processed yet, reinsert it. */
816 RemoveEntryList(&Message
->ListEntry
);
817 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
818 TRACE("Callback Message not processed yet. Requeuing the message\n");
824 { /* Call the window procedure. */
825 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
826 Message
->Msg
.message
,
828 Message
->Msg
.lParam
);
831 /* remove the message from the local dispatching list, because it doesn't need
832 to be cleaned up on thread termination anymore */
833 RemoveEntryList(&Message
->ListEntry
);
835 /* If the message is a callback, insert it in the callback senders MessageQueue */
836 if (Message
->CompletionCallback
)
838 if (Message
->ptiCallBackSender
)
840 Message
->lResult
= Result
;
841 Message
->QS_Flags
|= QS_SMRESULT
;
843 /* insert it in the callers message queue */
844 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
845 MsqWakeQueue(Message
->ptiCallBackSender
, QS_SENDMESSAGE
, TRUE
);
851 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
852 if (Message
->ptiSender
)
854 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
856 /* only remove it from the dispatching list if not already removed by a timeout */
857 RemoveEntryList(&Message
->DispatchingListEntry
);
860 /* still keep the sender's message queue locked, so the sender can't exit the
861 MsqSendMessage() function (if timed out) */
863 if (Message
->QS_Flags
& QS_SMRESULT
)
865 Result
= Message
->lResult
;
868 /* Let the sender know the result. */
869 if (Message
->Result
!= NULL
)
871 *Message
->Result
= Result
;
874 if (Message
->HasPackedLParam
)
876 if (Message
->Msg
.lParam
)
877 ExFreePool((PVOID
)Message
->Msg
.lParam
);
880 /* Notify the sender. */
881 if (Message
->CompletionEvent
!= NULL
)
883 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
886 /* free the message */
887 ExFreePoolWithTag(Message
, TAG_USRMSG
);
890 /* do not hangup on the user if this is reentering */
891 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
892 pti
->pusmCurrent
= SaveMsg
;
898 MsqRemoveWindowMessagesFromQueue(PWND Window
)
901 PUSER_SENT_MESSAGE SentMessage
;
902 PUSER_MESSAGE PostedMessage
;
903 PLIST_ENTRY CurrentEntry
, ListHead
;
907 pti
= Window
->head
.pti
;
909 /* remove the posted messages for this window */
910 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
911 ListHead
= &pti
->PostedMessagesListHead
;
912 while (CurrentEntry
!= ListHead
)
914 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
916 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
918 RemoveEntryList(&PostedMessage
->ListEntry
);
919 ClearMsgBitsMask(pti
, PostedMessage
->QS_Flags
);
920 MsqDestroyMessage(PostedMessage
);
921 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
925 CurrentEntry
= CurrentEntry
->Flink
;
929 /* remove the sent messages for this window */
930 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
931 ListHead
= &pti
->SentMessagesListHead
;
932 while (CurrentEntry
!= ListHead
)
934 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
936 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
938 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
940 RemoveEntryList(&SentMessage
->ListEntry
);
941 ClearMsgBitsMask(pti
, SentMessage
->QS_Flags
);
943 /* Only if the message has a sender was the queue referenced */
944 if ((SentMessage
->ptiSender
)
945 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
947 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
950 /* wake the sender's thread */
951 if (SentMessage
->CompletionEvent
!= NULL
)
953 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
956 if (SentMessage
->HasPackedLParam
)
958 if (SentMessage
->Msg
.lParam
)
959 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
962 /* free the message */
963 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
965 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
969 CurrentEntry
= CurrentEntry
->Flink
;
975 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
980 SENDASYNCPROC CompletionCallback
,
981 ULONG_PTR CompletionCallbackContext
,
982 BOOL HasPackedLParam
,
986 PTHREADINFO ptiSender
;
987 PUSER_SENT_MESSAGE Message
;
989 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
991 ERR("MsqSendMessage(): Not enough memory to allocate a message");
995 ptiSender
= PsGetCurrentThreadWin32Thread();
997 Message
->Msg
.hwnd
= hwnd
;
998 Message
->Msg
.message
= Msg
;
999 Message
->Msg
.wParam
= wParam
;
1000 Message
->Msg
.lParam
= lParam
;
1001 Message
->CompletionEvent
= NULL
;
1002 Message
->Result
= 0;
1003 Message
->lResult
= 0;
1004 Message
->ptiReceiver
= ptiReceiver
;
1005 Message
->ptiSender
= NULL
;
1006 Message
->ptiCallBackSender
= ptiSender
;
1007 Message
->DispatchingListEntry
.Flink
= NULL
;
1008 Message
->CompletionCallback
= CompletionCallback
;
1009 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
1010 Message
->HookMessage
= HookMessage
;
1011 Message
->HasPackedLParam
= HasPackedLParam
;
1012 Message
->QS_Flags
= QS_SENDMESSAGE
;
1014 InsertTailList(&ptiReceiver
->SentMessagesListHead
, &Message
->ListEntry
);
1015 MsqWakeQueue(ptiReceiver
, QS_SENDMESSAGE
, TRUE
);
1021 co_MsqSendMessage(PTHREADINFO ptirec
,
1022 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
1023 UINT uTimeout
, BOOL Block
, INT HookMessage
,
1027 PUSER_SENT_MESSAGE Message
;
1028 KEVENT CompletionEvent
;
1029 NTSTATUS WaitStatus
;
1030 LARGE_INTEGER Timeout
;
1033 LRESULT Result
= 0; //// Result could be trashed. ////
1035 pti
= PsGetCurrentThreadWin32Thread();
1036 ASSERT(pti
!= ptirec
);
1037 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
1039 /* Don't send from or to a dying thread */
1040 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
1042 // Unless we are dying and need to tell our parents.
1043 if (pti
->TIF_flags
& TIF_INCLEANUP
&& !(ptirec
->TIF_flags
& TIF_INCLEANUP
))
1045 // Parent notify is the big one. Fire and forget!
1046 TRACE("Send message from dying thread %d\n",Msg
);
1047 co_MsqSendMessageAsync(ptirec
, Wnd
, Msg
, wParam
, lParam
, NULL
, 0, FALSE
, HookMessage
);
1049 if (uResult
) *uResult
= -1;
1050 TRACE("MsqSM: Msg %d Current pti %lu or Rec pti %lu\n", Msg
, pti
->TIF_flags
& TIF_INCLEANUP
, ptirec
->TIF_flags
& TIF_INCLEANUP
);
1051 return STATUS_UNSUCCESSFUL
;
1054 if ( HookMessage
== MSQ_NORMAL
)
1056 pWnd
= ValidateHwndNoErr(Wnd
);
1058 // These can not cross International Border lines!
1059 if ( pti
->ppi
!= ptirec
->ppi
&& pWnd
)
1063 // Handle the special case when working with password transfers across bordering processes.
1065 case EM_SETPASSWORDCHAR
:
1067 // Look for edit controls setup for passwords.
1068 if ( gpsi
->atomSysClass
[ICLS_EDIT
] == pWnd
->pcls
->atomClassName
&& // Use atomNVClassName.
1069 pWnd
->style
& ES_PASSWORD
)
1071 if (uResult
) *uResult
= -1;
1072 ERR("Running across the border without a passport!\n");
1073 EngSetLastError(ERROR_ACCESS_DENIED
);
1074 return STATUS_UNSUCCESSFUL
;
1078 if (uResult
) *uResult
= -1;
1079 ERR("Running across the border without a passport!\n");
1080 return STATUS_UNSUCCESSFUL
;
1084 // These can not cross State lines!
1085 if ( Msg
== WM_CREATE
|| Msg
== WM_NCCREATE
)
1087 if (uResult
) *uResult
= -1;
1088 ERR("Can not tell the other State we have Create!\n");
1089 return STATUS_UNSUCCESSFUL
;
1093 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1095 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1096 return STATUS_INSUFFICIENT_RESOURCES
;
1099 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1101 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1103 /* FIXME: Increase reference counter of sender's message queue here */
1105 Message
->Msg
.hwnd
= Wnd
;
1106 Message
->Msg
.message
= Msg
;
1107 Message
->Msg
.wParam
= wParam
;
1108 Message
->Msg
.lParam
= lParam
;
1109 Message
->CompletionEvent
= &CompletionEvent
;
1110 Message
->Result
= &Result
;
1111 Message
->lResult
= 0;
1112 Message
->QS_Flags
= 0;
1113 Message
->ptiReceiver
= ptirec
;
1114 Message
->ptiSender
= pti
;
1115 Message
->ptiCallBackSender
= NULL
;
1116 Message
->CompletionCallback
= NULL
;
1117 Message
->CompletionCallbackContext
= 0;
1118 Message
->HookMessage
= HookMessage
;
1119 Message
->HasPackedLParam
= FALSE
;
1121 /* Add it to the list of pending messages */
1122 InsertTailList(&pti
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1124 /* Queue it in the destination's message queue */
1125 InsertTailList(&ptirec
->SentMessagesListHead
, &Message
->ListEntry
);
1127 Message
->QS_Flags
= QS_SENDMESSAGE
;
1128 MsqWakeQueue(ptirec
, QS_SENDMESSAGE
, TRUE
);
1130 /* We can't access the Message anymore since it could have already been deleted! */
1136 /* Don't process messages sent to the thread */
1137 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1138 FALSE
, (uTimeout
? &Timeout
: NULL
));
1142 if(WaitStatus
== STATUS_TIMEOUT
)
1144 /* Look up if the message has not yet dispatched, if so
1145 make sure it can't pass a result and it must not set the completion event anymore */
1146 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1147 while (Entry
!= &ptirec
->SentMessagesListHead
)
1149 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1152 /* We can access Message here, it's secure because the message queue is locked
1153 and the message is still hasn't been dispatched */
1154 Message
->CompletionEvent
= NULL
;
1155 Message
->Result
= NULL
;
1158 Entry
= Entry
->Flink
;
1161 /* Remove from the local dispatching list so the other thread knows,
1162 it can't pass a result and it must not set the completion event anymore */
1163 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1164 while (Entry
!= &pti
->DispatchingMessagesHead
)
1166 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1169 /* We can access Message here, it's secure because the sender's message is locked
1170 and the message has definitely not yet been destroyed, otherwise it would
1171 have been removed from this list by the dispatching routine right after
1172 dispatching the message */
1173 Message
->CompletionEvent
= NULL
;
1174 Message
->Result
= NULL
;
1175 RemoveEntryList(&Message
->DispatchingListEntry
);
1176 Message
->DispatchingListEntry
.Flink
= NULL
;
1179 Entry
= Entry
->Flink
;
1182 TRACE("MsqSendMessage (blocked) timed out 1\n");
1184 while (co_MsqDispatchOneSentMessage(ptirec
))
1189 PVOID WaitObjects
[3];
1191 WaitObjects
[0] = &CompletionEvent
; // Wait 0
1192 WaitObjects
[1] = pti
->pEventQueueServer
; // Wait 1
1193 WaitObjects
[2] = ptirec
->pEThread
; // Wait 2
1199 WaitStatus
= KeWaitForMultipleObjects(3, WaitObjects
, WaitAny
, UserRequest
,
1200 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1204 if(WaitStatus
== STATUS_TIMEOUT
)
1206 /* Look up if the message has not yet been dispatched, if so
1207 make sure it can't pass a result and it must not set the completion event anymore */
1208 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1209 while (Entry
!= &ptirec
->SentMessagesListHead
)
1211 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1214 /* We can access Message here, it's secure because the message queue is locked
1215 and the message is still hasn't been dispatched */
1216 Message
->CompletionEvent
= NULL
;
1217 Message
->Result
= NULL
;
1220 Entry
= Entry
->Flink
;
1223 /* Remove from the local dispatching list so the other thread knows,
1224 it can't pass a result and it must not set the completion event anymore */
1225 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1226 while (Entry
!= &pti
->DispatchingMessagesHead
)
1228 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1231 /* We can access Message here, it's secure because the sender's message is locked
1232 and the message has definitely not yet been destroyed, otherwise it would
1233 have been removed from this list by the dispatching routine right after
1234 dispatching the message */
1235 Message
->CompletionEvent
= NULL
;
1236 Message
->Result
= NULL
;
1237 RemoveEntryList(&Message
->DispatchingListEntry
);
1238 Message
->DispatchingListEntry
.Flink
= NULL
;
1241 Entry
= Entry
->Flink
;
1244 TRACE("MsqSendMessage timed out 2\n");
1247 // Receiving thread passed on and left us hanging with issues still pending.
1248 if ( WaitStatus
== STATUS_WAIT_2
)
1250 ERR("Receiving Thread woken up dead!\n");
1251 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1252 while (Entry
!= &pti
->DispatchingMessagesHead
)
1254 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1257 Message
->CompletionEvent
= NULL
;
1258 Message
->Result
= NULL
;
1259 RemoveEntryList(&Message
->DispatchingListEntry
);
1260 Message
->DispatchingListEntry
.Flink
= NULL
;
1263 Entry
= Entry
->Flink
;
1266 while (co_MsqDispatchOneSentMessage(pti
))
1269 while (NT_SUCCESS(WaitStatus
) && WaitStatus
== STATUS_WAIT_1
);
1272 if(WaitStatus
!= STATUS_TIMEOUT
)
1273 if (uResult
) *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1279 MsqPostMessage(PTHREADINFO pti
,
1281 BOOLEAN HardwareMessage
,
1286 PUSER_MESSAGE Message
;
1287 PUSER_MESSAGE_QUEUE MessageQueue
;
1289 if ( pti
->TIF_flags
& TIF_INCLEANUP
|| pti
->MessageQueue
->QF_flags
& QF_INDESTROY
)
1291 ERR("Post Msg; Thread or Q is Dead!\n");
1295 if(!(Message
= MsqCreateMessage(Msg
)))
1300 MessageQueue
= pti
->MessageQueue
;
1304 ERR("Post Msg; System Qeued Event Message!\n");
1305 InsertHeadList(&pti
->PostedMessagesListHead
,
1306 &Message
->ListEntry
);
1308 else if (!HardwareMessage
)
1310 InsertTailList(&pti
->PostedMessagesListHead
,
1311 &Message
->ListEntry
);
1315 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1316 &Message
->ListEntry
);
1319 if (Msg
->message
== WM_HOTKEY
) MessageBits
|= QS_HOTKEY
; // Justin Case, just set it.
1320 Message
->dwQEvent
= dwQEvent
;
1321 Message
->ExtraInfo
= ExtraInfo
;
1322 Message
->QS_Flags
= MessageBits
;
1324 MsqWakeQueue(pti
, MessageBits
, TRUE
);
1328 MsqPostQuitMessage(PTHREADINFO pti
, ULONG ExitCode
)
1330 pti
->QuitPosted
= TRUE
;
1331 pti
->exitCode
= ExitCode
;
1332 MsqWakeQueue(pti
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1335 /***********************************************************************
1336 * MsqSendParentNotify
1338 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1339 * the window has the WS_EX_NOPARENTNOTIFY style.
1341 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1343 PWND pwndDesktop
= UserGetDesktopWindow();
1345 /* pt has to be in the client coordinates of the parent window */
1346 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1347 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1353 if (!(pwnd
->style
& WS_CHILD
)) break;
1354 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1355 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1356 if (pwndParent
== pwndDesktop
) break;
1357 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1358 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1361 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1362 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1368 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1370 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1371 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
1373 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1374 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1375 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1377 TRACE("ITMM: Track Mouse Move!\n");
1379 /* Handle only the changing window track and mouse move across a border. */
1380 if ( pDesk
->spwndTrack
!= pwndTrack
||
1381 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1383 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1384 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1386 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1387 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1388 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1391 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1392 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1394 /* Clear the flags to sign a change. */
1395 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1397 /* Set the Track window and hit test. */
1398 pDesk
->spwndTrack
= pwndTrack
;
1399 pDesk
->htEx
= hittest
;
1402 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1403 if ( pDesk
->spwndTrack
== pwndTrack
&&
1404 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1405 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1407 TRACE("ITMM: Reset Hover points!\n");
1408 // Restart timer for the hover period.
1409 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1410 // Reset desktop mouse hover from the system default hover rectangle.
1411 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1412 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1413 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1414 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1415 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1419 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1426 MOUSEHOOKSTRUCT hook
;
1427 BOOL eatMsg
= FALSE
;
1429 PWND pwndMsg
, pwndDesktop
;
1430 PUSER_MESSAGE_QUEUE MessageQueue
;
1432 PSYSTEM_CURSORINFO CurInfo
;
1434 DECLARE_RETURN(BOOL
);
1436 pti
= PsGetCurrentThreadWin32Thread();
1437 pwndDesktop
= UserGetDesktopWindow();
1438 MessageQueue
= pti
->MessageQueue
;
1439 CurInfo
= IntGetSysCursorInfo();
1440 pwndMsg
= ValidateHwndNoErr(msg
->hwnd
);
1441 clk_msg
= MessageQueue
->msgDblClk
;
1442 pDesk
= pwndDesktop
->head
.rpdesk
;
1444 /* find the window to dispatch this mouse message to */
1445 if (MessageQueue
->spwndCapture
)
1448 pwndMsg
= MessageQueue
->spwndCapture
;
1449 if (pwndMsg
) UserReferenceObject(pwndMsg
);
1453 pwndMsg
= co_WinPosWindowFromPoint(pwndMsg
, &msg
->pt
, &hittest
, FALSE
);
1456 TRACE("Got mouse message for %p, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1458 // Null window or not the same "Hardware" message queue.
1459 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
->MessageQueue
!= pti
->MessageQueue
)
1461 /* Remove and ignore the message */
1462 *RemoveMessages
= TRUE
;
1466 if ( MessageQueue
== gpqCursor
) // Cursor must use the same Queue!
1468 IntTrackMouseMove(pwndMsg
, pDesk
, msg
, hittest
);
1472 ERR("Not the same cursor!\n");
1475 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1478 message
= msg
->message
;
1479 /* Note: windows has no concept of a non-client wheel message */
1480 if (message
!= WM_MOUSEWHEEL
)
1482 if (hittest
!= HTCLIENT
)
1484 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1485 msg
->wParam
= hittest
;
1489 /* coordinates don't get translated while tracking a menu */
1490 /* FIXME: should differentiate popups and top-level menus */
1491 if (!(MessageQueue
->MenuOwner
))
1493 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1494 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1498 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1500 /* translate double clicks */
1502 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1503 (msg
->message
== WM_RBUTTONDOWN
) ||
1504 (msg
->message
== WM_MBUTTONDOWN
) ||
1505 (msg
->message
== WM_XBUTTONDOWN
))
1507 BOOL update
= *RemoveMessages
;
1509 /* translate double clicks -
1510 * note that ...MOUSEMOVEs can slip in between
1511 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1513 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1514 hittest
!= HTCLIENT
||
1515 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1517 if ((msg
->message
== clk_msg
.message
) &&
1518 (msg
->hwnd
== clk_msg
.hwnd
) &&
1519 (msg
->wParam
== clk_msg
.wParam
) &&
1520 ((msg
->time
- clk_msg
.time
) < (ULONG
)gspv
.iDblClickTime
) &&
1521 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1522 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1524 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1527 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1533 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1535 TRACE("Message out of range!!!\n");
1539 /* update static double click conditions */
1540 if (update
) MessageQueue
->msgDblClk
= *msg
;
1544 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1546 TRACE("Message out of range!!!\n");
1550 // Update mouse move down keys.
1551 if (message
== WM_MOUSEMOVE
)
1553 msg
->wParam
= MsqGetDownKeyState(MessageQueue
);
1557 if(gspv
.bMouseClickLock
)
1559 BOOL IsClkLck
= FALSE
;
1561 if(msg
->message
== WM_LBUTTONUP
)
1563 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1564 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1566 CurInfo
->ClickLockActive
= TRUE
;
1569 else if (msg
->message
== WM_LBUTTONDOWN
)
1571 if (CurInfo
->ClickLockActive
)
1574 CurInfo
->ClickLockActive
= FALSE
;
1577 CurInfo
->ClickLockTime
= msg
->time
;
1582 /* Remove and ignore the message */
1583 *RemoveMessages
= TRUE
;
1588 /* message is accepted now (but may still get dropped) */
1590 event
.message
= msg
->message
;
1591 event
.time
= msg
->time
;
1592 event
.hwnd
= msg
->hwnd
;
1593 event
.paramL
= msg
->pt
.x
;
1594 event
.paramH
= msg
->pt
.y
;
1595 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1598 hook
.hwnd
= msg
->hwnd
;
1599 hook
.wHitTestCode
= hittest
;
1600 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1601 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1602 message
, (LPARAM
)&hook
))
1605 hook
.hwnd
= msg
->hwnd
;
1606 hook
.wHitTestCode
= hittest
;
1607 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1608 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1610 ERR("WH_MOUSE dropped mouse message!\n");
1612 /* Remove and skip message */
1613 *RemoveMessages
= TRUE
;
1617 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1619 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1620 MAKELONG( hittest
, msg
->message
));
1622 /* Remove and skip message */
1623 *RemoveMessages
= TRUE
;
1627 if ((*RemoveMessages
== FALSE
) || MessageQueue
->spwndCapture
)
1629 /* Accept the message */
1630 msg
->message
= message
;
1634 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1635 (msg
->message
== WM_RBUTTONDOWN
) ||
1636 (msg
->message
== WM_MBUTTONDOWN
) ||
1637 (msg
->message
== WM_XBUTTONDOWN
))
1639 /* Send the WM_PARENTNOTIFY,
1640 * note that even for double/nonclient clicks
1641 * notification message is still WM_L/M/RBUTTONDOWN.
1643 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1645 /* Activate the window if needed */
1647 if (pwndMsg
!= MessageQueue
->spwndActive
)
1649 PWND pwndTop
= pwndMsg
;
1650 pwndTop
= IntGetNonChildAncestor(pwndTop
);
1652 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1654 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1656 (WPARAM
)UserHMGetHandle(pwndTop
),
1657 MAKELONG( hittest
, msg
->message
));
1660 case MA_NOACTIVATEANDEAT
:
1665 case MA_ACTIVATEANDEAT
:
1670 if (!co_IntMouseActivateWindow( pwndTop
)) eatMsg
= TRUE
;
1673 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1680 /* send the WM_SETCURSOR message */
1682 /* Windows sends the normal mouse message as the message parameter
1683 in the WM_SETCURSOR message even if it's non-client mouse message */
1684 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1686 msg
->message
= message
;
1691 UserDereferenceObject(pwndMsg
);
1696 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1700 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1701 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1703 switch (Msg
->wParam
)
1705 case VK_LSHIFT
: case VK_RSHIFT
:
1706 Msg
->wParam
= VK_SHIFT
;
1708 case VK_LCONTROL
: case VK_RCONTROL
:
1709 Msg
->wParam
= VK_CONTROL
;
1711 case VK_LMENU
: case VK_RMENU
:
1712 Msg
->wParam
= VK_MENU
;
1717 Event
.message
= Msg
->message
;
1718 Event
.hwnd
= Msg
->hwnd
;
1719 Event
.time
= Msg
->time
;
1720 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1721 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1722 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1723 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1725 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1726 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1727 LOWORD(Msg
->wParam
),
1730 /* skip this message */
1731 co_HOOK_CallHooks( WH_CBT
,
1733 LOWORD(Msg
->wParam
),
1735 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1741 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1743 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1745 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1747 else if ( IS_KBD_MESSAGE(Msg
->message
))
1749 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1755 /* check whether a message filter contains at least one potential hardware message */
1757 filter_contains_hw_range( UINT first
, UINT last
)
1759 /* hardware message ranges are (in numerical order):
1760 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1761 * WM_KEYFIRST .. WM_KEYLAST
1762 * WM_MOUSEFIRST .. WM_MOUSELAST
1765 if (last
< WM_NCMOUSEFIRST
) return 0;
1766 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1767 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1768 if (first
> WM_MOUSELAST
) return 0;
1773 co_MsqPeekHardwareMessage(IN PTHREADINFO pti
,
1776 IN UINT MsgFilterLow
,
1777 IN UINT MsgFilterHigh
,
1783 PUSER_MESSAGE CurrentMessage
;
1784 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1787 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
1789 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1791 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1792 CurrentEntry
= ListHead
->Flink
;
1794 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1796 if (!MessageQueue
->ptiSysLock
)
1798 MessageQueue
->ptiSysLock
= pti
;
1799 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1802 if (MessageQueue
->ptiSysLock
!= pti
)
1804 ERR("MsqPeekHardwareMessage: Thread Q is locked to another pti!\n");
1808 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1812 if (IsListEmpty(CurrentEntry
)) break;
1813 if (!CurrentMessage
) break;
1814 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1815 if (!CurrentEntry
) break; //// Fix CORE-6734 reported crash.
1818 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1819 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1820 3: handle to the window whose messages are to be retrieved.
1822 if ( ( !Window
|| // 1
1823 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1824 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) || // 3
1825 ( CurrentMessage
->Msg
.message
== WM_MOUSEMOVE
) ) && // Null window for mouse moves.
1826 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1827 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1829 msg
= CurrentMessage
->Msg
;
1831 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
1832 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1836 RemoveEntryList(&CurrentMessage
->ListEntry
);
1837 ClearMsgBitsMask(pti
, CurrentMessage
->QS_Flags
);
1838 MsqDestroyMessage(CurrentMessage
);
1848 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
1850 while(CurrentEntry
!= ListHead
);
1852 MessageQueue
->ptiSysLock
= NULL
;
1853 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1858 MsqPeekMessage(IN PTHREADINFO pti
,
1861 IN UINT MsgFilterLow
,
1862 IN UINT MsgFilterHigh
,
1866 PLIST_ENTRY CurrentEntry
;
1867 PUSER_MESSAGE CurrentMessage
;
1868 PLIST_ENTRY ListHead
;
1871 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
1872 ListHead
= &pti
->PostedMessagesListHead
;
1874 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1876 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1880 if (IsListEmpty(CurrentEntry
)) break;
1881 if (!CurrentMessage
) break;
1882 CurrentEntry
= CurrentEntry
->Flink
;
1885 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1886 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1887 3: handle to the window whose messages are to be retrieved.
1889 if ( ( !Window
|| // 1
1890 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1891 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1892 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1893 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1895 *Message
= CurrentMessage
->Msg
;
1899 RemoveEntryList(&CurrentMessage
->ListEntry
);
1900 ClearMsgBitsMask(pti
, CurrentMessage
->QS_Flags
);
1901 MsqDestroyMessage(CurrentMessage
);
1906 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1909 while (CurrentEntry
!= ListHead
);
1915 co_MsqWaitForNewMessages(PTHREADINFO pti
, PWND WndFilter
,
1916 UINT MsgFilterMin
, UINT MsgFilterMax
)
1920 ret
= KeWaitForSingleObject( pti
->pEventQueueServer
,
1930 MsqIsHung(PTHREADINFO pti
)
1932 LARGE_INTEGER LargeTickCount
;
1934 KeQueryTickCount(&LargeTickCount
);
1935 return ((LargeTickCount
.u
.LowPart
- pti
->timeLast
) > MSQ_HUNG
);
1940 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1943 TRACE("HungAppSysTimerProc\n");
1944 // Process list of windows that are hung and waiting.
1948 MsqInitializeMessageQueue(PTHREADINFO pti
, PUSER_MESSAGE_QUEUE MessageQueue
)
1950 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1951 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
); // Keep here!
1952 MessageQueue
->spwndFocus
= NULL
;
1953 MessageQueue
->iCursorLevel
= 0;
1954 MessageQueue
->CursorObject
= NULL
;
1955 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
1956 MessageQueue
->ptiMouse
= pti
;
1957 MessageQueue
->ptiKeyboard
= pti
;
1958 MessageQueue
->cThreads
++;
1964 MsqCleanupThreadMsgs(PTHREADINFO pti
)
1966 PLIST_ENTRY CurrentEntry
;
1967 PUSER_MESSAGE CurrentMessage
;
1968 PUSER_SENT_MESSAGE CurrentSentMessage
;
1970 /* cleanup posted messages */
1971 while (!IsListEmpty(&pti
->PostedMessagesListHead
))
1973 CurrentEntry
= RemoveHeadList(&pti
->PostedMessagesListHead
);
1974 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1976 MsqDestroyMessage(CurrentMessage
);
1979 /* remove the messages that have not yet been dispatched */
1980 while (!IsListEmpty(&pti
->SentMessagesListHead
))
1982 CurrentEntry
= RemoveHeadList(&pti
->SentMessagesListHead
);
1983 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1986 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
1987 /* Only if the message has a sender was the message in the DispatchingList */
1988 if ((CurrentSentMessage
->ptiSender
)
1989 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1991 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1994 /* wake the sender's thread */
1995 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1997 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2000 if (CurrentSentMessage
->HasPackedLParam
)
2002 if (CurrentSentMessage
->Msg
.lParam
)
2003 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2006 /* free the message */
2007 ExFreePool(CurrentSentMessage
);
2010 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
2011 ExitThread() was called in a SendMessage() umode callback */
2012 while (!IsListEmpty(&pti
->LocalDispatchingMessagesHead
))
2014 CurrentEntry
= RemoveHeadList(&pti
->LocalDispatchingMessagesHead
);
2015 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2018 /* remove the message from the dispatching list */
2019 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
2021 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
2024 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
2026 /* wake the sender's thread */
2027 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
2029 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2032 if (CurrentSentMessage
->HasPackedLParam
)
2034 if (CurrentSentMessage
->Msg
.lParam
)
2035 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2038 /* free the message */
2039 ExFreePool(CurrentSentMessage
);
2042 /* tell other threads not to bother returning any info to us */
2043 while (! IsListEmpty(&pti
->DispatchingMessagesHead
))
2045 CurrentEntry
= RemoveHeadList(&pti
->DispatchingMessagesHead
);
2046 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2047 DispatchingListEntry
);
2048 CurrentSentMessage
->CompletionEvent
= NULL
;
2049 CurrentSentMessage
->Result
= NULL
;
2051 /* do NOT dereference our message queue as it might get attempted to be
2055 // Clear it all out.
2058 pti
->pcti
->fsWakeBits
= 0;
2059 pti
->pcti
->fsChangeBits
= 0;
2062 pti
->nCntsQBits
[QSRosKey
] = 0;
2063 pti
->nCntsQBits
[QSRosMouseMove
] = 0;
2064 pti
->nCntsQBits
[QSRosMouseButton
] = 0;
2065 pti
->nCntsQBits
[QSRosPostMessage
] = 0;
2066 pti
->nCntsQBits
[QSRosSendMessage
] = 0;
2067 pti
->nCntsQBits
[QSRosHotKey
] = 0;
2068 pti
->nCntsQBits
[QSRosEvent
] = 0;
2072 MsqCleanupMessageQueue(PTHREADINFO pti
)
2074 PUSER_MESSAGE_QUEUE MessageQueue
;
2076 MessageQueue
= pti
->MessageQueue
;
2077 MessageQueue
->cThreads
--;
2079 if (MessageQueue
->cThreads
)
2081 if (MessageQueue
->ptiSysLock
== pti
) MessageQueue
->ptiSysLock
= NULL
;
2084 if (MessageQueue
->CursorObject
)
2086 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2088 /* Change to another cursor if we going to dereference current one
2089 Note: we can't use UserSetCursor because it uses current thread
2090 message queue instead of queue given for cleanup */
2091 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2095 /* Get the screen DC */
2096 hdcScreen
= IntGetScreenDC();
2098 GreMovePointer(hdcScreen
, -1, -1);
2099 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2102 TRACE("DereferenceObject pCursor\n");
2103 UserDereferenceObject(pCursor
);
2106 if (gpqForeground
== MessageQueue
)
2108 IntSetFocusMessageQueue(NULL
);
2110 if (gpqForegroundPrev
== MessageQueue
)
2112 gpqForegroundPrev
= NULL
;
2114 if (gpqCursor
== MessageQueue
)
2120 PUSER_MESSAGE_QUEUE FASTCALL
2121 MsqCreateMessageQueue(PTHREADINFO pti
)
2123 PUSER_MESSAGE_QUEUE MessageQueue
;
2125 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2126 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2134 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2135 /* hold at least one reference until it'll be destroyed */
2136 IntReferenceMessageQueue(MessageQueue
);
2137 /* initialize the queue */
2138 if (!MsqInitializeMessageQueue(pti
, MessageQueue
))
2140 IntDereferenceMessageQueue(MessageQueue
);
2144 return MessageQueue
;
2148 MsqDestroyMessageQueue(PTHREADINFO pti
)
2151 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2153 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2155 /* remove the message queue from any desktops */
2156 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2158 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2159 IntDereferenceMessageQueue(MessageQueue
);
2163 MsqCleanupMessageQueue(pti
);
2165 /* decrease the reference counter, if it hits zero, the queue will be freed */
2166 IntDereferenceMessageQueue(MessageQueue
);
2170 MsqSetMessageExtraInfo(LPARAM lParam
)
2174 PUSER_MESSAGE_QUEUE MessageQueue
;
2176 pti
= PsGetCurrentThreadWin32Thread();
2177 MessageQueue
= pti
->MessageQueue
;
2183 Ret
= MessageQueue
->ExtraInfo
;
2184 MessageQueue
->ExtraInfo
= lParam
;
2190 MsqGetMessageExtraInfo(VOID
)
2193 PUSER_MESSAGE_QUEUE MessageQueue
;
2195 pti
= PsGetCurrentThreadWin32Thread();
2196 MessageQueue
= pti
->MessageQueue
;
2202 return MessageQueue
->ExtraInfo
;
2205 // ReplyMessage is called by the thread receiving the window message.
2207 co_MsqReplyMessage( LRESULT lResult
)
2209 PUSER_SENT_MESSAGE Message
;
2212 pti
= PsGetCurrentThreadWin32Thread();
2213 Message
= pti
->pusmCurrent
;
2215 if (!Message
) return FALSE
;
2217 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2219 // SendMessageXxx || Callback msg and not a notify msg
2220 if (Message
->ptiSender
|| Message
->CompletionCallback
)
2222 Message
->lResult
= lResult
;
2223 Message
->QS_Flags
|= QS_SMRESULT
;
2224 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2230 MsqSetStateWindow(PTHREADINFO pti
, ULONG Type
, HWND hWnd
)
2233 PUSER_MESSAGE_QUEUE MessageQueue
;
2235 MessageQueue
= pti
->MessageQueue
;
2239 case MSQ_STATE_CAPTURE
:
2240 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2241 MessageQueue
->spwndCapture
= ValidateHwndNoErr(hWnd
);
2243 case MSQ_STATE_ACTIVE
:
2244 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2245 MessageQueue
->spwndActive
= ValidateHwndNoErr(hWnd
);
2247 case MSQ_STATE_FOCUS
:
2248 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2249 MessageQueue
->spwndFocus
= ValidateHwndNoErr(hWnd
);
2251 case MSQ_STATE_MENUOWNER
:
2252 Prev
= MessageQueue
->MenuOwner
;
2253 MessageQueue
->MenuOwner
= hWnd
;
2255 case MSQ_STATE_MOVESIZE
:
2256 Prev
= MessageQueue
->MoveSize
;
2257 MessageQueue
->MoveSize
= hWnd
;
2259 case MSQ_STATE_CARET
:
2260 ASSERT(MessageQueue
->CaretInfo
);
2261 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2262 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2271 NtUserGetKeyState(INT key
)
2277 Ret
= UserGetKeyState(key
);
2287 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2289 DWORD i
, ret
= TRUE
;
2291 PUSER_MESSAGE_QUEUE MessageQueue
;
2295 pti
= PsGetCurrentThreadWin32Thread();
2296 MessageQueue
= pti
->MessageQueue
;
2300 /* Probe and copy key state to an array */
2301 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2302 for (i
= 0; i
< 256; ++i
)
2305 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2306 lpKeyState
[i
] |= KS_DOWN_BIT
;
2307 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2308 lpKeyState
[i
] |= KS_LOCK_BIT
;
2311 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2313 SetLastNtError(_SEH2_GetExceptionCode());
2325 NtUserSetKeyboardState(LPBYTE pKeyState
)
2330 PUSER_MESSAGE_QUEUE MessageQueue
;
2332 UserEnterExclusive();
2334 pti
= PsGetCurrentThreadWin32Thread();
2335 MessageQueue
= pti
->MessageQueue
;
2339 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2340 for (i
= 0; i
< 256; ++i
)
2342 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2343 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2346 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2348 SetLastNtError(_SEH2_GetExceptionCode());