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
;
19 /* FUNCTIONS *****************************************************************/
24 MsqInitializeImpl(VOID
)
26 pgMessageLookasideList
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(PAGED_LOOKASIDE_LIST
), TAG_USRMSG
);
27 if(!pgMessageLookasideList
)
28 return STATUS_NO_MEMORY
;
29 ExInitializePagedLookasideList(pgMessageLookasideList
,
37 return(STATUS_SUCCESS
);
41 IntChildrenWindowFromPoint(PWND pWndTop
, INT x
, INT y
)
45 if (!(pWndTop
->style
& WS_VISIBLE
)) return NULL
;
46 if ((pWndTop
->style
& WS_DISABLED
)) return NULL
;
47 if (!IntPtInWindow(pWndTop
, x
, y
)) return NULL
;
49 if (RECTL_bPointInRect(&pWndTop
->rcClient
, x
, y
))
51 for (pWnd
= pWndTop
->spwndChild
;
53 pWnd
= pWnd
->spwndNext
)
55 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
57 TRACE("The Window is in DESTROY!\n");
61 pWndChild
= IntChildrenWindowFromPoint(pWnd
, x
, y
);
73 IntTopLevelWindowFromPoint(INT x
, INT y
)
75 PWND pWnd
, pwndDesktop
;
77 /* Get the desktop window */
78 pwndDesktop
= UserGetDesktopWindow();
82 /* Loop all top level windows */
83 for (pWnd
= pwndDesktop
->spwndChild
;
85 pWnd
= pWnd
->spwndNext
)
87 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
89 TRACE("The Window is in DESTROY!\n");
93 if ((pWnd
->style
& WS_VISIBLE
) && IntPtInWindow(pWnd
, x
, y
))
97 /* Window has not been found */
104 PCURICON_OBJECT NewCursor
,
107 PCURICON_OBJECT OldCursor
;
110 PUSER_MESSAGE_QUEUE MessageQueue
;
113 pti
= PsGetCurrentThreadWin32Thread();
114 MessageQueue
= pti
->MessageQueue
;
116 /* Get the screen DC */
117 if(!(hdcScreen
= IntGetScreenDC()))
122 OldCursor
= MessageQueue
->CursorObject
;
124 /* Check if cursors are different */
125 if (OldCursor
== NewCursor
)
128 /* Update cursor for this message queue */
129 MessageQueue
->CursorObject
= NewCursor
;
131 /* If cursor is not visible we have nothing to do */
132 if (MessageQueue
->iCursorLevel
< 0)
135 /* Update cursor if this message queue controls it */
136 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
137 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
141 /* Call GDI to set the new screen cursor */
142 GreSetPointerShape(hdcScreen
,
143 NewCursor
->IconInfo
.hbmMask
,
144 NewCursor
->IconInfo
.hbmColor
,
145 NewCursor
->IconInfo
.xHotspot
,
146 NewCursor
->IconInfo
.yHotspot
,
150 else /* Note: OldCursor != NewCursor so we have to hide cursor */
152 /* Remove the cursor */
153 GreMovePointer(hdcScreen
, -1, -1);
154 TRACE("Removing pointer!\n");
156 IntGetSysCursorInfo()->CurrentCursorObject
= NewCursor
;
159 /* Return the old cursor */
163 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
164 * User32 macro NtUserShowCursor */
165 int UserShowCursor(BOOL bShow
)
169 PUSER_MESSAGE_QUEUE MessageQueue
;
172 if (!(hdcScreen
= IntGetScreenDC()))
174 return -1; /* No mouse */
177 pti
= PsGetCurrentThreadWin32Thread();
178 MessageQueue
= pti
->MessageQueue
;
181 MessageQueue
->iCursorLevel
+= bShow
? 1 : -1;
182 pti
->iCursorLevel
+= bShow
? 1 : -1;
184 /* Check for trivial cases */
185 if ((bShow
&& MessageQueue
->iCursorLevel
!= 0) ||
186 (!bShow
&& MessageQueue
->iCursorLevel
!= -1))
188 /* Note: w don't update global info here because it is used only
189 internally to check if cursor is visible */
190 return MessageQueue
->iCursorLevel
;
193 /* Check if cursor is above window owned by this MessageQueue */
194 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
195 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
199 /* Show the pointer */
200 GreMovePointer(hdcScreen
, gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
201 TRACE("Showing pointer!\n");
205 /* Remove the pointer */
206 GreMovePointer(hdcScreen
, -1, -1);
207 TRACE("Removing pointer!\n");
210 /* Update global info */
211 IntGetSysCursorInfo()->ShowingCursor
= MessageQueue
->iCursorLevel
;
214 return MessageQueue
->iCursorLevel
;
218 UserGetKeyState(DWORD dwKey
)
222 PUSER_MESSAGE_QUEUE MessageQueue
;
224 pti
= PsGetCurrentThreadWin32Thread();
225 MessageQueue
= pti
->MessageQueue
;
229 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, dwKey
))
230 dwRet
|= 0xFF80; // If down, windows returns 0xFF80.
231 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, dwKey
))
236 EngSetLastError(ERROR_INVALID_PARAMETER
);
241 /* change the input key state for a given key */
243 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue
, WORD wVk
, BOOL bIsDown
)
245 TRACE("UpdateKeyState wVk: %d, bIsDown: %d\n", wVk
, bIsDown
);
249 /* If it's first key down event, xor lock bit */
250 if (!IS_KEY_DOWN(MessageQueue
->afKeyState
, wVk
))
251 SET_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
, !IS_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
));
253 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, TRUE
);
254 MessageQueue
->afKeyRecentDown
[wVk
/ 8] |= (1 << (wVk
% 8));
257 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, FALSE
);
260 /* update the input key state for a keyboard message */
262 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
267 TRACE("UpdateKeyStateFromMsg message:%d\n", msg
->message
);
269 switch (msg
->message
)
275 UpdateKeyState(MessageQueue
, VK_LBUTTON
, down
);
281 UpdateKeyState(MessageQueue
, VK_MBUTTON
, down
);
287 UpdateKeyState(MessageQueue
, VK_RBUTTON
, down
);
293 if (msg
->wParam
== XBUTTON1
)
294 UpdateKeyState(MessageQueue
, VK_XBUTTON1
, down
);
295 else if (msg
->wParam
== XBUTTON2
)
296 UpdateKeyState(MessageQueue
, VK_XBUTTON2
, down
);
304 key
= (UCHAR
)msg
->wParam
;
305 UpdateKeyState(MessageQueue
, key
, down
);
310 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LCONTROL
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RCONTROL
);
311 UpdateKeyState(MessageQueue
, VK_CONTROL
, down
);
315 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LMENU
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RMENU
);
316 UpdateKeyState(MessageQueue
, VK_MENU
, down
);
320 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LSHIFT
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RSHIFT
);
321 UpdateKeyState(MessageQueue
, VK_SHIFT
, down
);
329 IntMsqSetWakeMask(DWORD WakeMask
)
331 PTHREADINFO Win32Thread
;
332 PUSER_MESSAGE_QUEUE MessageQueue
;
333 HANDLE MessageEventHandle
;
334 DWORD dwFlags
= HIWORD(WakeMask
);
336 Win32Thread
= PsGetCurrentThreadWin32Thread();
337 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
340 MessageQueue
= Win32Thread
->MessageQueue
;
341 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
342 MessageEventHandle
= MessageQueue
->NewMessagesHandle
;
344 if (Win32Thread
->pcti
)
346 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
347 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
349 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
350 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
351 return MessageEventHandle
;
357 return MessageEventHandle
;
361 IntMsqClearWakeMask(VOID
)
363 PTHREADINFO Win32Thread
;
365 Win32Thread
= PsGetCurrentThreadWin32Thread();
366 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
368 // Very hacky, but that is what they do.
369 Win32Thread
->pcti
->fsWakeBits
= 0;
377 Due to the uncertainty of knowing what was set in our multilevel message queue,
378 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
379 I think this is the best solution... (jt) */
381 MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue
, DWORD MessageBits
, BOOL KeyEvent
)
385 if (Queue
->QF_flags
& QF_INDESTROY
)
387 ERR("This Message Queue is in Destroy!\n");
389 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
390 pti
->pcti
->fsWakeBits
|= MessageBits
;
391 pti
->pcti
->fsChangeBits
|= MessageBits
;
393 // Start bit accounting to help clear the main set of bits.
394 if (MessageBits
& QS_KEY
) Queue
->nCntsQBits
[QSRosKey
]++;
395 if (MessageBits
& QS_MOUSEMOVE
) Queue
->nCntsQBits
[QSRosMouseMove
]++;
396 if (MessageBits
& QS_MOUSEBUTTON
) Queue
->nCntsQBits
[QSRosMouseButton
]++;
397 if (MessageBits
& QS_POSTMESSAGE
) Queue
->nCntsQBits
[QSRosPostMessage
]++;
398 if (MessageBits
& QS_SENDMESSAGE
) Queue
->nCntsQBits
[QSRosSendMessage
]++;
399 if (MessageBits
& QS_HOTKEY
) Queue
->nCntsQBits
[QSRosHotKey
]++;
402 KeSetEvent(Queue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
406 ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue
, UINT MessageBits
)
411 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
413 if (MessageBits
& QS_KEY
)
415 if (--Queue
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
417 if (MessageBits
& QS_MOUSEMOVE
) // ReactOS hard coded.
418 { // Account for tracking mouse moves..
419 if (--Queue
->nCntsQBits
[QSRosMouseMove
] == 0) ClrMask
|= QS_MOUSEMOVE
;
420 // Handle mouse move bits here.
421 if (Queue
->MouseMoved
) ClrMask
|= QS_MOUSEMOVE
;
423 if (MessageBits
& QS_MOUSEBUTTON
)
425 if (--Queue
->nCntsQBits
[QSRosMouseButton
] == 0) ClrMask
|= QS_MOUSEBUTTON
;
427 if (MessageBits
& QS_POSTMESSAGE
)
429 if (--Queue
->nCntsQBits
[QSRosPostMessage
] == 0) ClrMask
|= QS_POSTMESSAGE
;
431 if (MessageBits
& QS_TIMER
) // ReactOS hard coded.
432 { // Handle timer bits here.
433 if ( pti
->cTimersReady
)
435 if (--pti
->cTimersReady
== 0) ClrMask
|= QS_TIMER
;
438 if (MessageBits
& QS_PAINT
) // ReactOS hard coded.
439 { // Handle paint bits here.
440 if ( pti
->cPaintsReady
)
442 if (--pti
->cPaintsReady
== 0) ClrMask
|= QS_PAINT
;
445 if (MessageBits
& QS_SENDMESSAGE
)
447 if (--Queue
->nCntsQBits
[QSRosSendMessage
] == 0) ClrMask
|= QS_SENDMESSAGE
;
449 if (MessageBits
& QS_HOTKEY
)
451 if (--Queue
->nCntsQBits
[QSRosHotKey
] == 0) ClrMask
|= QS_HOTKEY
;
454 pti
->pcti
->fsWakeBits
&= ~ClrMask
;
455 pti
->pcti
->fsChangeBits
&= ~ClrMask
;
459 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
462 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
464 MsqWakeQueue(Queue
, QS_PAINT
, TRUE
);
468 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
470 ClearMsgBitsMask(Queue
, QS_PAINT
);
474 MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
)
476 MessageQueue
->MouseMoveMsg
= *Msg
;
477 MessageQueue
->MouseMoved
= TRUE
;
478 MsqWakeQueue(MessageQueue
, QS_MOUSEMOVE
, TRUE
);
482 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
484 LARGE_INTEGER LargeTickCount
;
485 MSLLHOOKSTRUCT MouseHookData
;
487 PWND pwnd
, pwndDesktop
;
489 PUSER_MESSAGE_QUEUE MessageQueue
;
490 PSYSTEM_CURSORINFO CurInfo
;
492 KeQueryTickCount(&LargeTickCount
);
493 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
495 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
496 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
497 switch (Msg
->message
)
500 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
504 case WM_XBUTTONDBLCLK
:
505 case WM_NCXBUTTONDOWN
:
507 case WM_NCXBUTTONDBLCLK
:
508 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
511 MouseHookData
.mouseData
= 0;
515 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
516 MouseHookData
.time
= Msg
->time
;
517 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
519 /* If the hook procedure returned non zero, dont send the message */
522 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
526 /* Get the desktop window */
527 pwndDesktop
= UserGetDesktopWindow();
528 if (!pwndDesktop
) return;
529 pDesk
= pwndDesktop
->head
.rpdesk
;
531 /* Check if the mouse is captured */
532 Msg
->hwnd
= IntGetCaptureWindow();
533 if (Msg
->hwnd
!= NULL
)
535 pwnd
= UserGetWindowObject(Msg
->hwnd
);
539 pwnd
= IntTopLevelWindowFromPoint(Msg
->pt
.x
, Msg
->pt
.y
);
540 if (pwnd
) Msg
->hwnd
= pwnd
->head
.h
;
543 hdcScreen
= IntGetScreenDC();
544 CurInfo
= IntGetSysCursorInfo();
546 /* Check if we found a window */
547 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
549 MessageQueue
= pwnd
->head
.pti
->MessageQueue
;
551 if ( pwnd
->head
.pti
->TIF_flags
& TIF_INCLEANUP
|| MessageQueue
->QF_flags
& QF_INDESTROY
)
553 ERR("Mouse is over the Window Thread is Dead!\n");
557 if (Msg
->message
== WM_MOUSEMOVE
)
559 /* Check if cursor should be visible */
561 MessageQueue
->CursorObject
&&
562 MessageQueue
->iCursorLevel
>= 0)
564 /* Check if shape has changed */
565 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
567 /* Call GDI to set the new screen cursor */
568 GreSetPointerShape(hdcScreen
,
569 MessageQueue
->CursorObject
->IconInfo
.hbmMask
,
570 MessageQueue
->CursorObject
->IconInfo
.hbmColor
,
571 MessageQueue
->CursorObject
->IconInfo
.xHotspot
,
572 MessageQueue
->CursorObject
->IconInfo
.yHotspot
,
576 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
578 /* Check if w have to hide cursor */
579 else if (CurInfo
->ShowingCursor
>= 0)
580 GreMovePointer(hdcScreen
, -1, -1);
582 /* Update global cursor info */
583 CurInfo
->ShowingCursor
= MessageQueue
->iCursorLevel
;
584 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
585 gpqCursor
= MessageQueue
;
587 /* Mouse move is a special case */
588 MsqPostMouseMove(MessageQueue
, Msg
);
592 TRACE("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd
));
593 MsqPostMessage(MessageQueue
, Msg
, TRUE
, QS_MOUSEBUTTON
);
598 /* always show cursor on background; FIXME: set default pointer */
599 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
600 CurInfo
->ShowingCursor
= 0;
605 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
608 PTHREADINFO Win32Thread
;
610 LARGE_INTEGER LargeTickCount
;
615 Status
= ObReferenceObjectByPointer (Thread
,
619 if (!NT_SUCCESS(Status
))
622 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
623 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
625 ObDereferenceObject ((PETHREAD
)Thread
);
629 Window
= IntGetWindowObject(hWnd
);
632 ObDereferenceObject ((PETHREAD
)Thread
);
636 id
= wParam
; // Check for hot keys unrelated to the hot keys set by RegisterHotKey.
639 Mesg
.message
= id
!= IDHK_REACTOS
? WM_HOTKEY
: WM_SYSCOMMAND
;
640 Mesg
.wParam
= id
!= IDHK_REACTOS
? wParam
: SC_HOTKEY
;
641 Mesg
.lParam
= id
!= IDHK_REACTOS
? lParam
: (LPARAM
)hWnd
;
642 Type
= id
!= IDHK_REACTOS
? QS_HOTKEY
: QS_POSTMESSAGE
;
643 KeQueryTickCount(&LargeTickCount
);
644 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
645 Mesg
.pt
= gpsi
->ptCursor
;
646 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, Type
);
647 UserDereferenceObject(Window
);
648 ObDereferenceObject (Thread
);
652 PUSER_MESSAGE FASTCALL
653 MsqCreateMessage(LPMSG Msg
)
655 PUSER_MESSAGE Message
;
657 Message
= ExAllocateFromPagedLookasideList(pgMessageLookasideList
);
663 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
669 MsqDestroyMessage(PUSER_MESSAGE Message
)
671 ExFreeToPagedLookasideList(pgMessageLookasideList
, Message
);
675 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
677 PUSER_SENT_MESSAGE SaveMsg
, Message
;
683 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
688 /* remove it from the list of pending messages */
689 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
690 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
692 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
694 SaveMsg
= pti
->pusmCurrent
;
695 pti
->pusmCurrent
= Message
;
697 // Processing a message sent to it from another thread.
698 if ( ( Message
->SenderQueue
&& MessageQueue
!= Message
->SenderQueue
) ||
699 ( Message
->CallBackSenderQueue
&& MessageQueue
!= Message
->CallBackSenderQueue
))
700 { // most likely, but, to be sure.
701 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
704 /* insert it to the list of messages that are currently dispatched by this
706 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
707 &Message
->ListEntry
);
709 ClearMsgBitsMask(MessageQueue
, Message
->QS_Flags
);
711 if (Message
->HookMessage
== MSQ_ISHOOK
)
712 { // Direct Hook Call processor
713 Result
= co_CallHook( Message
->Msg
.message
, // HookId
714 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
716 Message
->Msg
.lParam
);
718 else if (Message
->HookMessage
== MSQ_ISEVENT
)
719 { // Direct Event Call processor
720 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
723 Message
->Msg
.lParam
);
725 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
727 Result
= IntLoadHookModule(Message
->Msg
.message
,
728 (HHOOK
)Message
->Msg
.lParam
,
729 Message
->Msg
.wParam
);
731 else if ((Message
->CompletionCallback
) &&
732 (Message
->CallBackSenderQueue
== MessageQueue
))
733 { /* Call the callback routine */
734 if (Message
->QS_Flags
& QS_SMRESULT
)
736 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
738 Message
->Msg
.message
,
739 Message
->CompletionCallbackContext
,
741 /* Set callback to NULL to prevent reentry */
742 Message
->CompletionCallback
= NULL
;
746 /* The message has not been processed yet, reinsert it. */
747 RemoveEntryList(&Message
->ListEntry
);
748 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
749 TRACE("Callback Message not processed yet. Requeuing the message\n");
755 { /* Call the window procedure. */
756 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
757 Message
->Msg
.message
,
759 Message
->Msg
.lParam
);
762 /* remove the message from the local dispatching list, because it doesn't need
763 to be cleaned up on thread termination anymore */
764 RemoveEntryList(&Message
->ListEntry
);
766 /* If the message is a callback, insert it in the callback senders MessageQueue */
767 if (Message
->CompletionCallback
)
769 if (Message
->CallBackSenderQueue
)
771 Message
->lResult
= Result
;
772 Message
->QS_Flags
|= QS_SMRESULT
;
774 /* insert it in the callers message queue */
775 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
776 MsqWakeQueue(Message
->CallBackSenderQueue
, QS_SENDMESSAGE
, TRUE
);
777 IntDereferenceMessageQueue(Message
->CallBackSenderQueue
);
783 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
784 if (Message
->SenderQueue
)
786 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
788 /* only remove it from the dispatching list if not already removed by a timeout */
789 RemoveEntryList(&Message
->DispatchingListEntry
);
792 /* still keep the sender's message queue locked, so the sender can't exit the
793 MsqSendMessage() function (if timed out) */
795 if (Message
->QS_Flags
& QS_SMRESULT
)
797 Result
= Message
->lResult
;
800 /* Let the sender know the result. */
801 if (Message
->Result
!= NULL
)
803 *Message
->Result
= Result
;
806 if (Message
->HasPackedLParam
== TRUE
)
808 if (Message
->Msg
.lParam
)
809 ExFreePool((PVOID
)Message
->Msg
.lParam
);
812 /* Notify the sender. */
813 if (Message
->CompletionEvent
!= NULL
)
815 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
818 /* if the message has a sender */
819 if (Message
->SenderQueue
)
821 /* dereference our and the sender's message queue */
822 IntDereferenceMessageQueue(Message
->SenderQueue
);
823 IntDereferenceMessageQueue(MessageQueue
);
826 /* free the message */
827 ExFreePoolWithTag(Message
, TAG_USRMSG
);
830 /* do not hangup on the user if this is reentering */
831 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
832 pti
->pusmCurrent
= SaveMsg
;
838 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
840 PUSER_SENT_MESSAGE SentMessage
;
841 PUSER_MESSAGE PostedMessage
;
842 PUSER_MESSAGE_QUEUE MessageQueue
;
843 PLIST_ENTRY CurrentEntry
, ListHead
;
844 PWND Window
= pWindow
;
848 MessageQueue
= Window
->head
.pti
->MessageQueue
;
849 ASSERT(MessageQueue
);
851 /* remove the posted messages for this window */
852 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
853 ListHead
= &MessageQueue
->PostedMessagesListHead
;
854 while (CurrentEntry
!= ListHead
)
856 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
858 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
860 RemoveEntryList(&PostedMessage
->ListEntry
);
861 ClearMsgBitsMask(MessageQueue
, PostedMessage
->QS_Flags
);
862 MsqDestroyMessage(PostedMessage
);
863 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
867 CurrentEntry
= CurrentEntry
->Flink
;
871 /* remove the sent messages for this window */
872 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
873 ListHead
= &MessageQueue
->SentMessagesListHead
;
874 while (CurrentEntry
!= ListHead
)
876 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
878 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
880 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
882 RemoveEntryList(&SentMessage
->ListEntry
);
883 ClearMsgBitsMask(MessageQueue
, SentMessage
->QS_Flags
);
885 /* if it is a callback and this queue is not the sender queue, dereference queue */
886 if ((SentMessage
->CompletionCallback
) && (SentMessage
->CallBackSenderQueue
!= MessageQueue
))
888 IntDereferenceMessageQueue(SentMessage
->CallBackSenderQueue
);
890 /* Only if the message has a sender was the queue referenced */
891 if ((SentMessage
->SenderQueue
)
892 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
894 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
897 /* wake the sender's thread */
898 if (SentMessage
->CompletionEvent
!= NULL
)
900 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
903 if (SentMessage
->HasPackedLParam
== TRUE
)
905 if (SentMessage
->Msg
.lParam
)
906 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
909 /* if the message has a sender */
910 if (SentMessage
->SenderQueue
)
912 /* dereference our and the sender's message queue */
913 IntDereferenceMessageQueue(MessageQueue
);
914 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
917 /* free the message */
918 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
920 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
924 CurrentEntry
= CurrentEntry
->Flink
;
930 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
935 SENDASYNCPROC CompletionCallback
,
936 ULONG_PTR CompletionCallbackContext
,
937 BOOL HasPackedLParam
,
941 PTHREADINFO ptiSender
;
942 PUSER_SENT_MESSAGE Message
;
944 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
946 ERR("MsqSendMessage(): Not enough memory to allocate a message");
950 ptiSender
= PsGetCurrentThreadWin32Thread();
952 IntReferenceMessageQueue(ptiReceiver
->MessageQueue
);
953 /* Take reference on this MessageQueue if its a callback. It will be released
954 when message is processed or removed from target hwnd MessageQueue */
955 if (CompletionCallback
)
956 IntReferenceMessageQueue(ptiSender
->MessageQueue
);
958 Message
->Msg
.hwnd
= hwnd
;
959 Message
->Msg
.message
= Msg
;
960 Message
->Msg
.wParam
= wParam
;
961 Message
->Msg
.lParam
= lParam
;
962 Message
->CompletionEvent
= NULL
;
964 Message
->lResult
= 0;
965 Message
->SenderQueue
= NULL
;
966 Message
->CallBackSenderQueue
= ptiSender
->MessageQueue
;
967 Message
->DispatchingListEntry
.Flink
= NULL
;
968 Message
->CompletionCallback
= CompletionCallback
;
969 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
970 Message
->HookMessage
= HookMessage
;
971 Message
->HasPackedLParam
= HasPackedLParam
;
972 Message
->QS_Flags
= QS_SENDMESSAGE
;
974 InsertTailList(&ptiReceiver
->MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
975 MsqWakeQueue(ptiReceiver
->MessageQueue
, QS_SENDMESSAGE
, TRUE
);
976 IntDereferenceMessageQueue(ptiReceiver
->MessageQueue
);
982 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
983 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
984 UINT uTimeout
, BOOL Block
, INT HookMessage
,
987 PTHREADINFO pti
, ptirec
;
988 PUSER_SENT_MESSAGE Message
;
989 KEVENT CompletionEvent
;
991 PUSER_MESSAGE_QUEUE ThreadQueue
;
992 LARGE_INTEGER Timeout
;
994 LRESULT Result
= 0; //// Result could be trashed. ////
996 pti
= PsGetCurrentThreadWin32Thread();
997 ThreadQueue
= pti
->MessageQueue
;
998 ptirec
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
999 ASSERT(ThreadQueue
!= MessageQueue
);
1000 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
1002 /* Don't send from or to a dying thread */
1003 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
1005 if (uResult
) *uResult
= -1;
1006 ERR("MsqSM: Current pti %d or Rec pti %d\n",pti
->TIF_flags
& TIF_INCLEANUP
, ptirec
->TIF_flags
& TIF_INCLEANUP
);
1007 return STATUS_UNSUCCESSFUL
;
1010 if ( HookMessage
== MSQ_NORMAL
)
1012 // These can not cross International Border lines!
1013 if ( pti
->ppi
!= ptirec
->ppi
)
1018 case EM_SETPASSWORDCHAR
:
1021 if (uResult
) *uResult
= -1;
1022 ERR("Running across the border without a passport!\n");
1023 return STATUS_UNSUCCESSFUL
;
1027 // These can not cross State lines!
1028 if ( Msg
== WM_CREATE
|| Msg
== WM_NCCREATE
)
1030 if (uResult
) *uResult
= -1;
1031 ERR("Can not tell the other State we have Create!\n");
1032 return STATUS_UNSUCCESSFUL
;
1036 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1038 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1039 return STATUS_INSUFFICIENT_RESOURCES
;
1042 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1044 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1046 /* FIXME: Increase reference counter of sender's message queue here */
1048 Message
->Msg
.hwnd
= Wnd
;
1049 Message
->Msg
.message
= Msg
;
1050 Message
->Msg
.wParam
= wParam
;
1051 Message
->Msg
.lParam
= lParam
;
1052 Message
->CompletionEvent
= &CompletionEvent
;
1053 Message
->Result
= &Result
;
1054 Message
->lResult
= 0;
1055 Message
->QS_Flags
= 0;
1056 Message
->SenderQueue
= ThreadQueue
;
1057 Message
->CallBackSenderQueue
= NULL
;
1058 IntReferenceMessageQueue(ThreadQueue
);
1059 Message
->CompletionCallback
= NULL
;
1060 Message
->CompletionCallbackContext
= 0;
1061 Message
->HookMessage
= HookMessage
;
1062 Message
->HasPackedLParam
= FALSE
;
1064 IntReferenceMessageQueue(MessageQueue
);
1066 /* Add it to the list of pending messages */
1067 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1069 /* Queue it in the destination's message queue */
1070 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1072 Message
->QS_Flags
= QS_SENDMESSAGE
;
1073 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
, TRUE
);
1075 /* We can't access the Message anymore since it could have already been deleted! */
1081 /* Don't process messages sent to the thread */
1082 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1083 FALSE
, (uTimeout
? &Timeout
: NULL
));
1087 if(WaitStatus
== STATUS_TIMEOUT
)
1089 /* Look up if the message has not yet dispatched, if so
1090 make sure it can't pass a result and it must not set the completion event anymore */
1091 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1092 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1094 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1097 /* We can access Message here, it's secure because the message queue is locked
1098 and the message is still hasn't been dispatched */
1099 Message
->CompletionEvent
= NULL
;
1100 Message
->Result
= NULL
;
1103 Entry
= Entry
->Flink
;
1106 /* Remove from the local dispatching list so the other thread knows,
1107 it can't pass a result and it must not set the completion event anymore */
1108 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1109 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1111 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1114 /* We can access Message here, it's secure because the sender's message is locked
1115 and the message has definitely not yet been destroyed, otherwise it would
1116 have been removed from this list by the dispatching routine right after
1117 dispatching the message */
1118 Message
->CompletionEvent
= NULL
;
1119 Message
->Result
= NULL
;
1120 RemoveEntryList(&Message
->DispatchingListEntry
);
1121 Message
->DispatchingListEntry
.Flink
= NULL
;
1124 Entry
= Entry
->Flink
;
1127 TRACE("MsqSendMessage (blocked) timed out 1\n");
1129 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1134 PVOID WaitObjects
[2];
1136 WaitObjects
[0] = &CompletionEvent
;
1137 WaitObjects
[1] = ThreadQueue
->NewMessages
;
1142 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1143 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1147 if(WaitStatus
== STATUS_TIMEOUT
)
1149 /* Look up if the message has not yet been dispatched, if so
1150 make sure it can't pass a result and it must not set the completion event anymore */
1151 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1152 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1154 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1157 /* We can access Message here, it's secure because the message queue is locked
1158 and the message is still hasn't been dispatched */
1159 Message
->CompletionEvent
= NULL
;
1160 Message
->Result
= NULL
;
1163 Entry
= Entry
->Flink
;
1166 /* Remove from the local dispatching list so the other thread knows,
1167 it can't pass a result and it must not set the completion event anymore */
1168 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1169 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1171 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1174 /* We can access Message here, it's secure because the sender's message is locked
1175 and the message has definitely not yet been destroyed, otherwise it would
1176 have been removed from this list by the dispatching routine right after
1177 dispatching the message */
1178 Message
->CompletionEvent
= NULL
;
1179 Message
->Result
= NULL
;
1180 RemoveEntryList(&Message
->DispatchingListEntry
);
1181 Message
->DispatchingListEntry
.Flink
= NULL
;
1184 Entry
= Entry
->Flink
;
1187 TRACE("MsqSendMessage timed out 2\n");
1190 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1193 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
1196 if(WaitStatus
!= STATUS_TIMEOUT
)
1197 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1203 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
1206 PUSER_MESSAGE Message
;
1208 if(!(Message
= MsqCreateMessage(Msg
)))
1213 if(!HardwareMessage
)
1215 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1216 &Message
->ListEntry
);
1220 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1221 &Message
->ListEntry
);
1224 Message
->QS_Flags
= MessageBits
;
1225 MsqWakeQueue(MessageQueue
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
1229 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1231 MessageQueue
->QuitPosted
= TRUE
;
1232 MessageQueue
->QuitExitCode
= ExitCode
;
1233 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1236 /***********************************************************************
1237 * MsqSendParentNotify
1239 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1240 * the window has the WS_EX_NOPARENTNOTIFY style.
1242 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1244 PWND pwndDesktop
= UserGetDesktopWindow();
1246 /* pt has to be in the client coordinates of the parent window */
1247 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1248 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1254 if (!(pwnd
->style
& WS_CHILD
)) break;
1255 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1256 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1257 if (pwndParent
== pwndDesktop
) break;
1258 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1259 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1262 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1263 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1269 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1271 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1272 hittest
= GetNCHitEx(pwndTrack
, msg
->pt
);
1274 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1275 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1276 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1278 TRACE("ITMM: Track Mouse Move!\n");
1280 /* Handle only the changing window track and mouse move across a border. */
1281 if ( pDesk
->spwndTrack
!= pwndTrack
||
1282 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1284 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1285 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1287 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1288 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1289 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1292 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1293 IntKillTimer(UserHMGetHandle(pDesk
->spwndTrack
), ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1295 /* Clear the flags to sign a change. */
1296 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1298 /* Set the Track window and hit test. */
1299 pDesk
->spwndTrack
= pwndTrack
;
1300 pDesk
->htEx
= hittest
;
1303 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1304 if ( pDesk
->spwndTrack
== pwndTrack
&&
1305 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1306 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1308 TRACE("ITMM: Reset Hover points!\n");
1309 // Restart timer for the hover period.
1310 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1311 // Reset desktop mouse hover from the system default hover rectangle.
1312 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1313 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1314 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1315 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1316 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1320 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1327 MOUSEHOOKSTRUCT hook
;
1330 PWND pwndMsg
, pwndDesktop
;
1331 PUSER_MESSAGE_QUEUE MessageQueue
;
1333 PSYSTEM_CURSORINFO CurInfo
;
1335 DECLARE_RETURN(BOOL
);
1337 pti
= PsGetCurrentThreadWin32Thread();
1338 pwndDesktop
= UserGetDesktopWindow();
1339 MessageQueue
= pti
->MessageQueue
;
1340 CurInfo
= IntGetSysCursorInfo();
1341 pwndMsg
= UserGetWindowObject(msg
->hwnd
);
1342 clk_msg
= MessageQueue
->msgDblClk
;
1343 pDesk
= pwndDesktop
->head
.rpdesk
;
1345 /* find the window to dispatch this mouse message to */
1346 if (MessageQueue
->spwndCapture
)
1349 pwndMsg
= MessageQueue
->spwndCapture
;
1350 if (pwndMsg
) UserReferenceObject(pwndMsg
);
1354 pwndMsg
= co_WinPosWindowFromPoint(pwndMsg
, &msg
->pt
, &hittest
);
1357 TRACE("Got mouse message for 0x%x, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1359 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
1361 /* Remove and ignore the message */
1362 *RemoveMessages
= TRUE
;
1366 if ( MessageQueue
== gpqCursor
) // Cursor must use the same Queue!
1368 IntTrackMouseMove(pwndMsg
, pDesk
, msg
, hittest
);
1372 ERR("Not the same cursor!\n");
1375 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1378 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
1382 message
= msg
->message
;
1383 /* Note: windows has no concept of a non-client wheel message */
1384 if (message
!= WM_MOUSEWHEEL
)
1386 if (hittest
!= HTCLIENT
)
1388 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1389 msg
->wParam
= hittest
;
1393 /* coordinates don't get translated while tracking a menu */
1394 /* FIXME: should differentiate popups and top-level menus */
1395 if (!(MessageQueue
->MenuOwner
))
1397 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1398 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1402 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1404 /* translate double clicks */
1406 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1407 (msg
->message
== WM_RBUTTONDOWN
) ||
1408 (msg
->message
== WM_MBUTTONDOWN
) ||
1409 (msg
->message
== WM_XBUTTONDOWN
))
1411 BOOL update
= *RemoveMessages
;
1413 /* translate double clicks -
1414 * note that ...MOUSEMOVEs can slip in between
1415 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1417 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1418 hittest
!= HTCLIENT
||
1419 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1421 if ((msg
->message
== clk_msg
.message
) &&
1422 (msg
->hwnd
== clk_msg
.hwnd
) &&
1423 (msg
->wParam
== clk_msg
.wParam
) &&
1424 ((msg
->time
- clk_msg
.time
) < (ULONG
)gspv
.iDblClickTime
) &&
1425 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1426 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1428 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1431 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1437 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1439 TRACE("Message out of range!!!\n");
1443 /* update static double click conditions */
1444 if (update
) MessageQueue
->msgDblClk
= *msg
;
1448 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1450 TRACE("Message out of range!!!\n");
1455 if(gspv
.bMouseClickLock
)
1457 BOOL IsClkLck
= FALSE
;
1459 if(msg
->message
== WM_LBUTTONUP
)
1461 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1462 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1464 CurInfo
->ClickLockActive
= TRUE
;
1467 else if (msg
->message
== WM_LBUTTONDOWN
)
1469 if (CurInfo
->ClickLockActive
)
1472 CurInfo
->ClickLockActive
= FALSE
;
1475 CurInfo
->ClickLockTime
= msg
->time
;
1480 /* Remove and ignore the message */
1481 *RemoveMessages
= TRUE
;
1486 /* message is accepted now (but may still get dropped) */
1488 event
.message
= msg
->message
;
1489 event
.time
= msg
->time
;
1490 event
.hwnd
= msg
->hwnd
;
1491 event
.paramL
= msg
->pt
.x
;
1492 event
.paramH
= msg
->pt
.y
;
1493 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1496 hook
.hwnd
= msg
->hwnd
;
1497 hook
.wHitTestCode
= hittest
;
1498 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1499 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1500 message
, (LPARAM
)&hook
))
1503 hook
.hwnd
= msg
->hwnd
;
1504 hook
.wHitTestCode
= hittest
;
1505 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1506 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1508 ERR("WH_MOUSE dorpped mouse message!\n");
1510 /* Remove and skip message */
1511 *RemoveMessages
= TRUE
;
1515 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1517 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1518 MAKELONG( hittest
, msg
->message
));
1520 /* Remove and skip message */
1521 *RemoveMessages
= TRUE
;
1525 if ((*RemoveMessages
== FALSE
) || MessageQueue
->spwndCapture
)
1527 /* Accept the message */
1528 msg
->message
= message
;
1534 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1535 (msg
->message
== WM_RBUTTONDOWN
) ||
1536 (msg
->message
== WM_MBUTTONDOWN
) ||
1537 (msg
->message
== WM_XBUTTONDOWN
))
1539 /* Send the WM_PARENTNOTIFY,
1540 * note that even for double/nonclient clicks
1541 * notification message is still WM_L/M/RBUTTONDOWN.
1543 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1545 /* Activate the window if needed */
1547 if (pwndMsg
!= pti
->MessageQueue
->spwndActive
) //msg->hwnd != UserGetForegroundWindow())
1549 PWND pwndTop
= pwndMsg
;
1552 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
1553 pwndTop
= IntGetParent( pwndTop
);
1556 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1558 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1560 (WPARAM
)UserHMGetHandle(pwndTop
),
1561 MAKELONG( hittest
, msg
->message
));
1564 case MA_NOACTIVATEANDEAT
:
1569 case MA_ACTIVATEANDEAT
:
1574 if (!co_IntMouseActivateWindow( pwndTop
)) eatMsg
= TRUE
;
1577 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1584 /* send the WM_SETCURSOR message */
1586 /* Windows sends the normal mouse message as the message parameter
1587 in the WM_SETCURSOR message even if it's non-client mouse message */
1588 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1590 msg
->message
= message
;
1595 UserDereferenceObject(pwndMsg
);
1600 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1604 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1605 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1607 switch (Msg
->wParam
)
1609 case VK_LSHIFT
: case VK_RSHIFT
:
1610 Msg
->wParam
= VK_SHIFT
;
1612 case VK_LCONTROL
: case VK_RCONTROL
:
1613 Msg
->wParam
= VK_CONTROL
;
1615 case VK_LMENU
: case VK_RMENU
:
1616 Msg
->wParam
= VK_MENU
;
1621 Event
.message
= Msg
->message
;
1622 Event
.hwnd
= Msg
->hwnd
;
1623 Event
.time
= Msg
->time
;
1624 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1625 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1626 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1627 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1629 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1630 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1631 LOWORD(Msg
->wParam
),
1634 /* skip this message */
1635 co_HOOK_CallHooks( WH_CBT
,
1637 LOWORD(Msg
->wParam
),
1639 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1645 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1647 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1649 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1651 else if ( IS_KBD_MESSAGE(Msg
->message
))
1653 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1660 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1663 IN UINT MsgFilterLow
,
1664 IN UINT MsgFilterHigh
,
1670 if(!(MessageQueue
->MouseMoved
))
1673 msg
= MessageQueue
->MouseMoveMsg
;
1675 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1682 ClearMsgBitsMask(MessageQueue
, QS_MOUSEMOVE
);
1683 MessageQueue
->MouseMoved
= FALSE
;
1686 return AcceptMessage
;
1689 /* check whether a message filter contains at least one potential hardware message */
1691 filter_contains_hw_range( UINT first
, UINT last
)
1693 /* hardware message ranges are (in numerical order):
1694 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1695 * WM_KEYFIRST .. WM_KEYLAST
1696 * WM_MOUSEFIRST .. WM_MOUSELAST
1699 if (last
< WM_NCMOUSEFIRST
) return 0;
1700 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1701 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1702 if (first
> WM_MOUSELAST
) return 0;
1707 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1710 IN UINT MsgFilterLow
,
1711 IN UINT MsgFilterHigh
,
1717 PUSER_MESSAGE CurrentMessage
;
1718 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1721 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1723 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1724 CurrentEntry
= ListHead
->Flink
;
1726 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1728 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1732 if (IsListEmpty(CurrentEntry
)) break;
1733 if (!CurrentMessage
) break;
1734 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1737 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1738 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1739 3: handle to the window whose messages are to be retrieved.
1741 if ( ( !Window
|| // 1
1742 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1743 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1744 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1745 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1747 msg
= CurrentMessage
->Msg
;
1749 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
1750 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1754 RemoveEntryList(&CurrentMessage
->ListEntry
);
1755 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1756 MsqDestroyMessage(CurrentMessage
);
1765 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1768 while(CurrentEntry
!= ListHead
);
1774 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1777 IN UINT MsgFilterLow
,
1778 IN UINT MsgFilterHigh
,
1782 PLIST_ENTRY CurrentEntry
;
1783 PUSER_MESSAGE CurrentMessage
;
1784 PLIST_ENTRY ListHead
;
1786 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1787 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1789 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1791 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1795 if (IsListEmpty(CurrentEntry
)) break;
1796 if (!CurrentMessage
) break;
1797 CurrentEntry
= CurrentEntry
->Flink
;
1800 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1801 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1802 3: handle to the window whose messages are to be retrieved.
1804 if ( ( !Window
|| // 1
1805 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1806 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1807 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1808 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1810 *Message
= CurrentMessage
->Msg
;
1814 RemoveEntryList(&CurrentMessage
->ListEntry
);
1815 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1816 MsqDestroyMessage(CurrentMessage
);
1820 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1823 while (CurrentEntry
!= ListHead
);
1829 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1830 UINT MsgFilterMin
, UINT MsgFilterMax
)
1834 ret
= KeWaitForSingleObject( MessageQueue
->NewMessages
,
1844 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1846 LARGE_INTEGER LargeTickCount
;
1848 KeQueryTickCount(&LargeTickCount
);
1849 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1854 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1857 TRACE("HungAppSysTimerProc\n");
1858 // Process list of windows that are hung and waiting.
1862 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1864 LARGE_INTEGER LargeTickCount
;
1867 MessageQueue
->Thread
= Thread
;
1868 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1869 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1870 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1871 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1872 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1873 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1874 MessageQueue
->QuitPosted
= FALSE
;
1875 MessageQueue
->QuitExitCode
= 0;
1876 KeQueryTickCount(&LargeTickCount
);
1877 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1878 MessageQueue
->spwndFocus
= NULL
;
1879 MessageQueue
->NewMessagesHandle
= NULL
;
1880 MessageQueue
->iCursorLevel
= 0;
1881 MessageQueue
->CursorObject
= NULL
;
1882 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
1884 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1885 NULL
, SynchronizationEvent
, FALSE
);
1886 if (!NT_SUCCESS(Status
))
1891 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1892 ExEventObjectType
, KernelMode
,
1893 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1894 if (!NT_SUCCESS(Status
))
1896 ZwClose(MessageQueue
->NewMessagesHandle
);
1897 MessageQueue
->NewMessagesHandle
= NULL
;
1905 MsqCleanupMessageQueue(PTHREADINFO pti
)
1907 PUSER_MESSAGE_QUEUE MessageQueue
;
1908 PLIST_ENTRY CurrentEntry
;
1909 PUSER_MESSAGE CurrentMessage
;
1910 PUSER_SENT_MESSAGE CurrentSentMessage
;
1912 MessageQueue
= pti
->MessageQueue
;
1914 /* cleanup posted messages */
1915 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1917 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1918 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1920 MsqDestroyMessage(CurrentMessage
);
1923 /* remove the messages that have not yet been dispatched */
1924 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1926 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1927 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1930 /* if it is a callback and this queue is not the sender queue, dereference queue */
1931 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
1933 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
1936 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
1937 /* Only if the message has a sender was the message in the DispatchingList */
1938 if ((CurrentSentMessage
->SenderQueue
)
1939 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1941 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1944 /* wake the sender's thread */
1945 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1947 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1950 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1952 if (CurrentSentMessage
->Msg
.lParam
)
1953 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1956 /* if the message has a sender */
1957 if (CurrentSentMessage
->SenderQueue
)
1959 /* dereference our and the sender's message queue */
1960 IntDereferenceMessageQueue(MessageQueue
);
1961 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1964 /* free the message */
1965 ExFreePool(CurrentSentMessage
);
1968 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1969 ExitThread() was called in a SendMessage() umode callback */
1970 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1972 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1973 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1976 /* if it is a callback and this queue is not the sender queue, dereference queue */
1977 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
1979 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
1982 /* remove the message from the dispatching list */
1983 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1985 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1988 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
1990 /* wake the sender's thread */
1991 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1993 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1996 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1998 if (CurrentSentMessage
->Msg
.lParam
)
1999 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2002 /* if the message has a sender */
2003 if (CurrentSentMessage
->SenderQueue
)
2005 /* dereference our and the sender's message queue */
2006 IntDereferenceMessageQueue(MessageQueue
);
2007 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
2010 /* free the message */
2011 ExFreePool(CurrentSentMessage
);
2014 /* tell other threads not to bother returning any info to us */
2015 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
2017 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
2018 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2019 DispatchingListEntry
);
2020 CurrentSentMessage
->CompletionEvent
= NULL
;
2021 CurrentSentMessage
->Result
= NULL
;
2023 /* do NOT dereference our message queue as it might get attempted to be
2027 // Clear it all out.
2030 pti
->pcti
->fsWakeBits
= 0;
2031 pti
->pcti
->fsChangeBits
= 0;
2034 MessageQueue
->nCntsQBits
[QSRosKey
] = 0;
2035 MessageQueue
->nCntsQBits
[QSRosMouseMove
] = 0;
2036 MessageQueue
->nCntsQBits
[QSRosMouseButton
] = 0;
2037 MessageQueue
->nCntsQBits
[QSRosPostMessage
] = 0;
2038 MessageQueue
->nCntsQBits
[QSRosSendMessage
] = 0;
2039 MessageQueue
->nCntsQBits
[QSRosHotKey
] = 0;
2041 if (MessageQueue
->CursorObject
)
2043 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2045 /* Change to another cursor if we going to dereference current one
2046 Note: we can't use UserSetCursor because it uses current thread
2047 message queue instead of queue given for cleanup */
2048 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2052 /* Get the screen DC */
2053 hdcScreen
= IntGetScreenDC();
2055 GreMovePointer(hdcScreen
, -1, -1);
2056 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2059 UserDereferenceObject(pCursor
);
2063 PUSER_MESSAGE_QUEUE FASTCALL
2064 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
2066 PUSER_MESSAGE_QUEUE MessageQueue
;
2068 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2069 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2077 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2078 /* hold at least one reference until it'll be destroyed */
2079 IntReferenceMessageQueue(MessageQueue
);
2080 /* initialize the queue */
2081 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
2083 IntDereferenceMessageQueue(MessageQueue
);
2087 return MessageQueue
;
2091 MsqDestroyMessageQueue(PTHREADINFO pti
)
2094 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2096 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2098 /* remove the message queue from any desktops */
2099 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2101 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2102 IntDereferenceMessageQueue(MessageQueue
);
2106 MsqCleanupMessageQueue(pti
);
2108 if (MessageQueue
->NewMessagesHandle
!= NULL
)
2109 ZwClose(MessageQueue
->NewMessagesHandle
);
2110 MessageQueue
->NewMessagesHandle
= NULL
;
2111 /* decrease the reference counter, if it hits zero, the queue will be freed */
2112 IntDereferenceMessageQueue(MessageQueue
);
2116 MsqSetMessageExtraInfo(LPARAM lParam
)
2120 PUSER_MESSAGE_QUEUE MessageQueue
;
2122 pti
= PsGetCurrentThreadWin32Thread();
2123 MessageQueue
= pti
->MessageQueue
;
2129 Ret
= MessageQueue
->ExtraInfo
;
2130 MessageQueue
->ExtraInfo
= lParam
;
2136 MsqGetMessageExtraInfo(VOID
)
2139 PUSER_MESSAGE_QUEUE MessageQueue
;
2141 pti
= PsGetCurrentThreadWin32Thread();
2142 MessageQueue
= pti
->MessageQueue
;
2148 return MessageQueue
->ExtraInfo
;
2151 // ReplyMessage is called by the thread receiving the window message.
2153 co_MsqReplyMessage( LRESULT lResult
)
2155 PUSER_SENT_MESSAGE Message
;
2158 pti
= PsGetCurrentThreadWin32Thread();
2159 Message
= pti
->pusmCurrent
;
2161 if (!Message
) return FALSE
;
2163 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2165 // SendMessageXxx || Callback msg and not a notify msg
2166 if (Message
->SenderQueue
|| Message
->CompletionCallback
)
2168 Message
->lResult
= lResult
;
2169 Message
->QS_Flags
|= QS_SMRESULT
;
2170 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2176 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
2182 case MSQ_STATE_CAPTURE
:
2183 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2184 MessageQueue
->spwndCapture
= UserGetWindowObject(hWnd
);
2186 case MSQ_STATE_ACTIVE
:
2187 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2188 MessageQueue
->spwndActive
= UserGetWindowObject(hWnd
);
2190 case MSQ_STATE_FOCUS
:
2191 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2192 MessageQueue
->spwndFocus
= UserGetWindowObject(hWnd
);
2194 case MSQ_STATE_MENUOWNER
:
2195 Prev
= MessageQueue
->MenuOwner
;
2196 MessageQueue
->MenuOwner
= hWnd
;
2198 case MSQ_STATE_MOVESIZE
:
2199 Prev
= MessageQueue
->MoveSize
;
2200 MessageQueue
->MoveSize
= hWnd
;
2202 case MSQ_STATE_CARET
:
2203 ASSERT(MessageQueue
->CaretInfo
);
2204 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2205 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2214 NtUserGetKeyState(INT key
)
2220 Ret
= UserGetKeyState(key
);
2230 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2232 DWORD i
, ret
= TRUE
;
2234 PUSER_MESSAGE_QUEUE MessageQueue
;
2238 pti
= PsGetCurrentThreadWin32Thread();
2239 MessageQueue
= pti
->MessageQueue
;
2243 /* Probe and copy key state to an array */
2244 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2245 for (i
= 0; i
< 256; ++i
)
2248 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2249 lpKeyState
[i
] |= KS_DOWN_BIT
;
2250 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2251 lpKeyState
[i
] |= KS_LOCK_BIT
;
2254 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2256 SetLastNtError(_SEH2_GetExceptionCode());
2268 NtUserSetKeyboardState(LPBYTE pKeyState
)
2273 PUSER_MESSAGE_QUEUE MessageQueue
;
2275 UserEnterExclusive();
2277 pti
= PsGetCurrentThreadWin32Thread();
2278 MessageQueue
= pti
->MessageQueue
;
2282 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2283 for (i
= 0; i
< 256; ++i
)
2285 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2286 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2289 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2291 SetLastNtError(_SEH2_GetExceptionCode());