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
)
47 pWndTop
= UserGetDesktopWindow();
48 if ( !pWndTop
) return NULL
;
51 if (!(pWndTop
->style
& WS_VISIBLE
)) return NULL
;
52 if ((pWndTop
->style
& WS_DISABLED
)) return NULL
;
53 if (!IntPtInWindow(pWndTop
, x
, y
)) return NULL
;
55 if (RECTL_bPointInRect(&pWndTop
->rcClient
, x
, y
))
57 for (pWnd
= pWndTop
->spwndChild
;
59 pWnd
= pWnd
->spwndNext
)
61 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
63 TRACE("The Window is in DESTROY!\n");
67 pWndChild
= IntChildrenWindowFromPoint(pWnd
, x
, y
);
79 IntTopLevelWindowFromPoint(INT x
, INT y
)
81 PWND pWnd
, pwndDesktop
;
83 /* Get the desktop window */
84 pwndDesktop
= UserGetDesktopWindow();
88 /* Loop all top level windows */
89 for (pWnd
= pwndDesktop
->spwndChild
;
91 pWnd
= pWnd
->spwndNext
)
93 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
95 TRACE("The Window is in DESTROY!\n");
99 if ((pWnd
->style
& WS_VISIBLE
) && IntPtInWindow(pWnd
, x
, y
))
103 /* Window has not been found */
110 PCURICON_OBJECT NewCursor
,
113 PCURICON_OBJECT OldCursor
;
116 PUSER_MESSAGE_QUEUE MessageQueue
;
119 pti
= PsGetCurrentThreadWin32Thread();
120 MessageQueue
= pti
->MessageQueue
;
122 /* Get the screen DC */
123 if(!(hdcScreen
= IntGetScreenDC()))
128 OldCursor
= MessageQueue
->CursorObject
;
130 /* Check if cursors are different */
131 if (OldCursor
== NewCursor
)
134 /* Update cursor for this message queue */
135 MessageQueue
->CursorObject
= NewCursor
;
137 /* If cursor is not visible we have nothing to do */
138 if (MessageQueue
->iCursorLevel
< 0)
141 /* Update cursor if this message queue controls it */
142 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
143 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
147 /* Call GDI to set the new screen cursor */
148 #ifdef NEW_CURSORICON
149 GreSetPointerShape(hdcScreen
,
150 NewCursor
->hbmAlpha
? NULL
: NewCursor
->hbmMask
,
151 NewCursor
->hbmAlpha
? NewCursor
->hbmAlpha
: NewCursor
->hbmColor
,
156 NewCursor
->hbmAlpha
? SPS_ALPHA
: 0);
158 GreSetPointerShape(hdcScreen
,
159 NewCursor
->IconInfo
.hbmMask
,
160 NewCursor
->IconInfo
.hbmColor
,
161 NewCursor
->IconInfo
.xHotspot
,
162 NewCursor
->IconInfo
.yHotspot
,
168 else /* Note: OldCursor != NewCursor so we have to hide cursor */
170 /* Remove the cursor */
171 GreMovePointer(hdcScreen
, -1, -1);
172 TRACE("Removing pointer!\n");
174 IntGetSysCursorInfo()->CurrentCursorObject
= NewCursor
;
177 /* Return the old cursor */
181 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
182 * User32 macro NtUserShowCursor */
183 int UserShowCursor(BOOL bShow
)
187 PUSER_MESSAGE_QUEUE MessageQueue
;
190 if (!(hdcScreen
= IntGetScreenDC()))
192 return -1; /* No mouse */
195 pti
= PsGetCurrentThreadWin32Thread();
196 MessageQueue
= pti
->MessageQueue
;
199 MessageQueue
->iCursorLevel
+= bShow
? 1 : -1;
200 pti
->iCursorLevel
+= bShow
? 1 : -1;
202 /* Check for trivial cases */
203 if ((bShow
&& MessageQueue
->iCursorLevel
!= 0) ||
204 (!bShow
&& MessageQueue
->iCursorLevel
!= -1))
206 /* Note: w don't update global info here because it is used only
207 internally to check if cursor is visible */
208 return MessageQueue
->iCursorLevel
;
211 /* Check if cursor is above window owned by this MessageQueue */
212 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
213 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
217 /* Show the pointer */
218 GreMovePointer(hdcScreen
, gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
219 TRACE("Showing pointer!\n");
223 /* Remove the pointer */
224 GreMovePointer(hdcScreen
, -1, -1);
225 TRACE("Removing pointer!\n");
228 /* Update global info */
229 IntGetSysCursorInfo()->ShowingCursor
= MessageQueue
->iCursorLevel
;
232 return MessageQueue
->iCursorLevel
;
236 UserGetKeyState(DWORD dwKey
)
240 PUSER_MESSAGE_QUEUE MessageQueue
;
242 pti
= PsGetCurrentThreadWin32Thread();
243 MessageQueue
= pti
->MessageQueue
;
247 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, dwKey
))
248 dwRet
|= 0xFF80; // If down, windows returns 0xFF80.
249 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, dwKey
))
254 EngSetLastError(ERROR_INVALID_PARAMETER
);
259 /* change the input key state for a given key */
261 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue
, WORD wVk
, BOOL bIsDown
)
263 TRACE("UpdateKeyState wVk: %u, bIsDown: %d\n", wVk
, bIsDown
);
267 /* If it's first key down event, xor lock bit */
268 if (!IS_KEY_DOWN(MessageQueue
->afKeyState
, wVk
))
269 SET_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
, !IS_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
));
271 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, TRUE
);
272 MessageQueue
->afKeyRecentDown
[wVk
/ 8] |= (1 << (wVk
% 8));
275 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, FALSE
);
278 /* update the input key state for a keyboard message */
280 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
285 TRACE("UpdateKeyStateFromMsg message:%u\n", msg
->message
);
287 switch (msg
->message
)
293 UpdateKeyState(MessageQueue
, VK_LBUTTON
, down
);
299 UpdateKeyState(MessageQueue
, VK_MBUTTON
, down
);
305 UpdateKeyState(MessageQueue
, VK_RBUTTON
, down
);
311 if (msg
->wParam
== XBUTTON1
)
312 UpdateKeyState(MessageQueue
, VK_XBUTTON1
, down
);
313 else if (msg
->wParam
== XBUTTON2
)
314 UpdateKeyState(MessageQueue
, VK_XBUTTON2
, down
);
322 key
= (UCHAR
)msg
->wParam
;
323 UpdateKeyState(MessageQueue
, key
, down
);
328 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LCONTROL
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RCONTROL
);
329 UpdateKeyState(MessageQueue
, VK_CONTROL
, down
);
333 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LMENU
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RMENU
);
334 UpdateKeyState(MessageQueue
, VK_MENU
, down
);
338 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LSHIFT
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RSHIFT
);
339 UpdateKeyState(MessageQueue
, VK_SHIFT
, down
);
347 IntMsqSetWakeMask(DWORD WakeMask
)
349 PTHREADINFO Win32Thread
;
350 HANDLE MessageEventHandle
;
351 DWORD dwFlags
= HIWORD(WakeMask
);
353 Win32Thread
= PsGetCurrentThreadWin32Thread();
354 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
357 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
358 MessageEventHandle
= Win32Thread
->hEventQueueClient
;
360 if (Win32Thread
->pcti
)
362 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
363 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
365 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
366 KeSetEvent(Win32Thread
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
367 return MessageEventHandle
;
373 return MessageEventHandle
;
377 IntMsqClearWakeMask(VOID
)
379 PTHREADINFO Win32Thread
;
381 Win32Thread
= PsGetCurrentThreadWin32Thread();
382 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
384 // Very hacky, but that is what they do.
385 Win32Thread
->pcti
->fsWakeBits
= 0;
393 Due to the uncertainty of knowing what was set in our multilevel message queue,
394 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
395 I think this is the best solution... (jt) */
397 MsqWakeQueue(PTHREADINFO pti
, DWORD MessageBits
, BOOL KeyEvent
)
399 PUSER_MESSAGE_QUEUE Queue
;
401 Queue
= pti
->MessageQueue
;
403 if (Queue
->QF_flags
& QF_INDESTROY
)
405 ERR("This Message Queue is in Destroy!\n");
407 pti
->pcti
->fsWakeBits
|= MessageBits
;
408 pti
->pcti
->fsChangeBits
|= MessageBits
;
410 // Start bit accounting to help clear the main set of bits.
411 if (MessageBits
& QS_KEY
)
413 pti
->nCntsQBits
[QSRosKey
]++;
415 if (MessageBits
& QS_MOUSE
)
417 if (MessageBits
& QS_MOUSEMOVE
) pti
->nCntsQBits
[QSRosMouseMove
]++;
418 if (MessageBits
& QS_MOUSEBUTTON
) pti
->nCntsQBits
[QSRosMouseButton
]++;
420 if (MessageBits
& QS_POSTMESSAGE
) pti
->nCntsQBits
[QSRosPostMessage
]++;
421 if (MessageBits
& QS_SENDMESSAGE
) pti
->nCntsQBits
[QSRosSendMessage
]++;
422 if (MessageBits
& QS_HOTKEY
) pti
->nCntsQBits
[QSRosHotKey
]++;
423 if (MessageBits
& QS_EVENT
) pti
->nCntsQBits
[QSRosEvent
]++;
426 KeSetEvent(pti
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
);
430 ClearMsgBitsMask(PTHREADINFO pti
, UINT MessageBits
)
432 PUSER_MESSAGE_QUEUE Queue
;
435 Queue
= pti
->MessageQueue
;
437 if (MessageBits
& QS_KEY
)
439 if (--pti
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
441 if (MessageBits
& QS_MOUSEMOVE
) // ReactOS hard coded.
442 { // Account for tracking mouse moves..
443 if (--pti
->nCntsQBits
[QSRosMouseMove
] == 0) ClrMask
|= QS_MOUSEMOVE
;
444 // Handle mouse move bits here.
445 if (Queue
->MouseMoved
) ClrMask
|= QS_MOUSEMOVE
;
447 if (MessageBits
& QS_MOUSEBUTTON
)
449 if (--pti
->nCntsQBits
[QSRosMouseButton
] == 0) ClrMask
|= QS_MOUSEBUTTON
;
451 if (MessageBits
& QS_POSTMESSAGE
)
453 if (--pti
->nCntsQBits
[QSRosPostMessage
] == 0) ClrMask
|= QS_POSTMESSAGE
;
455 if (MessageBits
& QS_TIMER
) // ReactOS hard coded.
456 { // Handle timer bits here.
457 if ( pti
->cTimersReady
)
459 if (--pti
->cTimersReady
== 0) ClrMask
|= QS_TIMER
;
462 if (MessageBits
& QS_PAINT
) // ReactOS hard coded.
463 { // Handle paint bits here.
464 if ( pti
->cPaintsReady
)
466 if (--pti
->cPaintsReady
== 0) ClrMask
|= QS_PAINT
;
469 if (MessageBits
& QS_SENDMESSAGE
)
471 if (--pti
->nCntsQBits
[QSRosSendMessage
] == 0) ClrMask
|= QS_SENDMESSAGE
;
473 if (MessageBits
& QS_HOTKEY
)
475 if (--pti
->nCntsQBits
[QSRosHotKey
] == 0) ClrMask
|= QS_HOTKEY
;
477 if (MessageBits
& QS_EVENT
)
479 if (--pti
->nCntsQBits
[QSRosEvent
] == 0) ClrMask
|= QS_EVENT
;
482 pti
->pcti
->fsWakeBits
&= ~ClrMask
;
483 pti
->pcti
->fsChangeBits
&= ~ClrMask
;
487 MsqIncPaintCountQueue(PTHREADINFO pti
)
490 MsqWakeQueue(pti
, QS_PAINT
, TRUE
);
494 MsqDecPaintCountQueue(PTHREADINFO pti
)
496 ClearMsgBitsMask(pti
, QS_PAINT
);
500 MsqPostMouseMove(PTHREADINFO pti
, MSG
* Msg
)
502 pti
->MessageQueue
->MouseMoveMsg
= *Msg
;
503 pti
->MessageQueue
->MouseMoved
= TRUE
;
504 MsqWakeQueue(pti
, QS_MOUSEMOVE
, TRUE
);
508 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
510 LARGE_INTEGER LargeTickCount
;
511 MSLLHOOKSTRUCT MouseHookData
;
513 PWND pwnd
, pwndDesktop
;
516 PUSER_MESSAGE_QUEUE MessageQueue
;
517 PSYSTEM_CURSORINFO CurInfo
;
519 KeQueryTickCount(&LargeTickCount
);
520 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
522 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
523 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
524 switch (Msg
->message
)
527 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
531 case WM_XBUTTONDBLCLK
:
532 case WM_NCXBUTTONDOWN
:
534 case WM_NCXBUTTONDBLCLK
:
535 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
538 MouseHookData
.mouseData
= 0;
542 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
543 MouseHookData
.time
= Msg
->time
;
544 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
546 /* If the hook procedure returned non zero, dont send the message */
549 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
553 /* Get the desktop window */
554 pwndDesktop
= UserGetDesktopWindow();
555 if (!pwndDesktop
) return;
556 // pDesk = pwndDesktop->head.rpdesk;
558 /* Check if the mouse is captured */
559 Msg
->hwnd
= IntGetCaptureWindow();
560 if (Msg
->hwnd
!= NULL
)
562 pwnd
= UserGetWindowObject(Msg
->hwnd
);
566 pwnd
= IntTopLevelWindowFromPoint(Msg
->pt
.x
, Msg
->pt
.y
);
567 if (pwnd
) Msg
->hwnd
= pwnd
->head
.h
;
570 hdcScreen
= IntGetScreenDC();
571 CurInfo
= IntGetSysCursorInfo();
573 /* Check if we found a window */
574 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
576 pti
= pwnd
->head
.pti
;
577 MessageQueue
= pti
->MessageQueue
;
578 // MessageQueue->ptiMouse = pti;
580 if ( pti
->TIF_flags
& TIF_INCLEANUP
|| MessageQueue
->QF_flags
& QF_INDESTROY
)
582 ERR("Mouse is over the Window Thread is Dead!\n");
586 if (Msg
->message
== WM_MOUSEMOVE
)
588 /* Check if cursor should be visible */
590 MessageQueue
->CursorObject
&&
591 MessageQueue
->iCursorLevel
>= 0)
593 /* Check if shape has changed */
594 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
596 /* Call GDI to set the new screen cursor */
597 #ifdef NEW_CURSORICON
598 GreSetPointerShape(hdcScreen
,
599 MessageQueue
->CursorObject
->hbmAlpha
?
600 NULL
: MessageQueue
->CursorObject
->hbmMask
,
601 MessageQueue
->CursorObject
->hbmAlpha
?
602 MessageQueue
->CursorObject
->hbmAlpha
: MessageQueue
->CursorObject
->hbmColor
,
603 MessageQueue
->CursorObject
->xHotspot
,
604 MessageQueue
->CursorObject
->yHotspot
,
607 MessageQueue
->CursorObject
->hbmAlpha
? SPS_ALPHA
: 0);
609 GreSetPointerShape(hdcScreen
,
610 MessageQueue
->CursorObject
->IconInfo
.hbmMask
,
611 MessageQueue
->CursorObject
->IconInfo
.hbmColor
,
612 MessageQueue
->CursorObject
->IconInfo
.xHotspot
,
613 MessageQueue
->CursorObject
->IconInfo
.yHotspot
,
619 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
621 /* Check if w have to hide cursor */
622 else if (CurInfo
->ShowingCursor
>= 0)
623 GreMovePointer(hdcScreen
, -1, -1);
625 /* Update global cursor info */
626 CurInfo
->ShowingCursor
= MessageQueue
->iCursorLevel
;
627 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
628 gpqCursor
= MessageQueue
;
630 /* Mouse move is a special case */
631 MsqPostMouseMove(pti
, Msg
);
635 if (!IntGetCaptureWindow())
637 // ERR("ptiLastInput is set\n");
638 // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
640 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd
));
641 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEBUTTON
, 0);
646 /* always show cursor on background; FIXME: set default pointer */
647 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
648 CurInfo
->ShowingCursor
= 0;
652 PUSER_MESSAGE FASTCALL
653 MsqCreateMessage(LPMSG Msg
)
655 PUSER_MESSAGE Message
;
657 Message
= ExAllocateFromPagedLookasideList(pgMessageLookasideList
);
663 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
669 MsqDestroyMessage(PUSER_MESSAGE Message
)
671 ExFreeToPagedLookasideList(pgMessageLookasideList
, Message
);
675 co_MsqDispatchOneSentMessage(PTHREADINFO pti
)
677 PUSER_SENT_MESSAGE SaveMsg
, Message
;
682 if (IsListEmpty(&pti
->SentMessagesListHead
))
687 /* remove it from the list of pending messages */
688 Entry
= RemoveHeadList(&pti
->SentMessagesListHead
);
689 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
691 SaveMsg
= pti
->pusmCurrent
;
692 pti
->pusmCurrent
= Message
;
694 // Processing a message sent to it from another thread.
695 if ( ( Message
->ptiSender
&& pti
!= Message
->ptiSender
) ||
696 ( Message
->ptiCallBackSender
&& pti
!= Message
->ptiCallBackSender
))
697 { // most likely, but, to be sure.
698 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
701 /* insert it to the list of messages that are currently dispatched by this
703 InsertTailList(&pti
->LocalDispatchingMessagesHead
,
704 &Message
->ListEntry
);
706 ClearMsgBitsMask(pti
, Message
->QS_Flags
);
708 if (Message
->HookMessage
== MSQ_ISHOOK
)
709 { // Direct Hook Call processor
710 Result
= co_CallHook( Message
->Msg
.message
, // HookId
711 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
713 Message
->Msg
.lParam
);
715 else if (Message
->HookMessage
== MSQ_ISEVENT
)
716 { // Direct Event Call processor
717 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
720 Message
->Msg
.lParam
);
722 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
724 Result
= IntLoadHookModule(Message
->Msg
.message
,
725 (HHOOK
)Message
->Msg
.lParam
,
726 Message
->Msg
.wParam
);
728 else if ((Message
->CompletionCallback
) &&
729 (Message
->ptiCallBackSender
== pti
))
730 { /* Call the callback routine */
731 if (Message
->QS_Flags
& QS_SMRESULT
)
733 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
735 Message
->Msg
.message
,
736 Message
->CompletionCallbackContext
,
738 /* Set callback to NULL to prevent reentry */
739 Message
->CompletionCallback
= NULL
;
743 /* The message has not been processed yet, reinsert it. */
744 RemoveEntryList(&Message
->ListEntry
);
745 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
746 TRACE("Callback Message not processed yet. Requeuing the message\n");
752 { /* Call the window procedure. */
753 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
754 Message
->Msg
.message
,
756 Message
->Msg
.lParam
);
759 /* remove the message from the local dispatching list, because it doesn't need
760 to be cleaned up on thread termination anymore */
761 RemoveEntryList(&Message
->ListEntry
);
763 /* If the message is a callback, insert it in the callback senders MessageQueue */
764 if (Message
->CompletionCallback
)
766 if (Message
->ptiCallBackSender
)
768 Message
->lResult
= Result
;
769 Message
->QS_Flags
|= QS_SMRESULT
;
771 /* insert it in the callers message queue */
772 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
773 MsqWakeQueue(Message
->ptiCallBackSender
, QS_SENDMESSAGE
, TRUE
);
779 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
780 if (Message
->ptiSender
)
782 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
784 /* only remove it from the dispatching list if not already removed by a timeout */
785 RemoveEntryList(&Message
->DispatchingListEntry
);
788 /* still keep the sender's message queue locked, so the sender can't exit the
789 MsqSendMessage() function (if timed out) */
791 if (Message
->QS_Flags
& QS_SMRESULT
)
793 Result
= Message
->lResult
;
796 /* Let the sender know the result. */
797 if (Message
->Result
!= NULL
)
799 *Message
->Result
= Result
;
802 if (Message
->HasPackedLParam
== TRUE
)
804 if (Message
->Msg
.lParam
)
805 ExFreePool((PVOID
)Message
->Msg
.lParam
);
808 /* Notify the sender. */
809 if (Message
->CompletionEvent
!= NULL
)
811 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
814 /* free the message */
815 ExFreePoolWithTag(Message
, TAG_USRMSG
);
818 /* do not hangup on the user if this is reentering */
819 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
820 pti
->pusmCurrent
= SaveMsg
;
826 MsqRemoveWindowMessagesFromQueue(PWND Window
)
829 PUSER_SENT_MESSAGE SentMessage
;
830 PUSER_MESSAGE PostedMessage
;
831 PLIST_ENTRY CurrentEntry
, ListHead
;
835 pti
= Window
->head
.pti
;
837 /* remove the posted messages for this window */
838 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
839 ListHead
= &pti
->PostedMessagesListHead
;
840 while (CurrentEntry
!= ListHead
)
842 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
844 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
846 RemoveEntryList(&PostedMessage
->ListEntry
);
847 ClearMsgBitsMask(pti
, PostedMessage
->QS_Flags
);
848 MsqDestroyMessage(PostedMessage
);
849 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
853 CurrentEntry
= CurrentEntry
->Flink
;
857 /* remove the sent messages for this window */
858 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
859 ListHead
= &pti
->SentMessagesListHead
;
860 while (CurrentEntry
!= ListHead
)
862 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
864 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
866 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
868 RemoveEntryList(&SentMessage
->ListEntry
);
869 ClearMsgBitsMask(pti
, SentMessage
->QS_Flags
);
871 /* Only if the message has a sender was the queue referenced */
872 if ((SentMessage
->ptiSender
)
873 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
875 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
878 /* wake the sender's thread */
879 if (SentMessage
->CompletionEvent
!= NULL
)
881 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
884 if (SentMessage
->HasPackedLParam
== TRUE
)
886 if (SentMessage
->Msg
.lParam
)
887 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
890 /* free the message */
891 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
893 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
897 CurrentEntry
= CurrentEntry
->Flink
;
903 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
908 SENDASYNCPROC CompletionCallback
,
909 ULONG_PTR CompletionCallbackContext
,
910 BOOL HasPackedLParam
,
914 PTHREADINFO ptiSender
;
915 PUSER_SENT_MESSAGE Message
;
917 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
919 ERR("MsqSendMessage(): Not enough memory to allocate a message");
923 ptiSender
= PsGetCurrentThreadWin32Thread();
925 Message
->Msg
.hwnd
= hwnd
;
926 Message
->Msg
.message
= Msg
;
927 Message
->Msg
.wParam
= wParam
;
928 Message
->Msg
.lParam
= lParam
;
929 Message
->CompletionEvent
= NULL
;
931 Message
->lResult
= 0;
932 Message
->ptiReceiver
= ptiReceiver
;
933 Message
->ptiSender
= NULL
;
934 Message
->ptiCallBackSender
= ptiSender
;
935 Message
->DispatchingListEntry
.Flink
= NULL
;
936 Message
->CompletionCallback
= CompletionCallback
;
937 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
938 Message
->HookMessage
= HookMessage
;
939 Message
->HasPackedLParam
= HasPackedLParam
;
940 Message
->QS_Flags
= QS_SENDMESSAGE
;
942 InsertTailList(&ptiReceiver
->SentMessagesListHead
, &Message
->ListEntry
);
943 MsqWakeQueue(ptiReceiver
, QS_SENDMESSAGE
, TRUE
);
949 co_MsqSendMessage(PTHREADINFO ptirec
,
950 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
951 UINT uTimeout
, BOOL Block
, INT HookMessage
,
955 PUSER_SENT_MESSAGE Message
;
956 KEVENT CompletionEvent
;
958 LARGE_INTEGER Timeout
;
961 LRESULT Result
= 0; //// Result could be trashed. ////
963 pti
= PsGetCurrentThreadWin32Thread();
964 ASSERT(pti
!= ptirec
);
965 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
967 /* Don't send from or to a dying thread */
968 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
970 if (uResult
) *uResult
= -1;
971 ERR("MsqSM: Current pti %lu or Rec pti %lu\n", pti
->TIF_flags
& TIF_INCLEANUP
, ptirec
->TIF_flags
& TIF_INCLEANUP
);
972 return STATUS_UNSUCCESSFUL
;
975 if ( HookMessage
== MSQ_NORMAL
)
977 pWnd
= ValidateHwndNoErr(Wnd
);
979 // These can not cross International Border lines!
980 if ( pti
->ppi
!= ptirec
->ppi
&& pWnd
)
984 // Handle the special case when working with password transfers across bordering processes.
986 case EM_SETPASSWORDCHAR
:
988 // Look for edit controls setup for passwords.
989 if ( gpsi
->atomSysClass
[ICLS_EDIT
] == pWnd
->pcls
->atomClassName
&& // Use atomNVClassName.
990 pWnd
->style
& ES_PASSWORD
)
992 if (uResult
) *uResult
= -1;
993 ERR("Running across the border without a passport!\n");
994 EngSetLastError(ERROR_ACCESS_DENIED
);
995 return STATUS_UNSUCCESSFUL
;
999 if (uResult
) *uResult
= -1;
1000 ERR("Running across the border without a passport!\n");
1001 return STATUS_UNSUCCESSFUL
;
1005 // These can not cross State lines!
1006 if ( Msg
== WM_CREATE
|| Msg
== WM_NCCREATE
)
1008 if (uResult
) *uResult
= -1;
1009 ERR("Can not tell the other State we have Create!\n");
1010 return STATUS_UNSUCCESSFUL
;
1014 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1016 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1017 return STATUS_INSUFFICIENT_RESOURCES
;
1020 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1022 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1024 /* FIXME: Increase reference counter of sender's message queue here */
1026 Message
->Msg
.hwnd
= Wnd
;
1027 Message
->Msg
.message
= Msg
;
1028 Message
->Msg
.wParam
= wParam
;
1029 Message
->Msg
.lParam
= lParam
;
1030 Message
->CompletionEvent
= &CompletionEvent
;
1031 Message
->Result
= &Result
;
1032 Message
->lResult
= 0;
1033 Message
->QS_Flags
= 0;
1034 Message
->ptiReceiver
= ptirec
;
1035 Message
->ptiSender
= pti
;
1036 Message
->ptiCallBackSender
= NULL
;
1037 Message
->CompletionCallback
= NULL
;
1038 Message
->CompletionCallbackContext
= 0;
1039 Message
->HookMessage
= HookMessage
;
1040 Message
->HasPackedLParam
= FALSE
;
1042 /* Add it to the list of pending messages */
1043 InsertTailList(&pti
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1045 /* Queue it in the destination's message queue */
1046 InsertTailList(&ptirec
->SentMessagesListHead
, &Message
->ListEntry
);
1048 Message
->QS_Flags
= QS_SENDMESSAGE
;
1049 MsqWakeQueue(ptirec
, QS_SENDMESSAGE
, TRUE
);
1051 /* We can't access the Message anymore since it could have already been deleted! */
1057 /* Don't process messages sent to the thread */
1058 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1059 FALSE
, (uTimeout
? &Timeout
: NULL
));
1063 if(WaitStatus
== STATUS_TIMEOUT
)
1065 /* Look up if the message has not yet dispatched, if so
1066 make sure it can't pass a result and it must not set the completion event anymore */
1067 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1068 while (Entry
!= &ptirec
->SentMessagesListHead
)
1070 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1073 /* We can access Message here, it's secure because the message queue is locked
1074 and the message is still hasn't been dispatched */
1075 Message
->CompletionEvent
= NULL
;
1076 Message
->Result
= NULL
;
1079 Entry
= Entry
->Flink
;
1082 /* Remove from the local dispatching list so the other thread knows,
1083 it can't pass a result and it must not set the completion event anymore */
1084 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1085 while (Entry
!= &pti
->DispatchingMessagesHead
)
1087 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1090 /* We can access Message here, it's secure because the sender's message is locked
1091 and the message has definitely not yet been destroyed, otherwise it would
1092 have been removed from this list by the dispatching routine right after
1093 dispatching the message */
1094 Message
->CompletionEvent
= NULL
;
1095 Message
->Result
= NULL
;
1096 RemoveEntryList(&Message
->DispatchingListEntry
);
1097 Message
->DispatchingListEntry
.Flink
= NULL
;
1100 Entry
= Entry
->Flink
;
1103 TRACE("MsqSendMessage (blocked) timed out 1\n");
1105 while (co_MsqDispatchOneSentMessage(ptirec
))
1110 PVOID WaitObjects
[3];
1112 WaitObjects
[0] = &CompletionEvent
; // Wait 0
1113 WaitObjects
[1] = pti
->pEventQueueServer
; // Wait 1
1114 WaitObjects
[2] = ptirec
->pEThread
; // Wait 2
1120 WaitStatus
= KeWaitForMultipleObjects(3, WaitObjects
, WaitAny
, UserRequest
,
1121 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1125 if(WaitStatus
== STATUS_TIMEOUT
)
1127 /* Look up if the message has not yet been dispatched, if so
1128 make sure it can't pass a result and it must not set the completion event anymore */
1129 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1130 while (Entry
!= &ptirec
->SentMessagesListHead
)
1132 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1135 /* We can access Message here, it's secure because the message queue is locked
1136 and the message is still hasn't been dispatched */
1137 Message
->CompletionEvent
= NULL
;
1138 Message
->Result
= NULL
;
1141 Entry
= Entry
->Flink
;
1144 /* Remove from the local dispatching list so the other thread knows,
1145 it can't pass a result and it must not set the completion event anymore */
1146 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1147 while (Entry
!= &pti
->DispatchingMessagesHead
)
1149 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1152 /* We can access Message here, it's secure because the sender's message is locked
1153 and the message has definitely not yet been destroyed, otherwise it would
1154 have been removed from this list by the dispatching routine right after
1155 dispatching the message */
1156 Message
->CompletionEvent
= NULL
;
1157 Message
->Result
= NULL
;
1158 RemoveEntryList(&Message
->DispatchingListEntry
);
1159 Message
->DispatchingListEntry
.Flink
= NULL
;
1162 Entry
= Entry
->Flink
;
1165 TRACE("MsqSendMessage timed out 2\n");
1168 // Receiving thread passed on and left us hanging with issues still pending.
1169 if ( WaitStatus
== STATUS_WAIT_2
)
1171 ERR("Receiving Thread woken up dead!\n");
1172 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1173 while (Entry
!= &pti
->DispatchingMessagesHead
)
1175 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1178 Message
->CompletionEvent
= NULL
;
1179 Message
->Result
= NULL
;
1180 RemoveEntryList(&Message
->DispatchingListEntry
);
1181 Message
->DispatchingListEntry
.Flink
= NULL
;
1184 Entry
= Entry
->Flink
;
1187 while (co_MsqDispatchOneSentMessage(pti
))
1190 while (NT_SUCCESS(WaitStatus
) && WaitStatus
== STATUS_WAIT_1
);
1193 if(WaitStatus
!= STATUS_TIMEOUT
)
1194 if (uResult
) *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1200 MsqPostMessage(PTHREADINFO pti
,
1202 BOOLEAN HardwareMessage
,
1206 PUSER_MESSAGE Message
;
1207 PUSER_MESSAGE_QUEUE MessageQueue
;
1209 if ( pti
->TIF_flags
& TIF_INCLEANUP
|| pti
->MessageQueue
->QF_flags
& QF_INDESTROY
)
1211 ERR("Post Msg; Thread or Q is Dead!\n");
1215 if(!(Message
= MsqCreateMessage(Msg
)))
1220 MessageQueue
= pti
->MessageQueue
;
1224 ERR("Post Msg; System Qeued Event Message!\n");
1225 InsertHeadList(&pti
->PostedMessagesListHead
,
1226 &Message
->ListEntry
);
1228 else if (!HardwareMessage
)
1230 InsertTailList(&pti
->PostedMessagesListHead
,
1231 &Message
->ListEntry
);
1235 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1236 &Message
->ListEntry
);
1239 if (Msg
->message
== WM_HOTKEY
) MessageBits
|= QS_HOTKEY
; // Justin Case, just set it.
1240 Message
->dwQEvent
= dwQEvent
;
1241 Message
->QS_Flags
= MessageBits
;
1243 MsqWakeQueue(pti
, MessageBits
, TRUE
);
1247 MsqPostQuitMessage(PTHREADINFO pti
, ULONG ExitCode
)
1249 pti
->QuitPosted
= TRUE
;
1250 pti
->exitCode
= ExitCode
;
1251 MsqWakeQueue(pti
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1254 /***********************************************************************
1255 * MsqSendParentNotify
1257 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1258 * the window has the WS_EX_NOPARENTNOTIFY style.
1260 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1262 PWND pwndDesktop
= UserGetDesktopWindow();
1264 /* pt has to be in the client coordinates of the parent window */
1265 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1266 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1272 if (!(pwnd
->style
& WS_CHILD
)) break;
1273 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1274 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1275 if (pwndParent
== pwndDesktop
) break;
1276 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1277 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1280 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1281 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1287 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1289 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1290 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
1292 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1293 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1294 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1296 TRACE("ITMM: Track Mouse Move!\n");
1298 /* Handle only the changing window track and mouse move across a border. */
1299 if ( pDesk
->spwndTrack
!= pwndTrack
||
1300 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1302 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1303 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1305 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1306 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1307 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1310 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1311 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1313 /* Clear the flags to sign a change. */
1314 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1316 /* Set the Track window and hit test. */
1317 pDesk
->spwndTrack
= pwndTrack
;
1318 pDesk
->htEx
= hittest
;
1321 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1322 if ( pDesk
->spwndTrack
== pwndTrack
&&
1323 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1324 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1326 TRACE("ITMM: Reset Hover points!\n");
1327 // Restart timer for the hover period.
1328 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1329 // Reset desktop mouse hover from the system default hover rectangle.
1330 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1331 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1332 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1333 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1334 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1338 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1345 MOUSEHOOKSTRUCT hook
;
1346 BOOL eatMsg
= FALSE
;
1348 PWND pwndMsg
, pwndDesktop
;
1349 PUSER_MESSAGE_QUEUE MessageQueue
;
1351 PSYSTEM_CURSORINFO CurInfo
;
1353 DECLARE_RETURN(BOOL
);
1355 pti
= PsGetCurrentThreadWin32Thread();
1356 pwndDesktop
= UserGetDesktopWindow();
1357 MessageQueue
= pti
->MessageQueue
;
1358 CurInfo
= IntGetSysCursorInfo();
1359 pwndMsg
= ValidateHwndNoErr(msg
->hwnd
);
1360 clk_msg
= MessageQueue
->msgDblClk
;
1361 pDesk
= pwndDesktop
->head
.rpdesk
;
1363 /* find the window to dispatch this mouse message to */
1364 if (MessageQueue
->spwndCapture
)
1367 pwndMsg
= MessageQueue
->spwndCapture
;
1368 if (pwndMsg
) UserReferenceObject(pwndMsg
);
1372 pwndMsg
= co_WinPosWindowFromPoint(NULL
, &msg
->pt
, &hittest
, FALSE
);//TRUE);
1375 TRACE("Got mouse message for %p, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1377 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
1379 /* Remove and ignore the message */
1380 *RemoveMessages
= TRUE
;
1384 if ( MessageQueue
== gpqCursor
) // Cursor must use the same Queue!
1386 IntTrackMouseMove(pwndMsg
, pDesk
, msg
, hittest
);
1390 ERR("Not the same cursor!\n");
1393 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1396 message
= msg
->message
;
1397 /* Note: windows has no concept of a non-client wheel message */
1398 if (message
!= WM_MOUSEWHEEL
)
1400 if (hittest
!= HTCLIENT
)
1402 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1403 msg
->wParam
= hittest
;
1407 /* coordinates don't get translated while tracking a menu */
1408 /* FIXME: should differentiate popups and top-level menus */
1409 if (!(MessageQueue
->MenuOwner
))
1411 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1412 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1416 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1418 /* translate double clicks */
1420 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1421 (msg
->message
== WM_RBUTTONDOWN
) ||
1422 (msg
->message
== WM_MBUTTONDOWN
) ||
1423 (msg
->message
== WM_XBUTTONDOWN
))
1425 BOOL update
= *RemoveMessages
;
1427 /* translate double clicks -
1428 * note that ...MOUSEMOVEs can slip in between
1429 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1431 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1432 hittest
!= HTCLIENT
||
1433 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1435 if ((msg
->message
== clk_msg
.message
) &&
1436 (msg
->hwnd
== clk_msg
.hwnd
) &&
1437 (msg
->wParam
== clk_msg
.wParam
) &&
1438 ((msg
->time
- clk_msg
.time
) < (ULONG
)gspv
.iDblClickTime
) &&
1439 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1440 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1442 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1445 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1451 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1453 TRACE("Message out of range!!!\n");
1457 /* update static double click conditions */
1458 if (update
) MessageQueue
->msgDblClk
= *msg
;
1462 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1464 TRACE("Message out of range!!!\n");
1469 if(gspv
.bMouseClickLock
)
1471 BOOL IsClkLck
= FALSE
;
1473 if(msg
->message
== WM_LBUTTONUP
)
1475 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1476 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1478 CurInfo
->ClickLockActive
= TRUE
;
1481 else if (msg
->message
== WM_LBUTTONDOWN
)
1483 if (CurInfo
->ClickLockActive
)
1486 CurInfo
->ClickLockActive
= FALSE
;
1489 CurInfo
->ClickLockTime
= msg
->time
;
1494 /* Remove and ignore the message */
1495 *RemoveMessages
= TRUE
;
1500 /* message is accepted now (but may still get dropped) */
1502 event
.message
= msg
->message
;
1503 event
.time
= msg
->time
;
1504 event
.hwnd
= msg
->hwnd
;
1505 event
.paramL
= msg
->pt
.x
;
1506 event
.paramH
= msg
->pt
.y
;
1507 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1510 hook
.hwnd
= msg
->hwnd
;
1511 hook
.wHitTestCode
= hittest
;
1512 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1513 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1514 message
, (LPARAM
)&hook
))
1517 hook
.hwnd
= msg
->hwnd
;
1518 hook
.wHitTestCode
= hittest
;
1519 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1520 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1522 ERR("WH_MOUSE dropped mouse message!\n");
1524 /* Remove and skip message */
1525 *RemoveMessages
= TRUE
;
1529 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1531 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1532 MAKELONG( hittest
, msg
->message
));
1534 /* Remove and skip message */
1535 *RemoveMessages
= TRUE
;
1539 if ((*RemoveMessages
== FALSE
) || MessageQueue
->spwndCapture
)
1541 /* Accept the message */
1542 msg
->message
= message
;
1546 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1547 (msg
->message
== WM_RBUTTONDOWN
) ||
1548 (msg
->message
== WM_MBUTTONDOWN
) ||
1549 (msg
->message
== WM_XBUTTONDOWN
))
1551 /* Send the WM_PARENTNOTIFY,
1552 * note that even for double/nonclient clicks
1553 * notification message is still WM_L/M/RBUTTONDOWN.
1555 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1557 /* Activate the window if needed */
1559 if (pwndMsg
!= MessageQueue
->spwndActive
)
1561 PWND pwndTop
= pwndMsg
;
1562 pwndTop
= IntGetNonChildAncestor(pwndTop
);
1564 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1566 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1568 (WPARAM
)UserHMGetHandle(pwndTop
),
1569 MAKELONG( hittest
, msg
->message
));
1572 case MA_NOACTIVATEANDEAT
:
1577 case MA_ACTIVATEANDEAT
:
1582 if (!co_IntMouseActivateWindow( pwndTop
)) eatMsg
= TRUE
;
1585 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1592 /* send the WM_SETCURSOR message */
1594 /* Windows sends the normal mouse message as the message parameter
1595 in the WM_SETCURSOR message even if it's non-client mouse message */
1596 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1598 msg
->message
= message
;
1603 UserDereferenceObject(pwndMsg
);
1608 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1612 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1613 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1615 switch (Msg
->wParam
)
1617 case VK_LSHIFT
: case VK_RSHIFT
:
1618 Msg
->wParam
= VK_SHIFT
;
1620 case VK_LCONTROL
: case VK_RCONTROL
:
1621 Msg
->wParam
= VK_CONTROL
;
1623 case VK_LMENU
: case VK_RMENU
:
1624 Msg
->wParam
= VK_MENU
;
1629 Event
.message
= Msg
->message
;
1630 Event
.hwnd
= Msg
->hwnd
;
1631 Event
.time
= Msg
->time
;
1632 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1633 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1634 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1635 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1637 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1638 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1639 LOWORD(Msg
->wParam
),
1642 /* skip this message */
1643 co_HOOK_CallHooks( WH_CBT
,
1645 LOWORD(Msg
->wParam
),
1647 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1653 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1655 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1657 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1659 else if ( IS_KBD_MESSAGE(Msg
->message
))
1661 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1668 co_MsqPeekMouseMove(IN PTHREADINFO pti
,
1671 IN UINT MsgFilterLow
,
1672 IN UINT MsgFilterHigh
,
1677 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
1679 if(!(MessageQueue
->MouseMoved
))
1682 if (!MessageQueue
->ptiSysLock
)
1684 MessageQueue
->ptiSysLock
= pti
;
1685 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1688 if (MessageQueue
->ptiSysLock
!= pti
)
1690 ERR("MsqPeekMouseMove: Thread Q is locked to another pti!\n");
1694 msg
= MessageQueue
->MouseMoveMsg
;
1696 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1703 ClearMsgBitsMask(pti
, QS_MOUSEMOVE
);
1704 MessageQueue
->MouseMoved
= FALSE
;
1707 MessageQueue
->ptiSysLock
= NULL
;
1708 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1709 return AcceptMessage
;
1712 /* check whether a message filter contains at least one potential hardware message */
1714 filter_contains_hw_range( UINT first
, UINT last
)
1716 /* hardware message ranges are (in numerical order):
1717 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1718 * WM_KEYFIRST .. WM_KEYLAST
1719 * WM_MOUSEFIRST .. WM_MOUSELAST
1722 if (last
< WM_NCMOUSEFIRST
) return 0;
1723 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1724 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1725 if (first
> WM_MOUSELAST
) return 0;
1730 co_MsqPeekHardwareMessage(IN PTHREADINFO pti
,
1733 IN UINT MsgFilterLow
,
1734 IN UINT MsgFilterHigh
,
1740 PUSER_MESSAGE CurrentMessage
;
1741 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1744 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
1746 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1748 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1749 CurrentEntry
= ListHead
->Flink
;
1751 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1753 if (!MessageQueue
->ptiSysLock
)
1755 MessageQueue
->ptiSysLock
= pti
;
1756 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1759 if (MessageQueue
->ptiSysLock
!= pti
)
1761 ERR("MsqPeekHardwareMessage: Thread Q is locked to another pti!\n");
1765 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1769 if (IsListEmpty(CurrentEntry
)) break;
1770 if (!CurrentMessage
) break;
1771 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1772 if (!CurrentEntry
) break; //// Fix CORE-6734 reported crash.
1775 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1776 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1777 3: handle to the window whose messages are to be retrieved.
1779 if ( ( !Window
|| // 1
1780 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1781 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1782 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1783 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1785 msg
= CurrentMessage
->Msg
;
1787 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
1788 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1792 RemoveEntryList(&CurrentMessage
->ListEntry
);
1793 ClearMsgBitsMask(pti
, CurrentMessage
->QS_Flags
);
1794 MsqDestroyMessage(CurrentMessage
);
1804 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
1806 while(CurrentEntry
!= ListHead
);
1808 MessageQueue
->ptiSysLock
= NULL
;
1809 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1814 MsqPeekMessage(IN PTHREADINFO pti
,
1817 IN UINT MsgFilterLow
,
1818 IN UINT MsgFilterHigh
,
1822 PLIST_ENTRY CurrentEntry
;
1823 PUSER_MESSAGE CurrentMessage
;
1824 PLIST_ENTRY ListHead
;
1827 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
1828 ListHead
= &pti
->PostedMessagesListHead
;
1830 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1832 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1836 if (IsListEmpty(CurrentEntry
)) break;
1837 if (!CurrentMessage
) break;
1838 CurrentEntry
= CurrentEntry
->Flink
;
1841 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1842 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1843 3: handle to the window whose messages are to be retrieved.
1845 if ( ( !Window
|| // 1
1846 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1847 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1848 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1849 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1851 *Message
= CurrentMessage
->Msg
;
1855 RemoveEntryList(&CurrentMessage
->ListEntry
);
1856 ClearMsgBitsMask(pti
, CurrentMessage
->QS_Flags
);
1857 MsqDestroyMessage(CurrentMessage
);
1862 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1865 while (CurrentEntry
!= ListHead
);
1871 co_MsqWaitForNewMessages(PTHREADINFO pti
, PWND WndFilter
,
1872 UINT MsgFilterMin
, UINT MsgFilterMax
)
1876 ret
= KeWaitForSingleObject( pti
->pEventQueueServer
,
1886 MsqIsHung(PTHREADINFO pti
)
1888 LARGE_INTEGER LargeTickCount
;
1890 KeQueryTickCount(&LargeTickCount
);
1891 return ((LargeTickCount
.u
.LowPart
- pti
->timeLast
) > MSQ_HUNG
);
1896 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1899 TRACE("HungAppSysTimerProc\n");
1900 // Process list of windows that are hung and waiting.
1904 MsqInitializeMessageQueue(PTHREADINFO pti
, PUSER_MESSAGE_QUEUE MessageQueue
)
1906 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1907 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
); // Keep here!
1908 MessageQueue
->spwndFocus
= NULL
;
1909 MessageQueue
->iCursorLevel
= 0;
1910 MessageQueue
->CursorObject
= NULL
;
1911 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
1912 MessageQueue
->ptiMouse
= pti
;
1913 MessageQueue
->ptiKeyboard
= pti
;
1914 MessageQueue
->cThreads
++;
1920 MsqCleanupThreadMsgs(PTHREADINFO pti
)
1922 PLIST_ENTRY CurrentEntry
;
1923 PUSER_MESSAGE CurrentMessage
;
1924 PUSER_SENT_MESSAGE CurrentSentMessage
;
1926 /* cleanup posted messages */
1927 while (!IsListEmpty(&pti
->PostedMessagesListHead
))
1929 CurrentEntry
= RemoveHeadList(&pti
->PostedMessagesListHead
);
1930 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1932 MsqDestroyMessage(CurrentMessage
);
1935 /* remove the messages that have not yet been dispatched */
1936 while (!IsListEmpty(&pti
->SentMessagesListHead
))
1938 CurrentEntry
= RemoveHeadList(&pti
->SentMessagesListHead
);
1939 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1942 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
1943 /* Only if the message has a sender was the message in the DispatchingList */
1944 if ((CurrentSentMessage
->ptiSender
)
1945 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1947 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1950 /* wake the sender's thread */
1951 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1953 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1956 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1958 if (CurrentSentMessage
->Msg
.lParam
)
1959 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1962 /* free the message */
1963 ExFreePool(CurrentSentMessage
);
1966 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1967 ExitThread() was called in a SendMessage() umode callback */
1968 while (!IsListEmpty(&pti
->LocalDispatchingMessagesHead
))
1970 CurrentEntry
= RemoveHeadList(&pti
->LocalDispatchingMessagesHead
);
1971 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1974 /* remove the message from the dispatching list */
1975 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1977 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1980 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
1982 /* wake the sender's thread */
1983 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1985 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1988 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1990 if (CurrentSentMessage
->Msg
.lParam
)
1991 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1994 /* free the message */
1995 ExFreePool(CurrentSentMessage
);
1998 /* tell other threads not to bother returning any info to us */
1999 while (! IsListEmpty(&pti
->DispatchingMessagesHead
))
2001 CurrentEntry
= RemoveHeadList(&pti
->DispatchingMessagesHead
);
2002 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2003 DispatchingListEntry
);
2004 CurrentSentMessage
->CompletionEvent
= NULL
;
2005 CurrentSentMessage
->Result
= NULL
;
2007 /* do NOT dereference our message queue as it might get attempted to be
2011 // Clear it all out.
2014 pti
->pcti
->fsWakeBits
= 0;
2015 pti
->pcti
->fsChangeBits
= 0;
2018 pti
->nCntsQBits
[QSRosKey
] = 0;
2019 pti
->nCntsQBits
[QSRosMouseMove
] = 0;
2020 pti
->nCntsQBits
[QSRosMouseButton
] = 0;
2021 pti
->nCntsQBits
[QSRosPostMessage
] = 0;
2022 pti
->nCntsQBits
[QSRosSendMessage
] = 0;
2023 pti
->nCntsQBits
[QSRosHotKey
] = 0;
2024 pti
->nCntsQBits
[QSRosEvent
] = 0;
2028 MsqCleanupMessageQueue(PTHREADINFO pti
)
2030 PUSER_MESSAGE_QUEUE MessageQueue
;
2032 MessageQueue
= pti
->MessageQueue
;
2033 MessageQueue
->cThreads
--;
2035 if (MessageQueue
->cThreads
)
2037 if (MessageQueue
->ptiSysLock
== pti
) MessageQueue
->ptiSysLock
= NULL
;
2040 if (MessageQueue
->CursorObject
)
2042 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2044 /* Change to another cursor if we going to dereference current one
2045 Note: we can't use UserSetCursor because it uses current thread
2046 message queue instead of queue given for cleanup */
2047 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2051 /* Get the screen DC */
2052 hdcScreen
= IntGetScreenDC();
2054 GreMovePointer(hdcScreen
, -1, -1);
2055 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2058 ERR("DereferenceObject pCursor\n");
2059 UserDereferenceObject(pCursor
);
2062 if (gpqForeground
== MessageQueue
)
2064 IntSetFocusMessageQueue(NULL
);
2066 if (gpqForegroundPrev
== MessageQueue
)
2068 gpqForegroundPrev
= NULL
;
2070 if (gpqCursor
== MessageQueue
)
2076 PUSER_MESSAGE_QUEUE FASTCALL
2077 MsqCreateMessageQueue(PTHREADINFO pti
)
2079 PUSER_MESSAGE_QUEUE MessageQueue
;
2081 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2082 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2090 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2091 /* hold at least one reference until it'll be destroyed */
2092 IntReferenceMessageQueue(MessageQueue
);
2093 /* initialize the queue */
2094 if (!MsqInitializeMessageQueue(pti
, MessageQueue
))
2096 IntDereferenceMessageQueue(MessageQueue
);
2100 return MessageQueue
;
2104 MsqDestroyMessageQueue(PTHREADINFO pti
)
2107 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2109 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2111 /* remove the message queue from any desktops */
2112 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2114 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2115 IntDereferenceMessageQueue(MessageQueue
);
2119 MsqCleanupMessageQueue(pti
);
2121 /* decrease the reference counter, if it hits zero, the queue will be freed */
2122 IntDereferenceMessageQueue(MessageQueue
);
2126 MsqSetMessageExtraInfo(LPARAM lParam
)
2130 PUSER_MESSAGE_QUEUE MessageQueue
;
2132 pti
= PsGetCurrentThreadWin32Thread();
2133 MessageQueue
= pti
->MessageQueue
;
2139 Ret
= MessageQueue
->ExtraInfo
;
2140 MessageQueue
->ExtraInfo
= lParam
;
2146 MsqGetMessageExtraInfo(VOID
)
2149 PUSER_MESSAGE_QUEUE MessageQueue
;
2151 pti
= PsGetCurrentThreadWin32Thread();
2152 MessageQueue
= pti
->MessageQueue
;
2158 return MessageQueue
->ExtraInfo
;
2161 // ReplyMessage is called by the thread receiving the window message.
2163 co_MsqReplyMessage( LRESULT lResult
)
2165 PUSER_SENT_MESSAGE Message
;
2168 pti
= PsGetCurrentThreadWin32Thread();
2169 Message
= pti
->pusmCurrent
;
2171 if (!Message
) return FALSE
;
2173 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2175 // SendMessageXxx || Callback msg and not a notify msg
2176 if (Message
->ptiSender
|| Message
->CompletionCallback
)
2178 Message
->lResult
= lResult
;
2179 Message
->QS_Flags
|= QS_SMRESULT
;
2180 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2186 MsqSetStateWindow(PTHREADINFO pti
, ULONG Type
, HWND hWnd
)
2189 PUSER_MESSAGE_QUEUE MessageQueue
;
2191 MessageQueue
= pti
->MessageQueue
;
2195 case MSQ_STATE_CAPTURE
:
2196 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2197 MessageQueue
->spwndCapture
= ValidateHwndNoErr(hWnd
);
2199 case MSQ_STATE_ACTIVE
:
2200 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2201 MessageQueue
->spwndActive
= ValidateHwndNoErr(hWnd
);
2203 case MSQ_STATE_FOCUS
:
2204 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2205 MessageQueue
->spwndFocus
= ValidateHwndNoErr(hWnd
);
2207 case MSQ_STATE_MENUOWNER
:
2208 Prev
= MessageQueue
->MenuOwner
;
2209 MessageQueue
->MenuOwner
= hWnd
;
2211 case MSQ_STATE_MOVESIZE
:
2212 Prev
= MessageQueue
->MoveSize
;
2213 MessageQueue
->MoveSize
= hWnd
;
2215 case MSQ_STATE_CARET
:
2216 ASSERT(MessageQueue
->CaretInfo
);
2217 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2218 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2227 NtUserGetKeyState(INT key
)
2233 Ret
= UserGetKeyState(key
);
2243 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2245 DWORD i
, ret
= TRUE
;
2247 PUSER_MESSAGE_QUEUE MessageQueue
;
2251 pti
= PsGetCurrentThreadWin32Thread();
2252 MessageQueue
= pti
->MessageQueue
;
2256 /* Probe and copy key state to an array */
2257 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2258 for (i
= 0; i
< 256; ++i
)
2261 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2262 lpKeyState
[i
] |= KS_DOWN_BIT
;
2263 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2264 lpKeyState
[i
] |= KS_LOCK_BIT
;
2267 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2269 SetLastNtError(_SEH2_GetExceptionCode());
2281 NtUserSetKeyboardState(LPBYTE pKeyState
)
2286 PUSER_MESSAGE_QUEUE MessageQueue
;
2288 UserEnterExclusive();
2290 pti
= PsGetCurrentThreadWin32Thread();
2291 MessageQueue
= pti
->MessageQueue
;
2295 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2296 for (i
= 0; i
< 256; ++i
)
2298 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2299 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2302 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2304 SetLastNtError(_SEH2_GetExceptionCode());