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
|= 0xFF00; // If down, windows returns 0xFF80.
232 EngSetLastError(ERROR_INVALID_PARAMETER
);
237 /* change the input key state for a given key */
238 static void set_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue
, UCHAR key
, BOOL down
)
240 TRACE("set_input_key_state key:%d, down:%d\n", key
, down
);
244 if (!(MessageQueue
->KeyState
[key
] & KS_DOWN_BIT
))
246 MessageQueue
->KeyState
[key
] ^= KS_LOCK_BIT
;
248 MessageQueue
->KeyState
[key
] |= KS_DOWN_BIT
;
252 MessageQueue
->KeyState
[key
] &= ~KS_DOWN_BIT
;
256 /* update the input key state for a keyboard message */
257 static void update_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
262 TRACE("update_input_key_state message:%d\n", msg
->message
);
264 switch (msg
->message
)
270 set_input_key_state( MessageQueue
, VK_LBUTTON
, down
);
276 set_input_key_state( MessageQueue
, VK_MBUTTON
, down
);
282 set_input_key_state( MessageQueue
, VK_RBUTTON
, down
);
288 if (msg
->wParam
== XBUTTON1
)
289 set_input_key_state( MessageQueue
, VK_XBUTTON1
, down
);
290 else if (msg
->wParam
== XBUTTON2
)
291 set_input_key_state( MessageQueue
, VK_XBUTTON2
, down
);
299 key
= (UCHAR
)msg
->wParam
;
300 set_input_key_state( MessageQueue
, key
, down
);
305 down
= (MessageQueue
->KeyState
[VK_LCONTROL
] | MessageQueue
->KeyState
[VK_RCONTROL
]) & KS_DOWN_BIT
;
306 set_input_key_state( MessageQueue
, VK_CONTROL
, down
);
310 down
= (MessageQueue
->KeyState
[VK_LMENU
] | MessageQueue
->KeyState
[VK_RMENU
]) & KS_DOWN_BIT
;
311 set_input_key_state( MessageQueue
, VK_MENU
, down
);
315 down
= (MessageQueue
->KeyState
[VK_LSHIFT
] | MessageQueue
->KeyState
[VK_RSHIFT
]) & KS_DOWN_BIT
;
316 set_input_key_state( MessageQueue
, VK_SHIFT
, down
);
324 IntMsqSetWakeMask(DWORD WakeMask
)
326 PTHREADINFO Win32Thread
;
327 PUSER_MESSAGE_QUEUE MessageQueue
;
328 HANDLE MessageEventHandle
;
329 DWORD dwFlags
= HIWORD(WakeMask
);
331 Win32Thread
= PsGetCurrentThreadWin32Thread();
332 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
335 MessageQueue
= Win32Thread
->MessageQueue
;
336 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
337 MessageEventHandle
= MessageQueue
->NewMessagesHandle
;
339 if (Win32Thread
->pcti
)
341 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
342 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
344 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
345 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
346 return MessageEventHandle
;
352 return MessageEventHandle
;
356 IntMsqClearWakeMask(VOID
)
358 PTHREADINFO Win32Thread
;
360 Win32Thread
= PsGetCurrentThreadWin32Thread();
361 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
363 // Very hacky, but that is what they do.
364 Win32Thread
->pcti
->fsWakeBits
= 0;
372 Due to the uncertainty of knowing what was set in our multilevel message queue,
373 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
374 I think this is the best solution... (jt) */
376 MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue
, DWORD MessageBits
, BOOL KeyEvent
)
380 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
381 pti
->pcti
->fsWakeBits
|= MessageBits
;
382 pti
->pcti
->fsChangeBits
|= MessageBits
;
384 // Start bit accounting to help clear the main set of bits.
385 if (MessageBits
& QS_KEY
) Queue
->nCntsQBits
[QSRosKey
]++;
386 if (MessageBits
& QS_MOUSEMOVE
) Queue
->nCntsQBits
[QSRosMouseMove
]++;
387 if (MessageBits
& QS_MOUSEBUTTON
) Queue
->nCntsQBits
[QSRosMouseButton
]++;
388 if (MessageBits
& QS_POSTMESSAGE
) Queue
->nCntsQBits
[QSRosPostMessage
]++;
389 if (MessageBits
& QS_SENDMESSAGE
) Queue
->nCntsQBits
[QSRosSendMessage
]++;
390 if (MessageBits
& QS_HOTKEY
) Queue
->nCntsQBits
[QSRosHotKey
]++;
393 KeSetEvent(Queue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
397 ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue
, UINT MessageBits
)
402 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
404 if (MessageBits
& QS_KEY
)
406 if (--Queue
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
408 if (MessageBits
& QS_MOUSEMOVE
) // ReactOS hard coded.
409 { // Account for tracking mouse moves..
410 if (--Queue
->nCntsQBits
[QSRosMouseMove
] == 0) ClrMask
|= QS_MOUSEMOVE
;
411 // Handle mouse move bits here.
412 if (Queue
->MouseMoved
) ClrMask
|= QS_MOUSEMOVE
;
414 if (MessageBits
& QS_MOUSEBUTTON
)
416 if (--Queue
->nCntsQBits
[QSRosMouseButton
] == 0) ClrMask
|= QS_MOUSEBUTTON
;
418 if (MessageBits
& QS_POSTMESSAGE
)
420 if (--Queue
->nCntsQBits
[QSRosPostMessage
] == 0) ClrMask
|= QS_POSTMESSAGE
;
422 if (MessageBits
& QS_TIMER
) // ReactOS hard coded.
423 { // Handle timer bits here.
424 if ( pti
->cTimersReady
)
426 if (--pti
->cTimersReady
== 0) ClrMask
|= QS_TIMER
;
429 if (MessageBits
& QS_PAINT
) // ReactOS hard coded.
430 { // Handle paint bits here.
431 if ( pti
->cPaintsReady
)
433 if (--pti
->cPaintsReady
== 0) ClrMask
|= QS_PAINT
;
436 if (MessageBits
& QS_SENDMESSAGE
)
438 if (--Queue
->nCntsQBits
[QSRosSendMessage
] == 0) ClrMask
|= QS_SENDMESSAGE
;
440 if (MessageBits
& QS_HOTKEY
)
442 if (--Queue
->nCntsQBits
[QSRosHotKey
] == 0) ClrMask
|= QS_HOTKEY
;
445 pti
->pcti
->fsWakeBits
&= ~ClrMask
;
446 pti
->pcti
->fsChangeBits
&= ~ClrMask
;
450 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
453 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
455 MsqWakeQueue(Queue
, QS_PAINT
, TRUE
);
459 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
461 ClearMsgBitsMask(Queue
, QS_PAINT
);
465 MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
)
467 MessageQueue
->MouseMoveMsg
= *Msg
;
468 MessageQueue
->MouseMoved
= TRUE
;
469 MsqWakeQueue(MessageQueue
, QS_MOUSEMOVE
, TRUE
);
473 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
475 LARGE_INTEGER LargeTickCount
;
476 MSLLHOOKSTRUCT MouseHookData
;
478 PWND pwnd
, pwndDesktop
;
480 PSYSTEM_CURSORINFO CurInfo
;
482 KeQueryTickCount(&LargeTickCount
);
483 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
485 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
486 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
487 switch (Msg
->message
)
490 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
494 case WM_XBUTTONDBLCLK
:
495 case WM_NCXBUTTONDOWN
:
497 case WM_NCXBUTTONDBLCLK
:
498 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
501 MouseHookData
.mouseData
= 0;
505 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
506 MouseHookData
.time
= Msg
->time
;
507 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
509 /* If the hook procedure returned non zero, dont send the message */
512 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
516 /* Get the desktop window */
517 pwndDesktop
= UserGetDesktopWindow();
518 if (!pwndDesktop
) return;
519 pDesk
= pwndDesktop
->head
.rpdesk
;
521 /* Check if the mouse is captured */
522 Msg
->hwnd
= IntGetCaptureWindow();
523 if (Msg
->hwnd
!= NULL
)
525 pwnd
= UserGetWindowObject(Msg
->hwnd
);
529 pwnd
= IntTopLevelWindowFromPoint(Msg
->pt
.x
, Msg
->pt
.y
);
530 if (pwnd
) Msg
->hwnd
= pwnd
->head
.h
;
535 /* If we a re tracking the mouse and it moves to another top level window */
536 if(pDesk
->spwndTrack
&&
537 UserGetAncestor(pDesk
->spwndTrack
, GA_ROOT
) != pwnd
)
539 /* Generate a WM_MOUSELEAVE message */
540 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
544 TRACE("co_MsqInsertMouseMessage: generating WM_MOUSELEAVE\n");
546 msgMouseLeave
.hwnd
= UserHMGetHandle(pDesk
->spwndTrack
);
547 msgMouseLeave
.message
= WM_MOUSELEAVE
;
548 msgMouseLeave
.pt
= Msg
->pt
;
549 msgMouseLeave
.time
= Msg
->time
;
550 msgMouseLeave
.lParam
= msgMouseLeave
.wParam
= 0;
552 MsqPostMessage(pwnd
->head
.pti
->MessageQueue
, Msg
, TRUE
, QS_MOUSE
);
556 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
558 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
561 pDesk
->spwndTrack
= NULL
;
566 hdcScreen
= IntGetScreenDC();
567 CurInfo
= IntGetSysCursorInfo();
569 /* Check if we found a window */
570 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
572 if (Msg
->message
== WM_MOUSEMOVE
)
574 PUSER_MESSAGE_QUEUE MessageQueue
= pwnd
->head
.pti
->MessageQueue
;
576 /* Check if cursor should be visible */
578 MessageQueue
->CursorObject
&&
579 MessageQueue
->ShowingCursor
>= 0)
581 /* Check if shape has changed */
582 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
584 /* Call GDI to set the new screen cursor */
585 GreSetPointerShape(hdcScreen
,
586 MessageQueue
->CursorObject
->IconInfo
.hbmMask
,
587 MessageQueue
->CursorObject
->IconInfo
.hbmColor
,
588 MessageQueue
->CursorObject
->IconInfo
.xHotspot
,
589 MessageQueue
->CursorObject
->IconInfo
.yHotspot
,
593 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
595 /* Check if w have to hide cursor */
596 else if (CurInfo
->ShowingCursor
>= 0)
597 GreMovePointer(hdcScreen
, -1, -1);
599 /* Update global cursor info */
600 CurInfo
->ShowingCursor
= MessageQueue
->ShowingCursor
;
601 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
603 /* Mouse move is a special case */
604 MsqPostMouseMove(MessageQueue
, Msg
);
608 TRACE("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd
));
609 MsqPostMessage(pwnd
->head
.pti
->MessageQueue
, Msg
, TRUE
, QS_MOUSEBUTTON
);
614 /* always show cursor on background; FIXME: set default pointer */
615 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
616 CurInfo
->ShowingCursor
= 0;
619 /* Do GetMouseMovePointsEx FIFO. */
620 MouseHistoryOfMoves
[gcur_count
].x
= Msg
->pt
.x
;
621 MouseHistoryOfMoves
[gcur_count
].y
= Msg
->pt
.y
;
622 MouseHistoryOfMoves
[gcur_count
].time
= Msg
->time
;
623 MouseHistoryOfMoves
[gcur_count
].dwExtraInfo
= dwExtraInfo
;
624 if (++gcur_count
== ARRAYSIZE(MouseHistoryOfMoves
))
625 gcur_count
= 0; // 0 - 63 is 64, FIFO forwards.
629 // Note: Only called from input.c.
632 co_MsqPostKeyboardMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
634 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
636 LARGE_INTEGER LargeTickCount
;
637 KBDLLHOOKSTRUCT KbdHookData
;
639 TRACE("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
640 uMsg
, wParam
, lParam
);
642 // Condition may arise when calling MsqPostMessage and waiting for an event.
643 ASSERT(UserIsEntered());
645 FocusMessageQueue
= IntGetFocusMessageQueue();
649 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
650 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
656 KeQueryTickCount(&LargeTickCount
);
657 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
659 /* We can't get the Msg.pt point here since we don't know thread
660 (and thus the window station) the message will end up in yet. */
662 KbdHookData
.vkCode
= Msg
.wParam
;
663 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
664 KbdHookData
.flags
= (0 == (Msg
.lParam
& 0x01000000) ? 0 : LLKHF_EXTENDED
) |
665 (0 == (Msg
.lParam
& 0x20000000) ? 0 : LLKHF_ALTDOWN
) |
666 (0 == (Msg
.lParam
& 0x80000000) ? 0 : LLKHF_UP
);
667 KbdHookData
.time
= Msg
.time
;
668 KbdHookData
.dwExtraInfo
= 0;
669 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
671 ERR("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
672 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
676 if (FocusMessageQueue
== NULL
)
678 TRACE("No focus message queue\n");
682 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
684 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
685 TRACE("Msg.hwnd = %x\n", Msg
.hwnd
);
687 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
689 Msg
.pt
= gpsi
->ptCursor
;
690 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
694 TRACE("Invalid focus window handle\n");
701 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
704 PTHREADINFO Win32Thread
;
706 LARGE_INTEGER LargeTickCount
;
711 Status
= ObReferenceObjectByPointer (Thread
,
715 if (!NT_SUCCESS(Status
))
718 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
719 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
721 ObDereferenceObject ((PETHREAD
)Thread
);
725 Window
= IntGetWindowObject(hWnd
);
728 ObDereferenceObject ((PETHREAD
)Thread
);
732 id
= wParam
; // Check for hot keys unrelated to the hot keys set by RegisterHotKey.
735 Mesg
.message
= id
!= IDHOT_REACTOS
? WM_HOTKEY
: WM_SYSCOMMAND
;
736 Mesg
.wParam
= id
!= IDHOT_REACTOS
? wParam
: SC_HOTKEY
;
737 Mesg
.lParam
= id
!= IDHOT_REACTOS
? lParam
: (LPARAM
)hWnd
;
738 Type
= id
!= IDHOT_REACTOS
? QS_HOTKEY
: QS_POSTMESSAGE
;
739 KeQueryTickCount(&LargeTickCount
);
740 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
741 Mesg
.pt
= gpsi
->ptCursor
;
742 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, Type
);
743 UserDereferenceObject(Window
);
744 ObDereferenceObject (Thread
);
748 PUSER_MESSAGE FASTCALL
749 MsqCreateMessage(LPMSG Msg
)
751 PUSER_MESSAGE Message
;
753 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
759 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
765 MsqDestroyMessage(PUSER_MESSAGE Message
)
767 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
771 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
773 PUSER_SENT_MESSAGE SaveMsg
, Message
;
778 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
783 /* remove it from the list of pending messages */
784 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
785 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
787 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
789 SaveMsg
= pti
->pusmCurrent
;
790 pti
->pusmCurrent
= Message
;
792 // Processing a message sent to it from another thread.
793 if ( ( Message
->SenderQueue
&& MessageQueue
!= Message
->SenderQueue
) ||
794 ( Message
->CallBackSenderQueue
&& MessageQueue
!= Message
->CallBackSenderQueue
))
795 { // most likely, but, to be sure.
796 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
799 /* insert it to the list of messages that are currently dispatched by this
801 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
802 &Message
->ListEntry
);
804 ClearMsgBitsMask(MessageQueue
, Message
->QS_Flags
);
806 if (Message
->HookMessage
== MSQ_ISHOOK
)
807 { // Direct Hook Call processor
808 Result
= co_CallHook( Message
->Msg
.message
, // HookId
809 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
811 Message
->Msg
.lParam
);
813 else if (Message
->HookMessage
== MSQ_ISEVENT
)
814 { // Direct Event Call processor
815 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
818 Message
->Msg
.lParam
);
820 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
822 Result
= IntLoadHookModule(Message
->Msg
.message
,
823 (HHOOK
)Message
->Msg
.lParam
,
824 Message
->Msg
.wParam
);
826 else if ((Message
->CompletionCallback
)
827 && (Message
->CallBackSenderQueue
== MessageQueue
))
828 { /* Call the callback routine */
829 if (Message
->QS_Flags
& QS_SMRESULT
)
831 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
833 Message
->Msg
.message
,
834 Message
->CompletionCallbackContext
,
836 /* Set callback to NULL to prevent reentry */
837 Message
->CompletionCallback
= NULL
;
841 /* The message has not been processed yet, reinsert it. */
842 RemoveEntryList(&Message
->ListEntry
);
843 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
844 TRACE("Callback Message not processed yet. Requeuing the message\n");
849 { /* Call the window procedure. */
850 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
851 Message
->Msg
.message
,
853 Message
->Msg
.lParam
);
856 /* remove the message from the local dispatching list, because it doesn't need
857 to be cleaned up on thread termination anymore */
858 RemoveEntryList(&Message
->ListEntry
);
860 /* If the message is a callback, insert it in the callback senders MessageQueue */
861 if (Message
->CompletionCallback
)
863 if (Message
->CallBackSenderQueue
)
865 Message
->lResult
= Result
;
866 Message
->QS_Flags
|= QS_SMRESULT
;
868 /* insert it in the callers message queue */
869 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
870 MsqWakeQueue(Message
->CallBackSenderQueue
, QS_SENDMESSAGE
, TRUE
);
871 IntDereferenceMessageQueue(Message
->CallBackSenderQueue
);
876 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
877 if (Message
->SenderQueue
)
879 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
881 /* only remove it from the dispatching list if not already removed by a timeout */
882 RemoveEntryList(&Message
->DispatchingListEntry
);
885 /* still keep the sender's message queue locked, so the sender can't exit the
886 MsqSendMessage() function (if timed out) */
888 if (Message
->QS_Flags
& QS_SMRESULT
)
890 Result
= Message
->lResult
;
893 /* Let the sender know the result. */
894 if (Message
->Result
!= NULL
)
896 *Message
->Result
= Result
;
899 if (Message
->HasPackedLParam
== TRUE
)
901 if (Message
->Msg
.lParam
)
902 ExFreePool((PVOID
)Message
->Msg
.lParam
);
905 /* Notify the sender. */
906 if (Message
->CompletionEvent
!= NULL
)
908 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
911 /* if the message has a sender */
912 if (Message
->SenderQueue
)
914 /* dereference our and the sender's message queue */
915 IntDereferenceMessageQueue(Message
->SenderQueue
);
916 IntDereferenceMessageQueue(MessageQueue
);
919 /* free the message */
920 ExFreePoolWithTag(Message
, TAG_USRMSG
);
922 /* do not hangup on the user if this is reentering */
923 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
924 pti
->pusmCurrent
= SaveMsg
;
930 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
932 PUSER_SENT_MESSAGE SentMessage
;
933 PUSER_MESSAGE PostedMessage
;
934 PUSER_MESSAGE_QUEUE MessageQueue
;
935 PLIST_ENTRY CurrentEntry
, ListHead
;
936 PWND Window
= pWindow
;
940 MessageQueue
= Window
->head
.pti
->MessageQueue
;
941 ASSERT(MessageQueue
);
943 /* remove the posted messages for this window */
944 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
945 ListHead
= &MessageQueue
->PostedMessagesListHead
;
946 while (CurrentEntry
!= ListHead
)
948 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
950 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
952 RemoveEntryList(&PostedMessage
->ListEntry
);
953 ClearMsgBitsMask(MessageQueue
, PostedMessage
->QS_Flags
);
954 MsqDestroyMessage(PostedMessage
);
955 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
959 CurrentEntry
= CurrentEntry
->Flink
;
963 /* remove the sent messages for this window */
964 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
965 ListHead
= &MessageQueue
->SentMessagesListHead
;
966 while (CurrentEntry
!= ListHead
)
968 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
970 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
972 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
974 RemoveEntryList(&SentMessage
->ListEntry
);
975 ClearMsgBitsMask(MessageQueue
, SentMessage
->QS_Flags
);
977 /* if it is a callback and this queue is not the sender queue, dereference queue */
978 if ((SentMessage
->CompletionCallback
) && (SentMessage
->CallBackSenderQueue
!= MessageQueue
))
980 IntDereferenceMessageQueue(SentMessage
->CallBackSenderQueue
);
982 /* Only if the message has a sender was the queue referenced */
983 if ((SentMessage
->SenderQueue
)
984 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
986 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
989 /* wake the sender's thread */
990 if (SentMessage
->CompletionEvent
!= NULL
)
992 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
995 if (SentMessage
->HasPackedLParam
== TRUE
)
997 if (SentMessage
->Msg
.lParam
)
998 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
1001 /* if the message has a sender */
1002 if (SentMessage
->SenderQueue
)
1004 /* dereference our and the sender's message queue */
1005 IntDereferenceMessageQueue(MessageQueue
);
1006 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
1009 /* free the message */
1010 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
1012 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
1016 CurrentEntry
= CurrentEntry
->Flink
;
1022 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
1027 SENDASYNCPROC CompletionCallback
,
1028 ULONG_PTR CompletionCallbackContext
,
1029 BOOL HasPackedLParam
,
1033 PTHREADINFO ptiSender
;
1034 PUSER_SENT_MESSAGE Message
;
1036 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1038 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1042 ptiSender
= PsGetCurrentThreadWin32Thread();
1044 IntReferenceMessageQueue(ptiReceiver
->MessageQueue
);
1045 /* Take reference on this MessageQueue if its a callback. It will be released
1046 when message is processed or removed from target hwnd MessageQueue */
1047 if (CompletionCallback
)
1048 IntReferenceMessageQueue(ptiSender
->MessageQueue
);
1050 Message
->Msg
.hwnd
= hwnd
;
1051 Message
->Msg
.message
= Msg
;
1052 Message
->Msg
.wParam
= wParam
;
1053 Message
->Msg
.lParam
= lParam
;
1054 Message
->CompletionEvent
= NULL
;
1055 Message
->Result
= 0;
1056 Message
->lResult
= 0;
1057 Message
->SenderQueue
= NULL
;
1058 Message
->CallBackSenderQueue
= ptiSender
->MessageQueue
;
1059 Message
->DispatchingListEntry
.Flink
= NULL
;
1060 Message
->CompletionCallback
= CompletionCallback
;
1061 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
1062 Message
->HookMessage
= HookMessage
;
1063 Message
->HasPackedLParam
= HasPackedLParam
;
1064 Message
->QS_Flags
= QS_SENDMESSAGE
;
1066 InsertTailList(&ptiReceiver
->MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1067 MsqWakeQueue(ptiReceiver
->MessageQueue
, QS_SENDMESSAGE
, TRUE
);
1068 IntDereferenceMessageQueue(ptiReceiver
->MessageQueue
);
1074 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1075 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
1076 UINT uTimeout
, BOOL Block
, INT HookMessage
,
1079 PTHREADINFO pti
, ptirec
;
1080 PUSER_SENT_MESSAGE Message
;
1081 KEVENT CompletionEvent
;
1082 NTSTATUS WaitStatus
;
1083 PUSER_MESSAGE_QUEUE ThreadQueue
;
1084 LARGE_INTEGER Timeout
;
1086 LRESULT Result
= 0; //// Result could be trashed. ////
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 pti
= PsGetCurrentThreadWin32Thread();
1097 ThreadQueue
= pti
->MessageQueue
;
1098 ptirec
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1099 ASSERT(ThreadQueue
!= MessageQueue
);
1100 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
1102 /* Don't send from or to a dying thread */
1103 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
1106 return STATUS_TIMEOUT
;
1109 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1111 /* FIXME - increase reference counter of sender's message queue here */
1113 Message
->Msg
.hwnd
= Wnd
;
1114 Message
->Msg
.message
= Msg
;
1115 Message
->Msg
.wParam
= wParam
;
1116 Message
->Msg
.lParam
= lParam
;
1117 Message
->CompletionEvent
= &CompletionEvent
;
1118 Message
->Result
= &Result
;
1119 Message
->lResult
= 0;
1120 Message
->QS_Flags
= 0;
1121 Message
->SenderQueue
= ThreadQueue
;
1122 Message
->CallBackSenderQueue
= NULL
;
1123 IntReferenceMessageQueue(ThreadQueue
);
1124 Message
->CompletionCallback
= NULL
;
1125 Message
->CompletionCallbackContext
= 0;
1126 Message
->HookMessage
= HookMessage
;
1127 Message
->HasPackedLParam
= FALSE
;
1129 IntReferenceMessageQueue(MessageQueue
);
1131 /* add it to the list of pending messages */
1132 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1134 /* queue it in the destination's message queue */
1135 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1137 Message
->QS_Flags
= QS_SENDMESSAGE
;
1138 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
, TRUE
);
1140 /* we can't access the Message anymore since it could have already been deleted! */
1146 /* don't process messages sent to the thread */
1147 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1148 FALSE
, (uTimeout
? &Timeout
: NULL
));
1152 if(WaitStatus
== STATUS_TIMEOUT
)
1154 /* look up if the message has not yet dispatched, if so
1155 make sure it can't pass a result and it must not set the completion event anymore */
1156 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1157 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1159 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1162 /* we can access Message here, it's secure because the message queue is locked
1163 and the message is still hasn't been dispatched */
1164 Message
->CompletionEvent
= NULL
;
1165 Message
->Result
= NULL
;
1168 Entry
= Entry
->Flink
;
1171 /* remove from the local dispatching list so the other thread knows,
1172 it can't pass a result and it must not set the completion event anymore */
1173 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1174 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1176 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1179 /* we can access Message here, it's secure because the sender's message is locked
1180 and the message has definitely not yet been destroyed, otherwise it would
1181 have been removed from this list by the dispatching routine right after
1182 dispatching the message */
1183 Message
->CompletionEvent
= NULL
;
1184 Message
->Result
= NULL
;
1185 RemoveEntryList(&Message
->DispatchingListEntry
);
1186 Message
->DispatchingListEntry
.Flink
= NULL
;
1189 Entry
= Entry
->Flink
;
1192 TRACE("MsqSendMessage (blocked) timed out 1\n");
1194 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1199 PVOID WaitObjects
[2];
1201 WaitObjects
[0] = &CompletionEvent
;
1202 WaitObjects
[1] = ThreadQueue
->NewMessages
;
1207 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1208 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1212 if(WaitStatus
== STATUS_TIMEOUT
)
1214 /* look up if the message has not yet been dispatched, if so
1215 make sure it can't pass a result and it must not set the completion event anymore */
1216 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1217 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1219 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1222 /* we can access Message here, it's secure because the message queue is locked
1223 and the message is still hasn't been dispatched */
1224 Message
->CompletionEvent
= NULL
;
1225 Message
->Result
= NULL
;
1228 Entry
= Entry
->Flink
;
1231 /* remove from the local dispatching list so the other thread knows,
1232 it can't pass a result and it must not set the completion event anymore */
1233 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1234 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1236 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1239 /* we can access Message here, it's secure because the sender's message is locked
1240 and the message has definitely not yet been destroyed, otherwise it would
1241 have been removed from this list by the dispatching routine right after
1242 dispatching the message */
1243 Message
->CompletionEvent
= NULL
;
1244 Message
->Result
= NULL
;
1245 RemoveEntryList(&Message
->DispatchingListEntry
);
1246 Message
->DispatchingListEntry
.Flink
= NULL
;
1249 Entry
= Entry
->Flink
;
1252 TRACE("MsqSendMessage timed out 2\n");
1255 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1258 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
1261 if(WaitStatus
!= STATUS_TIMEOUT
)
1262 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1268 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
1271 PUSER_MESSAGE Message
;
1273 if(!(Message
= MsqCreateMessage(Msg
)))
1278 if(!HardwareMessage
)
1280 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1281 &Message
->ListEntry
);
1285 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1286 &Message
->ListEntry
);
1288 update_input_key_state( MessageQueue
, Msg
);
1291 Message
->QS_Flags
= MessageBits
;
1292 MsqWakeQueue(MessageQueue
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
1296 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1298 MessageQueue
->QuitPosted
= TRUE
;
1299 MessageQueue
->QuitExitCode
= ExitCode
;
1300 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1303 /***********************************************************************
1304 * MsqSendParentNotify
1306 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1307 * the window has the WS_EX_NOPARENTNOTIFY style.
1309 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1311 PWND pwndDesktop
= UserGetWindowObject(IntGetDesktopWindow());
1313 /* pt has to be in the client coordinates of the parent window */
1314 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1315 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1321 if (!(pwnd
->style
& WS_CHILD
)) break;
1322 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1323 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1324 if (pwndParent
== pwndDesktop
) break;
1325 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1326 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1329 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1330 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1334 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1341 MOUSEHOOKSTRUCT hook
;
1344 PWND pwndMsg
, pwndDesktop
;
1345 PUSER_MESSAGE_QUEUE MessageQueue
;
1347 PSYSTEM_CURSORINFO CurInfo
;
1349 DECLARE_RETURN(BOOL
);
1351 pti
= PsGetCurrentThreadWin32Thread();
1352 pwndDesktop
= UserGetDesktopWindow();
1353 MessageQueue
= pti
->MessageQueue
;
1354 CurInfo
= IntGetSysCursorInfo();
1355 pwndMsg
= UserGetWindowObject(msg
->hwnd
);
1356 clk_msg
= MessageQueue
->msgDblClk
;
1357 pDesk
= pwndDesktop
->head
.rpdesk
;
1359 /* find the window to dispatch this mouse message to */
1360 if (MessageQueue
->CaptureWindow
)
1363 pwndMsg
= IntGetWindowObject(MessageQueue
->CaptureWindow
);
1367 pwndMsg
= co_WinPosWindowFromPoint(pwndMsg
, &msg
->pt
, &hittest
);
1370 TRACE("Got mouse message for 0x%x, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1372 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
1374 /* Remove and ignore the message */
1375 *RemoveMessages
= TRUE
;
1379 /* If we a re tracking the mouse and it moves to another window */
1380 if(pDesk
->spwndTrack
&&
1381 pDesk
->spwndTrack
!= pwndMsg
&&
1382 msg
->message
!= WM_MOUSELEAVE
)
1384 /* Generate a WM_MOUSELEAVE message */
1385 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1389 TRACE("co_IntProcessMouseMessage: generating WM_MOUSELEAVE\n");
1391 msgMouseLeave
.hwnd
= UserHMGetHandle(pDesk
->spwndTrack
);
1392 msgMouseLeave
.message
= WM_MOUSELEAVE
;
1393 msgMouseLeave
.pt
= msg
->pt
;
1394 msgMouseLeave
.time
= msg
->time
;
1395 msgMouseLeave
.lParam
= msgMouseLeave
.wParam
= 0;
1397 MsqPostMessage(pwndMsg
->head
.pti
->MessageQueue
,
1404 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1406 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1409 pDesk
->spwndTrack
= NULL
;
1413 if(pDesk
->spwndTrack
)
1415 pDesk
->htEx
= hittest
;
1418 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1421 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
1425 message
= msg
->message
;
1426 /* Note: windows has no concept of a non-client wheel message */
1427 if (message
!= WM_MOUSEWHEEL
)
1429 if (hittest
!= HTCLIENT
)
1431 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1432 msg
->wParam
= hittest
;
1436 /* coordinates don't get translated while tracking a menu */
1437 /* FIXME: should differentiate popups and top-level menus */
1438 if (!(MessageQueue
->MenuOwner
))
1440 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1441 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1445 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1447 /* translate double clicks */
1449 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1450 (msg
->message
== WM_RBUTTONDOWN
) ||
1451 (msg
->message
== WM_MBUTTONDOWN
) ||
1452 (msg
->message
== WM_XBUTTONDOWN
))
1454 BOOL update
= *RemoveMessages
;
1456 /* translate double clicks -
1457 * note that ...MOUSEMOVEs can slip in between
1458 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1460 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1461 hittest
!= HTCLIENT
||
1462 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1464 if ((msg
->message
== clk_msg
.message
) &&
1465 (msg
->hwnd
== clk_msg
.hwnd
) &&
1466 (msg
->wParam
== clk_msg
.wParam
) &&
1467 (msg
->time
- clk_msg
.time
< gspv
.iDblClickTime
) &&
1468 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1469 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1471 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1474 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1480 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1482 TRACE("Message out of range!!!\n");
1486 /* update static double click conditions */
1487 if (update
) MessageQueue
->msgDblClk
= *msg
;
1491 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1493 TRACE("Message out of range!!!\n");
1498 if(gspv
.bMouseClickLock
)
1500 BOOL IsClkLck
= FALSE
;
1502 if(msg
->message
== WM_LBUTTONUP
)
1504 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1505 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1507 CurInfo
->ClickLockActive
= TRUE
;
1510 else if (msg
->message
== WM_LBUTTONDOWN
)
1512 if (CurInfo
->ClickLockActive
)
1515 CurInfo
->ClickLockActive
= FALSE
;
1518 CurInfo
->ClickLockTime
= msg
->time
;
1523 /* Remove and ignore the message */
1524 *RemoveMessages
= TRUE
;
1529 /* message is accepted now (but may still get dropped) */
1531 event
.message
= msg
->message
;
1532 event
.time
= msg
->time
;
1533 event
.hwnd
= msg
->hwnd
;
1534 event
.paramL
= msg
->pt
.x
;
1535 event
.paramH
= msg
->pt
.y
;
1536 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1539 hook
.hwnd
= msg
->hwnd
;
1540 hook
.wHitTestCode
= hittest
;
1541 hook
.dwExtraInfo
= 0/*extra_info*/;
1542 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1543 message
, (LPARAM
)&hook
))
1546 hook
.hwnd
= msg
->hwnd
;
1547 hook
.wHitTestCode
= hittest
;
1548 hook
.dwExtraInfo
= 0/*extra_info*/;
1549 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1551 ERR("WH_MOUSE dorpped mouse message!\n");
1553 /* Remove and skip message */
1554 *RemoveMessages
= TRUE
;
1558 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1560 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1561 MAKELONG( hittest
, msg
->message
));
1563 /* Remove and skip message */
1564 *RemoveMessages
= TRUE
;
1568 if ((*RemoveMessages
== FALSE
) || MessageQueue
->CaptureWindow
)
1570 /* Accept the message */
1571 msg
->message
= message
;
1577 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1578 (msg
->message
== WM_RBUTTONDOWN
) ||
1579 (msg
->message
== WM_MBUTTONDOWN
) ||
1580 (msg
->message
== WM_XBUTTONDOWN
))
1582 /* Send the WM_PARENTNOTIFY,
1583 * note that even for double/nonclient clicks
1584 * notification message is still WM_L/M/RBUTTONDOWN.
1586 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1588 /* Activate the window if needed */
1590 if (msg
->hwnd
!= UserGetForegroundWindow())
1592 PWND pwndTop
= pwndMsg
;
1595 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
1596 pwndTop
= IntGetParent( pwndTop
);
1599 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1601 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1603 (WPARAM
)UserHMGetHandle(pwndTop
),
1604 MAKELONG( hittest
, msg
->message
));
1607 case MA_NOACTIVATEANDEAT
:
1612 case MA_ACTIVATEANDEAT
:
1617 if(!co_IntMouseActivateWindow(pwndMsg
)) eatMsg
= TRUE
;
1620 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1627 /* send the WM_SETCURSOR message */
1629 /* Windows sends the normal mouse message as the message parameter
1630 in the WM_SETCURSOR message even if it's non-client mouse message */
1631 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1633 msg
->message
= message
;
1638 UserDereferenceObject(pwndMsg
);
1643 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1647 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1648 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1650 switch (Msg
->wParam
)
1652 case VK_LSHIFT
: case VK_RSHIFT
:
1653 Msg
->wParam
= VK_SHIFT
;
1655 case VK_LCONTROL
: case VK_RCONTROL
:
1656 Msg
->wParam
= VK_CONTROL
;
1658 case VK_LMENU
: case VK_RMENU
:
1659 Msg
->wParam
= VK_MENU
;
1664 Event
.message
= Msg
->message
;
1665 Event
.hwnd
= Msg
->hwnd
;
1666 Event
.time
= Msg
->time
;
1667 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1668 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1669 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1670 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1672 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1673 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1674 LOWORD(Msg
->wParam
),
1677 /* skip this message */
1678 co_HOOK_CallHooks( WH_CBT
,
1680 LOWORD(Msg
->wParam
),
1682 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1688 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1690 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1692 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1694 else if ( IS_KBD_MESSAGE(Msg
->message
))
1696 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1703 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1706 IN UINT MsgFilterLow
,
1707 IN UINT MsgFilterHigh
,
1713 if(!(MessageQueue
->MouseMoved
))
1716 msg
= MessageQueue
->MouseMoveMsg
;
1718 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1725 ClearMsgBitsMask(MessageQueue
, QS_MOUSEMOVE
);
1726 MessageQueue
->MouseMoved
= FALSE
;
1729 return AcceptMessage
;
1732 /* check whether a message filter contains at least one potential hardware message */
1734 filter_contains_hw_range( UINT first
, UINT last
)
1736 /* hardware message ranges are (in numerical order):
1737 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1738 * WM_KEYFIRST .. WM_KEYLAST
1739 * WM_MOUSEFIRST .. WM_MOUSELAST
1742 if (last
< WM_NCMOUSEFIRST
) return 0;
1743 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1744 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1745 if (first
> WM_MOUSELAST
) return 0;
1750 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1753 IN UINT MsgFilterLow
,
1754 IN UINT MsgFilterHigh
,
1760 PUSER_MESSAGE CurrentMessage
;
1761 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1764 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1766 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1767 CurrentEntry
= ListHead
->Flink
;
1769 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1771 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1775 if (IsListEmpty(CurrentEntry
)) break;
1776 if (!CurrentMessage
) break;
1777 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1780 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1781 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1782 3: handle to the window whose messages are to be retrieved.
1784 if ( ( !Window
|| // 1
1785 ( Window
== HWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1786 ( Window
!= HWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1787 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1788 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1790 msg
= CurrentMessage
->Msg
;
1792 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1796 update_input_key_state(MessageQueue
, &msg
);
1797 RemoveEntryList(&CurrentMessage
->ListEntry
);
1798 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1799 MsqDestroyMessage(CurrentMessage
);
1808 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1811 while(CurrentEntry
!= ListHead
);
1817 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1820 IN UINT MsgFilterLow
,
1821 IN UINT MsgFilterHigh
,
1825 PLIST_ENTRY CurrentEntry
;
1826 PUSER_MESSAGE CurrentMessage
;
1827 PLIST_ENTRY ListHead
;
1829 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1830 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1832 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1834 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1838 if (IsListEmpty(CurrentEntry
)) break;
1839 if (!CurrentMessage
) break;
1840 CurrentEntry
= CurrentEntry
->Flink
;
1843 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1844 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1845 3: handle to the window whose messages are to be retrieved.
1847 if ( ( !Window
|| // 1
1848 ( Window
== HWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1849 ( Window
!= HWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1850 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1851 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1853 *Message
= CurrentMessage
->Msg
;
1857 RemoveEntryList(&CurrentMessage
->ListEntry
);
1858 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1859 MsqDestroyMessage(CurrentMessage
);
1863 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1866 while (CurrentEntry
!= ListHead
);
1872 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1873 UINT MsgFilterMin
, UINT MsgFilterMax
)
1877 ret
= KeWaitForSingleObject( MessageQueue
->NewMessages
,
1887 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1889 LARGE_INTEGER LargeTickCount
;
1891 KeQueryTickCount(&LargeTickCount
);
1892 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1897 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1900 TRACE("HungAppSysTimerProc\n");
1901 // Process list of windows that are hung and waiting.
1905 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1907 LARGE_INTEGER LargeTickCount
;
1910 MessageQueue
->Thread
= Thread
;
1911 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1912 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1913 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1914 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1915 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1916 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1917 MessageQueue
->QuitPosted
= FALSE
;
1918 MessageQueue
->QuitExitCode
= 0;
1919 KeQueryTickCount(&LargeTickCount
);
1920 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1921 MessageQueue
->FocusWindow
= NULL
;
1922 MessageQueue
->NewMessagesHandle
= NULL
;
1923 MessageQueue
->ShowingCursor
= 0;
1924 MessageQueue
->CursorObject
= NULL
;
1926 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1927 NULL
, SynchronizationEvent
, FALSE
);
1928 if (!NT_SUCCESS(Status
))
1933 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1934 ExEventObjectType
, KernelMode
,
1935 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1936 if (!NT_SUCCESS(Status
))
1938 ZwClose(MessageQueue
->NewMessagesHandle
);
1939 MessageQueue
->NewMessagesHandle
= NULL
;
1947 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1949 PLIST_ENTRY CurrentEntry
;
1950 PUSER_MESSAGE CurrentMessage
;
1951 PUSER_SENT_MESSAGE CurrentSentMessage
;
1954 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1957 /* cleanup posted messages */
1958 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1960 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1961 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1963 MsqDestroyMessage(CurrentMessage
);
1966 /* remove the messages that have not yet been dispatched */
1967 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1969 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1970 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1973 /* if it is a callback and this queue is not the sender queue, dereference queue */
1974 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
1976 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
1979 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
1980 /* Only if the message has a sender was the message in the DispatchingList */
1981 if ((CurrentSentMessage
->SenderQueue
)
1982 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1984 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1987 /* wake the sender's thread */
1988 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1990 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1993 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1995 if (CurrentSentMessage
->Msg
.lParam
)
1996 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1999 /* if the message has a sender */
2000 if (CurrentSentMessage
->SenderQueue
)
2002 /* dereference our and the sender's message queue */
2003 IntDereferenceMessageQueue(MessageQueue
);
2004 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
2007 /* free the message */
2008 ExFreePool(CurrentSentMessage
);
2011 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
2012 ExitThread() was called in a SendMessage() umode callback */
2013 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
2015 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
2016 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2019 /* if it is a callback and this queue is not the sender queue, dereference queue */
2020 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
2022 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
2025 /* remove the message from the dispatching list */
2026 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
2028 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
2031 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
2033 /* wake the sender's thread */
2034 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
2036 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2039 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
2041 if (CurrentSentMessage
->Msg
.lParam
)
2042 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2045 /* if the message has a sender */
2046 if (CurrentSentMessage
->SenderQueue
)
2048 /* dereference our and the sender's message queue */
2049 IntDereferenceMessageQueue(MessageQueue
);
2050 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
2053 /* free the message */
2054 ExFreePool(CurrentSentMessage
);
2057 /* tell other threads not to bother returning any info to us */
2058 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
2060 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
2061 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2062 DispatchingListEntry
);
2063 CurrentSentMessage
->CompletionEvent
= NULL
;
2064 CurrentSentMessage
->Result
= NULL
;
2066 /* do NOT dereference our message queue as it might get attempted to be
2070 // Clear it all out.
2073 pti
->pcti
->fsWakeBits
= 0;
2074 pti
->pcti
->fsChangeBits
= 0;
2077 MessageQueue
->nCntsQBits
[QSRosKey
] = 0;
2078 MessageQueue
->nCntsQBits
[QSRosMouseMove
] = 0;
2079 MessageQueue
->nCntsQBits
[QSRosMouseButton
] = 0;
2080 MessageQueue
->nCntsQBits
[QSRosPostMessage
] = 0;
2081 MessageQueue
->nCntsQBits
[QSRosSendMessage
] = 0;
2082 MessageQueue
->nCntsQBits
[QSRosHotKey
] = 0;
2084 if (MessageQueue
->CursorObject
)
2086 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2088 /* Change to another cursor if we going to dereference current one */
2089 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2090 UserSetCursor(NULL
, TRUE
);
2092 UserDereferenceObject(pCursor
);
2097 PUSER_MESSAGE_QUEUE FASTCALL
2098 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
2100 PUSER_MESSAGE_QUEUE MessageQueue
;
2102 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2103 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2111 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2112 /* hold at least one reference until it'll be destroyed */
2113 IntReferenceMessageQueue(MessageQueue
);
2114 /* initialize the queue */
2115 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
2117 IntDereferenceMessageQueue(MessageQueue
);
2121 return MessageQueue
;
2125 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
2129 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2131 /* remove the message queue from any desktops */
2132 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2134 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2135 IntDereferenceMessageQueue(MessageQueue
);
2139 MsqCleanupMessageQueue(MessageQueue
);
2141 if (MessageQueue
->NewMessagesHandle
!= NULL
)
2142 ZwClose(MessageQueue
->NewMessagesHandle
);
2143 MessageQueue
->NewMessagesHandle
= NULL
;
2144 /* decrease the reference counter, if it hits zero, the queue will be freed */
2145 IntDereferenceMessageQueue(MessageQueue
);
2149 MsqSetMessageExtraInfo(LPARAM lParam
)
2153 PUSER_MESSAGE_QUEUE MessageQueue
;
2155 pti
= PsGetCurrentThreadWin32Thread();
2156 MessageQueue
= pti
->MessageQueue
;
2162 Ret
= MessageQueue
->ExtraInfo
;
2163 MessageQueue
->ExtraInfo
= lParam
;
2169 MsqGetMessageExtraInfo(VOID
)
2172 PUSER_MESSAGE_QUEUE MessageQueue
;
2174 pti
= PsGetCurrentThreadWin32Thread();
2175 MessageQueue
= pti
->MessageQueue
;
2181 return MessageQueue
->ExtraInfo
;
2184 // ReplyMessage is called by the thread receiving the window message.
2186 co_MsqReplyMessage( LRESULT lResult
)
2188 PUSER_SENT_MESSAGE Message
;
2191 pti
= PsGetCurrentThreadWin32Thread();
2192 Message
= pti
->pusmCurrent
;
2194 if (!Message
) return FALSE
;
2196 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2198 // SendMessageXxx || Callback msg and not a notify msg
2199 if (Message
->SenderQueue
|| Message
->CompletionCallback
)
2201 Message
->lResult
= lResult
;
2202 Message
->QS_Flags
|= QS_SMRESULT
;
2203 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2209 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
2215 case MSQ_STATE_CAPTURE
:
2216 Prev
= MessageQueue
->CaptureWindow
;
2217 MessageQueue
->CaptureWindow
= hWnd
;
2219 case MSQ_STATE_ACTIVE
:
2220 Prev
= MessageQueue
->ActiveWindow
;
2221 MessageQueue
->ActiveWindow
= hWnd
;
2223 case MSQ_STATE_FOCUS
:
2224 Prev
= MessageQueue
->FocusWindow
;
2225 MessageQueue
->FocusWindow
= hWnd
;
2227 case MSQ_STATE_MENUOWNER
:
2228 Prev
= MessageQueue
->MenuOwner
;
2229 MessageQueue
->MenuOwner
= hWnd
;
2231 case MSQ_STATE_MOVESIZE
:
2232 Prev
= MessageQueue
->MoveSize
;
2233 MessageQueue
->MoveSize
= hWnd
;
2235 case MSQ_STATE_CARET
:
2236 ASSERT(MessageQueue
->CaretInfo
);
2237 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2238 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2247 NtUserGetKeyState(INT key
)
2251 UserEnterExclusive();
2253 Ret
= UserGetKeyState(key
);
2263 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2267 PUSER_MESSAGE_QUEUE MessageQueue
;
2271 pti
= PsGetCurrentThreadWin32Thread();
2272 MessageQueue
= pti
->MessageQueue
;
2276 ProbeForWrite(lpKeyState
,sizeof(MessageQueue
->KeyState
) ,1);
2277 RtlCopyMemory(lpKeyState
,MessageQueue
->KeyState
,sizeof(MessageQueue
->KeyState
));
2279 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2281 SetLastNtError(_SEH2_GetExceptionCode());
2293 NtUserSetKeyboardState(LPBYTE lpKeyState
)
2297 PUSER_MESSAGE_QUEUE MessageQueue
;
2299 UserEnterExclusive();
2301 pti
= PsGetCurrentThreadWin32Thread();
2302 MessageQueue
= pti
->MessageQueue
;
2306 ProbeForRead(lpKeyState
,sizeof(MessageQueue
->KeyState
) ,1);
2307 RtlCopyMemory(MessageQueue
->KeyState
,lpKeyState
,sizeof(MessageQueue
->KeyState
));
2309 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2311 SetLastNtError(_SEH2_GetExceptionCode());