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
)
47 pWndTop
= UserGetDesktopWindow();
48 if ( !pWndTop
) return NULL
;
51 if (!(pWndTop
->style
& WS_VISIBLE
)) return NULL
;
52 if ((pWndTop
->style
& WS_DISABLED
)) return NULL
;
53 if (!IntPtInWindow(pWndTop
, x
, y
)) return NULL
;
55 if (RECTL_bPointInRect(&pWndTop
->rcClient
, x
, y
))
57 for (pWnd
= pWndTop
->spwndChild
;
59 pWnd
= pWnd
->spwndNext
)
61 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
63 TRACE("The Window is in DESTROY!\n");
67 pWndChild
= IntChildrenWindowFromPoint(pWnd
, x
, y
);
79 IntTopLevelWindowFromPoint(INT x
, INT y
)
81 PWND pWnd
, pwndDesktop
;
83 /* Get the desktop window */
84 pwndDesktop
= UserGetDesktopWindow();
88 /* Loop all top level windows */
89 for (pWnd
= pwndDesktop
->spwndChild
;
91 pWnd
= pWnd
->spwndNext
)
93 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
95 TRACE("The Window is in DESTROY!\n");
99 if ((pWnd
->style
& WS_VISIBLE
) && IntPtInWindow(pWnd
, x
, y
))
103 /* Window has not been found */
110 PCURICON_OBJECT NewCursor
,
113 PCURICON_OBJECT OldCursor
;
116 PUSER_MESSAGE_QUEUE MessageQueue
;
119 pti
= PsGetCurrentThreadWin32Thread();
120 MessageQueue
= pti
->MessageQueue
;
122 /* Get the screen DC */
123 if(!(hdcScreen
= IntGetScreenDC()))
128 OldCursor
= MessageQueue
->CursorObject
;
130 /* Check if cursors are different */
131 if (OldCursor
== NewCursor
)
134 /* Update cursor for this message queue */
135 MessageQueue
->CursorObject
= NewCursor
;
137 /* If cursor is not visible we have nothing to do */
138 if (MessageQueue
->iCursorLevel
< 0)
141 /* Update cursor if this message queue controls it */
142 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
143 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
147 /* Call GDI to set the new screen cursor */
148 #ifdef NEW_CURSORICON
149 GreSetPointerShape(hdcScreen
,
150 NewCursor
->hbmAlpha
? NULL
: NewCursor
->hbmMask
,
151 NewCursor
->hbmAlpha
? NewCursor
->hbmAlpha
: NewCursor
->hbmColor
,
156 NewCursor
->hbmAlpha
? SPS_ALPHA
: 0);
158 GreSetPointerShape(hdcScreen
,
159 NewCursor
->IconInfo
.hbmMask
,
160 NewCursor
->IconInfo
.hbmColor
,
161 NewCursor
->IconInfo
.xHotspot
,
162 NewCursor
->IconInfo
.yHotspot
,
168 else /* Note: OldCursor != NewCursor so we have to hide cursor */
170 /* Remove the cursor */
171 GreMovePointer(hdcScreen
, -1, -1);
172 TRACE("Removing pointer!\n");
174 IntGetSysCursorInfo()->CurrentCursorObject
= NewCursor
;
177 /* Return the old cursor */
181 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
182 * User32 macro NtUserShowCursor */
183 int UserShowCursor(BOOL bShow
)
187 PUSER_MESSAGE_QUEUE MessageQueue
;
190 if (!(hdcScreen
= IntGetScreenDC()))
192 return -1; /* No mouse */
195 pti
= PsGetCurrentThreadWin32Thread();
196 MessageQueue
= pti
->MessageQueue
;
199 MessageQueue
->iCursorLevel
+= bShow
? 1 : -1;
200 pti
->iCursorLevel
+= bShow
? 1 : -1;
202 /* Check for trivial cases */
203 if ((bShow
&& MessageQueue
->iCursorLevel
!= 0) ||
204 (!bShow
&& MessageQueue
->iCursorLevel
!= -1))
206 /* Note: w don't update global info here because it is used only
207 internally to check if cursor is visible */
208 return MessageQueue
->iCursorLevel
;
211 /* Check if cursor is above window owned by this MessageQueue */
212 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
213 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
217 /* Show the pointer */
218 GreMovePointer(hdcScreen
, gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
219 TRACE("Showing pointer!\n");
223 /* Remove the pointer */
224 GreMovePointer(hdcScreen
, -1, -1);
225 TRACE("Removing pointer!\n");
228 /* Update global info */
229 IntGetSysCursorInfo()->ShowingCursor
= MessageQueue
->iCursorLevel
;
232 return MessageQueue
->iCursorLevel
;
236 UserGetKeyState(DWORD dwKey
)
240 PUSER_MESSAGE_QUEUE MessageQueue
;
242 pti
= PsGetCurrentThreadWin32Thread();
243 MessageQueue
= pti
->MessageQueue
;
247 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, dwKey
))
248 dwRet
|= 0xFF80; // If down, windows returns 0xFF80.
249 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, dwKey
))
254 EngSetLastError(ERROR_INVALID_PARAMETER
);
259 /* change the input key state for a given key */
261 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue
, WORD wVk
, BOOL bIsDown
)
263 TRACE("UpdateKeyState wVk: %d, bIsDown: %d\n", wVk
, bIsDown
);
267 /* If it's first key down event, xor lock bit */
268 if (!IS_KEY_DOWN(MessageQueue
->afKeyState
, wVk
))
269 SET_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
, !IS_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
));
271 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, TRUE
);
272 MessageQueue
->afKeyRecentDown
[wVk
/ 8] |= (1 << (wVk
% 8));
275 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, FALSE
);
278 /* update the input key state for a keyboard message */
280 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
285 TRACE("UpdateKeyStateFromMsg message:%d\n", msg
->message
);
287 switch (msg
->message
)
293 UpdateKeyState(MessageQueue
, VK_LBUTTON
, down
);
299 UpdateKeyState(MessageQueue
, VK_MBUTTON
, down
);
305 UpdateKeyState(MessageQueue
, VK_RBUTTON
, down
);
311 if (msg
->wParam
== XBUTTON1
)
312 UpdateKeyState(MessageQueue
, VK_XBUTTON1
, down
);
313 else if (msg
->wParam
== XBUTTON2
)
314 UpdateKeyState(MessageQueue
, VK_XBUTTON2
, down
);
322 key
= (UCHAR
)msg
->wParam
;
323 UpdateKeyState(MessageQueue
, key
, down
);
328 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LCONTROL
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RCONTROL
);
329 UpdateKeyState(MessageQueue
, VK_CONTROL
, down
);
333 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LMENU
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RMENU
);
334 UpdateKeyState(MessageQueue
, VK_MENU
, down
);
338 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LSHIFT
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RSHIFT
);
339 UpdateKeyState(MessageQueue
, VK_SHIFT
, down
);
347 IntMsqSetWakeMask(DWORD WakeMask
)
349 PTHREADINFO Win32Thread
;
350 PUSER_MESSAGE_QUEUE MessageQueue
;
351 HANDLE MessageEventHandle
;
352 DWORD dwFlags
= HIWORD(WakeMask
);
354 Win32Thread
= PsGetCurrentThreadWin32Thread();
355 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
358 MessageQueue
= Win32Thread
->MessageQueue
;
359 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
360 MessageEventHandle
= MessageQueue
->NewMessagesHandle
;
362 if (Win32Thread
->pcti
)
364 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
365 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
367 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
368 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
369 return MessageEventHandle
;
375 return MessageEventHandle
;
379 IntMsqClearWakeMask(VOID
)
381 PTHREADINFO Win32Thread
;
383 Win32Thread
= PsGetCurrentThreadWin32Thread();
384 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
386 // Very hacky, but that is what they do.
387 Win32Thread
->pcti
->fsWakeBits
= 0;
395 Due to the uncertainty of knowing what was set in our multilevel message queue,
396 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
397 I think this is the best solution... (jt) */
399 MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue
, DWORD MessageBits
, BOOL KeyEvent
)
403 if (Queue
->QF_flags
& QF_INDESTROY
)
405 ERR("This Message Queue is in Destroy!\n");
407 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
408 pti
->pcti
->fsWakeBits
|= MessageBits
;
409 pti
->pcti
->fsChangeBits
|= MessageBits
;
411 // Start bit accounting to help clear the main set of bits.
412 if (MessageBits
& QS_KEY
) Queue
->nCntsQBits
[QSRosKey
]++;
413 if (MessageBits
& QS_MOUSEMOVE
) Queue
->nCntsQBits
[QSRosMouseMove
]++;
414 if (MessageBits
& QS_MOUSEBUTTON
) Queue
->nCntsQBits
[QSRosMouseButton
]++;
415 if (MessageBits
& QS_POSTMESSAGE
) Queue
->nCntsQBits
[QSRosPostMessage
]++;
416 if (MessageBits
& QS_SENDMESSAGE
) Queue
->nCntsQBits
[QSRosSendMessage
]++;
417 if (MessageBits
& QS_HOTKEY
) Queue
->nCntsQBits
[QSRosHotKey
]++;
420 KeSetEvent(Queue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
424 ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue
, UINT MessageBits
)
429 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
431 if (MessageBits
& QS_KEY
)
433 if (--Queue
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
435 if (MessageBits
& QS_MOUSEMOVE
) // ReactOS hard coded.
436 { // Account for tracking mouse moves..
437 if (--Queue
->nCntsQBits
[QSRosMouseMove
] == 0) ClrMask
|= QS_MOUSEMOVE
;
438 // Handle mouse move bits here.
439 if (Queue
->MouseMoved
) ClrMask
|= QS_MOUSEMOVE
;
441 if (MessageBits
& QS_MOUSEBUTTON
)
443 if (--Queue
->nCntsQBits
[QSRosMouseButton
] == 0) ClrMask
|= QS_MOUSEBUTTON
;
445 if (MessageBits
& QS_POSTMESSAGE
)
447 if (--Queue
->nCntsQBits
[QSRosPostMessage
] == 0) ClrMask
|= QS_POSTMESSAGE
;
449 if (MessageBits
& QS_TIMER
) // ReactOS hard coded.
450 { // Handle timer bits here.
451 if ( pti
->cTimersReady
)
453 if (--pti
->cTimersReady
== 0) ClrMask
|= QS_TIMER
;
456 if (MessageBits
& QS_PAINT
) // ReactOS hard coded.
457 { // Handle paint bits here.
458 if ( pti
->cPaintsReady
)
460 if (--pti
->cPaintsReady
== 0) ClrMask
|= QS_PAINT
;
463 if (MessageBits
& QS_SENDMESSAGE
)
465 if (--Queue
->nCntsQBits
[QSRosSendMessage
] == 0) ClrMask
|= QS_SENDMESSAGE
;
467 if (MessageBits
& QS_HOTKEY
)
469 if (--Queue
->nCntsQBits
[QSRosHotKey
] == 0) ClrMask
|= QS_HOTKEY
;
472 pti
->pcti
->fsWakeBits
&= ~ClrMask
;
473 pti
->pcti
->fsChangeBits
&= ~ClrMask
;
477 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
480 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
482 MsqWakeQueue(Queue
, QS_PAINT
, TRUE
);
486 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
488 ClearMsgBitsMask(Queue
, QS_PAINT
);
492 MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
)
494 MessageQueue
->MouseMoveMsg
= *Msg
;
495 MessageQueue
->MouseMoved
= TRUE
;
496 MsqWakeQueue(MessageQueue
, QS_MOUSEMOVE
, TRUE
);
500 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
502 LARGE_INTEGER LargeTickCount
;
503 MSLLHOOKSTRUCT MouseHookData
;
505 PWND pwnd
, pwndDesktop
;
507 PUSER_MESSAGE_QUEUE MessageQueue
;
508 PSYSTEM_CURSORINFO CurInfo
;
510 KeQueryTickCount(&LargeTickCount
);
511 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
513 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
514 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
515 switch (Msg
->message
)
518 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
522 case WM_XBUTTONDBLCLK
:
523 case WM_NCXBUTTONDOWN
:
525 case WM_NCXBUTTONDBLCLK
:
526 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
529 MouseHookData
.mouseData
= 0;
533 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
534 MouseHookData
.time
= Msg
->time
;
535 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
537 /* If the hook procedure returned non zero, dont send the message */
540 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
544 /* Get the desktop window */
545 pwndDesktop
= UserGetDesktopWindow();
546 if (!pwndDesktop
) return;
547 pDesk
= pwndDesktop
->head
.rpdesk
;
549 /* Check if the mouse is captured */
550 Msg
->hwnd
= IntGetCaptureWindow();
551 if (Msg
->hwnd
!= NULL
)
553 pwnd
= UserGetWindowObject(Msg
->hwnd
);
557 pwnd
= IntTopLevelWindowFromPoint(Msg
->pt
.x
, Msg
->pt
.y
);
558 if (pwnd
) Msg
->hwnd
= pwnd
->head
.h
;
561 hdcScreen
= IntGetScreenDC();
562 CurInfo
= IntGetSysCursorInfo();
564 /* Check if we found a window */
565 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
567 MessageQueue
= pwnd
->head
.pti
->MessageQueue
;
569 if ( pwnd
->head
.pti
->TIF_flags
& TIF_INCLEANUP
|| MessageQueue
->QF_flags
& QF_INDESTROY
)
571 ERR("Mouse is over the Window Thread is Dead!\n");
575 if (Msg
->message
== WM_MOUSEMOVE
)
577 /* Check if cursor should be visible */
579 MessageQueue
->CursorObject
&&
580 MessageQueue
->iCursorLevel
>= 0)
582 /* Check if shape has changed */
583 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
585 /* Call GDI to set the new screen cursor */
586 #ifdef NEW_CURSORICON
587 GreSetPointerShape(hdcScreen
,
588 MessageQueue
->CursorObject
->hbmAlpha
?
589 NULL
: MessageQueue
->CursorObject
->hbmMask
,
590 MessageQueue
->CursorObject
->hbmAlpha
?
591 MessageQueue
->CursorObject
->hbmAlpha
: MessageQueue
->CursorObject
->hbmColor
,
592 MessageQueue
->CursorObject
->xHotspot
,
593 MessageQueue
->CursorObject
->yHotspot
,
596 MessageQueue
->CursorObject
->hbmAlpha
? SPS_ALPHA
: 0);
598 GreSetPointerShape(hdcScreen
,
599 MessageQueue
->CursorObject
->IconInfo
.hbmMask
,
600 MessageQueue
->CursorObject
->IconInfo
.hbmColor
,
601 MessageQueue
->CursorObject
->IconInfo
.xHotspot
,
602 MessageQueue
->CursorObject
->IconInfo
.yHotspot
,
608 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
610 /* Check if w have to hide cursor */
611 else if (CurInfo
->ShowingCursor
>= 0)
612 GreMovePointer(hdcScreen
, -1, -1);
614 /* Update global cursor info */
615 CurInfo
->ShowingCursor
= MessageQueue
->iCursorLevel
;
616 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
617 gpqCursor
= MessageQueue
;
619 /* Mouse move is a special case */
620 MsqPostMouseMove(MessageQueue
, Msg
);
624 TRACE("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd
));
625 MsqPostMessage(MessageQueue
, Msg
, TRUE
, QS_MOUSEBUTTON
, 0);
630 /* always show cursor on background; FIXME: set default pointer */
631 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
632 CurInfo
->ShowingCursor
= 0;
637 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
640 PTHREADINFO Win32Thread
;
642 LARGE_INTEGER LargeTickCount
;
647 Status
= ObReferenceObjectByPointer (Thread
,
651 if (!NT_SUCCESS(Status
))
654 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
655 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
657 ObDereferenceObject ((PETHREAD
)Thread
);
661 Window
= IntGetWindowObject(hWnd
);
664 ObDereferenceObject ((PETHREAD
)Thread
);
668 id
= wParam
; // Check for hot keys unrelated to the hot keys set by RegisterHotKey.
671 Mesg
.message
= id
!= IDHK_REACTOS
? WM_HOTKEY
: WM_SYSCOMMAND
;
672 Mesg
.wParam
= id
!= IDHK_REACTOS
? wParam
: SC_HOTKEY
;
673 Mesg
.lParam
= id
!= IDHK_REACTOS
? lParam
: (LPARAM
)hWnd
;
674 Type
= id
!= IDHK_REACTOS
? QS_HOTKEY
: QS_POSTMESSAGE
;
675 KeQueryTickCount(&LargeTickCount
);
676 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
677 Mesg
.pt
= gpsi
->ptCursor
;
678 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, Type
, 0);
679 UserDereferenceObject(Window
);
680 ObDereferenceObject (Thread
);
684 PUSER_MESSAGE FASTCALL
685 MsqCreateMessage(LPMSG Msg
)
687 PUSER_MESSAGE Message
;
689 Message
= ExAllocateFromPagedLookasideList(pgMessageLookasideList
);
695 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
701 MsqDestroyMessage(PUSER_MESSAGE Message
)
703 ExFreeToPagedLookasideList(pgMessageLookasideList
, Message
);
707 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
709 PUSER_SENT_MESSAGE SaveMsg
, Message
;
715 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
720 /* remove it from the list of pending messages */
721 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
722 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
724 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
726 SaveMsg
= pti
->pusmCurrent
;
727 pti
->pusmCurrent
= Message
;
729 // Processing a message sent to it from another thread.
730 if ( ( Message
->SenderQueue
&& MessageQueue
!= Message
->SenderQueue
) ||
731 ( Message
->CallBackSenderQueue
&& MessageQueue
!= Message
->CallBackSenderQueue
))
732 { // most likely, but, to be sure.
733 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
736 /* insert it to the list of messages that are currently dispatched by this
738 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
739 &Message
->ListEntry
);
741 ClearMsgBitsMask(MessageQueue
, Message
->QS_Flags
);
743 if (Message
->HookMessage
== MSQ_ISHOOK
)
744 { // Direct Hook Call processor
745 Result
= co_CallHook( Message
->Msg
.message
, // HookId
746 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
748 Message
->Msg
.lParam
);
750 else if (Message
->HookMessage
== MSQ_ISEVENT
)
751 { // Direct Event Call processor
752 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
755 Message
->Msg
.lParam
);
757 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
759 Result
= IntLoadHookModule(Message
->Msg
.message
,
760 (HHOOK
)Message
->Msg
.lParam
,
761 Message
->Msg
.wParam
);
763 else if ((Message
->CompletionCallback
) &&
764 (Message
->CallBackSenderQueue
== MessageQueue
))
765 { /* Call the callback routine */
766 if (Message
->QS_Flags
& QS_SMRESULT
)
768 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
770 Message
->Msg
.message
,
771 Message
->CompletionCallbackContext
,
773 /* Set callback to NULL to prevent reentry */
774 Message
->CompletionCallback
= NULL
;
778 /* The message has not been processed yet, reinsert it. */
779 RemoveEntryList(&Message
->ListEntry
);
780 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
781 TRACE("Callback Message not processed yet. Requeuing the message\n");
787 { /* Call the window procedure. */
788 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
789 Message
->Msg
.message
,
791 Message
->Msg
.lParam
);
794 /* remove the message from the local dispatching list, because it doesn't need
795 to be cleaned up on thread termination anymore */
796 RemoveEntryList(&Message
->ListEntry
);
798 /* If the message is a callback, insert it in the callback senders MessageQueue */
799 if (Message
->CompletionCallback
)
801 if (Message
->CallBackSenderQueue
)
803 Message
->lResult
= Result
;
804 Message
->QS_Flags
|= QS_SMRESULT
;
806 /* insert it in the callers message queue */
807 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
808 MsqWakeQueue(Message
->CallBackSenderQueue
, QS_SENDMESSAGE
, TRUE
);
809 IntDereferenceMessageQueue(Message
->CallBackSenderQueue
);
815 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
816 if (Message
->SenderQueue
)
818 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
820 /* only remove it from the dispatching list if not already removed by a timeout */
821 RemoveEntryList(&Message
->DispatchingListEntry
);
824 /* still keep the sender's message queue locked, so the sender can't exit the
825 MsqSendMessage() function (if timed out) */
827 if (Message
->QS_Flags
& QS_SMRESULT
)
829 Result
= Message
->lResult
;
832 /* Let the sender know the result. */
833 if (Message
->Result
!= NULL
)
835 *Message
->Result
= Result
;
838 if (Message
->HasPackedLParam
== TRUE
)
840 if (Message
->Msg
.lParam
)
841 ExFreePool((PVOID
)Message
->Msg
.lParam
);
844 /* Notify the sender. */
845 if (Message
->CompletionEvent
!= NULL
)
847 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
850 /* if the message has a sender */
851 if (Message
->SenderQueue
)
853 /* dereference our and the sender's message queue */
854 IntDereferenceMessageQueue(Message
->SenderQueue
);
855 IntDereferenceMessageQueue(MessageQueue
);
858 /* free the message */
859 ExFreePoolWithTag(Message
, TAG_USRMSG
);
862 /* do not hangup on the user if this is reentering */
863 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
864 pti
->pusmCurrent
= SaveMsg
;
870 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
872 PUSER_SENT_MESSAGE SentMessage
;
873 PUSER_MESSAGE PostedMessage
;
874 PUSER_MESSAGE_QUEUE MessageQueue
;
875 PLIST_ENTRY CurrentEntry
, ListHead
;
876 PWND Window
= pWindow
;
880 MessageQueue
= Window
->head
.pti
->MessageQueue
;
881 ASSERT(MessageQueue
);
883 /* remove the posted messages for this window */
884 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
885 ListHead
= &MessageQueue
->PostedMessagesListHead
;
886 while (CurrentEntry
!= ListHead
)
888 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
890 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
892 RemoveEntryList(&PostedMessage
->ListEntry
);
893 ClearMsgBitsMask(MessageQueue
, PostedMessage
->QS_Flags
);
894 MsqDestroyMessage(PostedMessage
);
895 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
899 CurrentEntry
= CurrentEntry
->Flink
;
903 /* Reference we message queue, so it won't get deleted */
904 IntReferenceMessageQueue(MessageQueue
);
906 /* remove the sent messages for this window */
907 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
908 ListHead
= &MessageQueue
->SentMessagesListHead
;
909 while (CurrentEntry
!= ListHead
)
911 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
913 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
915 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
917 RemoveEntryList(&SentMessage
->ListEntry
);
918 ClearMsgBitsMask(MessageQueue
, SentMessage
->QS_Flags
);
920 /* if it is a callback and this queue is not the sender queue, dereference queue */
921 if ((SentMessage
->CompletionCallback
) && (SentMessage
->CallBackSenderQueue
!= MessageQueue
))
923 IntDereferenceMessageQueue(SentMessage
->CallBackSenderQueue
);
925 /* Only if the message has a sender was the queue referenced */
926 if ((SentMessage
->SenderQueue
)
927 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
929 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
932 /* wake the sender's thread */
933 if (SentMessage
->CompletionEvent
!= NULL
)
935 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
938 if (SentMessage
->HasPackedLParam
== TRUE
)
940 if (SentMessage
->Msg
.lParam
)
941 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
944 /* if the message has a sender */
945 if (SentMessage
->SenderQueue
)
947 /* dereference our and the sender's message queue */
948 IntDereferenceMessageQueue(MessageQueue
);
949 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
952 /* free the message */
953 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
955 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
959 CurrentEntry
= CurrentEntry
->Flink
;
963 /* Remove the reference we added */
964 IntDereferenceMessageQueue(MessageQueue
);
968 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
973 SENDASYNCPROC CompletionCallback
,
974 ULONG_PTR CompletionCallbackContext
,
975 BOOL HasPackedLParam
,
979 PTHREADINFO ptiSender
;
980 PUSER_SENT_MESSAGE Message
;
982 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
984 ERR("MsqSendMessage(): Not enough memory to allocate a message");
988 ptiSender
= PsGetCurrentThreadWin32Thread();
990 IntReferenceMessageQueue(ptiReceiver
->MessageQueue
);
991 /* Take reference on this MessageQueue if its a callback. It will be released
992 when message is processed or removed from target hwnd MessageQueue */
993 if (CompletionCallback
)
994 IntReferenceMessageQueue(ptiSender
->MessageQueue
);
996 Message
->Msg
.hwnd
= hwnd
;
997 Message
->Msg
.message
= Msg
;
998 Message
->Msg
.wParam
= wParam
;
999 Message
->Msg
.lParam
= lParam
;
1000 Message
->CompletionEvent
= NULL
;
1001 Message
->Result
= 0;
1002 Message
->lResult
= 0;
1003 Message
->SenderQueue
= NULL
;
1004 Message
->CallBackSenderQueue
= ptiSender
->MessageQueue
;
1005 Message
->DispatchingListEntry
.Flink
= NULL
;
1006 Message
->CompletionCallback
= CompletionCallback
;
1007 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
1008 Message
->HookMessage
= HookMessage
;
1009 Message
->HasPackedLParam
= HasPackedLParam
;
1010 Message
->QS_Flags
= QS_SENDMESSAGE
;
1012 InsertTailList(&ptiReceiver
->MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1013 MsqWakeQueue(ptiReceiver
->MessageQueue
, QS_SENDMESSAGE
, TRUE
);
1014 IntDereferenceMessageQueue(ptiReceiver
->MessageQueue
);
1020 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1021 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
1022 UINT uTimeout
, BOOL Block
, INT HookMessage
,
1025 PTHREADINFO pti
, ptirec
;
1026 PUSER_SENT_MESSAGE Message
;
1027 KEVENT CompletionEvent
;
1028 NTSTATUS WaitStatus
;
1029 PUSER_MESSAGE_QUEUE ThreadQueue
;
1030 LARGE_INTEGER Timeout
;
1033 LRESULT Result
= 0; //// Result could be trashed. ////
1035 pti
= PsGetCurrentThreadWin32Thread();
1036 ThreadQueue
= pti
->MessageQueue
;
1037 ptirec
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1038 ASSERT(ThreadQueue
!= MessageQueue
);
1039 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
1041 /* Don't send from or to a dying thread */
1042 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
1044 if (uResult
) *uResult
= -1;
1045 ERR("MsqSM: Current pti %d or Rec pti %d\n",pti
->TIF_flags
& TIF_INCLEANUP
, ptirec
->TIF_flags
& TIF_INCLEANUP
);
1046 return STATUS_UNSUCCESSFUL
;
1049 if ( HookMessage
== MSQ_NORMAL
)
1051 pWnd
= ValidateHwndNoErr(Wnd
);
1053 // These can not cross International Border lines!
1054 if ( pti
->ppi
!= ptirec
->ppi
&& pWnd
)
1058 // Handle the special case when working with password transfers across bordering processes.
1060 case EM_SETPASSWORDCHAR
:
1062 // Look for edit controls setup for passwords.
1063 if ( gpsi
->atomSysClass
[ICLS_EDIT
] == pWnd
->pcls
->atomClassName
&& // Use atomNVClassName.
1064 pWnd
->style
& ES_PASSWORD
)
1066 if (uResult
) *uResult
= -1;
1067 ERR("Running across the border without a passport!\n");
1068 EngSetLastError(ERROR_ACCESS_DENIED
);
1069 return STATUS_UNSUCCESSFUL
;
1073 if (uResult
) *uResult
= -1;
1074 ERR("Running across the border without a passport!\n");
1075 return STATUS_UNSUCCESSFUL
;
1079 // These can not cross State lines!
1080 if ( Msg
== WM_CREATE
|| Msg
== WM_NCCREATE
)
1082 if (uResult
) *uResult
= -1;
1083 ERR("Can not tell the other State we have Create!\n");
1084 return STATUS_UNSUCCESSFUL
;
1088 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1090 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1091 return STATUS_INSUFFICIENT_RESOURCES
;
1094 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1096 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1098 /* FIXME: Increase reference counter of sender's message queue here */
1100 Message
->Msg
.hwnd
= Wnd
;
1101 Message
->Msg
.message
= Msg
;
1102 Message
->Msg
.wParam
= wParam
;
1103 Message
->Msg
.lParam
= lParam
;
1104 Message
->CompletionEvent
= &CompletionEvent
;
1105 Message
->Result
= &Result
;
1106 Message
->lResult
= 0;
1107 Message
->QS_Flags
= 0;
1108 Message
->SenderQueue
= ThreadQueue
;
1109 Message
->CallBackSenderQueue
= NULL
;
1110 IntReferenceMessageQueue(ThreadQueue
);
1111 Message
->CompletionCallback
= NULL
;
1112 Message
->CompletionCallbackContext
= 0;
1113 Message
->HookMessage
= HookMessage
;
1114 Message
->HasPackedLParam
= FALSE
;
1116 IntReferenceMessageQueue(MessageQueue
);
1118 /* Add it to the list of pending messages */
1119 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1121 /* Queue it in the destination's message queue */
1122 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1124 Message
->QS_Flags
= QS_SENDMESSAGE
;
1125 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
, TRUE
);
1127 /* We can't access the Message anymore since it could have already been deleted! */
1133 /* Don't process messages sent to the thread */
1134 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1135 FALSE
, (uTimeout
? &Timeout
: NULL
));
1139 if(WaitStatus
== STATUS_TIMEOUT
)
1141 /* Look up if the message has not yet dispatched, if so
1142 make sure it can't pass a result and it must not set the completion event anymore */
1143 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1144 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1146 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1149 /* We can access Message here, it's secure because the message queue is locked
1150 and the message is still hasn't been dispatched */
1151 Message
->CompletionEvent
= NULL
;
1152 Message
->Result
= NULL
;
1155 Entry
= Entry
->Flink
;
1158 /* Remove from the local dispatching list so the other thread knows,
1159 it can't pass a result and it must not set the completion event anymore */
1160 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1161 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1163 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1166 /* We can access Message here, it's secure because the sender's message is locked
1167 and the message has definitely not yet been destroyed, otherwise it would
1168 have been removed from this list by the dispatching routine right after
1169 dispatching the message */
1170 Message
->CompletionEvent
= NULL
;
1171 Message
->Result
= NULL
;
1172 RemoveEntryList(&Message
->DispatchingListEntry
);
1173 Message
->DispatchingListEntry
.Flink
= NULL
;
1176 Entry
= Entry
->Flink
;
1179 TRACE("MsqSendMessage (blocked) timed out 1\n");
1181 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1186 PVOID WaitObjects
[2];
1188 WaitObjects
[0] = &CompletionEvent
;
1189 WaitObjects
[1] = ThreadQueue
->NewMessages
;
1194 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1195 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1199 if(WaitStatus
== STATUS_TIMEOUT
)
1201 /* Look up if the message has not yet been dispatched, if so
1202 make sure it can't pass a result and it must not set the completion event anymore */
1203 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1204 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1206 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1209 /* We can access Message here, it's secure because the message queue is locked
1210 and the message is still hasn't been dispatched */
1211 Message
->CompletionEvent
= NULL
;
1212 Message
->Result
= NULL
;
1215 Entry
= Entry
->Flink
;
1218 /* Remove from the local dispatching list so the other thread knows,
1219 it can't pass a result and it must not set the completion event anymore */
1220 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1221 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1223 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1226 /* We can access Message here, it's secure because the sender's message is locked
1227 and the message has definitely not yet been destroyed, otherwise it would
1228 have been removed from this list by the dispatching routine right after
1229 dispatching the message */
1230 Message
->CompletionEvent
= NULL
;
1231 Message
->Result
= NULL
;
1232 RemoveEntryList(&Message
->DispatchingListEntry
);
1233 Message
->DispatchingListEntry
.Flink
= NULL
;
1236 Entry
= Entry
->Flink
;
1239 TRACE("MsqSendMessage timed out 2\n");
1242 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1245 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
1248 if(WaitStatus
!= STATUS_TIMEOUT
)
1249 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1255 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1257 BOOLEAN HardwareMessage
,
1261 PUSER_MESSAGE Message
;
1263 if(!(Message
= MsqCreateMessage(Msg
)))
1270 InsertHeadList(&MessageQueue
->PostedMessagesListHead
,
1271 &Message
->ListEntry
);
1273 else if (!HardwareMessage
)
1275 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1276 &Message
->ListEntry
);
1280 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1281 &Message
->ListEntry
);
1284 Message
->dwQEvent
= dwQEvent
;
1285 Message
->QS_Flags
= MessageBits
;
1286 //Message->pti = pti; Fixed in ATI changes. See CORE-6551
1287 MsqWakeQueue(MessageQueue
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
1291 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1293 MessageQueue
->QuitPosted
= TRUE
;
1294 MessageQueue
->QuitExitCode
= ExitCode
;
1295 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1298 /***********************************************************************
1299 * MsqSendParentNotify
1301 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1302 * the window has the WS_EX_NOPARENTNOTIFY style.
1304 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1306 PWND pwndDesktop
= UserGetDesktopWindow();
1308 /* pt has to be in the client coordinates of the parent window */
1309 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1310 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1316 if (!(pwnd
->style
& WS_CHILD
)) break;
1317 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1318 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1319 if (pwndParent
== pwndDesktop
) break;
1320 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1321 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1324 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1325 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1331 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1333 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1334 hittest
= GetNCHitEx(pwndTrack
, msg
->pt
);
1336 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1337 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1338 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1340 TRACE("ITMM: Track Mouse Move!\n");
1342 /* Handle only the changing window track and mouse move across a border. */
1343 if ( pDesk
->spwndTrack
!= pwndTrack
||
1344 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1346 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1347 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1349 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1350 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1351 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1354 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1355 IntKillTimer(UserHMGetHandle(pDesk
->spwndTrack
), ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1357 /* Clear the flags to sign a change. */
1358 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1360 /* Set the Track window and hit test. */
1361 pDesk
->spwndTrack
= pwndTrack
;
1362 pDesk
->htEx
= hittest
;
1365 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1366 if ( pDesk
->spwndTrack
== pwndTrack
&&
1367 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1368 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1370 TRACE("ITMM: Reset Hover points!\n");
1371 // Restart timer for the hover period.
1372 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1373 // Reset desktop mouse hover from the system default hover rectangle.
1374 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1375 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1376 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1377 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1378 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1382 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1389 MOUSEHOOKSTRUCT hook
;
1392 PWND pwndMsg
, pwndDesktop
;
1393 PUSER_MESSAGE_QUEUE MessageQueue
;
1395 PSYSTEM_CURSORINFO CurInfo
;
1397 DECLARE_RETURN(BOOL
);
1399 pti
= PsGetCurrentThreadWin32Thread();
1400 pwndDesktop
= UserGetDesktopWindow();
1401 MessageQueue
= pti
->MessageQueue
;
1402 CurInfo
= IntGetSysCursorInfo();
1403 pwndMsg
= ValidateHwndNoErr(msg
->hwnd
);
1404 clk_msg
= MessageQueue
->msgDblClk
;
1405 pDesk
= pwndDesktop
->head
.rpdesk
;
1407 /* find the window to dispatch this mouse message to */
1408 if (MessageQueue
->spwndCapture
)
1411 pwndMsg
= MessageQueue
->spwndCapture
;
1412 if (pwndMsg
) UserReferenceObject(pwndMsg
);
1415 { // Fix wine Msg test_HTTRANSPARENT. Start with a NULL window.
1416 // http://www.winehq.org/pipermail/wine-patches/2012-August/116776.html
1417 pwndMsg
= co_WinPosWindowFromPoint(NULL
, &msg
->pt
, &hittest
);
1420 TRACE("Got mouse message for 0x%x, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1422 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
1424 /* Remove and ignore the message */
1425 *RemoveMessages
= TRUE
;
1429 if ( MessageQueue
== gpqCursor
) // Cursor must use the same Queue!
1431 IntTrackMouseMove(pwndMsg
, pDesk
, msg
, hittest
);
1435 ERR("Not the same cursor!\n");
1438 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1441 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
1445 message
= msg
->message
;
1446 /* Note: windows has no concept of a non-client wheel message */
1447 if (message
!= WM_MOUSEWHEEL
)
1449 if (hittest
!= HTCLIENT
)
1451 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1452 msg
->wParam
= hittest
;
1456 /* coordinates don't get translated while tracking a menu */
1457 /* FIXME: should differentiate popups and top-level menus */
1458 if (!(MessageQueue
->MenuOwner
))
1460 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1461 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1465 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1467 /* translate double clicks */
1469 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1470 (msg
->message
== WM_RBUTTONDOWN
) ||
1471 (msg
->message
== WM_MBUTTONDOWN
) ||
1472 (msg
->message
== WM_XBUTTONDOWN
))
1474 BOOL update
= *RemoveMessages
;
1476 /* translate double clicks -
1477 * note that ...MOUSEMOVEs can slip in between
1478 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1480 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1481 hittest
!= HTCLIENT
||
1482 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1484 if ((msg
->message
== clk_msg
.message
) &&
1485 (msg
->hwnd
== clk_msg
.hwnd
) &&
1486 (msg
->wParam
== clk_msg
.wParam
) &&
1487 ((msg
->time
- clk_msg
.time
) < (ULONG
)gspv
.iDblClickTime
) &&
1488 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1489 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1491 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1494 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1500 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1502 TRACE("Message out of range!!!\n");
1506 /* update static double click conditions */
1507 if (update
) MessageQueue
->msgDblClk
= *msg
;
1511 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1513 TRACE("Message out of range!!!\n");
1518 if(gspv
.bMouseClickLock
)
1520 BOOL IsClkLck
= FALSE
;
1522 if(msg
->message
== WM_LBUTTONUP
)
1524 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1525 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1527 CurInfo
->ClickLockActive
= TRUE
;
1530 else if (msg
->message
== WM_LBUTTONDOWN
)
1532 if (CurInfo
->ClickLockActive
)
1535 CurInfo
->ClickLockActive
= FALSE
;
1538 CurInfo
->ClickLockTime
= msg
->time
;
1543 /* Remove and ignore the message */
1544 *RemoveMessages
= TRUE
;
1549 /* message is accepted now (but may still get dropped) */
1551 event
.message
= msg
->message
;
1552 event
.time
= msg
->time
;
1553 event
.hwnd
= msg
->hwnd
;
1554 event
.paramL
= msg
->pt
.x
;
1555 event
.paramH
= msg
->pt
.y
;
1556 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1559 hook
.hwnd
= msg
->hwnd
;
1560 hook
.wHitTestCode
= hittest
;
1561 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1562 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1563 message
, (LPARAM
)&hook
))
1566 hook
.hwnd
= msg
->hwnd
;
1567 hook
.wHitTestCode
= hittest
;
1568 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1569 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1571 ERR("WH_MOUSE dorpped mouse message!\n");
1573 /* Remove and skip message */
1574 *RemoveMessages
= TRUE
;
1578 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1580 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1581 MAKELONG( hittest
, msg
->message
));
1583 /* Remove and skip message */
1584 *RemoveMessages
= TRUE
;
1588 if ((*RemoveMessages
== FALSE
) || MessageQueue
->spwndCapture
)
1590 /* Accept the message */
1591 msg
->message
= message
;
1597 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1598 (msg
->message
== WM_RBUTTONDOWN
) ||
1599 (msg
->message
== WM_MBUTTONDOWN
) ||
1600 (msg
->message
== WM_XBUTTONDOWN
))
1602 /* Send the WM_PARENTNOTIFY,
1603 * note that even for double/nonclient clicks
1604 * notification message is still WM_L/M/RBUTTONDOWN.
1606 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1608 /* Activate the window if needed */
1610 if (pwndMsg
!= MessageQueue
->spwndActive
)
1612 PWND pwndTop
= pwndMsg
;
1613 while (pwndTop
&& ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
))
1615 pwndTop
= pwndTop
->spwndParent
;
1618 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1620 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1622 (WPARAM
)UserHMGetHandle(pwndTop
),
1623 MAKELONG( hittest
, msg
->message
));
1626 case MA_NOACTIVATEANDEAT
:
1631 case MA_ACTIVATEANDEAT
:
1636 if (!co_IntMouseActivateWindow( pwndTop
)) eatMsg
= TRUE
;
1639 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1646 /* send the WM_SETCURSOR message */
1648 /* Windows sends the normal mouse message as the message parameter
1649 in the WM_SETCURSOR message even if it's non-client mouse message */
1650 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1652 msg
->message
= message
;
1657 UserDereferenceObject(pwndMsg
);
1662 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1666 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1667 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1669 switch (Msg
->wParam
)
1671 case VK_LSHIFT
: case VK_RSHIFT
:
1672 Msg
->wParam
= VK_SHIFT
;
1674 case VK_LCONTROL
: case VK_RCONTROL
:
1675 Msg
->wParam
= VK_CONTROL
;
1677 case VK_LMENU
: case VK_RMENU
:
1678 Msg
->wParam
= VK_MENU
;
1683 Event
.message
= Msg
->message
;
1684 Event
.hwnd
= Msg
->hwnd
;
1685 Event
.time
= Msg
->time
;
1686 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1687 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1688 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1689 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1691 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1692 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1693 LOWORD(Msg
->wParam
),
1696 /* skip this message */
1697 co_HOOK_CallHooks( WH_CBT
,
1699 LOWORD(Msg
->wParam
),
1701 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1707 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1709 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1711 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1713 else if ( IS_KBD_MESSAGE(Msg
->message
))
1715 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1722 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1725 IN UINT MsgFilterLow
,
1726 IN UINT MsgFilterHigh
,
1731 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1733 if(!(MessageQueue
->MouseMoved
))
1736 if (!MessageQueue
->ptiSysLock
)
1738 MessageQueue
->ptiSysLock
= pti
;
1739 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1742 if (MessageQueue
->ptiSysLock
!= pti
)
1744 ERR("MsqPeekMouseMove: Thread Q is locked to another pti!\n");
1748 msg
= MessageQueue
->MouseMoveMsg
;
1750 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1757 ClearMsgBitsMask(MessageQueue
, QS_MOUSEMOVE
);
1758 MessageQueue
->MouseMoved
= FALSE
;
1761 MessageQueue
->ptiSysLock
= NULL
;
1762 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1763 return AcceptMessage
;
1766 /* check whether a message filter contains at least one potential hardware message */
1768 filter_contains_hw_range( UINT first
, UINT last
)
1770 /* hardware message ranges are (in numerical order):
1771 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1772 * WM_KEYFIRST .. WM_KEYLAST
1773 * WM_MOUSEFIRST .. WM_MOUSELAST
1776 if (last
< WM_NCMOUSEFIRST
) return 0;
1777 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1778 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1779 if (first
> WM_MOUSELAST
) return 0;
1784 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1787 IN UINT MsgFilterLow
,
1788 IN UINT MsgFilterHigh
,
1794 PUSER_MESSAGE CurrentMessage
;
1795 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1798 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1800 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1802 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1803 CurrentEntry
= ListHead
->Flink
;
1805 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1807 if (!MessageQueue
->ptiSysLock
)
1809 MessageQueue
->ptiSysLock
= pti
;
1810 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1813 if (MessageQueue
->ptiSysLock
!= pti
)
1815 ERR("MsqPeekHardwareMessage: Thread Q is locked to another pti!\n");
1819 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1823 if (IsListEmpty(CurrentEntry
)) break;
1824 if (!CurrentMessage
) break;
1825 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1828 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1829 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1830 3: handle to the window whose messages are to be retrieved.
1832 if ( ( !Window
|| // 1
1833 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1834 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1835 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1836 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1838 msg
= CurrentMessage
->Msg
;
1840 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
1841 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1845 RemoveEntryList(&CurrentMessage
->ListEntry
);
1846 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1847 MsqDestroyMessage(CurrentMessage
);
1857 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1860 while(CurrentEntry
!= ListHead
);
1862 MessageQueue
->ptiSysLock
= NULL
;
1863 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1868 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1871 IN UINT MsgFilterLow
,
1872 IN UINT MsgFilterHigh
,
1876 PLIST_ENTRY CurrentEntry
;
1877 PUSER_MESSAGE CurrentMessage
;
1878 PLIST_ENTRY ListHead
;
1880 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1882 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1883 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1885 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1887 if (!MessageQueue
->ptiSysLock
)
1889 MessageQueue
->ptiSysLock
= pti
;
1890 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1893 if (MessageQueue
->ptiSysLock
!= pti
)
1895 ERR("MsqPeekMessage: Thread Q is locked to another pti!\n");
1899 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1903 if (IsListEmpty(CurrentEntry
)) break;
1904 if (!CurrentMessage
) break;
1905 CurrentEntry
= CurrentEntry
->Flink
;
1908 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1909 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1910 3: handle to the window whose messages are to be retrieved.
1912 if ( ( !Window
|| // 1
1913 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1914 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1915 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1916 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1918 *Message
= CurrentMessage
->Msg
;
1922 RemoveEntryList(&CurrentMessage
->ListEntry
);
1923 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1924 MsqDestroyMessage(CurrentMessage
);
1929 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1932 while (CurrentEntry
!= ListHead
);
1934 MessageQueue
->ptiSysLock
= NULL
;
1935 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1940 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1941 UINT MsgFilterMin
, UINT MsgFilterMax
)
1945 ret
= KeWaitForSingleObject( MessageQueue
->NewMessages
,
1955 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1957 LARGE_INTEGER LargeTickCount
;
1959 KeQueryTickCount(&LargeTickCount
);
1960 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1965 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1968 TRACE("HungAppSysTimerProc\n");
1969 // Process list of windows that are hung and waiting.
1973 MsqInitializeMessageQueue(PTHREADINFO pti
, PUSER_MESSAGE_QUEUE MessageQueue
)
1975 struct _ETHREAD
*Thread
;
1976 LARGE_INTEGER LargeTickCount
;
1979 Thread
= pti
->pEThread
;
1980 MessageQueue
->Thread
= Thread
;
1981 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1982 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1983 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1984 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1985 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1986 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1987 MessageQueue
->QuitPosted
= FALSE
;
1988 MessageQueue
->QuitExitCode
= 0;
1989 KeQueryTickCount(&LargeTickCount
);
1990 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1991 MessageQueue
->spwndFocus
= NULL
;
1992 MessageQueue
->NewMessagesHandle
= NULL
;
1993 MessageQueue
->iCursorLevel
= 0;
1994 MessageQueue
->CursorObject
= NULL
;
1995 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
1997 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1998 NULL
, SynchronizationEvent
, FALSE
);
1999 if (!NT_SUCCESS(Status
))
2004 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
2005 ExEventObjectType
, KernelMode
,
2006 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
2007 if (!NT_SUCCESS(Status
))
2009 ZwClose(MessageQueue
->NewMessagesHandle
);
2010 MessageQueue
->NewMessagesHandle
= NULL
;
2018 MsqCleanupMessageQueue(PTHREADINFO pti
)
2020 PUSER_MESSAGE_QUEUE MessageQueue
;
2021 PLIST_ENTRY CurrentEntry
;
2022 PUSER_MESSAGE CurrentMessage
;
2023 PUSER_SENT_MESSAGE CurrentSentMessage
;
2025 MessageQueue
= pti
->MessageQueue
;
2027 /* cleanup posted messages */
2028 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
2030 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
2031 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
2033 MsqDestroyMessage(CurrentMessage
);
2036 /* remove the messages that have not yet been dispatched */
2037 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
2039 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
2040 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2043 /* if it is a callback and this queue is not the sender queue, dereference queue */
2044 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
2046 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
2049 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
2050 /* Only if the message has a sender was the message in the DispatchingList */
2051 if ((CurrentSentMessage
->SenderQueue
)
2052 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
2054 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
2057 /* wake the sender's thread */
2058 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
2060 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2063 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
2065 if (CurrentSentMessage
->Msg
.lParam
)
2066 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2069 /* if the message has a sender */
2070 if (CurrentSentMessage
->SenderQueue
)
2072 /* dereference our and the sender's message queue */
2073 IntDereferenceMessageQueue(MessageQueue
);
2074 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
2077 /* free the message */
2078 ExFreePool(CurrentSentMessage
);
2081 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
2082 ExitThread() was called in a SendMessage() umode callback */
2083 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
2085 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
2086 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2089 /* if it is a callback and this queue is not the sender queue, dereference queue */
2090 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
2092 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
2095 /* remove the message from the dispatching list */
2096 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
2098 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
2101 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
2103 /* wake the sender's thread */
2104 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
2106 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2109 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
2111 if (CurrentSentMessage
->Msg
.lParam
)
2112 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2115 /* if the message has a sender */
2116 if (CurrentSentMessage
->SenderQueue
)
2118 /* dereference our and the sender's message queue */
2119 IntDereferenceMessageQueue(MessageQueue
);
2120 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
2123 /* free the message */
2124 ExFreePool(CurrentSentMessage
);
2127 /* tell other threads not to bother returning any info to us */
2128 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
2130 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
2131 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2132 DispatchingListEntry
);
2133 CurrentSentMessage
->CompletionEvent
= NULL
;
2134 CurrentSentMessage
->Result
= NULL
;
2136 /* do NOT dereference our message queue as it might get attempted to be
2140 // Clear it all out.
2143 pti
->pcti
->fsWakeBits
= 0;
2144 pti
->pcti
->fsChangeBits
= 0;
2147 MessageQueue
->nCntsQBits
[QSRosKey
] = 0;
2148 MessageQueue
->nCntsQBits
[QSRosMouseMove
] = 0;
2149 MessageQueue
->nCntsQBits
[QSRosMouseButton
] = 0;
2150 MessageQueue
->nCntsQBits
[QSRosPostMessage
] = 0;
2151 MessageQueue
->nCntsQBits
[QSRosSendMessage
] = 0;
2152 MessageQueue
->nCntsQBits
[QSRosHotKey
] = 0;
2154 if (MessageQueue
->CursorObject
)
2156 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2158 /* Change to another cursor if we going to dereference current one
2159 Note: we can't use UserSetCursor because it uses current thread
2160 message queue instead of queue given for cleanup */
2161 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2165 /* Get the screen DC */
2166 hdcScreen
= IntGetScreenDC();
2168 GreMovePointer(hdcScreen
, -1, -1);
2169 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2172 UserDereferenceObject(pCursor
);
2176 PUSER_MESSAGE_QUEUE FASTCALL
2177 MsqCreateMessageQueue(PTHREADINFO pti
)
2179 PUSER_MESSAGE_QUEUE MessageQueue
;
2181 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2182 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2190 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2191 /* hold at least one reference until it'll be destroyed */
2192 IntReferenceMessageQueue(MessageQueue
);
2193 /* initialize the queue */
2194 if (!MsqInitializeMessageQueue(pti
, MessageQueue
))
2196 IntDereferenceMessageQueue(MessageQueue
);
2200 return MessageQueue
;
2204 MsqDestroyMessageQueue(PTHREADINFO pti
)
2207 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2209 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2211 /* remove the message queue from any desktops */
2212 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2214 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2215 IntDereferenceMessageQueue(MessageQueue
);
2219 MsqCleanupMessageQueue(pti
);
2221 if (MessageQueue
->NewMessagesHandle
!= NULL
)
2222 ZwClose(MessageQueue
->NewMessagesHandle
);
2223 MessageQueue
->NewMessagesHandle
= NULL
;
2224 /* decrease the reference counter, if it hits zero, the queue will be freed */
2225 IntDereferenceMessageQueue(MessageQueue
);
2229 MsqSetMessageExtraInfo(LPARAM lParam
)
2233 PUSER_MESSAGE_QUEUE MessageQueue
;
2235 pti
= PsGetCurrentThreadWin32Thread();
2236 MessageQueue
= pti
->MessageQueue
;
2242 Ret
= MessageQueue
->ExtraInfo
;
2243 MessageQueue
->ExtraInfo
= lParam
;
2249 MsqGetMessageExtraInfo(VOID
)
2252 PUSER_MESSAGE_QUEUE MessageQueue
;
2254 pti
= PsGetCurrentThreadWin32Thread();
2255 MessageQueue
= pti
->MessageQueue
;
2261 return MessageQueue
->ExtraInfo
;
2264 // ReplyMessage is called by the thread receiving the window message.
2266 co_MsqReplyMessage( LRESULT lResult
)
2268 PUSER_SENT_MESSAGE Message
;
2271 pti
= PsGetCurrentThreadWin32Thread();
2272 Message
= pti
->pusmCurrent
;
2274 if (!Message
) return FALSE
;
2276 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2278 // SendMessageXxx || Callback msg and not a notify msg
2279 if (Message
->SenderQueue
|| Message
->CompletionCallback
)
2281 Message
->lResult
= lResult
;
2282 Message
->QS_Flags
|= QS_SMRESULT
;
2283 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2289 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
2295 case MSQ_STATE_CAPTURE
:
2296 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2297 MessageQueue
->spwndCapture
= ValidateHwndNoErr(hWnd
);
2299 case MSQ_STATE_ACTIVE
:
2300 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2301 MessageQueue
->spwndActive
= ValidateHwndNoErr(hWnd
);
2303 case MSQ_STATE_FOCUS
:
2304 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2305 MessageQueue
->spwndFocus
= ValidateHwndNoErr(hWnd
);
2307 case MSQ_STATE_MENUOWNER
:
2308 Prev
= MessageQueue
->MenuOwner
;
2309 MessageQueue
->MenuOwner
= hWnd
;
2311 case MSQ_STATE_MOVESIZE
:
2312 Prev
= MessageQueue
->MoveSize
;
2313 MessageQueue
->MoveSize
= hWnd
;
2315 case MSQ_STATE_CARET
:
2316 ASSERT(MessageQueue
->CaretInfo
);
2317 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2318 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2327 NtUserGetKeyState(INT key
)
2333 Ret
= UserGetKeyState(key
);
2343 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2345 DWORD i
, ret
= TRUE
;
2347 PUSER_MESSAGE_QUEUE MessageQueue
;
2351 pti
= PsGetCurrentThreadWin32Thread();
2352 MessageQueue
= pti
->MessageQueue
;
2356 /* Probe and copy key state to an array */
2357 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2358 for (i
= 0; i
< 256; ++i
)
2361 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2362 lpKeyState
[i
] |= KS_DOWN_BIT
;
2363 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2364 lpKeyState
[i
] |= KS_LOCK_BIT
;
2367 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2369 SetLastNtError(_SEH2_GetExceptionCode());
2381 NtUserSetKeyboardState(LPBYTE pKeyState
)
2386 PUSER_MESSAGE_QUEUE MessageQueue
;
2388 UserEnterExclusive();
2390 pti
= PsGetCurrentThreadWin32Thread();
2391 MessageQueue
= pti
->MessageQueue
;
2395 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2396 for (i
= 0; i
< 256; ++i
)
2398 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2399 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2402 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2404 SetLastNtError(_SEH2_GetExceptionCode());