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 pti
= PsGetCurrentThreadWin32Thread();
986 ThreadQueue
= pti
->MessageQueue
;
987 ptirec
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
988 ASSERT(ThreadQueue
!= MessageQueue
);
989 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
991 /* Don't send from or to a dying thread */
992 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
994 if (uResult
) *uResult
= -1;
995 ERR("MsqSM: Current pti %d or Rec pti %d\n",pti
->TIF_flags
& TIF_INCLEANUP
, ptirec
->TIF_flags
& TIF_INCLEANUP
);
996 return STATUS_UNSUCCESSFUL
;
999 if ( HookMessage
== MSQ_NORMAL
)
1001 // These can not cross International Border lines!
1002 if ( pti
->ppi
!= ptirec
->ppi
)
1007 case EM_SETPASSWORDCHAR
:
1010 if (uResult
) *uResult
= -1;
1011 ERR("Running across the border without a passport!\n");
1012 return STATUS_UNSUCCESSFUL
;
1016 // These can not cross State lines!
1017 if ( Msg
== WM_CREATE
|| Msg
== WM_NCCREATE
)
1019 if (uResult
) *uResult
= -1;
1020 ERR("Can not tell the other State we have Create!\n");
1021 return STATUS_UNSUCCESSFUL
;
1025 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1027 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1028 return STATUS_INSUFFICIENT_RESOURCES
;
1031 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1033 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1035 /* FIXME: Increase reference counter of sender's message queue here */
1037 Message
->Msg
.hwnd
= Wnd
;
1038 Message
->Msg
.message
= Msg
;
1039 Message
->Msg
.wParam
= wParam
;
1040 Message
->Msg
.lParam
= lParam
;
1041 Message
->CompletionEvent
= &CompletionEvent
;
1042 Message
->Result
= &Result
;
1043 Message
->lResult
= 0;
1044 Message
->QS_Flags
= 0;
1045 Message
->SenderQueue
= ThreadQueue
;
1046 Message
->CallBackSenderQueue
= NULL
;
1047 IntReferenceMessageQueue(ThreadQueue
);
1048 Message
->CompletionCallback
= NULL
;
1049 Message
->CompletionCallbackContext
= 0;
1050 Message
->HookMessage
= HookMessage
;
1051 Message
->HasPackedLParam
= FALSE
;
1053 IntReferenceMessageQueue(MessageQueue
);
1055 /* Add it to the list of pending messages */
1056 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1058 /* Queue it in the destination's message queue */
1059 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1061 Message
->QS_Flags
= QS_SENDMESSAGE
;
1062 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
, TRUE
);
1064 /* We can't access the Message anymore since it could have already been deleted! */
1070 /* Don't process messages sent to the thread */
1071 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1072 FALSE
, (uTimeout
? &Timeout
: NULL
));
1076 if(WaitStatus
== STATUS_TIMEOUT
)
1078 /* Look up if the message has not yet dispatched, if so
1079 make sure it can't pass a result and it must not set the completion event anymore */
1080 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1081 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1083 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1086 /* We can access Message here, it's secure because the message queue is locked
1087 and the message is still hasn't been dispatched */
1088 Message
->CompletionEvent
= NULL
;
1089 Message
->Result
= NULL
;
1092 Entry
= Entry
->Flink
;
1095 /* Remove from the local dispatching list so the other thread knows,
1096 it can't pass a result and it must not set the completion event anymore */
1097 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1098 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1100 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1103 /* We can access Message here, it's secure because the sender's message is locked
1104 and the message has definitely not yet been destroyed, otherwise it would
1105 have been removed from this list by the dispatching routine right after
1106 dispatching the message */
1107 Message
->CompletionEvent
= NULL
;
1108 Message
->Result
= NULL
;
1109 RemoveEntryList(&Message
->DispatchingListEntry
);
1110 Message
->DispatchingListEntry
.Flink
= NULL
;
1113 Entry
= Entry
->Flink
;
1116 TRACE("MsqSendMessage (blocked) timed out 1\n");
1118 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1123 PVOID WaitObjects
[2];
1125 WaitObjects
[0] = &CompletionEvent
;
1126 WaitObjects
[1] = ThreadQueue
->NewMessages
;
1131 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1132 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1136 if(WaitStatus
== STATUS_TIMEOUT
)
1138 /* Look up if the message has not yet been dispatched, if so
1139 make sure it can't pass a result and it must not set the completion event anymore */
1140 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1141 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1143 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1146 /* We can access Message here, it's secure because the message queue is locked
1147 and the message is still hasn't been dispatched */
1148 Message
->CompletionEvent
= NULL
;
1149 Message
->Result
= NULL
;
1152 Entry
= Entry
->Flink
;
1155 /* Remove from the local dispatching list so the other thread knows,
1156 it can't pass a result and it must not set the completion event anymore */
1157 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1158 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1160 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1163 /* We can access Message here, it's secure because the sender's message is locked
1164 and the message has definitely not yet been destroyed, otherwise it would
1165 have been removed from this list by the dispatching routine right after
1166 dispatching the message */
1167 Message
->CompletionEvent
= NULL
;
1168 Message
->Result
= NULL
;
1169 RemoveEntryList(&Message
->DispatchingListEntry
);
1170 Message
->DispatchingListEntry
.Flink
= NULL
;
1173 Entry
= Entry
->Flink
;
1176 TRACE("MsqSendMessage timed out 2\n");
1179 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1182 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
1185 if(WaitStatus
!= STATUS_TIMEOUT
)
1186 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1192 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
1195 PUSER_MESSAGE Message
;
1197 if(!(Message
= MsqCreateMessage(Msg
)))
1202 if(!HardwareMessage
)
1204 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1205 &Message
->ListEntry
);
1209 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1210 &Message
->ListEntry
);
1213 Message
->QS_Flags
= MessageBits
;
1214 MsqWakeQueue(MessageQueue
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
1218 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1220 MessageQueue
->QuitPosted
= TRUE
;
1221 MessageQueue
->QuitExitCode
= ExitCode
;
1222 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1225 /***********************************************************************
1226 * MsqSendParentNotify
1228 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1229 * the window has the WS_EX_NOPARENTNOTIFY style.
1231 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1233 PWND pwndDesktop
= UserGetDesktopWindow();
1235 /* pt has to be in the client coordinates of the parent window */
1236 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1237 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1243 if (!(pwnd
->style
& WS_CHILD
)) break;
1244 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1245 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1246 if (pwndParent
== pwndDesktop
) break;
1247 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1248 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1251 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1252 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1258 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1260 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1261 hittest
= GetNCHitEx(pwndTrack
, msg
->pt
);
1263 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1264 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1265 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1267 TRACE("ITMM: Track Mouse Move!\n");
1269 /* Handle only the changing window track and mouse move across a border. */
1270 if ( pDesk
->spwndTrack
!= pwndTrack
||
1271 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1273 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1274 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1276 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1277 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1278 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1281 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1282 IntKillTimer(UserHMGetHandle(pDesk
->spwndTrack
), ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1284 /* Clear the flags to sign a change. */
1285 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1287 /* Set the Track window and hit test. */
1288 pDesk
->spwndTrack
= pwndTrack
;
1289 pDesk
->htEx
= hittest
;
1292 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1293 if ( pDesk
->spwndTrack
== pwndTrack
&&
1294 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1295 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1297 TRACE("ITMM: Reset Hover points!\n");
1298 // Restart timer for the hover period.
1299 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1300 // Reset desktop mouse hover from the system default hover rectangle.
1301 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1302 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1303 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1304 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1305 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1309 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1316 MOUSEHOOKSTRUCT hook
;
1319 PWND pwndMsg
, pwndDesktop
;
1320 PUSER_MESSAGE_QUEUE MessageQueue
;
1322 PSYSTEM_CURSORINFO CurInfo
;
1324 DECLARE_RETURN(BOOL
);
1326 pti
= PsGetCurrentThreadWin32Thread();
1327 pwndDesktop
= UserGetDesktopWindow();
1328 MessageQueue
= pti
->MessageQueue
;
1329 CurInfo
= IntGetSysCursorInfo();
1330 pwndMsg
= UserGetWindowObject(msg
->hwnd
);
1331 clk_msg
= MessageQueue
->msgDblClk
;
1332 pDesk
= pwndDesktop
->head
.rpdesk
;
1334 /* find the window to dispatch this mouse message to */
1335 if (MessageQueue
->CaptureWindow
)
1338 pwndMsg
= IntGetWindowObject(MessageQueue
->CaptureWindow
);
1342 pwndMsg
= co_WinPosWindowFromPoint(pwndMsg
, &msg
->pt
, &hittest
);
1345 TRACE("Got mouse message for 0x%x, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1347 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
1349 /* Remove and ignore the message */
1350 *RemoveMessages
= TRUE
;
1354 if ( MessageQueue
== gpqCursor
) // Cursor must use the same Queue!
1356 IntTrackMouseMove(pwndMsg
, pDesk
, msg
, hittest
);
1360 ERR("Not the same cursor!\n");
1363 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1366 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
1370 message
= msg
->message
;
1371 /* Note: windows has no concept of a non-client wheel message */
1372 if (message
!= WM_MOUSEWHEEL
)
1374 if (hittest
!= HTCLIENT
)
1376 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1377 msg
->wParam
= hittest
;
1381 /* coordinates don't get translated while tracking a menu */
1382 /* FIXME: should differentiate popups and top-level menus */
1383 if (!(MessageQueue
->MenuOwner
))
1385 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1386 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1390 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1392 /* translate double clicks */
1394 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1395 (msg
->message
== WM_RBUTTONDOWN
) ||
1396 (msg
->message
== WM_MBUTTONDOWN
) ||
1397 (msg
->message
== WM_XBUTTONDOWN
))
1399 BOOL update
= *RemoveMessages
;
1401 /* translate double clicks -
1402 * note that ...MOUSEMOVEs can slip in between
1403 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1405 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1406 hittest
!= HTCLIENT
||
1407 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1409 if ((msg
->message
== clk_msg
.message
) &&
1410 (msg
->hwnd
== clk_msg
.hwnd
) &&
1411 (msg
->wParam
== clk_msg
.wParam
) &&
1412 ((msg
->time
- clk_msg
.time
) < (ULONG
)gspv
.iDblClickTime
) &&
1413 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1414 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1416 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1419 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1425 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1427 TRACE("Message out of range!!!\n");
1431 /* update static double click conditions */
1432 if (update
) MessageQueue
->msgDblClk
= *msg
;
1436 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1438 TRACE("Message out of range!!!\n");
1443 if(gspv
.bMouseClickLock
)
1445 BOOL IsClkLck
= FALSE
;
1447 if(msg
->message
== WM_LBUTTONUP
)
1449 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1450 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1452 CurInfo
->ClickLockActive
= TRUE
;
1455 else if (msg
->message
== WM_LBUTTONDOWN
)
1457 if (CurInfo
->ClickLockActive
)
1460 CurInfo
->ClickLockActive
= FALSE
;
1463 CurInfo
->ClickLockTime
= msg
->time
;
1468 /* Remove and ignore the message */
1469 *RemoveMessages
= TRUE
;
1474 /* message is accepted now (but may still get dropped) */
1476 event
.message
= msg
->message
;
1477 event
.time
= msg
->time
;
1478 event
.hwnd
= msg
->hwnd
;
1479 event
.paramL
= msg
->pt
.x
;
1480 event
.paramH
= msg
->pt
.y
;
1481 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1484 hook
.hwnd
= msg
->hwnd
;
1485 hook
.wHitTestCode
= hittest
;
1486 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1487 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1488 message
, (LPARAM
)&hook
))
1491 hook
.hwnd
= msg
->hwnd
;
1492 hook
.wHitTestCode
= hittest
;
1493 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1494 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1496 ERR("WH_MOUSE dorpped mouse message!\n");
1498 /* Remove and skip message */
1499 *RemoveMessages
= TRUE
;
1503 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1505 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1506 MAKELONG( hittest
, msg
->message
));
1508 /* Remove and skip message */
1509 *RemoveMessages
= TRUE
;
1513 if ((*RemoveMessages
== FALSE
) || MessageQueue
->CaptureWindow
)
1515 /* Accept the message */
1516 msg
->message
= message
;
1522 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1523 (msg
->message
== WM_RBUTTONDOWN
) ||
1524 (msg
->message
== WM_MBUTTONDOWN
) ||
1525 (msg
->message
== WM_XBUTTONDOWN
))
1527 /* Send the WM_PARENTNOTIFY,
1528 * note that even for double/nonclient clicks
1529 * notification message is still WM_L/M/RBUTTONDOWN.
1531 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1533 /* Activate the window if needed */
1535 if (msg
->hwnd
!= UserGetForegroundWindow())
1537 PWND pwndTop
= pwndMsg
;
1540 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
1541 pwndTop
= IntGetParent( pwndTop
);
1544 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1546 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1548 (WPARAM
)UserHMGetHandle(pwndTop
),
1549 MAKELONG( hittest
, msg
->message
));
1552 case MA_NOACTIVATEANDEAT
:
1557 case MA_ACTIVATEANDEAT
:
1562 if(!co_IntMouseActivateWindow(pwndMsg
)) eatMsg
= TRUE
;
1565 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1572 /* send the WM_SETCURSOR message */
1574 /* Windows sends the normal mouse message as the message parameter
1575 in the WM_SETCURSOR message even if it's non-client mouse message */
1576 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1578 msg
->message
= message
;
1583 UserDereferenceObject(pwndMsg
);
1588 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1592 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1593 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1595 switch (Msg
->wParam
)
1597 case VK_LSHIFT
: case VK_RSHIFT
:
1598 Msg
->wParam
= VK_SHIFT
;
1600 case VK_LCONTROL
: case VK_RCONTROL
:
1601 Msg
->wParam
= VK_CONTROL
;
1603 case VK_LMENU
: case VK_RMENU
:
1604 Msg
->wParam
= VK_MENU
;
1609 Event
.message
= Msg
->message
;
1610 Event
.hwnd
= Msg
->hwnd
;
1611 Event
.time
= Msg
->time
;
1612 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1613 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1614 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1615 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1617 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1618 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1619 LOWORD(Msg
->wParam
),
1622 /* skip this message */
1623 co_HOOK_CallHooks( WH_CBT
,
1625 LOWORD(Msg
->wParam
),
1627 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1633 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1635 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1637 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1639 else if ( IS_KBD_MESSAGE(Msg
->message
))
1641 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1648 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1651 IN UINT MsgFilterLow
,
1652 IN UINT MsgFilterHigh
,
1658 if(!(MessageQueue
->MouseMoved
))
1661 msg
= MessageQueue
->MouseMoveMsg
;
1663 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1670 ClearMsgBitsMask(MessageQueue
, QS_MOUSEMOVE
);
1671 MessageQueue
->MouseMoved
= FALSE
;
1674 return AcceptMessage
;
1677 /* check whether a message filter contains at least one potential hardware message */
1679 filter_contains_hw_range( UINT first
, UINT last
)
1681 /* hardware message ranges are (in numerical order):
1682 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1683 * WM_KEYFIRST .. WM_KEYLAST
1684 * WM_MOUSEFIRST .. WM_MOUSELAST
1687 if (last
< WM_NCMOUSEFIRST
) return 0;
1688 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1689 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1690 if (first
> WM_MOUSELAST
) return 0;
1695 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1698 IN UINT MsgFilterLow
,
1699 IN UINT MsgFilterHigh
,
1705 PUSER_MESSAGE CurrentMessage
;
1706 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1709 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1711 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1712 CurrentEntry
= ListHead
->Flink
;
1714 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1716 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1720 if (IsListEmpty(CurrentEntry
)) break;
1721 if (!CurrentMessage
) break;
1722 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1725 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1726 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1727 3: handle to the window whose messages are to be retrieved.
1729 if ( ( !Window
|| // 1
1730 ( Window
== (PWND
)HWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1731 ( Window
!= (PWND
)HWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1732 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1733 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1735 msg
= CurrentMessage
->Msg
;
1737 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
1738 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1742 RemoveEntryList(&CurrentMessage
->ListEntry
);
1743 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1744 MsqDestroyMessage(CurrentMessage
);
1753 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1756 while(CurrentEntry
!= ListHead
);
1762 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1765 IN UINT MsgFilterLow
,
1766 IN UINT MsgFilterHigh
,
1770 PLIST_ENTRY CurrentEntry
;
1771 PUSER_MESSAGE CurrentMessage
;
1772 PLIST_ENTRY ListHead
;
1774 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1775 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1777 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1779 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1783 if (IsListEmpty(CurrentEntry
)) break;
1784 if (!CurrentMessage
) break;
1785 CurrentEntry
= CurrentEntry
->Flink
;
1788 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1789 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1790 3: handle to the window whose messages are to be retrieved.
1792 if ( ( !Window
|| // 1
1793 ( Window
== (PWND
)HWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1794 ( Window
!= (PWND
)HWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1795 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1796 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1798 *Message
= CurrentMessage
->Msg
;
1802 RemoveEntryList(&CurrentMessage
->ListEntry
);
1803 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1804 MsqDestroyMessage(CurrentMessage
);
1808 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1811 while (CurrentEntry
!= ListHead
);
1817 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1818 UINT MsgFilterMin
, UINT MsgFilterMax
)
1822 ret
= KeWaitForSingleObject( MessageQueue
->NewMessages
,
1832 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1834 LARGE_INTEGER LargeTickCount
;
1836 KeQueryTickCount(&LargeTickCount
);
1837 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1842 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1845 TRACE("HungAppSysTimerProc\n");
1846 // Process list of windows that are hung and waiting.
1850 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1852 LARGE_INTEGER LargeTickCount
;
1855 MessageQueue
->Thread
= Thread
;
1856 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1857 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1858 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1859 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1860 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1861 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1862 MessageQueue
->QuitPosted
= FALSE
;
1863 MessageQueue
->QuitExitCode
= 0;
1864 KeQueryTickCount(&LargeTickCount
);
1865 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1866 MessageQueue
->spwndFocus
= NULL
;
1867 MessageQueue
->NewMessagesHandle
= NULL
;
1868 MessageQueue
->ShowingCursor
= 0;
1869 MessageQueue
->CursorObject
= NULL
;
1870 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
1872 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1873 NULL
, SynchronizationEvent
, FALSE
);
1874 if (!NT_SUCCESS(Status
))
1879 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1880 ExEventObjectType
, KernelMode
,
1881 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1882 if (!NT_SUCCESS(Status
))
1884 ZwClose(MessageQueue
->NewMessagesHandle
);
1885 MessageQueue
->NewMessagesHandle
= NULL
;
1893 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1895 PLIST_ENTRY CurrentEntry
;
1896 PUSER_MESSAGE CurrentMessage
;
1897 PUSER_SENT_MESSAGE CurrentSentMessage
;
1900 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1903 /* cleanup posted messages */
1904 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1906 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1907 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1909 MsqDestroyMessage(CurrentMessage
);
1912 /* remove the messages that have not yet been dispatched */
1913 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1915 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1916 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1919 /* if it is a callback and this queue is not the sender queue, dereference queue */
1920 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
1922 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
1925 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
1926 /* Only if the message has a sender was the message in the DispatchingList */
1927 if ((CurrentSentMessage
->SenderQueue
)
1928 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1930 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1933 /* wake the sender's thread */
1934 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1936 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1939 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1941 if (CurrentSentMessage
->Msg
.lParam
)
1942 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1945 /* if the message has a sender */
1946 if (CurrentSentMessage
->SenderQueue
)
1948 /* dereference our and the sender's message queue */
1949 IntDereferenceMessageQueue(MessageQueue
);
1950 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1953 /* free the message */
1954 ExFreePool(CurrentSentMessage
);
1957 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1958 ExitThread() was called in a SendMessage() umode callback */
1959 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1961 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1962 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1965 /* if it is a callback and this queue is not the sender queue, dereference queue */
1966 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
1968 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
1971 /* remove the message from the dispatching list */
1972 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1974 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1977 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
1979 /* wake the sender's thread */
1980 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1982 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1985 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1987 if (CurrentSentMessage
->Msg
.lParam
)
1988 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1991 /* if the message has a sender */
1992 if (CurrentSentMessage
->SenderQueue
)
1994 /* dereference our and the sender's message queue */
1995 IntDereferenceMessageQueue(MessageQueue
);
1996 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1999 /* free the message */
2000 ExFreePool(CurrentSentMessage
);
2003 /* tell other threads not to bother returning any info to us */
2004 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
2006 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
2007 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2008 DispatchingListEntry
);
2009 CurrentSentMessage
->CompletionEvent
= NULL
;
2010 CurrentSentMessage
->Result
= NULL
;
2012 /* do NOT dereference our message queue as it might get attempted to be
2016 // Clear it all out.
2019 pti
->pcti
->fsWakeBits
= 0;
2020 pti
->pcti
->fsChangeBits
= 0;
2023 MessageQueue
->nCntsQBits
[QSRosKey
] = 0;
2024 MessageQueue
->nCntsQBits
[QSRosMouseMove
] = 0;
2025 MessageQueue
->nCntsQBits
[QSRosMouseButton
] = 0;
2026 MessageQueue
->nCntsQBits
[QSRosPostMessage
] = 0;
2027 MessageQueue
->nCntsQBits
[QSRosSendMessage
] = 0;
2028 MessageQueue
->nCntsQBits
[QSRosHotKey
] = 0;
2030 if (MessageQueue
->CursorObject
)
2032 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2034 /* Change to another cursor if we going to dereference current one
2035 Note: we can't use UserSetCursor because it uses current thread
2036 message queue instead of queue given for cleanup */
2037 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2041 /* Get the screen DC */
2042 hdcScreen
= IntGetScreenDC();
2044 GreMovePointer(hdcScreen
, -1, -1);
2045 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2048 UserDereferenceObject(pCursor
);
2053 PUSER_MESSAGE_QUEUE FASTCALL
2054 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
2056 PUSER_MESSAGE_QUEUE MessageQueue
;
2058 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2059 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2067 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2068 /* hold at least one reference until it'll be destroyed */
2069 IntReferenceMessageQueue(MessageQueue
);
2070 /* initialize the queue */
2071 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
2073 IntDereferenceMessageQueue(MessageQueue
);
2077 return MessageQueue
;
2081 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
2085 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2087 /* remove the message queue from any desktops */
2088 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2090 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2091 IntDereferenceMessageQueue(MessageQueue
);
2095 MsqCleanupMessageQueue(MessageQueue
);
2097 if (MessageQueue
->NewMessagesHandle
!= NULL
)
2098 ZwClose(MessageQueue
->NewMessagesHandle
);
2099 MessageQueue
->NewMessagesHandle
= NULL
;
2100 /* decrease the reference counter, if it hits zero, the queue will be freed */
2101 IntDereferenceMessageQueue(MessageQueue
);
2105 MsqSetMessageExtraInfo(LPARAM lParam
)
2109 PUSER_MESSAGE_QUEUE MessageQueue
;
2111 pti
= PsGetCurrentThreadWin32Thread();
2112 MessageQueue
= pti
->MessageQueue
;
2118 Ret
= MessageQueue
->ExtraInfo
;
2119 MessageQueue
->ExtraInfo
= lParam
;
2125 MsqGetMessageExtraInfo(VOID
)
2128 PUSER_MESSAGE_QUEUE MessageQueue
;
2130 pti
= PsGetCurrentThreadWin32Thread();
2131 MessageQueue
= pti
->MessageQueue
;
2137 return MessageQueue
->ExtraInfo
;
2140 // ReplyMessage is called by the thread receiving the window message.
2142 co_MsqReplyMessage( LRESULT lResult
)
2144 PUSER_SENT_MESSAGE Message
;
2147 pti
= PsGetCurrentThreadWin32Thread();
2148 Message
= pti
->pusmCurrent
;
2150 if (!Message
) return FALSE
;
2152 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2154 // SendMessageXxx || Callback msg and not a notify msg
2155 if (Message
->SenderQueue
|| Message
->CompletionCallback
)
2157 Message
->lResult
= lResult
;
2158 Message
->QS_Flags
|= QS_SMRESULT
;
2159 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2165 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
2171 case MSQ_STATE_CAPTURE
:
2172 Prev
= MessageQueue
->CaptureWindow
;
2173 MessageQueue
->CaptureWindow
= hWnd
;
2175 case MSQ_STATE_ACTIVE
:
2176 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2177 MessageQueue
->spwndActive
= UserGetWindowObject(hWnd
);
2179 case MSQ_STATE_FOCUS
:
2180 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2181 MessageQueue
->spwndFocus
= UserGetWindowObject(hWnd
);
2183 case MSQ_STATE_MENUOWNER
:
2184 Prev
= MessageQueue
->MenuOwner
;
2185 MessageQueue
->MenuOwner
= hWnd
;
2187 case MSQ_STATE_MOVESIZE
:
2188 Prev
= MessageQueue
->MoveSize
;
2189 MessageQueue
->MoveSize
= hWnd
;
2191 case MSQ_STATE_CARET
:
2192 ASSERT(MessageQueue
->CaretInfo
);
2193 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2194 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2203 NtUserGetKeyState(INT key
)
2209 Ret
= UserGetKeyState(key
);
2219 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2221 DWORD i
, ret
= TRUE
;
2223 PUSER_MESSAGE_QUEUE MessageQueue
;
2227 pti
= PsGetCurrentThreadWin32Thread();
2228 MessageQueue
= pti
->MessageQueue
;
2232 /* Probe and copy key state to an array */
2233 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2234 for (i
= 0; i
< 256; ++i
)
2237 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2238 lpKeyState
[i
] |= KS_DOWN_BIT
;
2239 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2240 lpKeyState
[i
] |= KS_LOCK_BIT
;
2243 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2245 SetLastNtError(_SEH2_GetExceptionCode());
2257 NtUserSetKeyboardState(LPBYTE pKeyState
)
2262 PUSER_MESSAGE_QUEUE MessageQueue
;
2264 UserEnterExclusive();
2266 pti
= PsGetCurrentThreadWin32Thread();
2267 MessageQueue
= pti
->MessageQueue
;
2271 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2272 for (i
= 0; i
< 256; ++i
)
2274 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2275 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2278 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2280 SetLastNtError(_SEH2_GetExceptionCode());