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)
10 * 06-06-2001 CSH Created
13 /* INCLUDES ******************************************************************/
17 DBG_DEFAULT_CHANNEL(UserMsgQ
);
19 /* GLOBALS *******************************************************************/
21 static PAGED_LOOKASIDE_LIST MessageLookasideList
;
22 MOUSEMOVEPOINT MouseHistoryOfMoves
[64];
25 /* FUNCTIONS *****************************************************************/
30 MsqInitializeImpl(VOID
)
32 ExInitializePagedLookasideList(&MessageLookasideList
,
40 return(STATUS_SUCCESS
);
44 IntChildrenWindowFromPoint(PWND pWndTop
, INT x
, INT y
)
48 if (!(pWndTop
->style
& WS_VISIBLE
)) return NULL
;
49 if ((pWndTop
->style
& WS_DISABLED
)) return NULL
;
50 if (!IntPtInWindow(pWndTop
, x
, y
)) return NULL
;
52 if (x
- pWndTop
->rcClient
.left
< pWndTop
->rcClient
.right
&&
53 y
- pWndTop
->rcClient
.top
< pWndTop
->rcClient
.bottom
)
55 for (pWnd
= pWndTop
->spwndChild
;
57 pWnd
= pWnd
->spwndNext
)
59 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
61 TRACE("The Window is in DESTROY!\n");
65 pWndChild
= IntChildrenWindowFromPoint(pWnd
, x
, y
);
77 IntTopLevelWindowFromPoint(INT x
, INT y
)
79 PWND pWnd
, pwndDesktop
;
81 /* Get the desktop window */
82 pwndDesktop
= UserGetDesktopWindow();
86 /* Loop all top level windows */
87 for (pWnd
= pwndDesktop
->spwndChild
;
89 pWnd
= pWnd
->spwndNext
)
91 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
93 TRACE("The Window is in DESTROY!\n");
97 if ((pWnd
->style
& WS_VISIBLE
) && IntPtInWindow(pWnd
, x
, y
))
101 /* Window has not been found */
108 PCURICON_OBJECT NewCursor
,
111 PCURICON_OBJECT OldCursor
;
114 PUSER_MESSAGE_QUEUE MessageQueue
;
117 pti
= PsGetCurrentThreadWin32Thread();
118 MessageQueue
= pti
->MessageQueue
;
120 /* Get the screen DC */
121 if(!(hdcScreen
= IntGetScreenDC()))
126 OldCursor
= MessageQueue
->CursorObject
;
128 /* Check if cursors are different */
129 if (OldCursor
== NewCursor
)
132 /* Update cursor for this message queue */
133 MessageQueue
->CursorObject
= NewCursor
;
135 /* If cursor is not visible we have nothing to do */
136 if (MessageQueue
->ShowingCursor
< 0)
139 /* Update cursor if this message queue controls it */
140 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
141 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
145 /* Call GDI to set the new screen cursor */
146 GreSetPointerShape(hdcScreen
,
147 NewCursor
->IconInfo
.hbmMask
,
148 NewCursor
->IconInfo
.hbmColor
,
149 NewCursor
->IconInfo
.xHotspot
,
150 NewCursor
->IconInfo
.yHotspot
,
154 else /* Note: OldCursor != NewCursor so we have to hide cursor */
156 /* Remove the cursor */
157 GreMovePointer(hdcScreen
, -1, -1);
158 TRACE("Removing pointer!\n");
160 IntGetSysCursorInfo()->CurrentCursorObject
= NewCursor
;
163 /* Return the old cursor */
167 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
168 * User32 macro NtUserShowCursor */
169 int UserShowCursor(BOOL bShow
)
173 PUSER_MESSAGE_QUEUE MessageQueue
;
176 if (!(hdcScreen
= IntGetScreenDC()))
178 return -1; /* No mouse */
181 pti
= PsGetCurrentThreadWin32Thread();
182 MessageQueue
= pti
->MessageQueue
;
185 MessageQueue
->ShowingCursor
+= bShow
? 1 : -1;
187 /* Check for trivial cases */
188 if ((bShow
&& MessageQueue
->ShowingCursor
!= 0) ||
189 (!bShow
&& MessageQueue
->ShowingCursor
!= -1))
191 /* Note: w don't update global info here because it is used only
192 internally to check if cursor is visible */
193 return MessageQueue
->ShowingCursor
;
196 /* Check if cursor is above window owned by this MessageQueue */
197 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
198 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
202 /* Show the pointer */
203 GreMovePointer(hdcScreen
, gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
204 TRACE("Showing pointer!\n");
208 /* Remove the pointer */
209 GreMovePointer(hdcScreen
, -1, -1);
210 TRACE("Removing pointer!\n");
213 /* Update global info */
214 IntGetSysCursorInfo()->ShowingCursor
= MessageQueue
->ShowingCursor
;
217 return MessageQueue
->ShowingCursor
;
220 DWORD FASTCALL
UserGetKeyState(DWORD key
)
224 PUSER_MESSAGE_QUEUE MessageQueue
;
226 pti
= PsGetCurrentThreadWin32Thread();
227 MessageQueue
= pti
->MessageQueue
;
231 ret
= (DWORD
)MessageQueue
->KeyState
[key
];
232 if (MessageQueue
->KeyState
[key
] & KS_DOWN_BIT
)
233 ret
|= 0xFF00; // If down, windows returns 0xFF80.
237 EngSetLastError(ERROR_INVALID_PARAMETER
);
242 /* change the input key state for a given key */
243 static void set_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue
, UCHAR key
, BOOL down
)
245 TRACE("set_input_key_state key:%d, down:%d\n", key
, down
);
249 if (!(MessageQueue
->KeyState
[key
] & KS_DOWN_BIT
))
251 MessageQueue
->KeyState
[key
] ^= KS_LOCK_BIT
;
253 MessageQueue
->KeyState
[key
] |= KS_DOWN_BIT
;
257 MessageQueue
->KeyState
[key
] &= ~KS_DOWN_BIT
;
261 /* update the input key state for a keyboard message */
262 static void update_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
267 TRACE("update_input_key_state message:%d\n", msg
->message
);
269 switch (msg
->message
)
275 set_input_key_state( MessageQueue
, VK_LBUTTON
, down
);
281 set_input_key_state( MessageQueue
, VK_MBUTTON
, down
);
287 set_input_key_state( MessageQueue
, VK_RBUTTON
, down
);
293 if (msg
->wParam
== XBUTTON1
)
294 set_input_key_state( MessageQueue
, VK_XBUTTON1
, down
);
295 else if (msg
->wParam
== XBUTTON2
)
296 set_input_key_state( MessageQueue
, VK_XBUTTON2
, down
);
304 key
= (UCHAR
)msg
->wParam
;
305 set_input_key_state( MessageQueue
, key
, down
);
310 down
= (MessageQueue
->KeyState
[VK_LCONTROL
] | MessageQueue
->KeyState
[VK_RCONTROL
]) & KS_DOWN_BIT
;
311 set_input_key_state( MessageQueue
, VK_CONTROL
, down
);
315 down
= (MessageQueue
->KeyState
[VK_LMENU
] | MessageQueue
->KeyState
[VK_RMENU
]) & KS_DOWN_BIT
;
316 set_input_key_state( MessageQueue
, VK_MENU
, down
);
320 down
= (MessageQueue
->KeyState
[VK_LSHIFT
] | MessageQueue
->KeyState
[VK_RSHIFT
]) & KS_DOWN_BIT
;
321 set_input_key_state( MessageQueue
, VK_SHIFT
, down
);
329 IntMsqSetWakeMask(DWORD WakeMask
)
331 PTHREADINFO Win32Thread
;
332 PUSER_MESSAGE_QUEUE MessageQueue
;
333 HANDLE MessageEventHandle
;
334 DWORD dwFlags
= HIWORD(WakeMask
);
336 Win32Thread
= PsGetCurrentThreadWin32Thread();
337 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
340 MessageQueue
= Win32Thread
->MessageQueue
;
341 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
342 MessageEventHandle
= MessageQueue
->NewMessagesHandle
;
344 if (Win32Thread
->pcti
)
346 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
347 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
349 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
350 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
351 return MessageEventHandle
;
357 return MessageEventHandle
;
361 IntMsqClearWakeMask(VOID
)
363 PTHREADINFO Win32Thread
;
365 Win32Thread
= PsGetCurrentThreadWin32Thread();
366 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
368 // Very hacky, but that is what they do.
369 Win32Thread
->pcti
->fsWakeBits
= 0;
377 Due to the uncertainty of knowing what was set in our multilevel message queue,
378 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
379 I think this is the best solution... (jt) */
381 MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue
, DWORD MessageBits
, BOOL KeyEvent
)
385 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
386 pti
->pcti
->fsWakeBits
|= MessageBits
;
387 pti
->pcti
->fsChangeBits
|= MessageBits
;
389 // Start bit accounting to help clear the main set of bits.
390 if (MessageBits
& QS_KEY
) Queue
->nCntsQBits
[QSRosKey
]++;
391 if (MessageBits
& QS_MOUSEMOVE
) Queue
->nCntsQBits
[QSRosMouseMove
]++;
392 if (MessageBits
& QS_MOUSEBUTTON
) Queue
->nCntsQBits
[QSRosMouseButton
]++;
393 if (MessageBits
& QS_POSTMESSAGE
) Queue
->nCntsQBits
[QSRosPostMessage
]++;
394 if (MessageBits
& QS_SENDMESSAGE
) Queue
->nCntsQBits
[QSRosSendMessage
]++;
395 if (MessageBits
& QS_HOTKEY
) Queue
->nCntsQBits
[QSRosHotKey
]++;
398 KeSetEvent(Queue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
402 ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue
, UINT MessageBits
)
407 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
409 if (MessageBits
& QS_KEY
)
411 if (--Queue
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
413 if (MessageBits
& QS_MOUSEMOVE
) // ReactOS hard coded.
414 { // Account for tracking mouse moves..
415 if (--Queue
->nCntsQBits
[QSRosMouseMove
] == 0) ClrMask
|= QS_MOUSEMOVE
;
416 // Handle mouse move bits here.
417 if (Queue
->MouseMoved
) ClrMask
|= QS_MOUSEMOVE
;
419 if (MessageBits
& QS_MOUSEBUTTON
)
421 if (--Queue
->nCntsQBits
[QSRosMouseButton
] == 0) ClrMask
|= QS_MOUSEBUTTON
;
423 if (MessageBits
& QS_POSTMESSAGE
)
425 if (--Queue
->nCntsQBits
[QSRosPostMessage
] == 0) ClrMask
|= QS_POSTMESSAGE
;
427 if (MessageBits
& QS_TIMER
) // ReactOS hard coded.
428 { // Handle timer bits here.
429 if ( pti
->cTimersReady
)
431 if (--pti
->cTimersReady
== 0) ClrMask
|= QS_TIMER
;
434 if (MessageBits
& QS_PAINT
) // ReactOS hard coded.
435 { // Handle paint bits here.
436 if ( pti
->cPaintsReady
)
438 if (--pti
->cPaintsReady
== 0) ClrMask
|= QS_PAINT
;
441 if (MessageBits
& QS_SENDMESSAGE
)
443 if (--Queue
->nCntsQBits
[QSRosSendMessage
] == 0) ClrMask
|= QS_SENDMESSAGE
;
445 if (MessageBits
& QS_HOTKEY
)
447 if (--Queue
->nCntsQBits
[QSRosHotKey
] == 0) ClrMask
|= QS_HOTKEY
;
450 pti
->pcti
->fsWakeBits
&= ~ClrMask
;
451 pti
->pcti
->fsChangeBits
&= ~ClrMask
;
455 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
458 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
460 MsqWakeQueue(Queue
, QS_PAINT
, TRUE
);
464 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
466 ClearMsgBitsMask(Queue
, QS_PAINT
);
470 MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
)
472 MessageQueue
->MouseMoveMsg
= *Msg
;
473 MessageQueue
->MouseMoved
= TRUE
;
474 MsqWakeQueue(MessageQueue
, QS_MOUSEMOVE
, TRUE
);
478 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
480 LARGE_INTEGER LargeTickCount
;
481 MSLLHOOKSTRUCT MouseHookData
;
483 PWND pwnd
, pwndDesktop
;
485 PSYSTEM_CURSORINFO CurInfo
;
487 KeQueryTickCount(&LargeTickCount
);
488 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
490 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
491 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
492 switch (Msg
->message
)
495 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
499 case WM_XBUTTONDBLCLK
:
500 case WM_NCXBUTTONDOWN
:
502 case WM_NCXBUTTONDBLCLK
:
503 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
506 MouseHookData
.mouseData
= 0;
510 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
511 MouseHookData
.time
= Msg
->time
;
512 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
514 /* If the hook procedure returned non zero, dont send the message */
517 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
521 /* Get the desktop window */
522 pwndDesktop
= UserGetDesktopWindow();
523 if (!pwndDesktop
) return;
524 pDesk
= pwndDesktop
->head
.rpdesk
;
526 /* Check if the mouse is captured */
527 Msg
->hwnd
= IntGetCaptureWindow();
528 if (Msg
->hwnd
!= NULL
)
530 pwnd
= UserGetWindowObject(Msg
->hwnd
);
534 pwnd
= IntTopLevelWindowFromPoint(Msg
->pt
.x
, Msg
->pt
.y
);
535 if (pwnd
) Msg
->hwnd
= pwnd
->head
.h
;
540 /* If we a re tracking the mouse and it moves to another top level window */
541 if(pDesk
->spwndTrack
&&
542 UserGetAncestor(pDesk
->spwndTrack
, GA_ROOT
) != pwnd
)
544 /* Generate a WM_MOUSELEAVE message */
545 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
549 TRACE("co_MsqInsertMouseMessage: generating WM_MOUSELEAVE\n");
551 msgMouseLeave
.hwnd
= UserHMGetHandle(pDesk
->spwndTrack
);
552 msgMouseLeave
.message
= WM_MOUSELEAVE
;
553 msgMouseLeave
.pt
= Msg
->pt
;
554 msgMouseLeave
.time
= Msg
->time
;
555 msgMouseLeave
.lParam
= msgMouseLeave
.wParam
= 0;
557 MsqPostMessage(pwnd
->head
.pti
->MessageQueue
, Msg
, TRUE
, QS_MOUSE
);
561 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
563 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
566 pDesk
->spwndTrack
= NULL
;
571 hdcScreen
= IntGetScreenDC();
572 CurInfo
= IntGetSysCursorInfo();
574 /* Check if we found a window */
575 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
577 if (Msg
->message
== WM_MOUSEMOVE
)
579 PUSER_MESSAGE_QUEUE MessageQueue
= pwnd
->head
.pti
->MessageQueue
;
581 /* Check if cursor should be visible */
583 MessageQueue
->CursorObject
&&
584 MessageQueue
->ShowingCursor
>= 0)
586 /* Check if shape has changed */
587 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
589 /* Call GDI to set the new screen cursor */
590 GreSetPointerShape(hdcScreen
,
591 MessageQueue
->CursorObject
->IconInfo
.hbmMask
,
592 MessageQueue
->CursorObject
->IconInfo
.hbmColor
,
593 MessageQueue
->CursorObject
->IconInfo
.xHotspot
,
594 MessageQueue
->CursorObject
->IconInfo
.yHotspot
,
598 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
600 /* Check if w have to hide cursor */
601 else if (CurInfo
->ShowingCursor
>= 0)
602 GreMovePointer(hdcScreen
, -1, -1);
604 /* Update global cursor info */
605 CurInfo
->ShowingCursor
= MessageQueue
->ShowingCursor
;
606 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
608 /* Mouse move is a special case */
609 MsqPostMouseMove(MessageQueue
, Msg
);
613 TRACE("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd
));
614 MsqPostMessage(pwnd
->head
.pti
->MessageQueue
, Msg
, TRUE
, QS_MOUSEBUTTON
);
619 /* always show cursor on background; FIXME: set default pointer */
620 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
621 CurInfo
->ShowingCursor
= 0;
624 /* Do GetMouseMovePointsEx FIFO. */
625 MouseHistoryOfMoves
[gcur_count
].x
= Msg
->pt
.x
;
626 MouseHistoryOfMoves
[gcur_count
].y
= Msg
->pt
.y
;
627 MouseHistoryOfMoves
[gcur_count
].time
= Msg
->time
;
628 MouseHistoryOfMoves
[gcur_count
].dwExtraInfo
= dwExtraInfo
;
629 if (++gcur_count
== ARRAYSIZE(MouseHistoryOfMoves
))
630 gcur_count
= 0; // 0 - 63 is 64, FIFO forwards.
634 // Note: Only called from input.c.
637 co_MsqPostKeyboardMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
639 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
641 LARGE_INTEGER LargeTickCount
;
642 KBDLLHOOKSTRUCT KbdHookData
;
644 TRACE("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
645 uMsg
, wParam
, lParam
);
647 // Condition may arise when calling MsqPostMessage and waiting for an event.
648 ASSERT(UserIsEntered());
650 FocusMessageQueue
= IntGetFocusMessageQueue();
654 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
655 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
661 KeQueryTickCount(&LargeTickCount
);
662 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
664 /* We can't get the Msg.pt point here since we don't know thread
665 (and thus the window station) the message will end up in yet. */
667 KbdHookData
.vkCode
= Msg
.wParam
;
668 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
669 KbdHookData
.flags
= (0 == (Msg
.lParam
& 0x01000000) ? 0 : LLKHF_EXTENDED
) |
670 (0 == (Msg
.lParam
& 0x20000000) ? 0 : LLKHF_ALTDOWN
) |
671 (0 == (Msg
.lParam
& 0x80000000) ? 0 : LLKHF_UP
);
672 KbdHookData
.time
= Msg
.time
;
673 KbdHookData
.dwExtraInfo
= 0;
674 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
676 ERR("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
677 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
681 if (FocusMessageQueue
== NULL
)
683 TRACE("No focus message queue\n");
687 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
689 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
690 TRACE("Msg.hwnd = %x\n", Msg
.hwnd
);
692 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
694 Msg
.pt
= gpsi
->ptCursor
;
695 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
699 TRACE("Invalid focus window handle\n");
706 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
709 PTHREADINFO Win32Thread
;
711 LARGE_INTEGER LargeTickCount
;
716 Status
= ObReferenceObjectByPointer (Thread
,
720 if (!NT_SUCCESS(Status
))
723 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
724 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
726 ObDereferenceObject ((PETHREAD
)Thread
);
730 Window
= IntGetWindowObject(hWnd
);
733 ObDereferenceObject ((PETHREAD
)Thread
);
737 id
= wParam
; // Check for hot keys unrelated to the hot keys set by RegisterHotKey.
740 Mesg
.message
= id
!= IDHOT_REACTOS
? WM_HOTKEY
: WM_SYSCOMMAND
;
741 Mesg
.wParam
= id
!= IDHOT_REACTOS
? wParam
: SC_HOTKEY
;
742 Mesg
.lParam
= id
!= IDHOT_REACTOS
? lParam
: (LPARAM
)hWnd
;
743 Type
= id
!= IDHOT_REACTOS
? QS_HOTKEY
: QS_POSTMESSAGE
;
744 KeQueryTickCount(&LargeTickCount
);
745 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
746 Mesg
.pt
= gpsi
->ptCursor
;
747 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, Type
);
748 UserDereferenceObject(Window
);
749 ObDereferenceObject (Thread
);
753 PUSER_MESSAGE FASTCALL
754 MsqCreateMessage(LPMSG Msg
)
756 PUSER_MESSAGE Message
;
758 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
764 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
770 MsqDestroyMessage(PUSER_MESSAGE Message
)
772 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
776 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
778 PUSER_SENT_MESSAGE SaveMsg
, Message
;
783 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
788 /* remove it from the list of pending messages */
789 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
790 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
792 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
794 SaveMsg
= pti
->pusmCurrent
;
795 pti
->pusmCurrent
= Message
;
797 // Processing a message sent to it from another thread.
798 if ( ( Message
->SenderQueue
&& MessageQueue
!= Message
->SenderQueue
) ||
799 ( Message
->CallBackSenderQueue
&& MessageQueue
!= Message
->CallBackSenderQueue
))
800 { // most likely, but, to be sure.
801 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
804 /* insert it to the list of messages that are currently dispatched by this
806 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
807 &Message
->ListEntry
);
809 ClearMsgBitsMask(MessageQueue
, Message
->QS_Flags
);
811 if (Message
->HookMessage
== MSQ_ISHOOK
)
812 { // Direct Hook Call processor
813 Result
= co_CallHook( Message
->Msg
.message
, // HookId
814 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
816 Message
->Msg
.lParam
);
818 else if (Message
->HookMessage
== MSQ_ISEVENT
)
819 { // Direct Event Call processor
820 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
823 Message
->Msg
.lParam
);
825 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
827 Result
= IntLoadHookModule(Message
->Msg
.message
,
828 (HHOOK
)Message
->Msg
.lParam
,
829 Message
->Msg
.wParam
);
831 else if ((Message
->CompletionCallback
)
832 && (Message
->CallBackSenderQueue
== MessageQueue
))
833 { /* Call the callback routine */
834 if (Message
->QS_Flags
& QS_SMRESULT
)
836 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
838 Message
->Msg
.message
,
839 Message
->CompletionCallbackContext
,
841 /* Set callback to NULL to prevent reentry */
842 Message
->CompletionCallback
= NULL
;
846 /* The message has not been processed yet, reinsert it. */
847 RemoveEntryList(&Message
->ListEntry
);
848 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
849 TRACE("Callback Message not processed yet. Requeuing the message\n");
854 { /* Call the window procedure. */
855 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
856 Message
->Msg
.message
,
858 Message
->Msg
.lParam
);
861 /* remove the message from the local dispatching list, because it doesn't need
862 to be cleaned up on thread termination anymore */
863 RemoveEntryList(&Message
->ListEntry
);
865 /* If the message is a callback, insert it in the callback senders MessageQueue */
866 if (Message
->CompletionCallback
)
868 if (Message
->CallBackSenderQueue
)
870 Message
->lResult
= Result
;
871 Message
->QS_Flags
|= QS_SMRESULT
;
873 /* insert it in the callers message queue */
874 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
875 MsqWakeQueue(Message
->CallBackSenderQueue
, QS_SENDMESSAGE
, TRUE
);
876 IntDereferenceMessageQueue(Message
->CallBackSenderQueue
);
881 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
882 if (Message
->SenderQueue
)
884 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
886 /* only remove it from the dispatching list if not already removed by a timeout */
887 RemoveEntryList(&Message
->DispatchingListEntry
);
890 /* still keep the sender's message queue locked, so the sender can't exit the
891 MsqSendMessage() function (if timed out) */
893 if (Message
->QS_Flags
& QS_SMRESULT
)
895 Result
= Message
->lResult
;
898 /* Let the sender know the result. */
899 if (Message
->Result
!= NULL
)
901 *Message
->Result
= Result
;
904 if (Message
->HasPackedLParam
== TRUE
)
906 if (Message
->Msg
.lParam
)
907 ExFreePool((PVOID
)Message
->Msg
.lParam
);
910 /* Notify the sender. */
911 if (Message
->CompletionEvent
!= NULL
)
913 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
916 /* if the message has a sender */
917 if (Message
->SenderQueue
)
919 /* dereference our and the sender's message queue */
920 IntDereferenceMessageQueue(Message
->SenderQueue
);
921 IntDereferenceMessageQueue(MessageQueue
);
924 /* free the message */
925 ExFreePoolWithTag(Message
, TAG_USRMSG
);
927 /* do not hangup on the user if this is reentering */
928 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
929 pti
->pusmCurrent
= SaveMsg
;
935 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
937 PUSER_SENT_MESSAGE SentMessage
;
938 PUSER_MESSAGE PostedMessage
;
939 PUSER_MESSAGE_QUEUE MessageQueue
;
940 PLIST_ENTRY CurrentEntry
, ListHead
;
941 PWND Window
= pWindow
;
945 MessageQueue
= Window
->head
.pti
->MessageQueue
;
946 ASSERT(MessageQueue
);
948 /* remove the posted messages for this window */
949 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
950 ListHead
= &MessageQueue
->PostedMessagesListHead
;
951 while (CurrentEntry
!= ListHead
)
953 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
955 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
957 RemoveEntryList(&PostedMessage
->ListEntry
);
958 ClearMsgBitsMask(MessageQueue
, PostedMessage
->QS_Flags
);
959 MsqDestroyMessage(PostedMessage
);
960 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
964 CurrentEntry
= CurrentEntry
->Flink
;
968 /* remove the sent messages for this window */
969 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
970 ListHead
= &MessageQueue
->SentMessagesListHead
;
971 while (CurrentEntry
!= ListHead
)
973 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
975 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
977 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
979 RemoveEntryList(&SentMessage
->ListEntry
);
980 ClearMsgBitsMask(MessageQueue
, SentMessage
->QS_Flags
);
982 /* if it is a callback and this queue is not the sender queue, dereference queue */
983 if ((SentMessage
->CompletionCallback
) && (SentMessage
->CallBackSenderQueue
!= MessageQueue
))
985 IntDereferenceMessageQueue(SentMessage
->CallBackSenderQueue
);
987 /* Only if the message has a sender was the queue referenced */
988 if ((SentMessage
->SenderQueue
)
989 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
991 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
994 /* wake the sender's thread */
995 if (SentMessage
->CompletionEvent
!= NULL
)
997 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1000 if (SentMessage
->HasPackedLParam
== TRUE
)
1002 if (SentMessage
->Msg
.lParam
)
1003 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
1006 /* if the message has a sender */
1007 if (SentMessage
->SenderQueue
)
1009 /* dereference our and the sender's message queue */
1010 IntDereferenceMessageQueue(MessageQueue
);
1011 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
1014 /* free the message */
1015 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
1017 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
1021 CurrentEntry
= CurrentEntry
->Flink
;
1027 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
1032 SENDASYNCPROC CompletionCallback
,
1033 ULONG_PTR CompletionCallbackContext
,
1034 BOOL HasPackedLParam
,
1038 PTHREADINFO ptiSender
;
1039 PUSER_SENT_MESSAGE Message
;
1041 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1043 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1047 ptiSender
= PsGetCurrentThreadWin32Thread();
1049 IntReferenceMessageQueue(ptiReceiver
->MessageQueue
);
1050 /* Take reference on this MessageQueue if its a callback. It will be released
1051 when message is processed or removed from target hwnd MessageQueue */
1052 if (CompletionCallback
)
1053 IntReferenceMessageQueue(ptiSender
->MessageQueue
);
1055 Message
->Msg
.hwnd
= hwnd
;
1056 Message
->Msg
.message
= Msg
;
1057 Message
->Msg
.wParam
= wParam
;
1058 Message
->Msg
.lParam
= lParam
;
1059 Message
->CompletionEvent
= NULL
;
1060 Message
->Result
= 0;
1061 Message
->lResult
= 0;
1062 Message
->SenderQueue
= NULL
;
1063 Message
->CallBackSenderQueue
= ptiSender
->MessageQueue
;
1064 Message
->DispatchingListEntry
.Flink
= NULL
;
1065 Message
->CompletionCallback
= CompletionCallback
;
1066 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
1067 Message
->HookMessage
= HookMessage
;
1068 Message
->HasPackedLParam
= HasPackedLParam
;
1069 Message
->QS_Flags
= QS_SENDMESSAGE
;
1071 InsertTailList(&ptiReceiver
->MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1072 MsqWakeQueue(ptiReceiver
->MessageQueue
, QS_SENDMESSAGE
, TRUE
);
1073 IntDereferenceMessageQueue(ptiReceiver
->MessageQueue
);
1079 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1080 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
1081 UINT uTimeout
, BOOL Block
, INT HookMessage
,
1084 PTHREADINFO pti
, ptirec
;
1085 PUSER_SENT_MESSAGE Message
;
1086 KEVENT CompletionEvent
;
1087 NTSTATUS WaitStatus
;
1088 PUSER_MESSAGE_QUEUE ThreadQueue
;
1089 LARGE_INTEGER Timeout
;
1091 LRESULT Result
= 0; //// Result could be trashed. ////
1093 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1095 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1096 return STATUS_INSUFFICIENT_RESOURCES
;
1099 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1101 pti
= PsGetCurrentThreadWin32Thread();
1102 ThreadQueue
= pti
->MessageQueue
;
1103 ptirec
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1104 ASSERT(ThreadQueue
!= MessageQueue
);
1105 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
1107 /* Don't send from or to a dying thread */
1108 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
1111 return STATUS_TIMEOUT
;
1114 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1116 /* FIXME - increase reference counter of sender's message queue here */
1118 Message
->Msg
.hwnd
= Wnd
;
1119 Message
->Msg
.message
= Msg
;
1120 Message
->Msg
.wParam
= wParam
;
1121 Message
->Msg
.lParam
= lParam
;
1122 Message
->CompletionEvent
= &CompletionEvent
;
1123 Message
->Result
= &Result
;
1124 Message
->lResult
= 0;
1125 Message
->QS_Flags
= 0;
1126 Message
->SenderQueue
= ThreadQueue
;
1127 Message
->CallBackSenderQueue
= NULL
;
1128 IntReferenceMessageQueue(ThreadQueue
);
1129 Message
->CompletionCallback
= NULL
;
1130 Message
->CompletionCallbackContext
= 0;
1131 Message
->HookMessage
= HookMessage
;
1132 Message
->HasPackedLParam
= FALSE
;
1134 IntReferenceMessageQueue(MessageQueue
);
1136 /* add it to the list of pending messages */
1137 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1139 /* queue it in the destination's message queue */
1140 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1142 Message
->QS_Flags
= QS_SENDMESSAGE
;
1143 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
, TRUE
);
1145 /* we can't access the Message anymore since it could have already been deleted! */
1151 /* don't process messages sent to the thread */
1152 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1153 FALSE
, (uTimeout
? &Timeout
: NULL
));
1157 if(WaitStatus
== STATUS_TIMEOUT
)
1159 /* look up if the message has not yet dispatched, if so
1160 make sure it can't pass a result and it must not set the completion event anymore */
1161 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1162 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1164 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1167 /* we can access Message here, it's secure because the message queue is locked
1168 and the message is still hasn't been dispatched */
1169 Message
->CompletionEvent
= NULL
;
1170 Message
->Result
= NULL
;
1173 Entry
= Entry
->Flink
;
1176 /* remove from the local dispatching list so the other thread knows,
1177 it can't pass a result and it must not set the completion event anymore */
1178 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1179 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1181 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1184 /* we can access Message here, it's secure because the sender's message is locked
1185 and the message has definitely not yet been destroyed, otherwise it would
1186 have been removed from this list by the dispatching routine right after
1187 dispatching the message */
1188 Message
->CompletionEvent
= NULL
;
1189 Message
->Result
= NULL
;
1190 RemoveEntryList(&Message
->DispatchingListEntry
);
1191 Message
->DispatchingListEntry
.Flink
= NULL
;
1194 Entry
= Entry
->Flink
;
1197 TRACE("MsqSendMessage (blocked) timed out 1\n");
1199 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1204 PVOID WaitObjects
[2];
1206 WaitObjects
[0] = &CompletionEvent
;
1207 WaitObjects
[1] = ThreadQueue
->NewMessages
;
1212 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1213 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1217 if(WaitStatus
== STATUS_TIMEOUT
)
1219 /* look up if the message has not yet been dispatched, if so
1220 make sure it can't pass a result and it must not set the completion event anymore */
1221 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1222 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1224 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1227 /* we can access Message here, it's secure because the message queue is locked
1228 and the message is still hasn't been dispatched */
1229 Message
->CompletionEvent
= NULL
;
1230 Message
->Result
= NULL
;
1233 Entry
= Entry
->Flink
;
1236 /* remove from the local dispatching list so the other thread knows,
1237 it can't pass a result and it must not set the completion event anymore */
1238 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1239 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1241 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1244 /* we can access Message here, it's secure because the sender's message is locked
1245 and the message has definitely not yet been destroyed, otherwise it would
1246 have been removed from this list by the dispatching routine right after
1247 dispatching the message */
1248 Message
->CompletionEvent
= NULL
;
1249 Message
->Result
= NULL
;
1250 RemoveEntryList(&Message
->DispatchingListEntry
);
1251 Message
->DispatchingListEntry
.Flink
= NULL
;
1254 Entry
= Entry
->Flink
;
1257 TRACE("MsqSendMessage timed out 2\n");
1260 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1263 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
1266 if(WaitStatus
!= STATUS_TIMEOUT
)
1267 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1273 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
1276 PUSER_MESSAGE Message
;
1278 if(!(Message
= MsqCreateMessage(Msg
)))
1283 if(!HardwareMessage
)
1285 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1286 &Message
->ListEntry
);
1290 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1291 &Message
->ListEntry
);
1293 update_input_key_state( MessageQueue
, Msg
);
1296 Message
->QS_Flags
= MessageBits
;
1297 MsqWakeQueue(MessageQueue
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
1301 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1303 MessageQueue
->QuitPosted
= TRUE
;
1304 MessageQueue
->QuitExitCode
= ExitCode
;
1305 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1308 /***********************************************************************
1309 * MsqSendParentNotify
1311 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1312 * the window has the WS_EX_NOPARENTNOTIFY style.
1314 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1316 PWND pwndDesktop
= UserGetWindowObject(IntGetDesktopWindow());
1318 /* pt has to be in the client coordinates of the parent window */
1319 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1320 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1326 if (!(pwnd
->style
& WS_CHILD
)) break;
1327 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1328 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1329 if (pwndParent
== pwndDesktop
) break;
1330 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1331 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1334 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1335 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1339 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1346 MOUSEHOOKSTRUCT hook
;
1349 PWND pwndMsg
, pwndDesktop
;
1350 PUSER_MESSAGE_QUEUE MessageQueue
;
1352 PSYSTEM_CURSORINFO CurInfo
;
1354 DECLARE_RETURN(BOOL
);
1356 pti
= PsGetCurrentThreadWin32Thread();
1357 pwndDesktop
= UserGetDesktopWindow();
1358 MessageQueue
= pti
->MessageQueue
;
1359 CurInfo
= IntGetSysCursorInfo();
1360 pwndMsg
= UserGetWindowObject(msg
->hwnd
);
1361 clk_msg
= MessageQueue
->msgDblClk
;
1362 pDesk
= pwndDesktop
->head
.rpdesk
;
1364 /* find the window to dispatch this mouse message to */
1365 if (MessageQueue
->CaptureWindow
)
1368 pwndMsg
= IntGetWindowObject(MessageQueue
->CaptureWindow
);
1372 pwndMsg
= co_WinPosWindowFromPoint(pwndMsg
, &msg
->pt
, &hittest
);
1375 TRACE("Got mouse message for 0x%x, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1377 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
1379 /* Remove and ignore the message */
1380 *RemoveMessages
= TRUE
;
1384 /* If we a re tracking the mouse and it moves to another window */
1385 if(pDesk
->spwndTrack
&&
1386 pDesk
->spwndTrack
!= pwndMsg
&&
1387 msg
->message
!= WM_MOUSELEAVE
)
1389 /* Generate a WM_MOUSELEAVE message */
1390 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1394 TRACE("co_IntProcessMouseMessage: generating WM_MOUSELEAVE\n");
1396 msgMouseLeave
.hwnd
= UserHMGetHandle(pDesk
->spwndTrack
);
1397 msgMouseLeave
.message
= WM_MOUSELEAVE
;
1398 msgMouseLeave
.pt
= msg
->pt
;
1399 msgMouseLeave
.time
= msg
->time
;
1400 msgMouseLeave
.lParam
= msgMouseLeave
.wParam
= 0;
1402 MsqPostMessage(pwndMsg
->head
.pti
->MessageQueue
,
1409 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1411 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1414 pDesk
->spwndTrack
= NULL
;
1418 if(pDesk
->spwndTrack
)
1420 pDesk
->htEx
= hittest
;
1423 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1426 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
1430 message
= msg
->message
;
1431 /* Note: windows has no concept of a non-client wheel message */
1432 if (message
!= WM_MOUSEWHEEL
)
1434 if (hittest
!= HTCLIENT
)
1436 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1437 msg
->wParam
= hittest
;
1441 /* coordinates don't get translated while tracking a menu */
1442 /* FIXME: should differentiate popups and top-level menus */
1443 if (!(MessageQueue
->MenuOwner
))
1445 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1446 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1450 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1452 /* translate double clicks */
1454 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1455 (msg
->message
== WM_RBUTTONDOWN
) ||
1456 (msg
->message
== WM_MBUTTONDOWN
) ||
1457 (msg
->message
== WM_XBUTTONDOWN
))
1459 BOOL update
= *RemoveMessages
;
1461 /* translate double clicks -
1462 * note that ...MOUSEMOVEs can slip in between
1463 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1465 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1466 hittest
!= HTCLIENT
||
1467 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1469 if ((msg
->message
== clk_msg
.message
) &&
1470 (msg
->hwnd
== clk_msg
.hwnd
) &&
1471 (msg
->wParam
== clk_msg
.wParam
) &&
1472 (msg
->time
- clk_msg
.time
< gspv
.iDblClickTime
) &&
1473 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1474 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1476 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1479 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1485 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1487 TRACE("Message out of range!!!\n");
1491 /* update static double click conditions */
1492 if (update
) MessageQueue
->msgDblClk
= *msg
;
1496 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1498 TRACE("Message out of range!!!\n");
1503 if(gspv
.bMouseClickLock
)
1505 BOOL IsClkLck
= FALSE
;
1507 if(msg
->message
== WM_LBUTTONUP
)
1509 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1510 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1512 CurInfo
->ClickLockActive
= TRUE
;
1515 else if (msg
->message
== WM_LBUTTONDOWN
)
1517 if (CurInfo
->ClickLockActive
)
1520 CurInfo
->ClickLockActive
= FALSE
;
1523 CurInfo
->ClickLockTime
= msg
->time
;
1528 /* Remove and ignore the message */
1529 *RemoveMessages
= TRUE
;
1534 /* message is accepted now (but may still get dropped) */
1536 event
.message
= msg
->message
;
1537 event
.time
= msg
->time
;
1538 event
.hwnd
= msg
->hwnd
;
1539 event
.paramL
= msg
->pt
.x
;
1540 event
.paramH
= msg
->pt
.y
;
1541 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1544 hook
.hwnd
= msg
->hwnd
;
1545 hook
.wHitTestCode
= hittest
;
1546 hook
.dwExtraInfo
= 0/*extra_info*/;
1547 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1548 message
, (LPARAM
)&hook
))
1551 hook
.hwnd
= msg
->hwnd
;
1552 hook
.wHitTestCode
= hittest
;
1553 hook
.dwExtraInfo
= 0/*extra_info*/;
1554 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1556 ERR("WH_MOUSE dorpped mouse message!\n");
1558 /* Remove and skip message */
1559 *RemoveMessages
= TRUE
;
1563 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1565 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1566 MAKELONG( hittest
, msg
->message
));
1568 /* Remove and skip message */
1569 *RemoveMessages
= TRUE
;
1573 if ((*RemoveMessages
== FALSE
) || MessageQueue
->CaptureWindow
)
1575 /* Accept the message */
1576 msg
->message
= message
;
1582 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1583 (msg
->message
== WM_RBUTTONDOWN
) ||
1584 (msg
->message
== WM_MBUTTONDOWN
) ||
1585 (msg
->message
== WM_XBUTTONDOWN
))
1587 /* Send the WM_PARENTNOTIFY,
1588 * note that even for double/nonclient clicks
1589 * notification message is still WM_L/M/RBUTTONDOWN.
1591 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1593 /* Activate the window if needed */
1595 if (msg
->hwnd
!= UserGetForegroundWindow())
1597 PWND pwndTop
= pwndMsg
;
1600 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
1601 pwndTop
= IntGetParent( pwndTop
);
1604 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1606 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1608 (WPARAM
)UserHMGetHandle(pwndTop
),
1609 MAKELONG( hittest
, msg
->message
));
1612 case MA_NOACTIVATEANDEAT
:
1617 case MA_ACTIVATEANDEAT
:
1622 if(!co_IntMouseActivateWindow(pwndMsg
)) eatMsg
= TRUE
;
1625 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1632 /* send the WM_SETCURSOR message */
1634 /* Windows sends the normal mouse message as the message parameter
1635 in the WM_SETCURSOR message even if it's non-client mouse message */
1636 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1638 msg
->message
= message
;
1643 UserDereferenceObject(pwndMsg
);
1648 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1652 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1653 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1655 switch (Msg
->wParam
)
1657 case VK_LSHIFT
: case VK_RSHIFT
:
1658 Msg
->wParam
= VK_SHIFT
;
1660 case VK_LCONTROL
: case VK_RCONTROL
:
1661 Msg
->wParam
= VK_CONTROL
;
1663 case VK_LMENU
: case VK_RMENU
:
1664 Msg
->wParam
= VK_MENU
;
1669 Event
.message
= Msg
->message
;
1670 Event
.hwnd
= Msg
->hwnd
;
1671 Event
.time
= Msg
->time
;
1672 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1673 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1674 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1675 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1677 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1678 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1679 LOWORD(Msg
->wParam
),
1682 /* skip this message */
1683 co_HOOK_CallHooks( WH_CBT
,
1685 LOWORD(Msg
->wParam
),
1687 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1693 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1695 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1697 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1699 else if ( IS_KBD_MESSAGE(Msg
->message
))
1701 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1708 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1711 IN UINT MsgFilterLow
,
1712 IN UINT MsgFilterHigh
,
1718 if(!(MessageQueue
->MouseMoved
))
1721 msg
= MessageQueue
->MouseMoveMsg
;
1723 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1730 ClearMsgBitsMask(MessageQueue
, QS_MOUSEMOVE
);
1731 MessageQueue
->MouseMoved
= FALSE
;
1734 return AcceptMessage
;
1737 /* check whether a message filter contains at least one potential hardware message */
1739 filter_contains_hw_range( UINT first
, UINT last
)
1741 /* hardware message ranges are (in numerical order):
1742 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1743 * WM_KEYFIRST .. WM_KEYLAST
1744 * WM_MOUSEFIRST .. WM_MOUSELAST
1747 if (last
< WM_NCMOUSEFIRST
) return 0;
1748 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1749 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1750 if (first
> WM_MOUSELAST
) return 0;
1755 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1758 IN UINT MsgFilterLow
,
1759 IN UINT MsgFilterHigh
,
1765 PUSER_MESSAGE CurrentMessage
;
1766 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1769 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1771 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1772 CurrentEntry
= ListHead
->Flink
;
1774 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1776 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1780 if (IsListEmpty(CurrentEntry
)) break;
1781 if (!CurrentMessage
) break;
1782 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1785 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1786 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1787 3: handle to the window whose messages are to be retrieved.
1789 if ( ( !Window
|| // 1
1790 ( Window
== HWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1791 ( Window
!= HWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1792 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1793 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1795 msg
= CurrentMessage
->Msg
;
1797 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1801 update_input_key_state(MessageQueue
, &msg
);
1802 RemoveEntryList(&CurrentMessage
->ListEntry
);
1803 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1804 MsqDestroyMessage(CurrentMessage
);
1813 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1816 while(CurrentEntry
!= ListHead
);
1822 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1825 IN UINT MsgFilterLow
,
1826 IN UINT MsgFilterHigh
,
1830 PLIST_ENTRY CurrentEntry
;
1831 PUSER_MESSAGE CurrentMessage
;
1832 PLIST_ENTRY ListHead
;
1834 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1835 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1837 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1839 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1843 if (IsListEmpty(CurrentEntry
)) break;
1844 if (!CurrentMessage
) break;
1845 CurrentEntry
= CurrentEntry
->Flink
;
1848 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1849 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1850 3: handle to the window whose messages are to be retrieved.
1852 if ( ( !Window
|| // 1
1853 ( Window
== HWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1854 ( Window
!= HWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1855 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1856 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1858 *Message
= CurrentMessage
->Msg
;
1862 RemoveEntryList(&CurrentMessage
->ListEntry
);
1863 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1864 MsqDestroyMessage(CurrentMessage
);
1868 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1871 while (CurrentEntry
!= ListHead
);
1877 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1878 UINT MsgFilterMin
, UINT MsgFilterMax
)
1882 ret
= KeWaitForSingleObject( MessageQueue
->NewMessages
,
1892 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1894 LARGE_INTEGER LargeTickCount
;
1896 KeQueryTickCount(&LargeTickCount
);
1897 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1902 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1905 TRACE("HungAppSysTimerProc\n");
1906 // Process list of windows that are hung and waiting.
1910 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1912 LARGE_INTEGER LargeTickCount
;
1915 MessageQueue
->Thread
= Thread
;
1916 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1917 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1918 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1919 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1920 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1921 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1922 MessageQueue
->QuitPosted
= FALSE
;
1923 MessageQueue
->QuitExitCode
= 0;
1924 KeQueryTickCount(&LargeTickCount
);
1925 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1926 MessageQueue
->FocusWindow
= NULL
;
1927 MessageQueue
->NewMessagesHandle
= NULL
;
1928 MessageQueue
->ShowingCursor
= 0;
1929 MessageQueue
->CursorObject
= NULL
;
1931 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1932 NULL
, SynchronizationEvent
, FALSE
);
1933 if (!NT_SUCCESS(Status
))
1938 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1939 ExEventObjectType
, KernelMode
,
1940 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1941 if (!NT_SUCCESS(Status
))
1943 ZwClose(MessageQueue
->NewMessagesHandle
);
1944 MessageQueue
->NewMessagesHandle
= NULL
;
1952 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1954 PLIST_ENTRY CurrentEntry
;
1955 PUSER_MESSAGE CurrentMessage
;
1956 PUSER_SENT_MESSAGE CurrentSentMessage
;
1959 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1962 /* cleanup posted messages */
1963 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1965 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1966 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1968 MsqDestroyMessage(CurrentMessage
);
1971 /* remove the messages that have not yet been dispatched */
1972 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1974 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1975 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1978 /* if it is a callback and this queue is not the sender queue, dereference queue */
1979 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
1981 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
1984 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
1985 /* Only if the message has a sender was the message in the DispatchingList */
1986 if ((CurrentSentMessage
->SenderQueue
)
1987 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1989 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1992 /* wake the sender's thread */
1993 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1995 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1998 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
2000 if (CurrentSentMessage
->Msg
.lParam
)
2001 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2004 /* if the message has a sender */
2005 if (CurrentSentMessage
->SenderQueue
)
2007 /* dereference our and the sender's message queue */
2008 IntDereferenceMessageQueue(MessageQueue
);
2009 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
2012 /* free the message */
2013 ExFreePool(CurrentSentMessage
);
2016 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
2017 ExitThread() was called in a SendMessage() umode callback */
2018 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
2020 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
2021 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2024 /* if it is a callback and this queue is not the sender queue, dereference queue */
2025 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
2027 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
2030 /* remove the message from the dispatching list */
2031 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
2033 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
2036 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
2038 /* wake the sender's thread */
2039 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
2041 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2044 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
2046 if (CurrentSentMessage
->Msg
.lParam
)
2047 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2050 /* if the message has a sender */
2051 if (CurrentSentMessage
->SenderQueue
)
2053 /* dereference our and the sender's message queue */
2054 IntDereferenceMessageQueue(MessageQueue
);
2055 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
2058 /* free the message */
2059 ExFreePool(CurrentSentMessage
);
2062 /* tell other threads not to bother returning any info to us */
2063 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
2065 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
2066 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2067 DispatchingListEntry
);
2068 CurrentSentMessage
->CompletionEvent
= NULL
;
2069 CurrentSentMessage
->Result
= NULL
;
2071 /* do NOT dereference our message queue as it might get attempted to be
2075 // Clear it all out.
2078 pti
->pcti
->fsWakeBits
= 0;
2079 pti
->pcti
->fsChangeBits
= 0;
2082 MessageQueue
->nCntsQBits
[QSRosKey
] = 0;
2083 MessageQueue
->nCntsQBits
[QSRosMouseMove
] = 0;
2084 MessageQueue
->nCntsQBits
[QSRosMouseButton
] = 0;
2085 MessageQueue
->nCntsQBits
[QSRosPostMessage
] = 0;
2086 MessageQueue
->nCntsQBits
[QSRosSendMessage
] = 0;
2087 MessageQueue
->nCntsQBits
[QSRosHotKey
] = 0;
2089 if (MessageQueue
->CursorObject
)
2091 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2093 /* Change to another cursor if we going to dereference current one */
2094 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2095 UserSetCursor(NULL
, TRUE
);
2097 UserDereferenceObject(pCursor
);
2102 PUSER_MESSAGE_QUEUE FASTCALL
2103 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
2105 PUSER_MESSAGE_QUEUE MessageQueue
;
2107 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2108 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2116 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2117 /* hold at least one reference until it'll be destroyed */
2118 IntReferenceMessageQueue(MessageQueue
);
2119 /* initialize the queue */
2120 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
2122 IntDereferenceMessageQueue(MessageQueue
);
2126 return MessageQueue
;
2130 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
2134 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2136 /* remove the message queue from any desktops */
2137 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2139 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2140 IntDereferenceMessageQueue(MessageQueue
);
2144 MsqCleanupMessageQueue(MessageQueue
);
2146 if (MessageQueue
->NewMessagesHandle
!= NULL
)
2147 ZwClose(MessageQueue
->NewMessagesHandle
);
2148 MessageQueue
->NewMessagesHandle
= NULL
;
2149 /* decrease the reference counter, if it hits zero, the queue will be freed */
2150 IntDereferenceMessageQueue(MessageQueue
);
2154 MsqSetMessageExtraInfo(LPARAM lParam
)
2158 PUSER_MESSAGE_QUEUE MessageQueue
;
2160 pti
= PsGetCurrentThreadWin32Thread();
2161 MessageQueue
= pti
->MessageQueue
;
2167 Ret
= MessageQueue
->ExtraInfo
;
2168 MessageQueue
->ExtraInfo
= lParam
;
2174 MsqGetMessageExtraInfo(VOID
)
2177 PUSER_MESSAGE_QUEUE MessageQueue
;
2179 pti
= PsGetCurrentThreadWin32Thread();
2180 MessageQueue
= pti
->MessageQueue
;
2186 return MessageQueue
->ExtraInfo
;
2189 // ReplyMessage is called by the thread receiving the window message.
2191 co_MsqReplyMessage( LRESULT lResult
)
2193 PUSER_SENT_MESSAGE Message
;
2196 pti
= PsGetCurrentThreadWin32Thread();
2197 Message
= pti
->pusmCurrent
;
2199 if (!Message
) return FALSE
;
2201 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2203 // SendMessageXxx || Callback msg and not a notify msg
2204 if (Message
->SenderQueue
|| Message
->CompletionCallback
)
2206 Message
->lResult
= lResult
;
2207 Message
->QS_Flags
|= QS_SMRESULT
;
2208 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2214 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
2220 case MSQ_STATE_CAPTURE
:
2221 Prev
= MessageQueue
->CaptureWindow
;
2222 MessageQueue
->CaptureWindow
= hWnd
;
2224 case MSQ_STATE_ACTIVE
:
2225 Prev
= MessageQueue
->ActiveWindow
;
2226 MessageQueue
->ActiveWindow
= hWnd
;
2228 case MSQ_STATE_FOCUS
:
2229 Prev
= MessageQueue
->FocusWindow
;
2230 MessageQueue
->FocusWindow
= hWnd
;
2232 case MSQ_STATE_MENUOWNER
:
2233 Prev
= MessageQueue
->MenuOwner
;
2234 MessageQueue
->MenuOwner
= hWnd
;
2236 case MSQ_STATE_MOVESIZE
:
2237 Prev
= MessageQueue
->MoveSize
;
2238 MessageQueue
->MoveSize
= hWnd
;
2240 case MSQ_STATE_CARET
:
2241 ASSERT(MessageQueue
->CaretInfo
);
2242 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2243 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2252 NtUserGetKeyState(INT key
)
2256 UserEnterExclusive();
2258 Ret
= UserGetKeyState(key
);
2268 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2272 PUSER_MESSAGE_QUEUE MessageQueue
;
2276 pti
= PsGetCurrentThreadWin32Thread();
2277 MessageQueue
= pti
->MessageQueue
;
2281 ProbeForWrite(lpKeyState
,sizeof(MessageQueue
->KeyState
) ,1);
2282 RtlCopyMemory(lpKeyState
,MessageQueue
->KeyState
,sizeof(MessageQueue
->KeyState
));
2284 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2286 SetLastNtError(_SEH2_GetExceptionCode());
2298 NtUserSetKeyboardState(LPBYTE lpKeyState
)
2302 PUSER_MESSAGE_QUEUE MessageQueue
;
2304 UserEnterExclusive();
2306 pti
= PsGetCurrentThreadWin32Thread();
2307 MessageQueue
= pti
->MessageQueue
;
2311 ProbeForRead(lpKeyState
,sizeof(MessageQueue
->KeyState
) ,1);
2312 RtlCopyMemory(MessageQueue
->KeyState
,lpKeyState
,sizeof(MessageQueue
->KeyState
));
2314 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2316 SetLastNtError(_SEH2_GetExceptionCode());