2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
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 PAGED_LOOKASIDE_LIST MessageLookasideList
;
17 MOUSEMOVEPOINT MouseHistoryOfMoves
[64];
20 /* FUNCTIONS *****************************************************************/
25 MsqInitializeImpl(VOID
)
27 ExInitializePagedLookasideList(&MessageLookasideList
,
35 return(STATUS_SUCCESS
);
39 IntChildrenWindowFromPoint(PWND pWndTop
, INT x
, INT y
)
43 if (!(pWndTop
->style
& WS_VISIBLE
)) return NULL
;
44 if ((pWndTop
->style
& WS_DISABLED
)) return NULL
;
45 if (!IntPtInWindow(pWndTop
, x
, y
)) return NULL
;
47 if (x
- pWndTop
->rcClient
.left
< pWndTop
->rcClient
.right
&&
48 y
- pWndTop
->rcClient
.top
< pWndTop
->rcClient
.bottom
)
50 for (pWnd
= pWndTop
->spwndChild
;
52 pWnd
= pWnd
->spwndNext
)
54 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
56 TRACE("The Window is in DESTROY!\n");
60 pWndChild
= IntChildrenWindowFromPoint(pWnd
, x
, y
);
72 IntTopLevelWindowFromPoint(INT x
, INT y
)
74 PWND pWnd
, pwndDesktop
;
76 /* Get the desktop window */
77 pwndDesktop
= UserGetDesktopWindow();
81 /* Loop all top level windows */
82 for (pWnd
= pwndDesktop
->spwndChild
;
84 pWnd
= pWnd
->spwndNext
)
86 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
88 TRACE("The Window is in DESTROY!\n");
92 if ((pWnd
->style
& WS_VISIBLE
) && IntPtInWindow(pWnd
, x
, y
))
96 /* Window has not been found */
103 PCURICON_OBJECT NewCursor
,
106 PCURICON_OBJECT OldCursor
;
109 PUSER_MESSAGE_QUEUE MessageQueue
;
112 pti
= PsGetCurrentThreadWin32Thread();
113 MessageQueue
= pti
->MessageQueue
;
115 /* Get the screen DC */
116 if(!(hdcScreen
= IntGetScreenDC()))
121 OldCursor
= MessageQueue
->CursorObject
;
123 /* Check if cursors are different */
124 if (OldCursor
== NewCursor
)
127 /* Update cursor for this message queue */
128 MessageQueue
->CursorObject
= NewCursor
;
130 /* If cursor is not visible we have nothing to do */
131 if (MessageQueue
->ShowingCursor
< 0)
134 /* Update cursor if this message queue controls it */
135 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
136 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
140 /* Call GDI to set the new screen cursor */
141 GreSetPointerShape(hdcScreen
,
142 NewCursor
->IconInfo
.hbmMask
,
143 NewCursor
->IconInfo
.hbmColor
,
144 NewCursor
->IconInfo
.xHotspot
,
145 NewCursor
->IconInfo
.yHotspot
,
149 else /* Note: OldCursor != NewCursor so we have to hide cursor */
151 /* Remove the cursor */
152 GreMovePointer(hdcScreen
, -1, -1);
153 TRACE("Removing pointer!\n");
155 IntGetSysCursorInfo()->CurrentCursorObject
= NewCursor
;
158 /* Return the old cursor */
162 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
163 * User32 macro NtUserShowCursor */
164 int UserShowCursor(BOOL bShow
)
168 PUSER_MESSAGE_QUEUE MessageQueue
;
171 if (!(hdcScreen
= IntGetScreenDC()))
173 return -1; /* No mouse */
176 pti
= PsGetCurrentThreadWin32Thread();
177 MessageQueue
= pti
->MessageQueue
;
180 MessageQueue
->ShowingCursor
+= bShow
? 1 : -1;
182 /* Check for trivial cases */
183 if ((bShow
&& MessageQueue
->ShowingCursor
!= 0) ||
184 (!bShow
&& MessageQueue
->ShowingCursor
!= -1))
186 /* Note: w don't update global info here because it is used only
187 internally to check if cursor is visible */
188 return MessageQueue
->ShowingCursor
;
191 /* Check if cursor is above window owned by this MessageQueue */
192 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
193 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
197 /* Show the pointer */
198 GreMovePointer(hdcScreen
, gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
199 TRACE("Showing pointer!\n");
203 /* Remove the pointer */
204 GreMovePointer(hdcScreen
, -1, -1);
205 TRACE("Removing pointer!\n");
208 /* Update global info */
209 IntGetSysCursorInfo()->ShowingCursor
= MessageQueue
->ShowingCursor
;
212 return MessageQueue
->ShowingCursor
;
215 DWORD FASTCALL
UserGetKeyState(DWORD key
)
219 PUSER_MESSAGE_QUEUE MessageQueue
;
221 pti
= PsGetCurrentThreadWin32Thread();
222 MessageQueue
= pti
->MessageQueue
;
226 ret
= (DWORD
)MessageQueue
->KeyState
[key
];
227 if (MessageQueue
->KeyState
[key
] & KS_DOWN_BIT
)
228 ret
|= 0xFF80; // If down, windows returns 0xFF80.
229 if (MessageQueue
->KeyState
[key
] & KS_LOCK_BIT
)
234 EngSetLastError(ERROR_INVALID_PARAMETER
);
239 /* change the input key state for a given key */
240 static void set_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue
, UCHAR key
, BOOL down
)
242 TRACE("set_input_key_state key:%d, down:%d\n", key
, down
);
246 if (!(MessageQueue
->KeyState
[key
] & KS_DOWN_BIT
))
248 MessageQueue
->KeyState
[key
] ^= KS_LOCK_BIT
;
250 MessageQueue
->KeyState
[key
] |= KS_DOWN_BIT
;
254 MessageQueue
->KeyState
[key
] &= ~KS_DOWN_BIT
;
258 /* update the input key state for a keyboard message */
259 static void update_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
264 TRACE("update_input_key_state message:%d\n", msg
->message
);
266 switch (msg
->message
)
272 set_input_key_state( MessageQueue
, VK_LBUTTON
, down
);
278 set_input_key_state( MessageQueue
, VK_MBUTTON
, down
);
284 set_input_key_state( MessageQueue
, VK_RBUTTON
, down
);
290 if (msg
->wParam
== XBUTTON1
)
291 set_input_key_state( MessageQueue
, VK_XBUTTON1
, down
);
292 else if (msg
->wParam
== XBUTTON2
)
293 set_input_key_state( MessageQueue
, VK_XBUTTON2
, down
);
301 key
= (UCHAR
)msg
->wParam
;
302 set_input_key_state( MessageQueue
, key
, down
);
307 down
= (MessageQueue
->KeyState
[VK_LCONTROL
] | MessageQueue
->KeyState
[VK_RCONTROL
]) & KS_DOWN_BIT
;
308 set_input_key_state( MessageQueue
, VK_CONTROL
, down
);
312 down
= (MessageQueue
->KeyState
[VK_LMENU
] | MessageQueue
->KeyState
[VK_RMENU
]) & KS_DOWN_BIT
;
313 set_input_key_state( MessageQueue
, VK_MENU
, down
);
317 down
= (MessageQueue
->KeyState
[VK_LSHIFT
] | MessageQueue
->KeyState
[VK_RSHIFT
]) & KS_DOWN_BIT
;
318 set_input_key_state( MessageQueue
, VK_SHIFT
, down
);
326 IntMsqSetWakeMask(DWORD WakeMask
)
328 PTHREADINFO Win32Thread
;
329 PUSER_MESSAGE_QUEUE MessageQueue
;
330 HANDLE MessageEventHandle
;
331 DWORD dwFlags
= HIWORD(WakeMask
);
333 Win32Thread
= PsGetCurrentThreadWin32Thread();
334 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
337 MessageQueue
= Win32Thread
->MessageQueue
;
338 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
339 MessageEventHandle
= MessageQueue
->NewMessagesHandle
;
341 if (Win32Thread
->pcti
)
343 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
344 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
346 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
347 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
348 return MessageEventHandle
;
354 return MessageEventHandle
;
358 IntMsqClearWakeMask(VOID
)
360 PTHREADINFO Win32Thread
;
362 Win32Thread
= PsGetCurrentThreadWin32Thread();
363 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
365 // Very hacky, but that is what they do.
366 Win32Thread
->pcti
->fsWakeBits
= 0;
374 Due to the uncertainty of knowing what was set in our multilevel message queue,
375 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
376 I think this is the best solution... (jt) */
378 MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue
, DWORD MessageBits
, BOOL KeyEvent
)
382 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
383 pti
->pcti
->fsWakeBits
|= MessageBits
;
384 pti
->pcti
->fsChangeBits
|= MessageBits
;
386 // Start bit accounting to help clear the main set of bits.
387 if (MessageBits
& QS_KEY
) Queue
->nCntsQBits
[QSRosKey
]++;
388 if (MessageBits
& QS_MOUSEMOVE
) Queue
->nCntsQBits
[QSRosMouseMove
]++;
389 if (MessageBits
& QS_MOUSEBUTTON
) Queue
->nCntsQBits
[QSRosMouseButton
]++;
390 if (MessageBits
& QS_POSTMESSAGE
) Queue
->nCntsQBits
[QSRosPostMessage
]++;
391 if (MessageBits
& QS_SENDMESSAGE
) Queue
->nCntsQBits
[QSRosSendMessage
]++;
392 if (MessageBits
& QS_HOTKEY
) Queue
->nCntsQBits
[QSRosHotKey
]++;
395 KeSetEvent(Queue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
399 ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue
, UINT MessageBits
)
404 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
406 if (MessageBits
& QS_KEY
)
408 if (--Queue
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
410 if (MessageBits
& QS_MOUSEMOVE
) // ReactOS hard coded.
411 { // Account for tracking mouse moves..
412 if (--Queue
->nCntsQBits
[QSRosMouseMove
] == 0) ClrMask
|= QS_MOUSEMOVE
;
413 // Handle mouse move bits here.
414 if (Queue
->MouseMoved
) ClrMask
|= QS_MOUSEMOVE
;
416 if (MessageBits
& QS_MOUSEBUTTON
)
418 if (--Queue
->nCntsQBits
[QSRosMouseButton
] == 0) ClrMask
|= QS_MOUSEBUTTON
;
420 if (MessageBits
& QS_POSTMESSAGE
)
422 if (--Queue
->nCntsQBits
[QSRosPostMessage
] == 0) ClrMask
|= QS_POSTMESSAGE
;
424 if (MessageBits
& QS_TIMER
) // ReactOS hard coded.
425 { // Handle timer bits here.
426 if ( pti
->cTimersReady
)
428 if (--pti
->cTimersReady
== 0) ClrMask
|= QS_TIMER
;
431 if (MessageBits
& QS_PAINT
) // ReactOS hard coded.
432 { // Handle paint bits here.
433 if ( pti
->cPaintsReady
)
435 if (--pti
->cPaintsReady
== 0) ClrMask
|= QS_PAINT
;
438 if (MessageBits
& QS_SENDMESSAGE
)
440 if (--Queue
->nCntsQBits
[QSRosSendMessage
] == 0) ClrMask
|= QS_SENDMESSAGE
;
442 if (MessageBits
& QS_HOTKEY
)
444 if (--Queue
->nCntsQBits
[QSRosHotKey
] == 0) ClrMask
|= QS_HOTKEY
;
447 pti
->pcti
->fsWakeBits
&= ~ClrMask
;
448 pti
->pcti
->fsChangeBits
&= ~ClrMask
;
452 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
455 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
457 MsqWakeQueue(Queue
, QS_PAINT
, TRUE
);
461 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
463 ClearMsgBitsMask(Queue
, QS_PAINT
);
467 MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
)
469 MessageQueue
->MouseMoveMsg
= *Msg
;
470 MessageQueue
->MouseMoved
= TRUE
;
471 MsqWakeQueue(MessageQueue
, QS_MOUSEMOVE
, TRUE
);
475 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
477 LARGE_INTEGER LargeTickCount
;
478 MSLLHOOKSTRUCT MouseHookData
;
480 PWND pwnd
, pwndDesktop
;
482 PSYSTEM_CURSORINFO CurInfo
;
484 KeQueryTickCount(&LargeTickCount
);
485 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
487 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
488 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
489 switch (Msg
->message
)
492 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
496 case WM_XBUTTONDBLCLK
:
497 case WM_NCXBUTTONDOWN
:
499 case WM_NCXBUTTONDBLCLK
:
500 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
503 MouseHookData
.mouseData
= 0;
507 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
508 MouseHookData
.time
= Msg
->time
;
509 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
511 /* If the hook procedure returned non zero, dont send the message */
514 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
518 /* Get the desktop window */
519 pwndDesktop
= UserGetDesktopWindow();
520 if (!pwndDesktop
) return;
521 pDesk
= pwndDesktop
->head
.rpdesk
;
523 /* Check if the mouse is captured */
524 Msg
->hwnd
= IntGetCaptureWindow();
525 if (Msg
->hwnd
!= NULL
)
527 pwnd
= UserGetWindowObject(Msg
->hwnd
);
531 pwnd
= IntTopLevelWindowFromPoint(Msg
->pt
.x
, Msg
->pt
.y
);
532 if (pwnd
) Msg
->hwnd
= pwnd
->head
.h
;
537 /* If we a re tracking the mouse and it moves to another top level window */
538 if(pDesk
->spwndTrack
&&
539 UserGetAncestor(pDesk
->spwndTrack
, GA_ROOT
) != pwnd
)
541 /* Generate a WM_MOUSELEAVE message */
542 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
546 TRACE("co_MsqInsertMouseMessage: generating WM_MOUSELEAVE\n");
548 msgMouseLeave
.hwnd
= UserHMGetHandle(pDesk
->spwndTrack
);
549 msgMouseLeave
.message
= WM_MOUSELEAVE
;
550 msgMouseLeave
.pt
= Msg
->pt
;
551 msgMouseLeave
.time
= Msg
->time
;
552 msgMouseLeave
.lParam
= msgMouseLeave
.wParam
= 0;
554 MsqPostMessage(pwnd
->head
.pti
->MessageQueue
, Msg
, TRUE
, QS_MOUSE
);
558 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
560 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
563 pDesk
->spwndTrack
= NULL
;
568 hdcScreen
= IntGetScreenDC();
569 CurInfo
= IntGetSysCursorInfo();
571 /* Check if we found a window */
572 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
574 if (Msg
->message
== WM_MOUSEMOVE
)
576 PUSER_MESSAGE_QUEUE MessageQueue
= pwnd
->head
.pti
->MessageQueue
;
578 /* Check if cursor should be visible */
580 MessageQueue
->CursorObject
&&
581 MessageQueue
->ShowingCursor
>= 0)
583 /* Check if shape has changed */
584 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
586 /* Call GDI to set the new screen cursor */
587 GreSetPointerShape(hdcScreen
,
588 MessageQueue
->CursorObject
->IconInfo
.hbmMask
,
589 MessageQueue
->CursorObject
->IconInfo
.hbmColor
,
590 MessageQueue
->CursorObject
->IconInfo
.xHotspot
,
591 MessageQueue
->CursorObject
->IconInfo
.yHotspot
,
595 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
597 /* Check if w have to hide cursor */
598 else if (CurInfo
->ShowingCursor
>= 0)
599 GreMovePointer(hdcScreen
, -1, -1);
601 /* Update global cursor info */
602 CurInfo
->ShowingCursor
= MessageQueue
->ShowingCursor
;
603 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
605 /* Mouse move is a special case */
606 MsqPostMouseMove(MessageQueue
, Msg
);
610 TRACE("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd
));
611 MsqPostMessage(pwnd
->head
.pti
->MessageQueue
, Msg
, TRUE
, QS_MOUSEBUTTON
);
616 /* always show cursor on background; FIXME: set default pointer */
617 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
618 CurInfo
->ShowingCursor
= 0;
621 /* Do GetMouseMovePointsEx FIFO. */
622 MouseHistoryOfMoves
[gcur_count
].x
= Msg
->pt
.x
;
623 MouseHistoryOfMoves
[gcur_count
].y
= Msg
->pt
.y
;
624 MouseHistoryOfMoves
[gcur_count
].time
= Msg
->time
;
625 MouseHistoryOfMoves
[gcur_count
].dwExtraInfo
= dwExtraInfo
;
626 if (++gcur_count
== ARRAYSIZE(MouseHistoryOfMoves
))
627 gcur_count
= 0; // 0 - 63 is 64, FIFO forwards.
631 // Note: Only called from input.c.
634 co_MsqPostKeyboardMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL bInjected
)
636 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
638 LARGE_INTEGER LargeTickCount
;
639 KBDLLHOOKSTRUCT KbdHookData
;
641 TRACE("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
642 uMsg
, wParam
, lParam
);
644 // Condition may arise when calling MsqPostMessage and waiting for an event.
645 ASSERT(UserIsEntered());
647 FocusMessageQueue
= IntGetFocusMessageQueue();
651 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
652 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
658 KeQueryTickCount(&LargeTickCount
);
659 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
661 /* We can't get the Msg.pt point here since we don't know thread
662 (and thus the window station) the message will end up in yet. */
664 KbdHookData
.vkCode
= Msg
.wParam
;
665 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
666 KbdHookData
.flags
= 0;
667 if (Msg
.lParam
& 0x01000000)
668 KbdHookData
.flags
|= LLKHF_EXTENDED
;
669 if (Msg
.lParam
& 0x20000000)
670 KbdHookData
.flags
|= LLKHF_ALTDOWN
;
671 if (Msg
.lParam
& 0x80000000)
672 KbdHookData
.flags
|= LLKHF_UP
;
674 KbdHookData
.flags
|= LLKHF_INJECTED
;
675 KbdHookData
.time
= Msg
.time
;
676 KbdHookData
.dwExtraInfo
= 0;
677 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
679 ERR("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
680 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
684 if (FocusMessageQueue
== NULL
)
686 TRACE("No focus message queue\n");
690 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
692 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
693 TRACE("Msg.hwnd = %x\n", Msg
.hwnd
);
695 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
697 Msg
.pt
= gpsi
->ptCursor
;
698 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
702 TRACE("Invalid focus window handle\n");
709 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
712 PTHREADINFO Win32Thread
;
714 LARGE_INTEGER LargeTickCount
;
719 Status
= ObReferenceObjectByPointer (Thread
,
723 if (!NT_SUCCESS(Status
))
726 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
727 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
729 ObDereferenceObject ((PETHREAD
)Thread
);
733 Window
= IntGetWindowObject(hWnd
);
736 ObDereferenceObject ((PETHREAD
)Thread
);
740 id
= wParam
; // Check for hot keys unrelated to the hot keys set by RegisterHotKey.
743 Mesg
.message
= id
!= IDHOT_REACTOS
? WM_HOTKEY
: WM_SYSCOMMAND
;
744 Mesg
.wParam
= id
!= IDHOT_REACTOS
? wParam
: SC_HOTKEY
;
745 Mesg
.lParam
= id
!= IDHOT_REACTOS
? lParam
: (LPARAM
)hWnd
;
746 Type
= id
!= IDHOT_REACTOS
? QS_HOTKEY
: QS_POSTMESSAGE
;
747 KeQueryTickCount(&LargeTickCount
);
748 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
749 Mesg
.pt
= gpsi
->ptCursor
;
750 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, Type
);
751 UserDereferenceObject(Window
);
752 ObDereferenceObject (Thread
);
756 PUSER_MESSAGE FASTCALL
757 MsqCreateMessage(LPMSG Msg
)
759 PUSER_MESSAGE Message
;
761 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
767 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
773 MsqDestroyMessage(PUSER_MESSAGE Message
)
775 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
779 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
781 PUSER_SENT_MESSAGE SaveMsg
, Message
;
786 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
791 /* remove it from the list of pending messages */
792 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
793 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
795 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
797 SaveMsg
= pti
->pusmCurrent
;
798 pti
->pusmCurrent
= Message
;
800 // Processing a message sent to it from another thread.
801 if ( ( Message
->SenderQueue
&& MessageQueue
!= Message
->SenderQueue
) ||
802 ( Message
->CallBackSenderQueue
&& MessageQueue
!= Message
->CallBackSenderQueue
))
803 { // most likely, but, to be sure.
804 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
807 /* insert it to the list of messages that are currently dispatched by this
809 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
810 &Message
->ListEntry
);
812 ClearMsgBitsMask(MessageQueue
, Message
->QS_Flags
);
814 if (Message
->HookMessage
== MSQ_ISHOOK
)
815 { // Direct Hook Call processor
816 Result
= co_CallHook( Message
->Msg
.message
, // HookId
817 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
819 Message
->Msg
.lParam
);
821 else if (Message
->HookMessage
== MSQ_ISEVENT
)
822 { // Direct Event Call processor
823 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
826 Message
->Msg
.lParam
);
828 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
830 Result
= IntLoadHookModule(Message
->Msg
.message
,
831 (HHOOK
)Message
->Msg
.lParam
,
832 Message
->Msg
.wParam
);
834 else if ((Message
->CompletionCallback
)
835 && (Message
->CallBackSenderQueue
== MessageQueue
))
836 { /* Call the callback routine */
837 if (Message
->QS_Flags
& QS_SMRESULT
)
839 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
841 Message
->Msg
.message
,
842 Message
->CompletionCallbackContext
,
844 /* Set callback to NULL to prevent reentry */
845 Message
->CompletionCallback
= NULL
;
849 /* The message has not been processed yet, reinsert it. */
850 RemoveEntryList(&Message
->ListEntry
);
851 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
852 TRACE("Callback Message not processed yet. Requeuing the message\n");
857 { /* Call the window procedure. */
858 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
859 Message
->Msg
.message
,
861 Message
->Msg
.lParam
);
864 /* remove the message from the local dispatching list, because it doesn't need
865 to be cleaned up on thread termination anymore */
866 RemoveEntryList(&Message
->ListEntry
);
868 /* If the message is a callback, insert it in the callback senders MessageQueue */
869 if (Message
->CompletionCallback
)
871 if (Message
->CallBackSenderQueue
)
873 Message
->lResult
= Result
;
874 Message
->QS_Flags
|= QS_SMRESULT
;
876 /* insert it in the callers message queue */
877 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
878 MsqWakeQueue(Message
->CallBackSenderQueue
, QS_SENDMESSAGE
, TRUE
);
879 IntDereferenceMessageQueue(Message
->CallBackSenderQueue
);
884 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
885 if (Message
->SenderQueue
)
887 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
889 /* only remove it from the dispatching list if not already removed by a timeout */
890 RemoveEntryList(&Message
->DispatchingListEntry
);
893 /* still keep the sender's message queue locked, so the sender can't exit the
894 MsqSendMessage() function (if timed out) */
896 if (Message
->QS_Flags
& QS_SMRESULT
)
898 Result
= Message
->lResult
;
901 /* Let the sender know the result. */
902 if (Message
->Result
!= NULL
)
904 *Message
->Result
= Result
;
907 if (Message
->HasPackedLParam
== TRUE
)
909 if (Message
->Msg
.lParam
)
910 ExFreePool((PVOID
)Message
->Msg
.lParam
);
913 /* Notify the sender. */
914 if (Message
->CompletionEvent
!= NULL
)
916 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
919 /* if the message has a sender */
920 if (Message
->SenderQueue
)
922 /* dereference our and the sender's message queue */
923 IntDereferenceMessageQueue(Message
->SenderQueue
);
924 IntDereferenceMessageQueue(MessageQueue
);
927 /* free the message */
928 ExFreePoolWithTag(Message
, TAG_USRMSG
);
930 /* do not hangup on the user if this is reentering */
931 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
932 pti
->pusmCurrent
= SaveMsg
;
938 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
940 PUSER_SENT_MESSAGE SentMessage
;
941 PUSER_MESSAGE PostedMessage
;
942 PUSER_MESSAGE_QUEUE MessageQueue
;
943 PLIST_ENTRY CurrentEntry
, ListHead
;
944 PWND Window
= pWindow
;
948 MessageQueue
= Window
->head
.pti
->MessageQueue
;
949 ASSERT(MessageQueue
);
951 /* remove the posted messages for this window */
952 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
953 ListHead
= &MessageQueue
->PostedMessagesListHead
;
954 while (CurrentEntry
!= ListHead
)
956 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
958 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
960 RemoveEntryList(&PostedMessage
->ListEntry
);
961 ClearMsgBitsMask(MessageQueue
, PostedMessage
->QS_Flags
);
962 MsqDestroyMessage(PostedMessage
);
963 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
967 CurrentEntry
= CurrentEntry
->Flink
;
971 /* remove the sent messages for this window */
972 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
973 ListHead
= &MessageQueue
->SentMessagesListHead
;
974 while (CurrentEntry
!= ListHead
)
976 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
978 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
980 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
982 RemoveEntryList(&SentMessage
->ListEntry
);
983 ClearMsgBitsMask(MessageQueue
, SentMessage
->QS_Flags
);
985 /* if it is a callback and this queue is not the sender queue, dereference queue */
986 if ((SentMessage
->CompletionCallback
) && (SentMessage
->CallBackSenderQueue
!= MessageQueue
))
988 IntDereferenceMessageQueue(SentMessage
->CallBackSenderQueue
);
990 /* Only if the message has a sender was the queue referenced */
991 if ((SentMessage
->SenderQueue
)
992 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
994 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
997 /* wake the sender's thread */
998 if (SentMessage
->CompletionEvent
!= NULL
)
1000 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1003 if (SentMessage
->HasPackedLParam
== TRUE
)
1005 if (SentMessage
->Msg
.lParam
)
1006 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
1009 /* if the message has a sender */
1010 if (SentMessage
->SenderQueue
)
1012 /* dereference our and the sender's message queue */
1013 IntDereferenceMessageQueue(MessageQueue
);
1014 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
1017 /* free the message */
1018 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
1020 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
1024 CurrentEntry
= CurrentEntry
->Flink
;
1030 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
1035 SENDASYNCPROC CompletionCallback
,
1036 ULONG_PTR CompletionCallbackContext
,
1037 BOOL HasPackedLParam
,
1041 PTHREADINFO ptiSender
;
1042 PUSER_SENT_MESSAGE Message
;
1044 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1046 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1050 ptiSender
= PsGetCurrentThreadWin32Thread();
1052 IntReferenceMessageQueue(ptiReceiver
->MessageQueue
);
1053 /* Take reference on this MessageQueue if its a callback. It will be released
1054 when message is processed or removed from target hwnd MessageQueue */
1055 if (CompletionCallback
)
1056 IntReferenceMessageQueue(ptiSender
->MessageQueue
);
1058 Message
->Msg
.hwnd
= hwnd
;
1059 Message
->Msg
.message
= Msg
;
1060 Message
->Msg
.wParam
= wParam
;
1061 Message
->Msg
.lParam
= lParam
;
1062 Message
->CompletionEvent
= NULL
;
1063 Message
->Result
= 0;
1064 Message
->lResult
= 0;
1065 Message
->SenderQueue
= NULL
;
1066 Message
->CallBackSenderQueue
= ptiSender
->MessageQueue
;
1067 Message
->DispatchingListEntry
.Flink
= NULL
;
1068 Message
->CompletionCallback
= CompletionCallback
;
1069 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
1070 Message
->HookMessage
= HookMessage
;
1071 Message
->HasPackedLParam
= HasPackedLParam
;
1072 Message
->QS_Flags
= QS_SENDMESSAGE
;
1074 InsertTailList(&ptiReceiver
->MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1075 MsqWakeQueue(ptiReceiver
->MessageQueue
, QS_SENDMESSAGE
, TRUE
);
1076 IntDereferenceMessageQueue(ptiReceiver
->MessageQueue
);
1082 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1083 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
1084 UINT uTimeout
, BOOL Block
, INT HookMessage
,
1087 PTHREADINFO pti
, ptirec
;
1088 PUSER_SENT_MESSAGE Message
;
1089 KEVENT CompletionEvent
;
1090 NTSTATUS WaitStatus
;
1091 PUSER_MESSAGE_QUEUE ThreadQueue
;
1092 LARGE_INTEGER Timeout
;
1094 LRESULT Result
= 0; //// Result could be trashed. ////
1096 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1098 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1099 return STATUS_INSUFFICIENT_RESOURCES
;
1102 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1104 pti
= PsGetCurrentThreadWin32Thread();
1105 ThreadQueue
= pti
->MessageQueue
;
1106 ptirec
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1107 ASSERT(ThreadQueue
!= MessageQueue
);
1108 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
1110 /* Don't send from or to a dying thread */
1111 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
1114 return STATUS_TIMEOUT
;
1117 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1119 /* FIXME - increase reference counter of sender's message queue here */
1121 Message
->Msg
.hwnd
= Wnd
;
1122 Message
->Msg
.message
= Msg
;
1123 Message
->Msg
.wParam
= wParam
;
1124 Message
->Msg
.lParam
= lParam
;
1125 Message
->CompletionEvent
= &CompletionEvent
;
1126 Message
->Result
= &Result
;
1127 Message
->lResult
= 0;
1128 Message
->QS_Flags
= 0;
1129 Message
->SenderQueue
= ThreadQueue
;
1130 Message
->CallBackSenderQueue
= NULL
;
1131 IntReferenceMessageQueue(ThreadQueue
);
1132 Message
->CompletionCallback
= NULL
;
1133 Message
->CompletionCallbackContext
= 0;
1134 Message
->HookMessage
= HookMessage
;
1135 Message
->HasPackedLParam
= FALSE
;
1137 IntReferenceMessageQueue(MessageQueue
);
1139 /* add it to the list of pending messages */
1140 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1142 /* queue it in the destination's message queue */
1143 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1145 Message
->QS_Flags
= QS_SENDMESSAGE
;
1146 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
, TRUE
);
1148 /* we can't access the Message anymore since it could have already been deleted! */
1154 /* don't process messages sent to the thread */
1155 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1156 FALSE
, (uTimeout
? &Timeout
: NULL
));
1160 if(WaitStatus
== STATUS_TIMEOUT
)
1162 /* look up if the message has not yet dispatched, if so
1163 make sure it can't pass a result and it must not set the completion event anymore */
1164 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1165 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1167 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1170 /* we can access Message here, it's secure because the message queue is locked
1171 and the message is still hasn't been dispatched */
1172 Message
->CompletionEvent
= NULL
;
1173 Message
->Result
= NULL
;
1176 Entry
= Entry
->Flink
;
1179 /* remove from the local dispatching list so the other thread knows,
1180 it can't pass a result and it must not set the completion event anymore */
1181 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1182 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1184 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1187 /* we can access Message here, it's secure because the sender's message is locked
1188 and the message has definitely not yet been destroyed, otherwise it would
1189 have been removed from this list by the dispatching routine right after
1190 dispatching the message */
1191 Message
->CompletionEvent
= NULL
;
1192 Message
->Result
= NULL
;
1193 RemoveEntryList(&Message
->DispatchingListEntry
);
1194 Message
->DispatchingListEntry
.Flink
= NULL
;
1197 Entry
= Entry
->Flink
;
1200 TRACE("MsqSendMessage (blocked) timed out 1\n");
1202 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1207 PVOID WaitObjects
[2];
1209 WaitObjects
[0] = &CompletionEvent
;
1210 WaitObjects
[1] = ThreadQueue
->NewMessages
;
1215 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1216 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1220 if(WaitStatus
== STATUS_TIMEOUT
)
1222 /* look up if the message has not yet been dispatched, if so
1223 make sure it can't pass a result and it must not set the completion event anymore */
1224 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1225 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1227 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1230 /* we can access Message here, it's secure because the message queue is locked
1231 and the message is still hasn't been dispatched */
1232 Message
->CompletionEvent
= NULL
;
1233 Message
->Result
= NULL
;
1236 Entry
= Entry
->Flink
;
1239 /* remove from the local dispatching list so the other thread knows,
1240 it can't pass a result and it must not set the completion event anymore */
1241 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1242 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1244 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1247 /* we can access Message here, it's secure because the sender's message is locked
1248 and the message has definitely not yet been destroyed, otherwise it would
1249 have been removed from this list by the dispatching routine right after
1250 dispatching the message */
1251 Message
->CompletionEvent
= NULL
;
1252 Message
->Result
= NULL
;
1253 RemoveEntryList(&Message
->DispatchingListEntry
);
1254 Message
->DispatchingListEntry
.Flink
= NULL
;
1257 Entry
= Entry
->Flink
;
1260 TRACE("MsqSendMessage timed out 2\n");
1263 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1266 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
1269 if(WaitStatus
!= STATUS_TIMEOUT
)
1270 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1276 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
1279 PUSER_MESSAGE Message
;
1281 if(!(Message
= MsqCreateMessage(Msg
)))
1286 if(!HardwareMessage
)
1288 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1289 &Message
->ListEntry
);
1293 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1294 &Message
->ListEntry
);
1296 update_input_key_state( MessageQueue
, Msg
);
1299 Message
->QS_Flags
= MessageBits
;
1300 MsqWakeQueue(MessageQueue
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
1304 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1306 MessageQueue
->QuitPosted
= TRUE
;
1307 MessageQueue
->QuitExitCode
= ExitCode
;
1308 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1311 /***********************************************************************
1312 * MsqSendParentNotify
1314 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1315 * the window has the WS_EX_NOPARENTNOTIFY style.
1317 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1319 PWND pwndDesktop
= UserGetWindowObject(IntGetDesktopWindow());
1321 /* pt has to be in the client coordinates of the parent window */
1322 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1323 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1329 if (!(pwnd
->style
& WS_CHILD
)) break;
1330 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1331 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1332 if (pwndParent
== pwndDesktop
) break;
1333 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1334 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1337 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1338 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1342 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1349 MOUSEHOOKSTRUCT hook
;
1352 PWND pwndMsg
, pwndDesktop
;
1353 PUSER_MESSAGE_QUEUE MessageQueue
;
1355 PSYSTEM_CURSORINFO CurInfo
;
1357 DECLARE_RETURN(BOOL
);
1359 pti
= PsGetCurrentThreadWin32Thread();
1360 pwndDesktop
= UserGetDesktopWindow();
1361 MessageQueue
= pti
->MessageQueue
;
1362 CurInfo
= IntGetSysCursorInfo();
1363 pwndMsg
= UserGetWindowObject(msg
->hwnd
);
1364 clk_msg
= MessageQueue
->msgDblClk
;
1365 pDesk
= pwndDesktop
->head
.rpdesk
;
1367 /* find the window to dispatch this mouse message to */
1368 if (MessageQueue
->CaptureWindow
)
1371 pwndMsg
= IntGetWindowObject(MessageQueue
->CaptureWindow
);
1375 pwndMsg
= co_WinPosWindowFromPoint(pwndMsg
, &msg
->pt
, &hittest
);
1378 TRACE("Got mouse message for 0x%x, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1380 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
1382 /* Remove and ignore the message */
1383 *RemoveMessages
= TRUE
;
1387 /* If we a re tracking the mouse and it moves to another window */
1388 if(pDesk
->spwndTrack
&&
1389 pDesk
->spwndTrack
!= pwndMsg
&&
1390 msg
->message
!= WM_MOUSELEAVE
)
1392 /* Generate a WM_MOUSELEAVE message */
1393 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1397 TRACE("co_IntProcessMouseMessage: generating WM_MOUSELEAVE\n");
1399 msgMouseLeave
.hwnd
= UserHMGetHandle(pDesk
->spwndTrack
);
1400 msgMouseLeave
.message
= WM_MOUSELEAVE
;
1401 msgMouseLeave
.pt
= msg
->pt
;
1402 msgMouseLeave
.time
= msg
->time
;
1403 msgMouseLeave
.lParam
= msgMouseLeave
.wParam
= 0;
1405 MsqPostMessage(pwndMsg
->head
.pti
->MessageQueue
,
1412 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1414 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1417 pDesk
->spwndTrack
= NULL
;
1421 if(pDesk
->spwndTrack
)
1423 pDesk
->htEx
= hittest
;
1426 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1429 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
1433 message
= msg
->message
;
1434 /* Note: windows has no concept of a non-client wheel message */
1435 if (message
!= WM_MOUSEWHEEL
)
1437 if (hittest
!= HTCLIENT
)
1439 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1440 msg
->wParam
= hittest
;
1444 /* coordinates don't get translated while tracking a menu */
1445 /* FIXME: should differentiate popups and top-level menus */
1446 if (!(MessageQueue
->MenuOwner
))
1448 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1449 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1453 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1455 /* translate double clicks */
1457 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1458 (msg
->message
== WM_RBUTTONDOWN
) ||
1459 (msg
->message
== WM_MBUTTONDOWN
) ||
1460 (msg
->message
== WM_XBUTTONDOWN
))
1462 BOOL update
= *RemoveMessages
;
1464 /* translate double clicks -
1465 * note that ...MOUSEMOVEs can slip in between
1466 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1468 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1469 hittest
!= HTCLIENT
||
1470 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1472 if ((msg
->message
== clk_msg
.message
) &&
1473 (msg
->hwnd
== clk_msg
.hwnd
) &&
1474 (msg
->wParam
== clk_msg
.wParam
) &&
1475 (msg
->time
- clk_msg
.time
< gspv
.iDblClickTime
) &&
1476 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1477 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1479 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1482 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1488 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1490 TRACE("Message out of range!!!\n");
1494 /* update static double click conditions */
1495 if (update
) MessageQueue
->msgDblClk
= *msg
;
1499 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1501 TRACE("Message out of range!!!\n");
1506 if(gspv
.bMouseClickLock
)
1508 BOOL IsClkLck
= FALSE
;
1510 if(msg
->message
== WM_LBUTTONUP
)
1512 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1513 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1515 CurInfo
->ClickLockActive
= TRUE
;
1518 else if (msg
->message
== WM_LBUTTONDOWN
)
1520 if (CurInfo
->ClickLockActive
)
1523 CurInfo
->ClickLockActive
= FALSE
;
1526 CurInfo
->ClickLockTime
= msg
->time
;
1531 /* Remove and ignore the message */
1532 *RemoveMessages
= TRUE
;
1537 /* message is accepted now (but may still get dropped) */
1539 event
.message
= msg
->message
;
1540 event
.time
= msg
->time
;
1541 event
.hwnd
= msg
->hwnd
;
1542 event
.paramL
= msg
->pt
.x
;
1543 event
.paramH
= msg
->pt
.y
;
1544 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1547 hook
.hwnd
= msg
->hwnd
;
1548 hook
.wHitTestCode
= hittest
;
1549 hook
.dwExtraInfo
= 0/*extra_info*/;
1550 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1551 message
, (LPARAM
)&hook
))
1554 hook
.hwnd
= msg
->hwnd
;
1555 hook
.wHitTestCode
= hittest
;
1556 hook
.dwExtraInfo
= 0/*extra_info*/;
1557 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1559 ERR("WH_MOUSE dorpped mouse message!\n");
1561 /* Remove and skip message */
1562 *RemoveMessages
= TRUE
;
1566 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1568 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1569 MAKELONG( hittest
, msg
->message
));
1571 /* Remove and skip message */
1572 *RemoveMessages
= TRUE
;
1576 if ((*RemoveMessages
== FALSE
) || MessageQueue
->CaptureWindow
)
1578 /* Accept the message */
1579 msg
->message
= message
;
1585 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1586 (msg
->message
== WM_RBUTTONDOWN
) ||
1587 (msg
->message
== WM_MBUTTONDOWN
) ||
1588 (msg
->message
== WM_XBUTTONDOWN
))
1590 /* Send the WM_PARENTNOTIFY,
1591 * note that even for double/nonclient clicks
1592 * notification message is still WM_L/M/RBUTTONDOWN.
1594 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1596 /* Activate the window if needed */
1598 if (msg
->hwnd
!= UserGetForegroundWindow())
1600 PWND pwndTop
= pwndMsg
;
1603 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
1604 pwndTop
= IntGetParent( pwndTop
);
1607 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1609 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1611 (WPARAM
)UserHMGetHandle(pwndTop
),
1612 MAKELONG( hittest
, msg
->message
));
1615 case MA_NOACTIVATEANDEAT
:
1620 case MA_ACTIVATEANDEAT
:
1625 if(!co_IntMouseActivateWindow(pwndMsg
)) eatMsg
= TRUE
;
1628 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1635 /* send the WM_SETCURSOR message */
1637 /* Windows sends the normal mouse message as the message parameter
1638 in the WM_SETCURSOR message even if it's non-client mouse message */
1639 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1641 msg
->message
= message
;
1646 UserDereferenceObject(pwndMsg
);
1651 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1655 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1656 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1658 switch (Msg
->wParam
)
1660 case VK_LSHIFT
: case VK_RSHIFT
:
1661 Msg
->wParam
= VK_SHIFT
;
1663 case VK_LCONTROL
: case VK_RCONTROL
:
1664 Msg
->wParam
= VK_CONTROL
;
1666 case VK_LMENU
: case VK_RMENU
:
1667 Msg
->wParam
= VK_MENU
;
1672 Event
.message
= Msg
->message
;
1673 Event
.hwnd
= Msg
->hwnd
;
1674 Event
.time
= Msg
->time
;
1675 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1676 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1677 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1678 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1680 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1681 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1682 LOWORD(Msg
->wParam
),
1685 /* skip this message */
1686 co_HOOK_CallHooks( WH_CBT
,
1688 LOWORD(Msg
->wParam
),
1690 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1696 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1698 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1700 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1702 else if ( IS_KBD_MESSAGE(Msg
->message
))
1704 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1711 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1714 IN UINT MsgFilterLow
,
1715 IN UINT MsgFilterHigh
,
1721 if(!(MessageQueue
->MouseMoved
))
1724 msg
= MessageQueue
->MouseMoveMsg
;
1726 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1733 ClearMsgBitsMask(MessageQueue
, QS_MOUSEMOVE
);
1734 MessageQueue
->MouseMoved
= FALSE
;
1737 return AcceptMessage
;
1740 /* check whether a message filter contains at least one potential hardware message */
1742 filter_contains_hw_range( UINT first
, UINT last
)
1744 /* hardware message ranges are (in numerical order):
1745 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1746 * WM_KEYFIRST .. WM_KEYLAST
1747 * WM_MOUSEFIRST .. WM_MOUSELAST
1750 if (last
< WM_NCMOUSEFIRST
) return 0;
1751 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1752 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1753 if (first
> WM_MOUSELAST
) return 0;
1758 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1761 IN UINT MsgFilterLow
,
1762 IN UINT MsgFilterHigh
,
1768 PUSER_MESSAGE CurrentMessage
;
1769 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1772 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1774 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1775 CurrentEntry
= ListHead
->Flink
;
1777 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1779 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1783 if (IsListEmpty(CurrentEntry
)) break;
1784 if (!CurrentMessage
) break;
1785 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1788 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1789 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1790 3: handle to the window whose messages are to be retrieved.
1792 if ( ( !Window
|| // 1
1793 ( Window
== HWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1794 ( Window
!= HWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1795 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1796 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1798 msg
= CurrentMessage
->Msg
;
1800 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1804 update_input_key_state(MessageQueue
, &msg
);
1805 RemoveEntryList(&CurrentMessage
->ListEntry
);
1806 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1807 MsqDestroyMessage(CurrentMessage
);
1816 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1819 while(CurrentEntry
!= ListHead
);
1825 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1828 IN UINT MsgFilterLow
,
1829 IN UINT MsgFilterHigh
,
1833 PLIST_ENTRY CurrentEntry
;
1834 PUSER_MESSAGE CurrentMessage
;
1835 PLIST_ENTRY ListHead
;
1837 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1838 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1840 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1842 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1846 if (IsListEmpty(CurrentEntry
)) break;
1847 if (!CurrentMessage
) break;
1848 CurrentEntry
= CurrentEntry
->Flink
;
1851 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1852 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1853 3: handle to the window whose messages are to be retrieved.
1855 if ( ( !Window
|| // 1
1856 ( Window
== HWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1857 ( Window
!= HWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1858 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1859 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1861 *Message
= CurrentMessage
->Msg
;
1865 RemoveEntryList(&CurrentMessage
->ListEntry
);
1866 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1867 MsqDestroyMessage(CurrentMessage
);
1871 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1874 while (CurrentEntry
!= ListHead
);
1880 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1881 UINT MsgFilterMin
, UINT MsgFilterMax
)
1885 ret
= KeWaitForSingleObject( MessageQueue
->NewMessages
,
1895 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1897 LARGE_INTEGER LargeTickCount
;
1899 KeQueryTickCount(&LargeTickCount
);
1900 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1905 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1908 TRACE("HungAppSysTimerProc\n");
1909 // Process list of windows that are hung and waiting.
1913 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1915 LARGE_INTEGER LargeTickCount
;
1918 MessageQueue
->Thread
= Thread
;
1919 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1920 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1921 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1922 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1923 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1924 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1925 MessageQueue
->QuitPosted
= FALSE
;
1926 MessageQueue
->QuitExitCode
= 0;
1927 KeQueryTickCount(&LargeTickCount
);
1928 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1929 MessageQueue
->FocusWindow
= NULL
;
1930 MessageQueue
->NewMessagesHandle
= NULL
;
1931 MessageQueue
->ShowingCursor
= 0;
1932 MessageQueue
->CursorObject
= NULL
;
1933 RtlCopyMemory(MessageQueue
->KeyState
, gKeyStateTable
, sizeof(gKeyStateTable
));
1935 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1936 NULL
, SynchronizationEvent
, FALSE
);
1937 if (!NT_SUCCESS(Status
))
1942 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1943 ExEventObjectType
, KernelMode
,
1944 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1945 if (!NT_SUCCESS(Status
))
1947 ZwClose(MessageQueue
->NewMessagesHandle
);
1948 MessageQueue
->NewMessagesHandle
= NULL
;
1956 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1958 PLIST_ENTRY CurrentEntry
;
1959 PUSER_MESSAGE CurrentMessage
;
1960 PUSER_SENT_MESSAGE CurrentSentMessage
;
1963 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1966 /* cleanup posted messages */
1967 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1969 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1970 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1972 MsqDestroyMessage(CurrentMessage
);
1975 /* remove the messages that have not yet been dispatched */
1976 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1978 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1979 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1982 /* if it is a callback and this queue is not the sender queue, dereference queue */
1983 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
1985 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
1988 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
1989 /* Only if the message has a sender was the message in the DispatchingList */
1990 if ((CurrentSentMessage
->SenderQueue
)
1991 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1993 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1996 /* wake the sender's thread */
1997 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1999 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2002 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
2004 if (CurrentSentMessage
->Msg
.lParam
)
2005 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2008 /* if the message has a sender */
2009 if (CurrentSentMessage
->SenderQueue
)
2011 /* dereference our and the sender's message queue */
2012 IntDereferenceMessageQueue(MessageQueue
);
2013 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
2016 /* free the message */
2017 ExFreePool(CurrentSentMessage
);
2020 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
2021 ExitThread() was called in a SendMessage() umode callback */
2022 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
2024 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
2025 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2028 /* if it is a callback and this queue is not the sender queue, dereference queue */
2029 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
2031 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
2034 /* remove the message from the dispatching list */
2035 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
2037 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
2040 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
2042 /* wake the sender's thread */
2043 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
2045 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2048 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
2050 if (CurrentSentMessage
->Msg
.lParam
)
2051 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2054 /* if the message has a sender */
2055 if (CurrentSentMessage
->SenderQueue
)
2057 /* dereference our and the sender's message queue */
2058 IntDereferenceMessageQueue(MessageQueue
);
2059 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
2062 /* free the message */
2063 ExFreePool(CurrentSentMessage
);
2066 /* tell other threads not to bother returning any info to us */
2067 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
2069 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
2070 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2071 DispatchingListEntry
);
2072 CurrentSentMessage
->CompletionEvent
= NULL
;
2073 CurrentSentMessage
->Result
= NULL
;
2075 /* do NOT dereference our message queue as it might get attempted to be
2079 // Clear it all out.
2082 pti
->pcti
->fsWakeBits
= 0;
2083 pti
->pcti
->fsChangeBits
= 0;
2086 MessageQueue
->nCntsQBits
[QSRosKey
] = 0;
2087 MessageQueue
->nCntsQBits
[QSRosMouseMove
] = 0;
2088 MessageQueue
->nCntsQBits
[QSRosMouseButton
] = 0;
2089 MessageQueue
->nCntsQBits
[QSRosPostMessage
] = 0;
2090 MessageQueue
->nCntsQBits
[QSRosSendMessage
] = 0;
2091 MessageQueue
->nCntsQBits
[QSRosHotKey
] = 0;
2093 if (MessageQueue
->CursorObject
)
2095 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2097 /* Change to another cursor if we going to dereference current one
2098 Note: we can't use UserSetCursor because it uses current thread
2099 message queue instead of queue given for cleanup */
2100 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2104 /* Get the screen DC */
2105 hdcScreen
= IntGetScreenDC();
2107 GreMovePointer(hdcScreen
, -1, -1);
2108 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2111 UserDereferenceObject(pCursor
);
2116 PUSER_MESSAGE_QUEUE FASTCALL
2117 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
2119 PUSER_MESSAGE_QUEUE MessageQueue
;
2121 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2122 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2130 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2131 /* hold at least one reference until it'll be destroyed */
2132 IntReferenceMessageQueue(MessageQueue
);
2133 /* initialize the queue */
2134 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
2136 IntDereferenceMessageQueue(MessageQueue
);
2140 return MessageQueue
;
2144 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
2148 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2150 /* remove the message queue from any desktops */
2151 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2153 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2154 IntDereferenceMessageQueue(MessageQueue
);
2158 MsqCleanupMessageQueue(MessageQueue
);
2160 if (MessageQueue
->NewMessagesHandle
!= NULL
)
2161 ZwClose(MessageQueue
->NewMessagesHandle
);
2162 MessageQueue
->NewMessagesHandle
= NULL
;
2163 /* decrease the reference counter, if it hits zero, the queue will be freed */
2164 IntDereferenceMessageQueue(MessageQueue
);
2168 MsqSetMessageExtraInfo(LPARAM lParam
)
2172 PUSER_MESSAGE_QUEUE MessageQueue
;
2174 pti
= PsGetCurrentThreadWin32Thread();
2175 MessageQueue
= pti
->MessageQueue
;
2181 Ret
= MessageQueue
->ExtraInfo
;
2182 MessageQueue
->ExtraInfo
= lParam
;
2188 MsqGetMessageExtraInfo(VOID
)
2191 PUSER_MESSAGE_QUEUE MessageQueue
;
2193 pti
= PsGetCurrentThreadWin32Thread();
2194 MessageQueue
= pti
->MessageQueue
;
2200 return MessageQueue
->ExtraInfo
;
2203 // ReplyMessage is called by the thread receiving the window message.
2205 co_MsqReplyMessage( LRESULT lResult
)
2207 PUSER_SENT_MESSAGE Message
;
2210 pti
= PsGetCurrentThreadWin32Thread();
2211 Message
= pti
->pusmCurrent
;
2213 if (!Message
) return FALSE
;
2215 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2217 // SendMessageXxx || Callback msg and not a notify msg
2218 if (Message
->SenderQueue
|| Message
->CompletionCallback
)
2220 Message
->lResult
= lResult
;
2221 Message
->QS_Flags
|= QS_SMRESULT
;
2222 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2228 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
2234 case MSQ_STATE_CAPTURE
:
2235 Prev
= MessageQueue
->CaptureWindow
;
2236 MessageQueue
->CaptureWindow
= hWnd
;
2238 case MSQ_STATE_ACTIVE
:
2239 Prev
= MessageQueue
->ActiveWindow
;
2240 MessageQueue
->ActiveWindow
= hWnd
;
2242 case MSQ_STATE_FOCUS
:
2243 Prev
= MessageQueue
->FocusWindow
;
2244 MessageQueue
->FocusWindow
= hWnd
;
2246 case MSQ_STATE_MENUOWNER
:
2247 Prev
= MessageQueue
->MenuOwner
;
2248 MessageQueue
->MenuOwner
= hWnd
;
2250 case MSQ_STATE_MOVESIZE
:
2251 Prev
= MessageQueue
->MoveSize
;
2252 MessageQueue
->MoveSize
= hWnd
;
2254 case MSQ_STATE_CARET
:
2255 ASSERT(MessageQueue
->CaretInfo
);
2256 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2257 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2266 NtUserGetKeyState(INT key
)
2270 UserEnterExclusive();
2272 Ret
= UserGetKeyState(key
);
2282 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2286 PUSER_MESSAGE_QUEUE MessageQueue
;
2290 pti
= PsGetCurrentThreadWin32Thread();
2291 MessageQueue
= pti
->MessageQueue
;
2295 ProbeForWrite(lpKeyState
,sizeof(MessageQueue
->KeyState
) ,1);
2296 RtlCopyMemory(lpKeyState
,MessageQueue
->KeyState
,sizeof(MessageQueue
->KeyState
));
2298 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2300 SetLastNtError(_SEH2_GetExceptionCode());
2312 NtUserSetKeyboardState(LPBYTE lpKeyState
)
2316 PUSER_MESSAGE_QUEUE MessageQueue
;
2318 UserEnterExclusive();
2320 pti
= PsGetCurrentThreadWin32Thread();
2321 MessageQueue
= pti
->MessageQueue
;
2325 ProbeForRead(lpKeyState
,sizeof(MessageQueue
->KeyState
) ,1);
2326 RtlCopyMemory(MessageQueue
->KeyState
,lpKeyState
,sizeof(MessageQueue
->KeyState
));
2328 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2330 SetLastNtError(_SEH2_GetExceptionCode());