2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Message queues
5 * FILE: subsystems/win32/win32k/ntuser/msgqueue.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
12 DBG_DEFAULT_CHANNEL(UserMsgQ
);
14 /* GLOBALS *******************************************************************/
16 static PPAGED_LOOKASIDE_LIST pgMessageLookasideList
;
17 PUSER_MESSAGE_QUEUE gpqCursor
;
19 /* FUNCTIONS *****************************************************************/
24 MsqInitializeImpl(VOID
)
26 pgMessageLookasideList
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(PAGED_LOOKASIDE_LIST
), TAG_USRMSG
);
27 if(!pgMessageLookasideList
)
28 return STATUS_NO_MEMORY
;
29 ExInitializePagedLookasideList(pgMessageLookasideList
,
37 return(STATUS_SUCCESS
);
41 IntChildrenWindowFromPoint(PWND pWndTop
, INT x
, INT y
)
45 if (!(pWndTop
->style
& WS_VISIBLE
)) return NULL
;
46 if ((pWndTop
->style
& WS_DISABLED
)) return NULL
;
47 if (!IntPtInWindow(pWndTop
, x
, y
)) return NULL
;
49 if (x
- pWndTop
->rcClient
.left
< pWndTop
->rcClient
.right
&&
50 y
- pWndTop
->rcClient
.top
< pWndTop
->rcClient
.bottom
)
52 for (pWnd
= pWndTop
->spwndChild
;
54 pWnd
= pWnd
->spwndNext
)
56 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
58 TRACE("The Window is in DESTROY!\n");
62 pWndChild
= IntChildrenWindowFromPoint(pWnd
, x
, y
);
74 IntTopLevelWindowFromPoint(INT x
, INT y
)
76 PWND pWnd
, pwndDesktop
;
78 /* Get the desktop window */
79 pwndDesktop
= UserGetDesktopWindow();
83 /* Loop all top level windows */
84 for (pWnd
= pwndDesktop
->spwndChild
;
86 pWnd
= pWnd
->spwndNext
)
88 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
90 TRACE("The Window is in DESTROY!\n");
94 if ((pWnd
->style
& WS_VISIBLE
) && IntPtInWindow(pWnd
, x
, y
))
98 /* Window has not been found */
105 PCURICON_OBJECT NewCursor
,
108 PCURICON_OBJECT OldCursor
;
111 PUSER_MESSAGE_QUEUE MessageQueue
;
114 pti
= PsGetCurrentThreadWin32Thread();
115 MessageQueue
= pti
->MessageQueue
;
117 /* Get the screen DC */
118 if(!(hdcScreen
= IntGetScreenDC()))
123 OldCursor
= MessageQueue
->CursorObject
;
125 /* Check if cursors are different */
126 if (OldCursor
== NewCursor
)
129 /* Update cursor for this message queue */
130 MessageQueue
->CursorObject
= NewCursor
;
132 /* If cursor is not visible we have nothing to do */
133 if (MessageQueue
->ShowingCursor
< 0)
136 /* Update cursor if this message queue controls it */
137 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
138 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
142 /* Call GDI to set the new screen cursor */
143 GreSetPointerShape(hdcScreen
,
144 NewCursor
->IconInfo
.hbmMask
,
145 NewCursor
->IconInfo
.hbmColor
,
146 NewCursor
->IconInfo
.xHotspot
,
147 NewCursor
->IconInfo
.yHotspot
,
151 else /* Note: OldCursor != NewCursor so we have to hide cursor */
153 /* Remove the cursor */
154 GreMovePointer(hdcScreen
, -1, -1);
155 TRACE("Removing pointer!\n");
157 IntGetSysCursorInfo()->CurrentCursorObject
= NewCursor
;
160 /* Return the old cursor */
164 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
165 * User32 macro NtUserShowCursor */
166 int UserShowCursor(BOOL bShow
)
170 PUSER_MESSAGE_QUEUE MessageQueue
;
173 if (!(hdcScreen
= IntGetScreenDC()))
175 return -1; /* No mouse */
178 pti
= PsGetCurrentThreadWin32Thread();
179 MessageQueue
= pti
->MessageQueue
;
182 MessageQueue
->ShowingCursor
+= bShow
? 1 : -1;
184 /* Check for trivial cases */
185 if ((bShow
&& MessageQueue
->ShowingCursor
!= 0) ||
186 (!bShow
&& MessageQueue
->ShowingCursor
!= -1))
188 /* Note: w don't update global info here because it is used only
189 internally to check if cursor is visible */
190 return MessageQueue
->ShowingCursor
;
193 /* Check if cursor is above window owned by this MessageQueue */
194 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
195 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
199 /* Show the pointer */
200 GreMovePointer(hdcScreen
, gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
201 TRACE("Showing pointer!\n");
205 /* Remove the pointer */
206 GreMovePointer(hdcScreen
, -1, -1);
207 TRACE("Removing pointer!\n");
210 /* Update global info */
211 IntGetSysCursorInfo()->ShowingCursor
= MessageQueue
->ShowingCursor
;
214 return MessageQueue
->ShowingCursor
;
218 UserGetKeyState(DWORD dwKey
)
222 PUSER_MESSAGE_QUEUE MessageQueue
;
224 pti
= PsGetCurrentThreadWin32Thread();
225 MessageQueue
= pti
->MessageQueue
;
229 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, dwKey
))
230 dwRet
|= 0xFF80; // If down, windows returns 0xFF80.
231 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, dwKey
))
236 EngSetLastError(ERROR_INVALID_PARAMETER
);
241 /* change the input key state for a given key */
243 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue
, WORD wVk
, BOOL bIsDown
)
245 TRACE("UpdateKeyState wVk: %d, bIsDown: %d\n", wVk
, bIsDown
);
249 /* If it's first key down event, xor lock bit */
250 if (!IS_KEY_DOWN(MessageQueue
->afKeyState
, wVk
))
251 SET_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
, !IS_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
));
253 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, TRUE
);
254 MessageQueue
->afKeyRecentDown
[wVk
/ 8] |= (1 << (wVk
% 8));
257 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, FALSE
);
260 /* update the input key state for a keyboard message */
262 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
267 TRACE("UpdateKeyStateFromMsg message:%d\n", msg
->message
);
269 switch (msg
->message
)
275 UpdateKeyState(MessageQueue
, VK_LBUTTON
, down
);
281 UpdateKeyState(MessageQueue
, VK_MBUTTON
, down
);
287 UpdateKeyState(MessageQueue
, VK_RBUTTON
, down
);
293 if (msg
->wParam
== XBUTTON1
)
294 UpdateKeyState(MessageQueue
, VK_XBUTTON1
, down
);
295 else if (msg
->wParam
== XBUTTON2
)
296 UpdateKeyState(MessageQueue
, VK_XBUTTON2
, down
);
304 key
= (UCHAR
)msg
->wParam
;
305 UpdateKeyState(MessageQueue
, key
, down
);
310 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LCONTROL
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RCONTROL
);
311 UpdateKeyState(MessageQueue
, VK_CONTROL
, down
);
315 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LMENU
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RMENU
);
316 UpdateKeyState(MessageQueue
, VK_MENU
, down
);
320 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LSHIFT
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RSHIFT
);
321 UpdateKeyState(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
;
538 hdcScreen
= IntGetScreenDC();
539 CurInfo
= IntGetSysCursorInfo();
541 /* Check if we found a window */
542 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
544 if (Msg
->message
== WM_MOUSEMOVE
)
546 PUSER_MESSAGE_QUEUE MessageQueue
= pwnd
->head
.pti
->MessageQueue
;
548 /* Check if cursor should be visible */
550 MessageQueue
->CursorObject
&&
551 MessageQueue
->ShowingCursor
>= 0)
553 /* Check if shape has changed */
554 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
556 /* Call GDI to set the new screen cursor */
557 GreSetPointerShape(hdcScreen
,
558 MessageQueue
->CursorObject
->IconInfo
.hbmMask
,
559 MessageQueue
->CursorObject
->IconInfo
.hbmColor
,
560 MessageQueue
->CursorObject
->IconInfo
.xHotspot
,
561 MessageQueue
->CursorObject
->IconInfo
.yHotspot
,
565 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
567 /* Check if w have to hide cursor */
568 else if (CurInfo
->ShowingCursor
>= 0)
569 GreMovePointer(hdcScreen
, -1, -1);
571 /* Update global cursor info */
572 CurInfo
->ShowingCursor
= MessageQueue
->ShowingCursor
;
573 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
574 gpqCursor
= MessageQueue
;
576 /* Mouse move is a special case */
577 MsqPostMouseMove(MessageQueue
, Msg
);
581 TRACE("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd
));
582 MsqPostMessage(pwnd
->head
.pti
->MessageQueue
, Msg
, TRUE
, QS_MOUSEBUTTON
);
587 /* always show cursor on background; FIXME: set default pointer */
588 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
589 CurInfo
->ShowingCursor
= 0;
594 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
597 PTHREADINFO Win32Thread
;
599 LARGE_INTEGER LargeTickCount
;
604 Status
= ObReferenceObjectByPointer (Thread
,
608 if (!NT_SUCCESS(Status
))
611 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
612 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
614 ObDereferenceObject ((PETHREAD
)Thread
);
618 Window
= IntGetWindowObject(hWnd
);
621 ObDereferenceObject ((PETHREAD
)Thread
);
625 id
= wParam
; // Check for hot keys unrelated to the hot keys set by RegisterHotKey.
628 Mesg
.message
= id
!= IDHK_REACTOS
? WM_HOTKEY
: WM_SYSCOMMAND
;
629 Mesg
.wParam
= id
!= IDHK_REACTOS
? wParam
: SC_HOTKEY
;
630 Mesg
.lParam
= id
!= IDHK_REACTOS
? lParam
: (LPARAM
)hWnd
;
631 Type
= id
!= IDHK_REACTOS
? QS_HOTKEY
: QS_POSTMESSAGE
;
632 KeQueryTickCount(&LargeTickCount
);
633 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
634 Mesg
.pt
= gpsi
->ptCursor
;
635 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, Type
);
636 UserDereferenceObject(Window
);
637 ObDereferenceObject (Thread
);
641 PUSER_MESSAGE FASTCALL
642 MsqCreateMessage(LPMSG Msg
)
644 PUSER_MESSAGE Message
;
646 Message
= ExAllocateFromPagedLookasideList(pgMessageLookasideList
);
652 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
658 MsqDestroyMessage(PUSER_MESSAGE Message
)
660 ExFreeToPagedLookasideList(pgMessageLookasideList
, Message
);
664 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
666 PUSER_SENT_MESSAGE SaveMsg
, Message
;
672 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
677 /* remove it from the list of pending messages */
678 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
679 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
681 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
683 SaveMsg
= pti
->pusmCurrent
;
684 pti
->pusmCurrent
= Message
;
686 // Processing a message sent to it from another thread.
687 if ( ( Message
->SenderQueue
&& MessageQueue
!= Message
->SenderQueue
) ||
688 ( Message
->CallBackSenderQueue
&& MessageQueue
!= Message
->CallBackSenderQueue
))
689 { // most likely, but, to be sure.
690 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
693 /* insert it to the list of messages that are currently dispatched by this
695 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
696 &Message
->ListEntry
);
698 ClearMsgBitsMask(MessageQueue
, Message
->QS_Flags
);
700 if (Message
->HookMessage
== MSQ_ISHOOK
)
701 { // Direct Hook Call processor
702 Result
= co_CallHook( Message
->Msg
.message
, // HookId
703 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
705 Message
->Msg
.lParam
);
707 else if (Message
->HookMessage
== MSQ_ISEVENT
)
708 { // Direct Event Call processor
709 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
712 Message
->Msg
.lParam
);
714 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
716 Result
= IntLoadHookModule(Message
->Msg
.message
,
717 (HHOOK
)Message
->Msg
.lParam
,
718 Message
->Msg
.wParam
);
720 else if ((Message
->CompletionCallback
)
721 && (Message
->CallBackSenderQueue
== MessageQueue
))
722 { /* Call the callback routine */
723 if (Message
->QS_Flags
& QS_SMRESULT
)
725 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
727 Message
->Msg
.message
,
728 Message
->CompletionCallbackContext
,
730 /* Set callback to NULL to prevent reentry */
731 Message
->CompletionCallback
= NULL
;
735 /* The message has not been processed yet, reinsert it. */
736 RemoveEntryList(&Message
->ListEntry
);
737 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
738 TRACE("Callback Message not processed yet. Requeuing the message\n");
744 { /* Call the window procedure. */
745 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
746 Message
->Msg
.message
,
748 Message
->Msg
.lParam
);
751 /* remove the message from the local dispatching list, because it doesn't need
752 to be cleaned up on thread termination anymore */
753 RemoveEntryList(&Message
->ListEntry
);
755 /* If the message is a callback, insert it in the callback senders MessageQueue */
756 if (Message
->CompletionCallback
)
758 if (Message
->CallBackSenderQueue
)
760 Message
->lResult
= Result
;
761 Message
->QS_Flags
|= QS_SMRESULT
;
763 /* insert it in the callers message queue */
764 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
765 MsqWakeQueue(Message
->CallBackSenderQueue
, QS_SENDMESSAGE
, TRUE
);
766 IntDereferenceMessageQueue(Message
->CallBackSenderQueue
);
772 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
773 if (Message
->SenderQueue
)
775 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
777 /* only remove it from the dispatching list if not already removed by a timeout */
778 RemoveEntryList(&Message
->DispatchingListEntry
);
781 /* still keep the sender's message queue locked, so the sender can't exit the
782 MsqSendMessage() function (if timed out) */
784 if (Message
->QS_Flags
& QS_SMRESULT
)
786 Result
= Message
->lResult
;
789 /* Let the sender know the result. */
790 if (Message
->Result
!= NULL
)
792 *Message
->Result
= Result
;
795 if (Message
->HasPackedLParam
== TRUE
)
797 if (Message
->Msg
.lParam
)
798 ExFreePool((PVOID
)Message
->Msg
.lParam
);
801 /* Notify the sender. */
802 if (Message
->CompletionEvent
!= NULL
)
804 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
807 /* if the message has a sender */
808 if (Message
->SenderQueue
)
810 /* dereference our and the sender's message queue */
811 IntDereferenceMessageQueue(Message
->SenderQueue
);
812 IntDereferenceMessageQueue(MessageQueue
);
815 /* free the message */
816 ExFreePoolWithTag(Message
, TAG_USRMSG
);
819 /* do not hangup on the user if this is reentering */
820 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
821 pti
->pusmCurrent
= SaveMsg
;
827 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
829 PUSER_SENT_MESSAGE SentMessage
;
830 PUSER_MESSAGE PostedMessage
;
831 PUSER_MESSAGE_QUEUE MessageQueue
;
832 PLIST_ENTRY CurrentEntry
, ListHead
;
833 PWND Window
= pWindow
;
837 MessageQueue
= Window
->head
.pti
->MessageQueue
;
838 ASSERT(MessageQueue
);
840 /* remove the posted messages for this window */
841 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
842 ListHead
= &MessageQueue
->PostedMessagesListHead
;
843 while (CurrentEntry
!= ListHead
)
845 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
847 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
849 RemoveEntryList(&PostedMessage
->ListEntry
);
850 ClearMsgBitsMask(MessageQueue
, PostedMessage
->QS_Flags
);
851 MsqDestroyMessage(PostedMessage
);
852 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
856 CurrentEntry
= CurrentEntry
->Flink
;
860 /* remove the sent messages for this window */
861 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
862 ListHead
= &MessageQueue
->SentMessagesListHead
;
863 while (CurrentEntry
!= ListHead
)
865 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
867 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
869 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
871 RemoveEntryList(&SentMessage
->ListEntry
);
872 ClearMsgBitsMask(MessageQueue
, SentMessage
->QS_Flags
);
874 /* if it is a callback and this queue is not the sender queue, dereference queue */
875 if ((SentMessage
->CompletionCallback
) && (SentMessage
->CallBackSenderQueue
!= MessageQueue
))
877 IntDereferenceMessageQueue(SentMessage
->CallBackSenderQueue
);
879 /* Only if the message has a sender was the queue referenced */
880 if ((SentMessage
->SenderQueue
)
881 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
883 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
886 /* wake the sender's thread */
887 if (SentMessage
->CompletionEvent
!= NULL
)
889 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
892 if (SentMessage
->HasPackedLParam
== TRUE
)
894 if (SentMessage
->Msg
.lParam
)
895 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
898 /* if the message has a sender */
899 if (SentMessage
->SenderQueue
)
901 /* dereference our and the sender's message queue */
902 IntDereferenceMessageQueue(MessageQueue
);
903 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
906 /* free the message */
907 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
909 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
913 CurrentEntry
= CurrentEntry
->Flink
;
919 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
924 SENDASYNCPROC CompletionCallback
,
925 ULONG_PTR CompletionCallbackContext
,
926 BOOL HasPackedLParam
,
930 PTHREADINFO ptiSender
;
931 PUSER_SENT_MESSAGE Message
;
933 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
935 ERR("MsqSendMessage(): Not enough memory to allocate a message");
939 ptiSender
= PsGetCurrentThreadWin32Thread();
941 IntReferenceMessageQueue(ptiReceiver
->MessageQueue
);
942 /* Take reference on this MessageQueue if its a callback. It will be released
943 when message is processed or removed from target hwnd MessageQueue */
944 if (CompletionCallback
)
945 IntReferenceMessageQueue(ptiSender
->MessageQueue
);
947 Message
->Msg
.hwnd
= hwnd
;
948 Message
->Msg
.message
= Msg
;
949 Message
->Msg
.wParam
= wParam
;
950 Message
->Msg
.lParam
= lParam
;
951 Message
->CompletionEvent
= NULL
;
953 Message
->lResult
= 0;
954 Message
->SenderQueue
= NULL
;
955 Message
->CallBackSenderQueue
= ptiSender
->MessageQueue
;
956 Message
->DispatchingListEntry
.Flink
= NULL
;
957 Message
->CompletionCallback
= CompletionCallback
;
958 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
959 Message
->HookMessage
= HookMessage
;
960 Message
->HasPackedLParam
= HasPackedLParam
;
961 Message
->QS_Flags
= QS_SENDMESSAGE
;
963 InsertTailList(&ptiReceiver
->MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
964 MsqWakeQueue(ptiReceiver
->MessageQueue
, QS_SENDMESSAGE
, TRUE
);
965 IntDereferenceMessageQueue(ptiReceiver
->MessageQueue
);
971 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
972 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
973 UINT uTimeout
, BOOL Block
, INT HookMessage
,
976 PTHREADINFO pti
, ptirec
;
977 PUSER_SENT_MESSAGE Message
;
978 KEVENT CompletionEvent
;
980 PUSER_MESSAGE_QUEUE ThreadQueue
;
981 LARGE_INTEGER Timeout
;
983 LRESULT Result
= 0; //// Result could be trashed. ////
985 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
987 ERR("MsqSendMessage(): Not enough memory to allocate a message");
988 return STATUS_INSUFFICIENT_RESOURCES
;
991 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
993 pti
= PsGetCurrentThreadWin32Thread();
994 ThreadQueue
= pti
->MessageQueue
;
995 ptirec
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
996 ASSERT(ThreadQueue
!= MessageQueue
);
997 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
999 /* Don't send from or to a dying thread */
1000 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
1003 return STATUS_TIMEOUT
;
1006 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1008 /* FIXME: Increase reference counter of sender's message queue here */
1010 Message
->Msg
.hwnd
= Wnd
;
1011 Message
->Msg
.message
= Msg
;
1012 Message
->Msg
.wParam
= wParam
;
1013 Message
->Msg
.lParam
= lParam
;
1014 Message
->CompletionEvent
= &CompletionEvent
;
1015 Message
->Result
= &Result
;
1016 Message
->lResult
= 0;
1017 Message
->QS_Flags
= 0;
1018 Message
->SenderQueue
= ThreadQueue
;
1019 Message
->CallBackSenderQueue
= NULL
;
1020 IntReferenceMessageQueue(ThreadQueue
);
1021 Message
->CompletionCallback
= NULL
;
1022 Message
->CompletionCallbackContext
= 0;
1023 Message
->HookMessage
= HookMessage
;
1024 Message
->HasPackedLParam
= FALSE
;
1026 IntReferenceMessageQueue(MessageQueue
);
1028 /* Add it to the list of pending messages */
1029 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1031 /* Queue it in the destination's message queue */
1032 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1034 Message
->QS_Flags
= QS_SENDMESSAGE
;
1035 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
, TRUE
);
1037 /* We can't access the Message anymore since it could have already been deleted! */
1043 /* Don't process messages sent to the thread */
1044 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1045 FALSE
, (uTimeout
? &Timeout
: NULL
));
1049 if(WaitStatus
== STATUS_TIMEOUT
)
1051 /* Look up if the message has not yet dispatched, if so
1052 make sure it can't pass a result and it must not set the completion event anymore */
1053 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1054 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1056 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1059 /* We can access Message here, it's secure because the message queue is locked
1060 and the message is still hasn't been dispatched */
1061 Message
->CompletionEvent
= NULL
;
1062 Message
->Result
= NULL
;
1065 Entry
= Entry
->Flink
;
1068 /* Remove from the local dispatching list so the other thread knows,
1069 it can't pass a result and it must not set the completion event anymore */
1070 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1071 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1073 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1076 /* We can access Message here, it's secure because the sender's message is locked
1077 and the message has definitely not yet been destroyed, otherwise it would
1078 have been removed from this list by the dispatching routine right after
1079 dispatching the message */
1080 Message
->CompletionEvent
= NULL
;
1081 Message
->Result
= NULL
;
1082 RemoveEntryList(&Message
->DispatchingListEntry
);
1083 Message
->DispatchingListEntry
.Flink
= NULL
;
1086 Entry
= Entry
->Flink
;
1089 TRACE("MsqSendMessage (blocked) timed out 1\n");
1091 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1096 PVOID WaitObjects
[2];
1098 WaitObjects
[0] = &CompletionEvent
;
1099 WaitObjects
[1] = ThreadQueue
->NewMessages
;
1104 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1105 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1109 if(WaitStatus
== STATUS_TIMEOUT
)
1111 /* Look up if the message has not yet been dispatched, if so
1112 make sure it can't pass a result and it must not set the completion event anymore */
1113 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1114 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1116 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1119 /* We can access Message here, it's secure because the message queue is locked
1120 and the message is still hasn't been dispatched */
1121 Message
->CompletionEvent
= NULL
;
1122 Message
->Result
= NULL
;
1125 Entry
= Entry
->Flink
;
1128 /* Remove from the local dispatching list so the other thread knows,
1129 it can't pass a result and it must not set the completion event anymore */
1130 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1131 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1133 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1136 /* We can access Message here, it's secure because the sender's message is locked
1137 and the message has definitely not yet been destroyed, otherwise it would
1138 have been removed from this list by the dispatching routine right after
1139 dispatching the message */
1140 Message
->CompletionEvent
= NULL
;
1141 Message
->Result
= NULL
;
1142 RemoveEntryList(&Message
->DispatchingListEntry
);
1143 Message
->DispatchingListEntry
.Flink
= NULL
;
1146 Entry
= Entry
->Flink
;
1149 TRACE("MsqSendMessage timed out 2\n");
1152 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1155 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
1158 if(WaitStatus
!= STATUS_TIMEOUT
)
1159 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1165 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
1168 PUSER_MESSAGE Message
;
1170 if(!(Message
= MsqCreateMessage(Msg
)))
1175 if(!HardwareMessage
)
1177 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1178 &Message
->ListEntry
);
1182 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1183 &Message
->ListEntry
);
1186 Message
->QS_Flags
= MessageBits
;
1187 MsqWakeQueue(MessageQueue
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
1191 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1193 MessageQueue
->QuitPosted
= TRUE
;
1194 MessageQueue
->QuitExitCode
= ExitCode
;
1195 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1198 /***********************************************************************
1199 * MsqSendParentNotify
1201 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1202 * the window has the WS_EX_NOPARENTNOTIFY style.
1204 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1206 PWND pwndDesktop
= UserGetWindowObject(IntGetDesktopWindow());
1208 /* pt has to be in the client coordinates of the parent window */
1209 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1210 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1216 if (!(pwnd
->style
& WS_CHILD
)) break;
1217 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1218 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1219 if (pwndParent
== pwndDesktop
) break;
1220 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1221 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1224 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1225 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1231 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1233 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1234 // hittest = GetNCHitEx(pwndTrack, msg->pt);
1236 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1237 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1238 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1240 TRACE("ITMM: Track Mouse Move!\n");
1242 /* Handle only the changing window track and mouse move across a border. */
1243 if ( pDesk
->spwndTrack
!= pwndTrack
||
1244 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1246 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1247 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1249 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1250 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1251 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1254 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1255 IntKillTimer(UserHMGetHandle(pDesk
->spwndTrack
), ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1257 /* Clear the flags to sign a change. */
1258 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1260 /* Set the Track window and hit test. */
1261 pDesk
->spwndTrack
= pwndTrack
;
1262 pDesk
->htEx
= hittest
;
1265 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1266 if ( pDesk
->spwndTrack
== pwndTrack
&&
1267 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1268 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1270 TRACE("ITMM: Reset Hover points!\n");
1271 // Restart timer for the hover period.
1272 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1273 // Reset desktop mouse hover from the system default hover rectangle.
1274 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1275 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1276 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1277 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1278 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1282 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1289 MOUSEHOOKSTRUCT hook
;
1292 PWND pwndMsg
, pwndDesktop
;
1293 PUSER_MESSAGE_QUEUE MessageQueue
;
1295 PSYSTEM_CURSORINFO CurInfo
;
1297 DECLARE_RETURN(BOOL
);
1299 pti
= PsGetCurrentThreadWin32Thread();
1300 pwndDesktop
= UserGetDesktopWindow();
1301 MessageQueue
= pti
->MessageQueue
;
1302 CurInfo
= IntGetSysCursorInfo();
1303 pwndMsg
= UserGetWindowObject(msg
->hwnd
);
1304 clk_msg
= MessageQueue
->msgDblClk
;
1305 pDesk
= pwndDesktop
->head
.rpdesk
;
1307 /* find the window to dispatch this mouse message to */
1308 if (MessageQueue
->CaptureWindow
)
1311 pwndMsg
= IntGetWindowObject(MessageQueue
->CaptureWindow
);
1315 pwndMsg
= co_WinPosWindowFromPoint(pwndMsg
, &msg
->pt
, &hittest
);
1318 TRACE("Got mouse message for 0x%x, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1320 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
1322 /* Remove and ignore the message */
1323 *RemoveMessages
= TRUE
;
1327 if ( MessageQueue
== gpqCursor
) // Cursor must use the same Queue!
1329 IntTrackMouseMove(pwndMsg
, pDesk
, msg
, hittest
);
1333 ERR("Not the same cursor!\n");
1336 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1339 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
1343 message
= msg
->message
;
1344 /* Note: windows has no concept of a non-client wheel message */
1345 if (message
!= WM_MOUSEWHEEL
)
1347 if (hittest
!= HTCLIENT
)
1349 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1350 msg
->wParam
= hittest
;
1354 /* coordinates don't get translated while tracking a menu */
1355 /* FIXME: should differentiate popups and top-level menus */
1356 if (!(MessageQueue
->MenuOwner
))
1358 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1359 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1363 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1365 /* translate double clicks */
1367 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1368 (msg
->message
== WM_RBUTTONDOWN
) ||
1369 (msg
->message
== WM_MBUTTONDOWN
) ||
1370 (msg
->message
== WM_XBUTTONDOWN
))
1372 BOOL update
= *RemoveMessages
;
1374 /* translate double clicks -
1375 * note that ...MOUSEMOVEs can slip in between
1376 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1378 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1379 hittest
!= HTCLIENT
||
1380 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1382 if ((msg
->message
== clk_msg
.message
) &&
1383 (msg
->hwnd
== clk_msg
.hwnd
) &&
1384 (msg
->wParam
== clk_msg
.wParam
) &&
1385 (msg
->time
- clk_msg
.time
< gspv
.iDblClickTime
) &&
1386 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1387 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1389 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1392 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1398 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1400 TRACE("Message out of range!!!\n");
1404 /* update static double click conditions */
1405 if (update
) MessageQueue
->msgDblClk
= *msg
;
1409 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1411 TRACE("Message out of range!!!\n");
1416 if(gspv
.bMouseClickLock
)
1418 BOOL IsClkLck
= FALSE
;
1420 if(msg
->message
== WM_LBUTTONUP
)
1422 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1423 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1425 CurInfo
->ClickLockActive
= TRUE
;
1428 else if (msg
->message
== WM_LBUTTONDOWN
)
1430 if (CurInfo
->ClickLockActive
)
1433 CurInfo
->ClickLockActive
= FALSE
;
1436 CurInfo
->ClickLockTime
= msg
->time
;
1441 /* Remove and ignore the message */
1442 *RemoveMessages
= TRUE
;
1447 /* message is accepted now (but may still get dropped) */
1449 event
.message
= msg
->message
;
1450 event
.time
= msg
->time
;
1451 event
.hwnd
= msg
->hwnd
;
1452 event
.paramL
= msg
->pt
.x
;
1453 event
.paramH
= msg
->pt
.y
;
1454 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1457 hook
.hwnd
= msg
->hwnd
;
1458 hook
.wHitTestCode
= hittest
;
1459 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1460 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1461 message
, (LPARAM
)&hook
))
1464 hook
.hwnd
= msg
->hwnd
;
1465 hook
.wHitTestCode
= hittest
;
1466 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1467 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1469 ERR("WH_MOUSE dorpped mouse message!\n");
1471 /* Remove and skip message */
1472 *RemoveMessages
= TRUE
;
1476 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1478 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1479 MAKELONG( hittest
, msg
->message
));
1481 /* Remove and skip message */
1482 *RemoveMessages
= TRUE
;
1486 if ((*RemoveMessages
== FALSE
) || MessageQueue
->CaptureWindow
)
1488 /* Accept the message */
1489 msg
->message
= message
;
1495 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1496 (msg
->message
== WM_RBUTTONDOWN
) ||
1497 (msg
->message
== WM_MBUTTONDOWN
) ||
1498 (msg
->message
== WM_XBUTTONDOWN
))
1500 /* Send the WM_PARENTNOTIFY,
1501 * note that even for double/nonclient clicks
1502 * notification message is still WM_L/M/RBUTTONDOWN.
1504 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1506 /* Activate the window if needed */
1508 if (msg
->hwnd
!= UserGetForegroundWindow())
1510 PWND pwndTop
= pwndMsg
;
1513 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
1514 pwndTop
= IntGetParent( pwndTop
);
1517 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1519 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1521 (WPARAM
)UserHMGetHandle(pwndTop
),
1522 MAKELONG( hittest
, msg
->message
));
1525 case MA_NOACTIVATEANDEAT
:
1530 case MA_ACTIVATEANDEAT
:
1535 if(!co_IntMouseActivateWindow(pwndMsg
)) eatMsg
= TRUE
;
1538 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1545 /* send the WM_SETCURSOR message */
1547 /* Windows sends the normal mouse message as the message parameter
1548 in the WM_SETCURSOR message even if it's non-client mouse message */
1549 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1551 msg
->message
= message
;
1556 UserDereferenceObject(pwndMsg
);
1561 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1565 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1566 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1568 switch (Msg
->wParam
)
1570 case VK_LSHIFT
: case VK_RSHIFT
:
1571 Msg
->wParam
= VK_SHIFT
;
1573 case VK_LCONTROL
: case VK_RCONTROL
:
1574 Msg
->wParam
= VK_CONTROL
;
1576 case VK_LMENU
: case VK_RMENU
:
1577 Msg
->wParam
= VK_MENU
;
1582 Event
.message
= Msg
->message
;
1583 Event
.hwnd
= Msg
->hwnd
;
1584 Event
.time
= Msg
->time
;
1585 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1586 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1587 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1588 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1590 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1591 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1592 LOWORD(Msg
->wParam
),
1595 /* skip this message */
1596 co_HOOK_CallHooks( WH_CBT
,
1598 LOWORD(Msg
->wParam
),
1600 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1606 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1608 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1610 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1612 else if ( IS_KBD_MESSAGE(Msg
->message
))
1614 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1621 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1624 IN UINT MsgFilterLow
,
1625 IN UINT MsgFilterHigh
,
1631 if(!(MessageQueue
->MouseMoved
))
1634 msg
= MessageQueue
->MouseMoveMsg
;
1636 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1643 ClearMsgBitsMask(MessageQueue
, QS_MOUSEMOVE
);
1644 MessageQueue
->MouseMoved
= FALSE
;
1647 return AcceptMessage
;
1650 /* check whether a message filter contains at least one potential hardware message */
1652 filter_contains_hw_range( UINT first
, UINT last
)
1654 /* hardware message ranges are (in numerical order):
1655 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1656 * WM_KEYFIRST .. WM_KEYLAST
1657 * WM_MOUSEFIRST .. WM_MOUSELAST
1660 if (last
< WM_NCMOUSEFIRST
) return 0;
1661 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1662 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1663 if (first
> WM_MOUSELAST
) return 0;
1668 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1671 IN UINT MsgFilterLow
,
1672 IN UINT MsgFilterHigh
,
1678 PUSER_MESSAGE CurrentMessage
;
1679 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1682 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1684 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1685 CurrentEntry
= ListHead
->Flink
;
1687 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1689 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1693 if (IsListEmpty(CurrentEntry
)) break;
1694 if (!CurrentMessage
) break;
1695 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1698 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1699 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1700 3: handle to the window whose messages are to be retrieved.
1702 if ( ( !Window
|| // 1
1703 ( Window
== HWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1704 ( Window
!= HWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1705 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1706 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1708 msg
= CurrentMessage
->Msg
;
1710 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
1711 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1715 RemoveEntryList(&CurrentMessage
->ListEntry
);
1716 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1717 MsqDestroyMessage(CurrentMessage
);
1726 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1729 while(CurrentEntry
!= ListHead
);
1735 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1738 IN UINT MsgFilterLow
,
1739 IN UINT MsgFilterHigh
,
1743 PLIST_ENTRY CurrentEntry
;
1744 PUSER_MESSAGE CurrentMessage
;
1745 PLIST_ENTRY ListHead
;
1747 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1748 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1750 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1752 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1756 if (IsListEmpty(CurrentEntry
)) break;
1757 if (!CurrentMessage
) break;
1758 CurrentEntry
= CurrentEntry
->Flink
;
1761 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1762 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1763 3: handle to the window whose messages are to be retrieved.
1765 if ( ( !Window
|| // 1
1766 ( Window
== HWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1767 ( Window
!= HWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1768 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1769 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1771 *Message
= CurrentMessage
->Msg
;
1775 RemoveEntryList(&CurrentMessage
->ListEntry
);
1776 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1777 MsqDestroyMessage(CurrentMessage
);
1781 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1784 while (CurrentEntry
!= ListHead
);
1790 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1791 UINT MsgFilterMin
, UINT MsgFilterMax
)
1795 ret
= KeWaitForSingleObject( MessageQueue
->NewMessages
,
1805 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1807 LARGE_INTEGER LargeTickCount
;
1809 KeQueryTickCount(&LargeTickCount
);
1810 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1815 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1818 TRACE("HungAppSysTimerProc\n");
1819 // Process list of windows that are hung and waiting.
1823 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1825 LARGE_INTEGER LargeTickCount
;
1828 MessageQueue
->Thread
= Thread
;
1829 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1830 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1831 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1832 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1833 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1834 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1835 MessageQueue
->QuitPosted
= FALSE
;
1836 MessageQueue
->QuitExitCode
= 0;
1837 KeQueryTickCount(&LargeTickCount
);
1838 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1839 MessageQueue
->FocusWindow
= NULL
;
1840 MessageQueue
->NewMessagesHandle
= NULL
;
1841 MessageQueue
->ShowingCursor
= 0;
1842 MessageQueue
->CursorObject
= NULL
;
1843 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
1845 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1846 NULL
, SynchronizationEvent
, FALSE
);
1847 if (!NT_SUCCESS(Status
))
1852 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1853 ExEventObjectType
, KernelMode
,
1854 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1855 if (!NT_SUCCESS(Status
))
1857 ZwClose(MessageQueue
->NewMessagesHandle
);
1858 MessageQueue
->NewMessagesHandle
= NULL
;
1866 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1868 PLIST_ENTRY CurrentEntry
;
1869 PUSER_MESSAGE CurrentMessage
;
1870 PUSER_SENT_MESSAGE CurrentSentMessage
;
1873 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1876 /* cleanup posted messages */
1877 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1879 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1880 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1882 MsqDestroyMessage(CurrentMessage
);
1885 /* remove the messages that have not yet been dispatched */
1886 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1888 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1889 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1892 /* if it is a callback and this queue is not the sender queue, dereference queue */
1893 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
1895 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
1898 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
1899 /* Only if the message has a sender was the message in the DispatchingList */
1900 if ((CurrentSentMessage
->SenderQueue
)
1901 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1903 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1906 /* wake the sender's thread */
1907 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1909 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1912 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1914 if (CurrentSentMessage
->Msg
.lParam
)
1915 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1918 /* if the message has a sender */
1919 if (CurrentSentMessage
->SenderQueue
)
1921 /* dereference our and the sender's message queue */
1922 IntDereferenceMessageQueue(MessageQueue
);
1923 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1926 /* free the message */
1927 ExFreePool(CurrentSentMessage
);
1930 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1931 ExitThread() was called in a SendMessage() umode callback */
1932 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1934 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1935 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1938 /* if it is a callback and this queue is not the sender queue, dereference queue */
1939 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
1941 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
1944 /* remove the message from the dispatching list */
1945 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1947 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1950 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
1952 /* wake the sender's thread */
1953 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1955 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1958 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1960 if (CurrentSentMessage
->Msg
.lParam
)
1961 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1964 /* if the message has a sender */
1965 if (CurrentSentMessage
->SenderQueue
)
1967 /* dereference our and the sender's message queue */
1968 IntDereferenceMessageQueue(MessageQueue
);
1969 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1972 /* free the message */
1973 ExFreePool(CurrentSentMessage
);
1976 /* tell other threads not to bother returning any info to us */
1977 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
1979 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
1980 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1981 DispatchingListEntry
);
1982 CurrentSentMessage
->CompletionEvent
= NULL
;
1983 CurrentSentMessage
->Result
= NULL
;
1985 /* do NOT dereference our message queue as it might get attempted to be
1989 // Clear it all out.
1992 pti
->pcti
->fsWakeBits
= 0;
1993 pti
->pcti
->fsChangeBits
= 0;
1996 MessageQueue
->nCntsQBits
[QSRosKey
] = 0;
1997 MessageQueue
->nCntsQBits
[QSRosMouseMove
] = 0;
1998 MessageQueue
->nCntsQBits
[QSRosMouseButton
] = 0;
1999 MessageQueue
->nCntsQBits
[QSRosPostMessage
] = 0;
2000 MessageQueue
->nCntsQBits
[QSRosSendMessage
] = 0;
2001 MessageQueue
->nCntsQBits
[QSRosHotKey
] = 0;
2003 if (MessageQueue
->CursorObject
)
2005 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2007 /* Change to another cursor if we going to dereference current one
2008 Note: we can't use UserSetCursor because it uses current thread
2009 message queue instead of queue given for cleanup */
2010 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2014 /* Get the screen DC */
2015 hdcScreen
= IntGetScreenDC();
2017 GreMovePointer(hdcScreen
, -1, -1);
2018 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2021 UserDereferenceObject(pCursor
);
2026 PUSER_MESSAGE_QUEUE FASTCALL
2027 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
2029 PUSER_MESSAGE_QUEUE MessageQueue
;
2031 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2032 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2040 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2041 /* hold at least one reference until it'll be destroyed */
2042 IntReferenceMessageQueue(MessageQueue
);
2043 /* initialize the queue */
2044 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
2046 IntDereferenceMessageQueue(MessageQueue
);
2050 return MessageQueue
;
2054 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
2058 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2060 /* remove the message queue from any desktops */
2061 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2063 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2064 IntDereferenceMessageQueue(MessageQueue
);
2068 MsqCleanupMessageQueue(MessageQueue
);
2070 if (MessageQueue
->NewMessagesHandle
!= NULL
)
2071 ZwClose(MessageQueue
->NewMessagesHandle
);
2072 MessageQueue
->NewMessagesHandle
= NULL
;
2073 /* decrease the reference counter, if it hits zero, the queue will be freed */
2074 IntDereferenceMessageQueue(MessageQueue
);
2078 MsqSetMessageExtraInfo(LPARAM lParam
)
2082 PUSER_MESSAGE_QUEUE MessageQueue
;
2084 pti
= PsGetCurrentThreadWin32Thread();
2085 MessageQueue
= pti
->MessageQueue
;
2091 Ret
= MessageQueue
->ExtraInfo
;
2092 MessageQueue
->ExtraInfo
= lParam
;
2098 MsqGetMessageExtraInfo(VOID
)
2101 PUSER_MESSAGE_QUEUE MessageQueue
;
2103 pti
= PsGetCurrentThreadWin32Thread();
2104 MessageQueue
= pti
->MessageQueue
;
2110 return MessageQueue
->ExtraInfo
;
2113 // ReplyMessage is called by the thread receiving the window message.
2115 co_MsqReplyMessage( LRESULT lResult
)
2117 PUSER_SENT_MESSAGE Message
;
2120 pti
= PsGetCurrentThreadWin32Thread();
2121 Message
= pti
->pusmCurrent
;
2123 if (!Message
) return FALSE
;
2125 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2127 // SendMessageXxx || Callback msg and not a notify msg
2128 if (Message
->SenderQueue
|| Message
->CompletionCallback
)
2130 Message
->lResult
= lResult
;
2131 Message
->QS_Flags
|= QS_SMRESULT
;
2132 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2138 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
2144 case MSQ_STATE_CAPTURE
:
2145 Prev
= MessageQueue
->CaptureWindow
;
2146 MessageQueue
->CaptureWindow
= hWnd
;
2148 case MSQ_STATE_ACTIVE
:
2149 Prev
= MessageQueue
->ActiveWindow
;
2150 MessageQueue
->ActiveWindow
= hWnd
;
2152 case MSQ_STATE_FOCUS
:
2153 Prev
= MessageQueue
->FocusWindow
;
2154 MessageQueue
->FocusWindow
= hWnd
;
2156 case MSQ_STATE_MENUOWNER
:
2157 Prev
= MessageQueue
->MenuOwner
;
2158 MessageQueue
->MenuOwner
= hWnd
;
2160 case MSQ_STATE_MOVESIZE
:
2161 Prev
= MessageQueue
->MoveSize
;
2162 MessageQueue
->MoveSize
= hWnd
;
2164 case MSQ_STATE_CARET
:
2165 ASSERT(MessageQueue
->CaretInfo
);
2166 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2167 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2176 NtUserGetKeyState(INT key
)
2182 Ret
= UserGetKeyState(key
);
2192 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2194 DWORD i
, ret
= TRUE
;
2196 PUSER_MESSAGE_QUEUE MessageQueue
;
2200 pti
= PsGetCurrentThreadWin32Thread();
2201 MessageQueue
= pti
->MessageQueue
;
2205 /* Probe and copy key state to an array */
2206 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2207 for (i
= 0; i
< 256; ++i
)
2210 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2211 lpKeyState
[i
] |= KS_DOWN_BIT
;
2212 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2213 lpKeyState
[i
] |= KS_LOCK_BIT
;
2216 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2218 SetLastNtError(_SEH2_GetExceptionCode());
2230 NtUserSetKeyboardState(LPBYTE pKeyState
)
2235 PUSER_MESSAGE_QUEUE MessageQueue
;
2237 UserEnterExclusive();
2239 pti
= PsGetCurrentThreadWin32Thread();
2240 MessageQueue
= pti
->MessageQueue
;
2244 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2245 for (i
= 0; i
< 256; ++i
)
2247 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2248 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2251 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2253 SetLastNtError(_SEH2_GetExceptionCode());