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
);
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
);
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
, MSG
* Msg
, BOOLEAN HardwareMessage
,
1258 PUSER_MESSAGE Message
;
1260 if(!(Message
= MsqCreateMessage(Msg
)))
1265 if(!HardwareMessage
)
1267 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1268 &Message
->ListEntry
);
1272 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1273 &Message
->ListEntry
);
1276 Message
->QS_Flags
= MessageBits
;
1277 MsqWakeQueue(MessageQueue
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
1281 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1283 MessageQueue
->QuitPosted
= TRUE
;
1284 MessageQueue
->QuitExitCode
= ExitCode
;
1285 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1288 /***********************************************************************
1289 * MsqSendParentNotify
1291 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1292 * the window has the WS_EX_NOPARENTNOTIFY style.
1294 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1296 PWND pwndDesktop
= UserGetDesktopWindow();
1298 /* pt has to be in the client coordinates of the parent window */
1299 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1300 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1306 if (!(pwnd
->style
& WS_CHILD
)) break;
1307 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1308 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1309 if (pwndParent
== pwndDesktop
) break;
1310 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1311 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1314 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1315 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1321 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1323 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1324 hittest
= GetNCHitEx(pwndTrack
, msg
->pt
);
1326 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1327 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1328 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1330 TRACE("ITMM: Track Mouse Move!\n");
1332 /* Handle only the changing window track and mouse move across a border. */
1333 if ( pDesk
->spwndTrack
!= pwndTrack
||
1334 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1336 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1337 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1339 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1340 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1341 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1344 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1345 IntKillTimer(UserHMGetHandle(pDesk
->spwndTrack
), ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1347 /* Clear the flags to sign a change. */
1348 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1350 /* Set the Track window and hit test. */
1351 pDesk
->spwndTrack
= pwndTrack
;
1352 pDesk
->htEx
= hittest
;
1355 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1356 if ( pDesk
->spwndTrack
== pwndTrack
&&
1357 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1358 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1360 TRACE("ITMM: Reset Hover points!\n");
1361 // Restart timer for the hover period.
1362 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1363 // Reset desktop mouse hover from the system default hover rectangle.
1364 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1365 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1366 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1367 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1368 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1372 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1379 MOUSEHOOKSTRUCT hook
;
1382 PWND pwndMsg
, pwndDesktop
;
1383 PUSER_MESSAGE_QUEUE MessageQueue
;
1385 PSYSTEM_CURSORINFO CurInfo
;
1387 DECLARE_RETURN(BOOL
);
1389 pti
= PsGetCurrentThreadWin32Thread();
1390 pwndDesktop
= UserGetDesktopWindow();
1391 MessageQueue
= pti
->MessageQueue
;
1392 CurInfo
= IntGetSysCursorInfo();
1393 pwndMsg
= ValidateHwndNoErr(msg
->hwnd
);
1394 clk_msg
= MessageQueue
->msgDblClk
;
1395 pDesk
= pwndDesktop
->head
.rpdesk
;
1397 /* find the window to dispatch this mouse message to */
1398 if (MessageQueue
->spwndCapture
)
1401 pwndMsg
= MessageQueue
->spwndCapture
;
1402 if (pwndMsg
) UserReferenceObject(pwndMsg
);
1405 { // Fix wine Msg test_HTTRANSPARENT. Start with a NULL window.
1406 // http://www.winehq.org/pipermail/wine-patches/2012-August/116776.html
1407 pwndMsg
= co_WinPosWindowFromPoint(NULL
, &msg
->pt
, &hittest
);
1410 TRACE("Got mouse message for 0x%x, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1412 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
1414 /* Remove and ignore the message */
1415 *RemoveMessages
= TRUE
;
1419 if ( MessageQueue
== gpqCursor
) // Cursor must use the same Queue!
1421 IntTrackMouseMove(pwndMsg
, pDesk
, msg
, hittest
);
1425 ERR("Not the same cursor!\n");
1428 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1431 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
1435 message
= msg
->message
;
1436 /* Note: windows has no concept of a non-client wheel message */
1437 if (message
!= WM_MOUSEWHEEL
)
1439 if (hittest
!= HTCLIENT
)
1441 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1442 msg
->wParam
= hittest
;
1446 /* coordinates don't get translated while tracking a menu */
1447 /* FIXME: should differentiate popups and top-level menus */
1448 if (!(MessageQueue
->MenuOwner
))
1450 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1451 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1455 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1457 /* translate double clicks */
1459 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1460 (msg
->message
== WM_RBUTTONDOWN
) ||
1461 (msg
->message
== WM_MBUTTONDOWN
) ||
1462 (msg
->message
== WM_XBUTTONDOWN
))
1464 BOOL update
= *RemoveMessages
;
1466 /* translate double clicks -
1467 * note that ...MOUSEMOVEs can slip in between
1468 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1470 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1471 hittest
!= HTCLIENT
||
1472 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1474 if ((msg
->message
== clk_msg
.message
) &&
1475 (msg
->hwnd
== clk_msg
.hwnd
) &&
1476 (msg
->wParam
== clk_msg
.wParam
) &&
1477 ((msg
->time
- clk_msg
.time
) < (ULONG
)gspv
.iDblClickTime
) &&
1478 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1479 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1481 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1484 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1490 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1492 TRACE("Message out of range!!!\n");
1496 /* update static double click conditions */
1497 if (update
) MessageQueue
->msgDblClk
= *msg
;
1501 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1503 TRACE("Message out of range!!!\n");
1508 if(gspv
.bMouseClickLock
)
1510 BOOL IsClkLck
= FALSE
;
1512 if(msg
->message
== WM_LBUTTONUP
)
1514 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1515 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1517 CurInfo
->ClickLockActive
= TRUE
;
1520 else if (msg
->message
== WM_LBUTTONDOWN
)
1522 if (CurInfo
->ClickLockActive
)
1525 CurInfo
->ClickLockActive
= FALSE
;
1528 CurInfo
->ClickLockTime
= msg
->time
;
1533 /* Remove and ignore the message */
1534 *RemoveMessages
= TRUE
;
1539 /* message is accepted now (but may still get dropped) */
1541 event
.message
= msg
->message
;
1542 event
.time
= msg
->time
;
1543 event
.hwnd
= msg
->hwnd
;
1544 event
.paramL
= msg
->pt
.x
;
1545 event
.paramH
= msg
->pt
.y
;
1546 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1549 hook
.hwnd
= msg
->hwnd
;
1550 hook
.wHitTestCode
= hittest
;
1551 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1552 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1553 message
, (LPARAM
)&hook
))
1556 hook
.hwnd
= msg
->hwnd
;
1557 hook
.wHitTestCode
= hittest
;
1558 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1559 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1561 ERR("WH_MOUSE dorpped mouse message!\n");
1563 /* Remove and skip message */
1564 *RemoveMessages
= TRUE
;
1568 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1570 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1571 MAKELONG( hittest
, msg
->message
));
1573 /* Remove and skip message */
1574 *RemoveMessages
= TRUE
;
1578 if ((*RemoveMessages
== FALSE
) || MessageQueue
->spwndCapture
)
1580 /* Accept the message */
1581 msg
->message
= message
;
1587 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1588 (msg
->message
== WM_RBUTTONDOWN
) ||
1589 (msg
->message
== WM_MBUTTONDOWN
) ||
1590 (msg
->message
== WM_XBUTTONDOWN
))
1592 /* Send the WM_PARENTNOTIFY,
1593 * note that even for double/nonclient clicks
1594 * notification message is still WM_L/M/RBUTTONDOWN.
1596 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1598 /* Activate the window if needed */
1600 if (pwndMsg
!= MessageQueue
->spwndActive
)
1602 PWND pwndTop
= pwndMsg
;
1603 while (pwndTop
&& ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
))
1605 pwndTop
= pwndTop
->spwndParent
;
1608 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1610 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1612 (WPARAM
)UserHMGetHandle(pwndTop
),
1613 MAKELONG( hittest
, msg
->message
));
1616 case MA_NOACTIVATEANDEAT
:
1621 case MA_ACTIVATEANDEAT
:
1626 if (!co_IntMouseActivateWindow( pwndTop
)) eatMsg
= TRUE
;
1629 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1636 /* send the WM_SETCURSOR message */
1638 /* Windows sends the normal mouse message as the message parameter
1639 in the WM_SETCURSOR message even if it's non-client mouse message */
1640 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1642 msg
->message
= message
;
1647 UserDereferenceObject(pwndMsg
);
1652 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1656 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1657 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1659 switch (Msg
->wParam
)
1661 case VK_LSHIFT
: case VK_RSHIFT
:
1662 Msg
->wParam
= VK_SHIFT
;
1664 case VK_LCONTROL
: case VK_RCONTROL
:
1665 Msg
->wParam
= VK_CONTROL
;
1667 case VK_LMENU
: case VK_RMENU
:
1668 Msg
->wParam
= VK_MENU
;
1673 Event
.message
= Msg
->message
;
1674 Event
.hwnd
= Msg
->hwnd
;
1675 Event
.time
= Msg
->time
;
1676 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1677 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1678 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1679 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1681 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1682 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1683 LOWORD(Msg
->wParam
),
1686 /* skip this message */
1687 co_HOOK_CallHooks( WH_CBT
,
1689 LOWORD(Msg
->wParam
),
1691 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1697 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1699 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1701 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1703 else if ( IS_KBD_MESSAGE(Msg
->message
))
1705 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1712 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1715 IN UINT MsgFilterLow
,
1716 IN UINT MsgFilterHigh
,
1721 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1723 if(!(MessageQueue
->MouseMoved
))
1726 if (!MessageQueue
->ptiSysLock
)
1728 MessageQueue
->ptiSysLock
= pti
;
1729 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1732 if (MessageQueue
->ptiSysLock
!= pti
)
1734 ERR("MsqPeekMouseMove: Thread Q is locked to another pti!\n");
1738 msg
= MessageQueue
->MouseMoveMsg
;
1740 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1747 ClearMsgBitsMask(MessageQueue
, QS_MOUSEMOVE
);
1748 MessageQueue
->MouseMoved
= FALSE
;
1751 MessageQueue
->ptiSysLock
= NULL
;
1752 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1753 return AcceptMessage
;
1756 /* check whether a message filter contains at least one potential hardware message */
1758 filter_contains_hw_range( UINT first
, UINT last
)
1760 /* hardware message ranges are (in numerical order):
1761 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1762 * WM_KEYFIRST .. WM_KEYLAST
1763 * WM_MOUSEFIRST .. WM_MOUSELAST
1766 if (last
< WM_NCMOUSEFIRST
) return 0;
1767 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1768 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1769 if (first
> WM_MOUSELAST
) return 0;
1774 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1777 IN UINT MsgFilterLow
,
1778 IN UINT MsgFilterHigh
,
1784 PUSER_MESSAGE CurrentMessage
;
1785 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1788 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1790 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1792 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1793 CurrentEntry
= ListHead
->Flink
;
1795 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1797 if (!MessageQueue
->ptiSysLock
)
1799 MessageQueue
->ptiSysLock
= pti
;
1800 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1803 if (MessageQueue
->ptiSysLock
!= pti
)
1805 ERR("MsqPeekHardwareMessage: Thread Q is locked to another pti!\n");
1809 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1813 if (IsListEmpty(CurrentEntry
)) break;
1814 if (!CurrentMessage
) break;
1815 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1818 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1819 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1820 3: handle to the window whose messages are to be retrieved.
1822 if ( ( !Window
|| // 1
1823 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1824 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1825 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1826 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1828 msg
= CurrentMessage
->Msg
;
1830 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
1831 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1835 RemoveEntryList(&CurrentMessage
->ListEntry
);
1836 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1837 MsqDestroyMessage(CurrentMessage
);
1847 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1850 while(CurrentEntry
!= ListHead
);
1852 MessageQueue
->ptiSysLock
= NULL
;
1853 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1858 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1861 IN UINT MsgFilterLow
,
1862 IN UINT MsgFilterHigh
,
1866 PLIST_ENTRY CurrentEntry
;
1867 PUSER_MESSAGE CurrentMessage
;
1868 PLIST_ENTRY ListHead
;
1870 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1872 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1873 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1875 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1877 if (!MessageQueue
->ptiSysLock
)
1879 MessageQueue
->ptiSysLock
= pti
;
1880 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1883 if (MessageQueue
->ptiSysLock
!= pti
)
1885 ERR("MsqPeekMessage: Thread Q is locked to another pti!\n");
1889 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1893 if (IsListEmpty(CurrentEntry
)) break;
1894 if (!CurrentMessage
) break;
1895 CurrentEntry
= CurrentEntry
->Flink
;
1898 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1899 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1900 3: handle to the window whose messages are to be retrieved.
1902 if ( ( !Window
|| // 1
1903 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1904 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1905 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1906 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1908 *Message
= CurrentMessage
->Msg
;
1912 RemoveEntryList(&CurrentMessage
->ListEntry
);
1913 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1914 MsqDestroyMessage(CurrentMessage
);
1919 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1922 while (CurrentEntry
!= ListHead
);
1924 MessageQueue
->ptiSysLock
= NULL
;
1925 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1930 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1931 UINT MsgFilterMin
, UINT MsgFilterMax
)
1935 ret
= KeWaitForSingleObject( MessageQueue
->NewMessages
,
1945 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1947 LARGE_INTEGER LargeTickCount
;
1949 KeQueryTickCount(&LargeTickCount
);
1950 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1955 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1958 TRACE("HungAppSysTimerProc\n");
1959 // Process list of windows that are hung and waiting.
1963 MsqInitializeMessageQueue(PTHREADINFO pti
, PUSER_MESSAGE_QUEUE MessageQueue
)
1965 struct _ETHREAD
*Thread
;
1966 LARGE_INTEGER LargeTickCount
;
1969 Thread
= pti
->pEThread
;
1970 MessageQueue
->Thread
= Thread
;
1971 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1972 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1973 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1974 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1975 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1976 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1977 MessageQueue
->QuitPosted
= FALSE
;
1978 MessageQueue
->QuitExitCode
= 0;
1979 KeQueryTickCount(&LargeTickCount
);
1980 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1981 MessageQueue
->spwndFocus
= NULL
;
1982 MessageQueue
->NewMessagesHandle
= NULL
;
1983 MessageQueue
->iCursorLevel
= 0;
1984 MessageQueue
->CursorObject
= NULL
;
1985 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
1987 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1988 NULL
, SynchronizationEvent
, FALSE
);
1989 if (!NT_SUCCESS(Status
))
1994 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1995 ExEventObjectType
, KernelMode
,
1996 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1997 if (!NT_SUCCESS(Status
))
1999 ZwClose(MessageQueue
->NewMessagesHandle
);
2000 MessageQueue
->NewMessagesHandle
= NULL
;
2008 MsqCleanupMessageQueue(PTHREADINFO pti
)
2010 PUSER_MESSAGE_QUEUE MessageQueue
;
2011 PLIST_ENTRY CurrentEntry
;
2012 PUSER_MESSAGE CurrentMessage
;
2013 PUSER_SENT_MESSAGE CurrentSentMessage
;
2015 MessageQueue
= pti
->MessageQueue
;
2017 /* cleanup posted messages */
2018 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
2020 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
2021 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
2023 MsqDestroyMessage(CurrentMessage
);
2026 /* remove the messages that have not yet been dispatched */
2027 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
2029 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
2030 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2033 /* if it is a callback and this queue is not the sender queue, dereference queue */
2034 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
2036 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
2039 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
2040 /* Only if the message has a sender was the message in the DispatchingList */
2041 if ((CurrentSentMessage
->SenderQueue
)
2042 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
2044 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
2047 /* wake the sender's thread */
2048 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
2050 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2053 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
2055 if (CurrentSentMessage
->Msg
.lParam
)
2056 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2059 /* if the message has a sender */
2060 if (CurrentSentMessage
->SenderQueue
)
2062 /* dereference our and the sender's message queue */
2063 IntDereferenceMessageQueue(MessageQueue
);
2064 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
2067 /* free the message */
2068 ExFreePool(CurrentSentMessage
);
2071 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
2072 ExitThread() was called in a SendMessage() umode callback */
2073 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
2075 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
2076 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2079 /* if it is a callback and this queue is not the sender queue, dereference queue */
2080 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
2082 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
2085 /* remove the message from the dispatching list */
2086 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
2088 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
2091 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
2093 /* wake the sender's thread */
2094 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
2096 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2099 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
2101 if (CurrentSentMessage
->Msg
.lParam
)
2102 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2105 /* if the message has a sender */
2106 if (CurrentSentMessage
->SenderQueue
)
2108 /* dereference our and the sender's message queue */
2109 IntDereferenceMessageQueue(MessageQueue
);
2110 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
2113 /* free the message */
2114 ExFreePool(CurrentSentMessage
);
2117 /* tell other threads not to bother returning any info to us */
2118 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
2120 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
2121 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2122 DispatchingListEntry
);
2123 CurrentSentMessage
->CompletionEvent
= NULL
;
2124 CurrentSentMessage
->Result
= NULL
;
2126 /* do NOT dereference our message queue as it might get attempted to be
2130 // Clear it all out.
2133 pti
->pcti
->fsWakeBits
= 0;
2134 pti
->pcti
->fsChangeBits
= 0;
2137 MessageQueue
->nCntsQBits
[QSRosKey
] = 0;
2138 MessageQueue
->nCntsQBits
[QSRosMouseMove
] = 0;
2139 MessageQueue
->nCntsQBits
[QSRosMouseButton
] = 0;
2140 MessageQueue
->nCntsQBits
[QSRosPostMessage
] = 0;
2141 MessageQueue
->nCntsQBits
[QSRosSendMessage
] = 0;
2142 MessageQueue
->nCntsQBits
[QSRosHotKey
] = 0;
2144 if (MessageQueue
->CursorObject
)
2146 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2148 /* Change to another cursor if we going to dereference current one
2149 Note: we can't use UserSetCursor because it uses current thread
2150 message queue instead of queue given for cleanup */
2151 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2155 /* Get the screen DC */
2156 hdcScreen
= IntGetScreenDC();
2158 GreMovePointer(hdcScreen
, -1, -1);
2159 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2162 UserDereferenceObject(pCursor
);
2166 PUSER_MESSAGE_QUEUE FASTCALL
2167 MsqCreateMessageQueue(PTHREADINFO pti
)
2169 PUSER_MESSAGE_QUEUE MessageQueue
;
2171 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2172 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2180 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2181 /* hold at least one reference until it'll be destroyed */
2182 IntReferenceMessageQueue(MessageQueue
);
2183 /* initialize the queue */
2184 if (!MsqInitializeMessageQueue(pti
, MessageQueue
))
2186 IntDereferenceMessageQueue(MessageQueue
);
2190 return MessageQueue
;
2194 MsqDestroyMessageQueue(PTHREADINFO pti
)
2197 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2199 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2201 /* remove the message queue from any desktops */
2202 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2204 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2205 IntDereferenceMessageQueue(MessageQueue
);
2209 MsqCleanupMessageQueue(pti
);
2211 if (MessageQueue
->NewMessagesHandle
!= NULL
)
2212 ZwClose(MessageQueue
->NewMessagesHandle
);
2213 MessageQueue
->NewMessagesHandle
= NULL
;
2214 /* decrease the reference counter, if it hits zero, the queue will be freed */
2215 IntDereferenceMessageQueue(MessageQueue
);
2219 MsqSetMessageExtraInfo(LPARAM lParam
)
2223 PUSER_MESSAGE_QUEUE MessageQueue
;
2225 pti
= PsGetCurrentThreadWin32Thread();
2226 MessageQueue
= pti
->MessageQueue
;
2232 Ret
= MessageQueue
->ExtraInfo
;
2233 MessageQueue
->ExtraInfo
= lParam
;
2239 MsqGetMessageExtraInfo(VOID
)
2242 PUSER_MESSAGE_QUEUE MessageQueue
;
2244 pti
= PsGetCurrentThreadWin32Thread();
2245 MessageQueue
= pti
->MessageQueue
;
2251 return MessageQueue
->ExtraInfo
;
2254 // ReplyMessage is called by the thread receiving the window message.
2256 co_MsqReplyMessage( LRESULT lResult
)
2258 PUSER_SENT_MESSAGE Message
;
2261 pti
= PsGetCurrentThreadWin32Thread();
2262 Message
= pti
->pusmCurrent
;
2264 if (!Message
) return FALSE
;
2266 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2268 // SendMessageXxx || Callback msg and not a notify msg
2269 if (Message
->SenderQueue
|| Message
->CompletionCallback
)
2271 Message
->lResult
= lResult
;
2272 Message
->QS_Flags
|= QS_SMRESULT
;
2273 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2279 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
2285 case MSQ_STATE_CAPTURE
:
2286 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2287 MessageQueue
->spwndCapture
= ValidateHwndNoErr(hWnd
);
2289 case MSQ_STATE_ACTIVE
:
2290 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2291 MessageQueue
->spwndActive
= ValidateHwndNoErr(hWnd
);
2293 case MSQ_STATE_FOCUS
:
2294 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2295 MessageQueue
->spwndFocus
= ValidateHwndNoErr(hWnd
);
2297 case MSQ_STATE_MENUOWNER
:
2298 Prev
= MessageQueue
->MenuOwner
;
2299 MessageQueue
->MenuOwner
= hWnd
;
2301 case MSQ_STATE_MOVESIZE
:
2302 Prev
= MessageQueue
->MoveSize
;
2303 MessageQueue
->MoveSize
= hWnd
;
2305 case MSQ_STATE_CARET
:
2306 ASSERT(MessageQueue
->CaretInfo
);
2307 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2308 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2317 NtUserGetKeyState(INT key
)
2323 Ret
= UserGetKeyState(key
);
2333 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2335 DWORD i
, ret
= TRUE
;
2337 PUSER_MESSAGE_QUEUE MessageQueue
;
2341 pti
= PsGetCurrentThreadWin32Thread();
2342 MessageQueue
= pti
->MessageQueue
;
2346 /* Probe and copy key state to an array */
2347 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2348 for (i
= 0; i
< 256; ++i
)
2351 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2352 lpKeyState
[i
] |= KS_DOWN_BIT
;
2353 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2354 lpKeyState
[i
] |= KS_LOCK_BIT
;
2357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2359 SetLastNtError(_SEH2_GetExceptionCode());
2371 NtUserSetKeyboardState(LPBYTE pKeyState
)
2376 PUSER_MESSAGE_QUEUE MessageQueue
;
2378 UserEnterExclusive();
2380 pti
= PsGetCurrentThreadWin32Thread();
2381 MessageQueue
= pti
->MessageQueue
;
2385 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2386 for (i
= 0; i
< 256; ++i
)
2388 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2389 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2392 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2394 SetLastNtError(_SEH2_GetExceptionCode());