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(PUSER_MESSAGE_QUEUE MessageQueue
)
1907 PLIST_ENTRY CurrentEntry
;
1908 PUSER_MESSAGE CurrentMessage
;
1909 PUSER_SENT_MESSAGE CurrentSentMessage
;
1912 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1915 /* cleanup posted messages */
1916 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1918 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1919 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1921 MsqDestroyMessage(CurrentMessage
);
1924 /* remove the messages that have not yet been dispatched */
1925 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1927 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1928 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1931 /* if it is a callback and this queue is not the sender queue, dereference queue */
1932 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
1934 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
1937 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
1938 /* Only if the message has a sender was the message in the DispatchingList */
1939 if ((CurrentSentMessage
->SenderQueue
)
1940 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1942 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1945 /* wake the sender's thread */
1946 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1948 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1951 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1953 if (CurrentSentMessage
->Msg
.lParam
)
1954 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1957 /* if the message has a sender */
1958 if (CurrentSentMessage
->SenderQueue
)
1960 /* dereference our and the sender's message queue */
1961 IntDereferenceMessageQueue(MessageQueue
);
1962 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1965 /* free the message */
1966 ExFreePool(CurrentSentMessage
);
1969 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1970 ExitThread() was called in a SendMessage() umode callback */
1971 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1973 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1974 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1977 /* if it is a callback and this queue is not the sender queue, dereference queue */
1978 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
1980 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
1983 /* remove the message from the dispatching list */
1984 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1986 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1989 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
1991 /* wake the sender's thread */
1992 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1994 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1997 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1999 if (CurrentSentMessage
->Msg
.lParam
)
2000 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2003 /* if the message has a sender */
2004 if (CurrentSentMessage
->SenderQueue
)
2006 /* dereference our and the sender's message queue */
2007 IntDereferenceMessageQueue(MessageQueue
);
2008 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
2011 /* free the message */
2012 ExFreePool(CurrentSentMessage
);
2015 /* tell other threads not to bother returning any info to us */
2016 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
2018 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
2019 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2020 DispatchingListEntry
);
2021 CurrentSentMessage
->CompletionEvent
= NULL
;
2022 CurrentSentMessage
->Result
= NULL
;
2024 /* do NOT dereference our message queue as it might get attempted to be
2028 // Clear it all out.
2031 pti
->pcti
->fsWakeBits
= 0;
2032 pti
->pcti
->fsChangeBits
= 0;
2035 MessageQueue
->nCntsQBits
[QSRosKey
] = 0;
2036 MessageQueue
->nCntsQBits
[QSRosMouseMove
] = 0;
2037 MessageQueue
->nCntsQBits
[QSRosMouseButton
] = 0;
2038 MessageQueue
->nCntsQBits
[QSRosPostMessage
] = 0;
2039 MessageQueue
->nCntsQBits
[QSRosSendMessage
] = 0;
2040 MessageQueue
->nCntsQBits
[QSRosHotKey
] = 0;
2042 if (MessageQueue
->CursorObject
)
2044 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2046 /* Change to another cursor if we going to dereference current one
2047 Note: we can't use UserSetCursor because it uses current thread
2048 message queue instead of queue given for cleanup */
2049 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2053 /* Get the screen DC */
2054 hdcScreen
= IntGetScreenDC();
2056 GreMovePointer(hdcScreen
, -1, -1);
2057 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2060 UserDereferenceObject(pCursor
);
2065 PUSER_MESSAGE_QUEUE FASTCALL
2066 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
2068 PUSER_MESSAGE_QUEUE MessageQueue
;
2070 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2071 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2079 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2080 /* hold at least one reference until it'll be destroyed */
2081 IntReferenceMessageQueue(MessageQueue
);
2082 /* initialize the queue */
2083 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
2085 IntDereferenceMessageQueue(MessageQueue
);
2089 return MessageQueue
;
2093 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
2097 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2099 /* remove the message queue from any desktops */
2100 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2102 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2103 IntDereferenceMessageQueue(MessageQueue
);
2107 MsqCleanupMessageQueue(MessageQueue
);
2109 if (MessageQueue
->NewMessagesHandle
!= NULL
)
2110 ZwClose(MessageQueue
->NewMessagesHandle
);
2111 MessageQueue
->NewMessagesHandle
= NULL
;
2112 /* decrease the reference counter, if it hits zero, the queue will be freed */
2113 IntDereferenceMessageQueue(MessageQueue
);
2117 MsqSetMessageExtraInfo(LPARAM lParam
)
2121 PUSER_MESSAGE_QUEUE MessageQueue
;
2123 pti
= PsGetCurrentThreadWin32Thread();
2124 MessageQueue
= pti
->MessageQueue
;
2130 Ret
= MessageQueue
->ExtraInfo
;
2131 MessageQueue
->ExtraInfo
= lParam
;
2137 MsqGetMessageExtraInfo(VOID
)
2140 PUSER_MESSAGE_QUEUE MessageQueue
;
2142 pti
= PsGetCurrentThreadWin32Thread();
2143 MessageQueue
= pti
->MessageQueue
;
2149 return MessageQueue
->ExtraInfo
;
2152 // ReplyMessage is called by the thread receiving the window message.
2154 co_MsqReplyMessage( LRESULT lResult
)
2156 PUSER_SENT_MESSAGE Message
;
2159 pti
= PsGetCurrentThreadWin32Thread();
2160 Message
= pti
->pusmCurrent
;
2162 if (!Message
) return FALSE
;
2164 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2166 // SendMessageXxx || Callback msg and not a notify msg
2167 if (Message
->SenderQueue
|| Message
->CompletionCallback
)
2169 Message
->lResult
= lResult
;
2170 Message
->QS_Flags
|= QS_SMRESULT
;
2171 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2177 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
2183 case MSQ_STATE_CAPTURE
:
2184 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2185 MessageQueue
->spwndCapture
= UserGetWindowObject(hWnd
);
2187 case MSQ_STATE_ACTIVE
:
2188 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2189 MessageQueue
->spwndActive
= UserGetWindowObject(hWnd
);
2191 case MSQ_STATE_FOCUS
:
2192 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2193 MessageQueue
->spwndFocus
= UserGetWindowObject(hWnd
);
2195 case MSQ_STATE_MENUOWNER
:
2196 Prev
= MessageQueue
->MenuOwner
;
2197 MessageQueue
->MenuOwner
= hWnd
;
2199 case MSQ_STATE_MOVESIZE
:
2200 Prev
= MessageQueue
->MoveSize
;
2201 MessageQueue
->MoveSize
= hWnd
;
2203 case MSQ_STATE_CARET
:
2204 ASSERT(MessageQueue
->CaretInfo
);
2205 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2206 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2215 NtUserGetKeyState(INT key
)
2221 Ret
= UserGetKeyState(key
);
2231 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2233 DWORD i
, ret
= TRUE
;
2235 PUSER_MESSAGE_QUEUE MessageQueue
;
2239 pti
= PsGetCurrentThreadWin32Thread();
2240 MessageQueue
= pti
->MessageQueue
;
2244 /* Probe and copy key state to an array */
2245 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2246 for (i
= 0; i
< 256; ++i
)
2249 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2250 lpKeyState
[i
] |= KS_DOWN_BIT
;
2251 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2252 lpKeyState
[i
] |= KS_LOCK_BIT
;
2255 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2257 SetLastNtError(_SEH2_GetExceptionCode());
2269 NtUserSetKeyboardState(LPBYTE pKeyState
)
2274 PUSER_MESSAGE_QUEUE MessageQueue
;
2276 UserEnterExclusive();
2278 pti
= PsGetCurrentThreadWin32Thread();
2279 MessageQueue
= pti
->MessageQueue
;
2283 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2284 for (i
= 0; i
< 256; ++i
)
2286 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2287 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2290 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2292 SetLastNtError(_SEH2_GetExceptionCode());