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 PCURICON_OBJECT CursorFrame
= NewCursor
;
150 if(NewCursor
->CURSORF_flags
& CURSORF_ACON
)
152 FIXME("Should animate the cursor, using only the first frame now.\n");
153 CursorFrame
= ((PACON
)NewCursor
)->aspcur
[0];
155 GreSetPointerShape(hdcScreen
,
156 CursorFrame
->hbmAlpha
? NULL
: NewCursor
->hbmMask
,
157 CursorFrame
->hbmAlpha
? NewCursor
->hbmAlpha
: NewCursor
->hbmColor
,
158 CursorFrame
->xHotspot
,
159 CursorFrame
->yHotspot
,
162 CursorFrame
->hbmAlpha
? SPS_ALPHA
: 0);
164 GreSetPointerShape(hdcScreen
,
165 NewCursor
->IconInfo
.hbmMask
,
166 NewCursor
->IconInfo
.hbmColor
,
167 NewCursor
->IconInfo
.xHotspot
,
168 NewCursor
->IconInfo
.yHotspot
,
174 else /* Note: OldCursor != NewCursor so we have to hide cursor */
176 /* Remove the cursor */
177 GreMovePointer(hdcScreen
, -1, -1);
178 TRACE("Removing pointer!\n");
180 IntGetSysCursorInfo()->CurrentCursorObject
= NewCursor
;
183 /* Return the old cursor */
187 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
188 * User32 macro NtUserShowCursor */
189 int UserShowCursor(BOOL bShow
)
193 PUSER_MESSAGE_QUEUE MessageQueue
;
196 if (!(hdcScreen
= IntGetScreenDC()))
198 return -1; /* No mouse */
201 pti
= PsGetCurrentThreadWin32Thread();
202 MessageQueue
= pti
->MessageQueue
;
205 MessageQueue
->iCursorLevel
+= bShow
? 1 : -1;
206 pti
->iCursorLevel
+= bShow
? 1 : -1;
208 /* Check for trivial cases */
209 if ((bShow
&& MessageQueue
->iCursorLevel
!= 0) ||
210 (!bShow
&& MessageQueue
->iCursorLevel
!= -1))
212 /* Note: w don't update global info here because it is used only
213 internally to check if cursor is visible */
214 return MessageQueue
->iCursorLevel
;
217 /* Check if cursor is above window owned by this MessageQueue */
218 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
219 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
223 /* Show the pointer */
224 GreMovePointer(hdcScreen
, gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
225 TRACE("Showing pointer!\n");
229 /* Remove the pointer */
230 GreMovePointer(hdcScreen
, -1, -1);
231 TRACE("Removing pointer!\n");
234 /* Update global info */
235 IntGetSysCursorInfo()->ShowingCursor
= MessageQueue
->iCursorLevel
;
238 return MessageQueue
->iCursorLevel
;
242 UserGetKeyState(DWORD dwKey
)
246 PUSER_MESSAGE_QUEUE MessageQueue
;
248 pti
= PsGetCurrentThreadWin32Thread();
249 MessageQueue
= pti
->MessageQueue
;
253 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, dwKey
))
254 dwRet
|= 0xFF80; // If down, windows returns 0xFF80.
255 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, dwKey
))
260 EngSetLastError(ERROR_INVALID_PARAMETER
);
265 /* change the input key state for a given key */
267 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue
, WORD wVk
, BOOL bIsDown
)
269 TRACE("UpdateKeyState wVk: %u, bIsDown: %d\n", wVk
, bIsDown
);
273 /* If it's first key down event, xor lock bit */
274 if (!IS_KEY_DOWN(MessageQueue
->afKeyState
, wVk
))
275 SET_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
, !IS_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
));
277 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, TRUE
);
278 MessageQueue
->afKeyRecentDown
[wVk
/ 8] |= (1 << (wVk
% 8));
281 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, FALSE
);
284 /* update the input key state for a keyboard message */
286 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
291 TRACE("UpdateKeyStateFromMsg message:%u\n", msg
->message
);
293 switch (msg
->message
)
299 UpdateKeyState(MessageQueue
, VK_LBUTTON
, down
);
305 UpdateKeyState(MessageQueue
, VK_MBUTTON
, down
);
311 UpdateKeyState(MessageQueue
, VK_RBUTTON
, down
);
317 if (msg
->wParam
== XBUTTON1
)
318 UpdateKeyState(MessageQueue
, VK_XBUTTON1
, down
);
319 else if (msg
->wParam
== XBUTTON2
)
320 UpdateKeyState(MessageQueue
, VK_XBUTTON2
, down
);
328 key
= (UCHAR
)msg
->wParam
;
329 UpdateKeyState(MessageQueue
, key
, down
);
334 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LCONTROL
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RCONTROL
);
335 UpdateKeyState(MessageQueue
, VK_CONTROL
, down
);
339 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LMENU
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RMENU
);
340 UpdateKeyState(MessageQueue
, VK_MENU
, down
);
344 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LSHIFT
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RSHIFT
);
345 UpdateKeyState(MessageQueue
, VK_SHIFT
, down
);
353 IntMsqSetWakeMask(DWORD WakeMask
)
355 PTHREADINFO Win32Thread
;
356 HANDLE MessageEventHandle
;
357 DWORD dwFlags
= HIWORD(WakeMask
);
359 Win32Thread
= PsGetCurrentThreadWin32Thread();
360 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
363 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
364 MessageEventHandle
= Win32Thread
->hEventQueueClient
;
366 if (Win32Thread
->pcti
)
368 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
369 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
371 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
372 KeSetEvent(Win32Thread
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
373 return MessageEventHandle
;
379 return MessageEventHandle
;
383 IntMsqClearWakeMask(VOID
)
385 PTHREADINFO Win32Thread
;
387 Win32Thread
= PsGetCurrentThreadWin32Thread();
388 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
390 // Very hacky, but that is what they do.
391 Win32Thread
->pcti
->fsWakeBits
= 0;
399 Due to the uncertainty of knowing what was set in our multilevel message queue,
400 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
401 I think this is the best solution... (jt) */
403 MsqWakeQueue(PTHREADINFO pti
, DWORD MessageBits
, BOOL KeyEvent
)
405 PUSER_MESSAGE_QUEUE Queue
;
407 Queue
= pti
->MessageQueue
;
409 if (Queue
->QF_flags
& QF_INDESTROY
)
411 ERR("This Message Queue is in Destroy!\n");
413 pti
->pcti
->fsWakeBits
|= MessageBits
;
414 pti
->pcti
->fsChangeBits
|= MessageBits
;
416 // Start bit accounting to help clear the main set of bits.
417 if (MessageBits
& QS_KEY
)
419 pti
->nCntsQBits
[QSRosKey
]++;
421 if (MessageBits
& QS_MOUSE
)
423 if (MessageBits
& QS_MOUSEMOVE
) pti
->nCntsQBits
[QSRosMouseMove
]++;
424 if (MessageBits
& QS_MOUSEBUTTON
) pti
->nCntsQBits
[QSRosMouseButton
]++;
426 if (MessageBits
& QS_POSTMESSAGE
) pti
->nCntsQBits
[QSRosPostMessage
]++;
427 if (MessageBits
& QS_SENDMESSAGE
) pti
->nCntsQBits
[QSRosSendMessage
]++;
428 if (MessageBits
& QS_HOTKEY
) pti
->nCntsQBits
[QSRosHotKey
]++;
429 if (MessageBits
& QS_EVENT
) pti
->nCntsQBits
[QSRosEvent
]++;
432 KeSetEvent(pti
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
);
436 ClearMsgBitsMask(PTHREADINFO pti
, UINT MessageBits
)
438 PUSER_MESSAGE_QUEUE Queue
;
441 Queue
= pti
->MessageQueue
;
443 if (MessageBits
& QS_KEY
)
445 if (--pti
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
447 if (MessageBits
& QS_MOUSEMOVE
) // ReactOS hard coded.
448 { // Account for tracking mouse moves..
449 if (--pti
->nCntsQBits
[QSRosMouseMove
] == 0) ClrMask
|= QS_MOUSEMOVE
;
450 // Handle mouse move bits here.
451 if (Queue
->MouseMoved
) ClrMask
|= QS_MOUSEMOVE
;
453 if (MessageBits
& QS_MOUSEBUTTON
)
455 if (--pti
->nCntsQBits
[QSRosMouseButton
] == 0) ClrMask
|= QS_MOUSEBUTTON
;
457 if (MessageBits
& QS_POSTMESSAGE
)
459 if (--pti
->nCntsQBits
[QSRosPostMessage
] == 0) ClrMask
|= QS_POSTMESSAGE
;
461 if (MessageBits
& QS_TIMER
) // ReactOS hard coded.
462 { // Handle timer bits here.
463 if ( pti
->cTimersReady
)
465 if (--pti
->cTimersReady
== 0) ClrMask
|= QS_TIMER
;
468 if (MessageBits
& QS_PAINT
) // ReactOS hard coded.
469 { // Handle paint bits here.
470 if ( pti
->cPaintsReady
)
472 if (--pti
->cPaintsReady
== 0) ClrMask
|= QS_PAINT
;
475 if (MessageBits
& QS_SENDMESSAGE
)
477 if (--pti
->nCntsQBits
[QSRosSendMessage
] == 0) ClrMask
|= QS_SENDMESSAGE
;
479 if (MessageBits
& QS_HOTKEY
)
481 if (--pti
->nCntsQBits
[QSRosHotKey
] == 0) ClrMask
|= QS_HOTKEY
;
483 if (MessageBits
& QS_EVENT
)
485 if (--pti
->nCntsQBits
[QSRosEvent
] == 0) ClrMask
|= QS_EVENT
;
488 pti
->pcti
->fsWakeBits
&= ~ClrMask
;
489 pti
->pcti
->fsChangeBits
&= ~ClrMask
;
493 MsqIncPaintCountQueue(PTHREADINFO pti
)
496 MsqWakeQueue(pti
, QS_PAINT
, TRUE
);
500 MsqDecPaintCountQueue(PTHREADINFO pti
)
502 ClearMsgBitsMask(pti
, QS_PAINT
);
506 MsqPostMouseMove(PTHREADINFO pti
, MSG
* Msg
)
508 pti
->MessageQueue
->MouseMoveMsg
= *Msg
;
509 pti
->MessageQueue
->MouseMoved
= TRUE
;
510 MsqWakeQueue(pti
, QS_MOUSEMOVE
, TRUE
);
514 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
516 LARGE_INTEGER LargeTickCount
;
517 MSLLHOOKSTRUCT MouseHookData
;
519 PWND pwnd
, pwndDesktop
;
522 PUSER_MESSAGE_QUEUE MessageQueue
;
523 PSYSTEM_CURSORINFO CurInfo
;
525 KeQueryTickCount(&LargeTickCount
);
526 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
528 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
529 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
530 switch (Msg
->message
)
533 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
537 case WM_XBUTTONDBLCLK
:
538 case WM_NCXBUTTONDOWN
:
540 case WM_NCXBUTTONDBLCLK
:
541 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
544 MouseHookData
.mouseData
= 0;
548 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
549 MouseHookData
.time
= Msg
->time
;
550 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
552 /* If the hook procedure returned non zero, dont send the message */
555 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
559 /* Get the desktop window */
560 pwndDesktop
= UserGetDesktopWindow();
561 if (!pwndDesktop
) return;
562 // pDesk = pwndDesktop->head.rpdesk;
564 /* Check if the mouse is captured */
565 Msg
->hwnd
= IntGetCaptureWindow();
566 if (Msg
->hwnd
!= NULL
)
568 pwnd
= UserGetWindowObject(Msg
->hwnd
);
572 pwnd
= IntTopLevelWindowFromPoint(Msg
->pt
.x
, Msg
->pt
.y
);
573 if (pwnd
) Msg
->hwnd
= pwnd
->head
.h
;
576 hdcScreen
= IntGetScreenDC();
577 CurInfo
= IntGetSysCursorInfo();
579 /* Check if we found a window */
580 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
582 pti
= pwnd
->head
.pti
;
583 MessageQueue
= pti
->MessageQueue
;
584 // MessageQueue->ptiMouse = pti;
586 if ( pti
->TIF_flags
& TIF_INCLEANUP
|| MessageQueue
->QF_flags
& QF_INDESTROY
)
588 ERR("Mouse is over the Window Thread is Dead!\n");
592 if (Msg
->message
== WM_MOUSEMOVE
)
594 /* Check if cursor should be visible */
596 MessageQueue
->CursorObject
&&
597 MessageQueue
->iCursorLevel
>= 0)
599 /* Check if shape has changed */
600 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
602 /* Call GDI to set the new screen cursor */
603 #ifdef NEW_CURSORICON
604 GreSetPointerShape(hdcScreen
,
605 MessageQueue
->CursorObject
->hbmAlpha
?
606 NULL
: MessageQueue
->CursorObject
->hbmMask
,
607 MessageQueue
->CursorObject
->hbmAlpha
?
608 MessageQueue
->CursorObject
->hbmAlpha
: MessageQueue
->CursorObject
->hbmColor
,
609 MessageQueue
->CursorObject
->xHotspot
,
610 MessageQueue
->CursorObject
->yHotspot
,
613 MessageQueue
->CursorObject
->hbmAlpha
? SPS_ALPHA
: 0);
615 GreSetPointerShape(hdcScreen
,
616 MessageQueue
->CursorObject
->IconInfo
.hbmMask
,
617 MessageQueue
->CursorObject
->IconInfo
.hbmColor
,
618 MessageQueue
->CursorObject
->IconInfo
.xHotspot
,
619 MessageQueue
->CursorObject
->IconInfo
.yHotspot
,
625 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
627 /* Check if w have to hide cursor */
628 else if (CurInfo
->ShowingCursor
>= 0)
629 GreMovePointer(hdcScreen
, -1, -1);
631 /* Update global cursor info */
632 CurInfo
->ShowingCursor
= MessageQueue
->iCursorLevel
;
633 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
634 gpqCursor
= MessageQueue
;
636 /* Mouse move is a special case */
637 MsqPostMouseMove(pti
, Msg
);
641 if (!IntGetCaptureWindow())
643 // ERR("ptiLastInput is set\n");
644 // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
646 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd
));
647 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEBUTTON
, 0);
652 /* always show cursor on background; FIXME: set default pointer */
653 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
654 CurInfo
->ShowingCursor
= 0;
658 PUSER_MESSAGE FASTCALL
659 MsqCreateMessage(LPMSG Msg
)
661 PUSER_MESSAGE Message
;
663 Message
= ExAllocateFromPagedLookasideList(pgMessageLookasideList
);
669 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
675 MsqDestroyMessage(PUSER_MESSAGE Message
)
677 ExFreeToPagedLookasideList(pgMessageLookasideList
, Message
);
681 co_MsqDispatchOneSentMessage(PTHREADINFO pti
)
683 PUSER_SENT_MESSAGE SaveMsg
, Message
;
688 if (IsListEmpty(&pti
->SentMessagesListHead
))
693 /* remove it from the list of pending messages */
694 Entry
= RemoveHeadList(&pti
->SentMessagesListHead
);
695 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
697 SaveMsg
= pti
->pusmCurrent
;
698 pti
->pusmCurrent
= Message
;
700 // Processing a message sent to it from another thread.
701 if ( ( Message
->ptiSender
&& pti
!= Message
->ptiSender
) ||
702 ( Message
->ptiCallBackSender
&& pti
!= Message
->ptiCallBackSender
))
703 { // most likely, but, to be sure.
704 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
707 /* insert it to the list of messages that are currently dispatched by this
709 InsertTailList(&pti
->LocalDispatchingMessagesHead
,
710 &Message
->ListEntry
);
712 ClearMsgBitsMask(pti
, Message
->QS_Flags
);
714 if (Message
->HookMessage
== MSQ_ISHOOK
)
715 { // Direct Hook Call processor
716 Result
= co_CallHook( Message
->Msg
.message
, // HookId
717 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
719 Message
->Msg
.lParam
);
721 else if (Message
->HookMessage
== MSQ_ISEVENT
)
722 { // Direct Event Call processor
723 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
726 Message
->Msg
.lParam
);
728 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
730 Result
= IntLoadHookModule(Message
->Msg
.message
,
731 (HHOOK
)Message
->Msg
.lParam
,
732 Message
->Msg
.wParam
);
734 else if ((Message
->CompletionCallback
) &&
735 (Message
->ptiCallBackSender
== pti
))
736 { /* Call the callback routine */
737 if (Message
->QS_Flags
& QS_SMRESULT
)
739 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
741 Message
->Msg
.message
,
742 Message
->CompletionCallbackContext
,
744 /* Set callback to NULL to prevent reentry */
745 Message
->CompletionCallback
= NULL
;
749 /* The message has not been processed yet, reinsert it. */
750 RemoveEntryList(&Message
->ListEntry
);
751 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
752 TRACE("Callback Message not processed yet. Requeuing the message\n");
758 { /* Call the window procedure. */
759 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
760 Message
->Msg
.message
,
762 Message
->Msg
.lParam
);
765 /* remove the message from the local dispatching list, because it doesn't need
766 to be cleaned up on thread termination anymore */
767 RemoveEntryList(&Message
->ListEntry
);
769 /* If the message is a callback, insert it in the callback senders MessageQueue */
770 if (Message
->CompletionCallback
)
772 if (Message
->ptiCallBackSender
)
774 Message
->lResult
= Result
;
775 Message
->QS_Flags
|= QS_SMRESULT
;
777 /* insert it in the callers message queue */
778 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
779 MsqWakeQueue(Message
->ptiCallBackSender
, QS_SENDMESSAGE
, TRUE
);
785 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
786 if (Message
->ptiSender
)
788 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
790 /* only remove it from the dispatching list if not already removed by a timeout */
791 RemoveEntryList(&Message
->DispatchingListEntry
);
794 /* still keep the sender's message queue locked, so the sender can't exit the
795 MsqSendMessage() function (if timed out) */
797 if (Message
->QS_Flags
& QS_SMRESULT
)
799 Result
= Message
->lResult
;
802 /* Let the sender know the result. */
803 if (Message
->Result
!= NULL
)
805 *Message
->Result
= Result
;
808 if (Message
->HasPackedLParam
== TRUE
)
810 if (Message
->Msg
.lParam
)
811 ExFreePool((PVOID
)Message
->Msg
.lParam
);
814 /* Notify the sender. */
815 if (Message
->CompletionEvent
!= NULL
)
817 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
820 /* free the message */
821 ExFreePoolWithTag(Message
, TAG_USRMSG
);
824 /* do not hangup on the user if this is reentering */
825 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
826 pti
->pusmCurrent
= SaveMsg
;
832 MsqRemoveWindowMessagesFromQueue(PWND Window
)
835 PUSER_SENT_MESSAGE SentMessage
;
836 PUSER_MESSAGE PostedMessage
;
837 PLIST_ENTRY CurrentEntry
, ListHead
;
841 pti
= Window
->head
.pti
;
843 /* remove the posted messages for this window */
844 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
845 ListHead
= &pti
->PostedMessagesListHead
;
846 while (CurrentEntry
!= ListHead
)
848 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
850 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
852 RemoveEntryList(&PostedMessage
->ListEntry
);
853 ClearMsgBitsMask(pti
, PostedMessage
->QS_Flags
);
854 MsqDestroyMessage(PostedMessage
);
855 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
859 CurrentEntry
= CurrentEntry
->Flink
;
863 /* remove the sent messages for this window */
864 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
865 ListHead
= &pti
->SentMessagesListHead
;
866 while (CurrentEntry
!= ListHead
)
868 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
870 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
872 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
874 RemoveEntryList(&SentMessage
->ListEntry
);
875 ClearMsgBitsMask(pti
, SentMessage
->QS_Flags
);
877 /* Only if the message has a sender was the queue referenced */
878 if ((SentMessage
->ptiSender
)
879 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
881 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
884 /* wake the sender's thread */
885 if (SentMessage
->CompletionEvent
!= NULL
)
887 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
890 if (SentMessage
->HasPackedLParam
== TRUE
)
892 if (SentMessage
->Msg
.lParam
)
893 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
896 /* free the message */
897 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
899 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
903 CurrentEntry
= CurrentEntry
->Flink
;
909 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
914 SENDASYNCPROC CompletionCallback
,
915 ULONG_PTR CompletionCallbackContext
,
916 BOOL HasPackedLParam
,
920 PTHREADINFO ptiSender
;
921 PUSER_SENT_MESSAGE Message
;
923 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
925 ERR("MsqSendMessage(): Not enough memory to allocate a message");
929 ptiSender
= PsGetCurrentThreadWin32Thread();
931 Message
->Msg
.hwnd
= hwnd
;
932 Message
->Msg
.message
= Msg
;
933 Message
->Msg
.wParam
= wParam
;
934 Message
->Msg
.lParam
= lParam
;
935 Message
->CompletionEvent
= NULL
;
937 Message
->lResult
= 0;
938 Message
->ptiReceiver
= ptiReceiver
;
939 Message
->ptiSender
= NULL
;
940 Message
->ptiCallBackSender
= ptiSender
;
941 Message
->DispatchingListEntry
.Flink
= NULL
;
942 Message
->CompletionCallback
= CompletionCallback
;
943 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
944 Message
->HookMessage
= HookMessage
;
945 Message
->HasPackedLParam
= HasPackedLParam
;
946 Message
->QS_Flags
= QS_SENDMESSAGE
;
948 InsertTailList(&ptiReceiver
->SentMessagesListHead
, &Message
->ListEntry
);
949 MsqWakeQueue(ptiReceiver
, QS_SENDMESSAGE
, TRUE
);
955 co_MsqSendMessage(PTHREADINFO ptirec
,
956 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
957 UINT uTimeout
, BOOL Block
, INT HookMessage
,
961 PUSER_SENT_MESSAGE Message
;
962 KEVENT CompletionEvent
;
964 LARGE_INTEGER Timeout
;
967 LRESULT Result
= 0; //// Result could be trashed. ////
969 pti
= PsGetCurrentThreadWin32Thread();
970 ASSERT(pti
!= ptirec
);
971 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
973 /* Don't send from or to a dying thread */
974 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
976 // Unless we are dying and need to tell our parents.
977 if (pti
->TIF_flags
& TIF_INCLEANUP
&& !(ptirec
->TIF_flags
& TIF_INCLEANUP
))
979 // Parent notify is the big one. Fire and forget!
980 TRACE("Send message from dying thread %d\n",Msg
);
981 co_MsqSendMessageAsync(ptirec
, Wnd
, Msg
, wParam
, lParam
, NULL
, 0, FALSE
, HookMessage
);
983 if (uResult
) *uResult
= -1;
984 TRACE("MsqSM: Msg %d Current pti %lu or Rec pti %lu\n", Msg
, pti
->TIF_flags
& TIF_INCLEANUP
, ptirec
->TIF_flags
& TIF_INCLEANUP
);
985 return STATUS_UNSUCCESSFUL
;
988 if ( HookMessage
== MSQ_NORMAL
)
990 pWnd
= ValidateHwndNoErr(Wnd
);
992 // These can not cross International Border lines!
993 if ( pti
->ppi
!= ptirec
->ppi
&& pWnd
)
997 // Handle the special case when working with password transfers across bordering processes.
999 case EM_SETPASSWORDCHAR
:
1001 // Look for edit controls setup for passwords.
1002 if ( gpsi
->atomSysClass
[ICLS_EDIT
] == pWnd
->pcls
->atomClassName
&& // Use atomNVClassName.
1003 pWnd
->style
& ES_PASSWORD
)
1005 if (uResult
) *uResult
= -1;
1006 ERR("Running across the border without a passport!\n");
1007 EngSetLastError(ERROR_ACCESS_DENIED
);
1008 return STATUS_UNSUCCESSFUL
;
1012 if (uResult
) *uResult
= -1;
1013 ERR("Running across the border without a passport!\n");
1014 return STATUS_UNSUCCESSFUL
;
1018 // These can not cross State lines!
1019 if ( Msg
== WM_CREATE
|| Msg
== WM_NCCREATE
)
1021 if (uResult
) *uResult
= -1;
1022 ERR("Can not tell the other State we have Create!\n");
1023 return STATUS_UNSUCCESSFUL
;
1027 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1029 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1030 return STATUS_INSUFFICIENT_RESOURCES
;
1033 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1035 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1037 /* FIXME: Increase reference counter of sender's message queue here */
1039 Message
->Msg
.hwnd
= Wnd
;
1040 Message
->Msg
.message
= Msg
;
1041 Message
->Msg
.wParam
= wParam
;
1042 Message
->Msg
.lParam
= lParam
;
1043 Message
->CompletionEvent
= &CompletionEvent
;
1044 Message
->Result
= &Result
;
1045 Message
->lResult
= 0;
1046 Message
->QS_Flags
= 0;
1047 Message
->ptiReceiver
= ptirec
;
1048 Message
->ptiSender
= pti
;
1049 Message
->ptiCallBackSender
= NULL
;
1050 Message
->CompletionCallback
= NULL
;
1051 Message
->CompletionCallbackContext
= 0;
1052 Message
->HookMessage
= HookMessage
;
1053 Message
->HasPackedLParam
= FALSE
;
1055 /* Add it to the list of pending messages */
1056 InsertTailList(&pti
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1058 /* Queue it in the destination's message queue */
1059 InsertTailList(&ptirec
->SentMessagesListHead
, &Message
->ListEntry
);
1061 Message
->QS_Flags
= QS_SENDMESSAGE
;
1062 MsqWakeQueue(ptirec
, 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
= ptirec
->SentMessagesListHead
.Flink
;
1081 while (Entry
!= &ptirec
->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
= pti
->DispatchingMessagesHead
.Flink
;
1098 while (Entry
!= &pti
->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(ptirec
))
1123 PVOID WaitObjects
[3];
1125 WaitObjects
[0] = &CompletionEvent
; // Wait 0
1126 WaitObjects
[1] = pti
->pEventQueueServer
; // Wait 1
1127 WaitObjects
[2] = ptirec
->pEThread
; // Wait 2
1133 WaitStatus
= KeWaitForMultipleObjects(3, WaitObjects
, WaitAny
, UserRequest
,
1134 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1138 if(WaitStatus
== STATUS_TIMEOUT
)
1140 /* Look up if the message has not yet been dispatched, if so
1141 make sure it can't pass a result and it must not set the completion event anymore */
1142 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1143 while (Entry
!= &ptirec
->SentMessagesListHead
)
1145 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1148 /* We can access Message here, it's secure because the message queue is locked
1149 and the message is still hasn't been dispatched */
1150 Message
->CompletionEvent
= NULL
;
1151 Message
->Result
= NULL
;
1154 Entry
= Entry
->Flink
;
1157 /* Remove from the local dispatching list so the other thread knows,
1158 it can't pass a result and it must not set the completion event anymore */
1159 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1160 while (Entry
!= &pti
->DispatchingMessagesHead
)
1162 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1165 /* We can access Message here, it's secure because the sender's message is locked
1166 and the message has definitely not yet been destroyed, otherwise it would
1167 have been removed from this list by the dispatching routine right after
1168 dispatching the message */
1169 Message
->CompletionEvent
= NULL
;
1170 Message
->Result
= NULL
;
1171 RemoveEntryList(&Message
->DispatchingListEntry
);
1172 Message
->DispatchingListEntry
.Flink
= NULL
;
1175 Entry
= Entry
->Flink
;
1178 TRACE("MsqSendMessage timed out 2\n");
1181 // Receiving thread passed on and left us hanging with issues still pending.
1182 if ( WaitStatus
== STATUS_WAIT_2
)
1184 ERR("Receiving Thread woken up dead!\n");
1185 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1186 while (Entry
!= &pti
->DispatchingMessagesHead
)
1188 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1191 Message
->CompletionEvent
= NULL
;
1192 Message
->Result
= NULL
;
1193 RemoveEntryList(&Message
->DispatchingListEntry
);
1194 Message
->DispatchingListEntry
.Flink
= NULL
;
1197 Entry
= Entry
->Flink
;
1200 while (co_MsqDispatchOneSentMessage(pti
))
1203 while (NT_SUCCESS(WaitStatus
) && WaitStatus
== STATUS_WAIT_1
);
1206 if(WaitStatus
!= STATUS_TIMEOUT
)
1207 if (uResult
) *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1213 MsqPostMessage(PTHREADINFO pti
,
1215 BOOLEAN HardwareMessage
,
1219 PUSER_MESSAGE Message
;
1220 PUSER_MESSAGE_QUEUE MessageQueue
;
1222 if ( pti
->TIF_flags
& TIF_INCLEANUP
|| pti
->MessageQueue
->QF_flags
& QF_INDESTROY
)
1224 ERR("Post Msg; Thread or Q is Dead!\n");
1228 if(!(Message
= MsqCreateMessage(Msg
)))
1233 MessageQueue
= pti
->MessageQueue
;
1237 ERR("Post Msg; System Qeued Event Message!\n");
1238 InsertHeadList(&pti
->PostedMessagesListHead
,
1239 &Message
->ListEntry
);
1241 else if (!HardwareMessage
)
1243 InsertTailList(&pti
->PostedMessagesListHead
,
1244 &Message
->ListEntry
);
1248 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1249 &Message
->ListEntry
);
1252 if (Msg
->message
== WM_HOTKEY
) MessageBits
|= QS_HOTKEY
; // Justin Case, just set it.
1253 Message
->dwQEvent
= dwQEvent
;
1254 Message
->QS_Flags
= MessageBits
;
1256 MsqWakeQueue(pti
, MessageBits
, TRUE
);
1260 MsqPostQuitMessage(PTHREADINFO pti
, ULONG ExitCode
)
1262 pti
->QuitPosted
= TRUE
;
1263 pti
->exitCode
= ExitCode
;
1264 MsqWakeQueue(pti
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1267 /***********************************************************************
1268 * MsqSendParentNotify
1270 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1271 * the window has the WS_EX_NOPARENTNOTIFY style.
1273 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1275 PWND pwndDesktop
= UserGetDesktopWindow();
1277 /* pt has to be in the client coordinates of the parent window */
1278 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1279 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1285 if (!(pwnd
->style
& WS_CHILD
)) break;
1286 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1287 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1288 if (pwndParent
== pwndDesktop
) break;
1289 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1290 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1293 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1294 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1300 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1302 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1303 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
1305 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1306 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1307 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1309 TRACE("ITMM: Track Mouse Move!\n");
1311 /* Handle only the changing window track and mouse move across a border. */
1312 if ( pDesk
->spwndTrack
!= pwndTrack
||
1313 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1315 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1316 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1318 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1319 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1320 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1323 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1324 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1326 /* Clear the flags to sign a change. */
1327 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1329 /* Set the Track window and hit test. */
1330 pDesk
->spwndTrack
= pwndTrack
;
1331 pDesk
->htEx
= hittest
;
1334 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1335 if ( pDesk
->spwndTrack
== pwndTrack
&&
1336 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1337 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1339 TRACE("ITMM: Reset Hover points!\n");
1340 // Restart timer for the hover period.
1341 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1342 // Reset desktop mouse hover from the system default hover rectangle.
1343 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1344 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1345 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1346 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1347 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1351 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1358 MOUSEHOOKSTRUCT hook
;
1359 BOOL eatMsg
= FALSE
;
1361 PWND pwndMsg
, pwndDesktop
;
1362 PUSER_MESSAGE_QUEUE MessageQueue
;
1364 PSYSTEM_CURSORINFO CurInfo
;
1366 DECLARE_RETURN(BOOL
);
1368 pti
= PsGetCurrentThreadWin32Thread();
1369 pwndDesktop
= UserGetDesktopWindow();
1370 MessageQueue
= pti
->MessageQueue
;
1371 CurInfo
= IntGetSysCursorInfo();
1372 pwndMsg
= ValidateHwndNoErr(msg
->hwnd
);
1373 clk_msg
= MessageQueue
->msgDblClk
;
1374 pDesk
= pwndDesktop
->head
.rpdesk
;
1376 /* find the window to dispatch this mouse message to */
1377 if (MessageQueue
->spwndCapture
)
1380 pwndMsg
= MessageQueue
->spwndCapture
;
1381 if (pwndMsg
) UserReferenceObject(pwndMsg
);
1385 pwndMsg
= co_WinPosWindowFromPoint(NULL
, &msg
->pt
, &hittest
, FALSE
);//TRUE);
1388 TRACE("Got mouse message for %p, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1390 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
1392 /* Remove and ignore the message */
1393 *RemoveMessages
= TRUE
;
1397 if ( MessageQueue
== gpqCursor
) // Cursor must use the same Queue!
1399 IntTrackMouseMove(pwndMsg
, pDesk
, msg
, hittest
);
1403 ERR("Not the same cursor!\n");
1406 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1409 message
= msg
->message
;
1410 /* Note: windows has no concept of a non-client wheel message */
1411 if (message
!= WM_MOUSEWHEEL
)
1413 if (hittest
!= HTCLIENT
)
1415 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1416 msg
->wParam
= hittest
;
1420 /* coordinates don't get translated while tracking a menu */
1421 /* FIXME: should differentiate popups and top-level menus */
1422 if (!(MessageQueue
->MenuOwner
))
1424 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1425 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1429 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1431 /* translate double clicks */
1433 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1434 (msg
->message
== WM_RBUTTONDOWN
) ||
1435 (msg
->message
== WM_MBUTTONDOWN
) ||
1436 (msg
->message
== WM_XBUTTONDOWN
))
1438 BOOL update
= *RemoveMessages
;
1440 /* translate double clicks -
1441 * note that ...MOUSEMOVEs can slip in between
1442 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1444 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1445 hittest
!= HTCLIENT
||
1446 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1448 if ((msg
->message
== clk_msg
.message
) &&
1449 (msg
->hwnd
== clk_msg
.hwnd
) &&
1450 (msg
->wParam
== clk_msg
.wParam
) &&
1451 ((msg
->time
- clk_msg
.time
) < (ULONG
)gspv
.iDblClickTime
) &&
1452 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1453 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1455 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1458 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1464 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1466 TRACE("Message out of range!!!\n");
1470 /* update static double click conditions */
1471 if (update
) MessageQueue
->msgDblClk
= *msg
;
1475 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1477 TRACE("Message out of range!!!\n");
1482 if(gspv
.bMouseClickLock
)
1484 BOOL IsClkLck
= FALSE
;
1486 if(msg
->message
== WM_LBUTTONUP
)
1488 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1489 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1491 CurInfo
->ClickLockActive
= TRUE
;
1494 else if (msg
->message
== WM_LBUTTONDOWN
)
1496 if (CurInfo
->ClickLockActive
)
1499 CurInfo
->ClickLockActive
= FALSE
;
1502 CurInfo
->ClickLockTime
= msg
->time
;
1507 /* Remove and ignore the message */
1508 *RemoveMessages
= TRUE
;
1513 /* message is accepted now (but may still get dropped) */
1515 event
.message
= msg
->message
;
1516 event
.time
= msg
->time
;
1517 event
.hwnd
= msg
->hwnd
;
1518 event
.paramL
= msg
->pt
.x
;
1519 event
.paramH
= msg
->pt
.y
;
1520 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1523 hook
.hwnd
= msg
->hwnd
;
1524 hook
.wHitTestCode
= hittest
;
1525 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1526 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1527 message
, (LPARAM
)&hook
))
1530 hook
.hwnd
= msg
->hwnd
;
1531 hook
.wHitTestCode
= hittest
;
1532 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1533 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1535 ERR("WH_MOUSE dropped mouse message!\n");
1537 /* Remove and skip message */
1538 *RemoveMessages
= TRUE
;
1542 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1544 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1545 MAKELONG( hittest
, msg
->message
));
1547 /* Remove and skip message */
1548 *RemoveMessages
= TRUE
;
1552 if ((*RemoveMessages
== FALSE
) || MessageQueue
->spwndCapture
)
1554 /* Accept the message */
1555 msg
->message
= message
;
1559 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1560 (msg
->message
== WM_RBUTTONDOWN
) ||
1561 (msg
->message
== WM_MBUTTONDOWN
) ||
1562 (msg
->message
== WM_XBUTTONDOWN
))
1564 /* Send the WM_PARENTNOTIFY,
1565 * note that even for double/nonclient clicks
1566 * notification message is still WM_L/M/RBUTTONDOWN.
1568 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1570 /* Activate the window if needed */
1572 if (pwndMsg
!= MessageQueue
->spwndActive
)
1574 PWND pwndTop
= pwndMsg
;
1575 pwndTop
= IntGetNonChildAncestor(pwndTop
);
1577 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1579 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1581 (WPARAM
)UserHMGetHandle(pwndTop
),
1582 MAKELONG( hittest
, msg
->message
));
1585 case MA_NOACTIVATEANDEAT
:
1590 case MA_ACTIVATEANDEAT
:
1595 if (!co_IntMouseActivateWindow( pwndTop
)) eatMsg
= TRUE
;
1598 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1605 /* send the WM_SETCURSOR message */
1607 /* Windows sends the normal mouse message as the message parameter
1608 in the WM_SETCURSOR message even if it's non-client mouse message */
1609 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1611 msg
->message
= message
;
1616 UserDereferenceObject(pwndMsg
);
1621 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1625 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1626 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1628 switch (Msg
->wParam
)
1630 case VK_LSHIFT
: case VK_RSHIFT
:
1631 Msg
->wParam
= VK_SHIFT
;
1633 case VK_LCONTROL
: case VK_RCONTROL
:
1634 Msg
->wParam
= VK_CONTROL
;
1636 case VK_LMENU
: case VK_RMENU
:
1637 Msg
->wParam
= VK_MENU
;
1642 Event
.message
= Msg
->message
;
1643 Event
.hwnd
= Msg
->hwnd
;
1644 Event
.time
= Msg
->time
;
1645 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1646 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1647 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1648 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1650 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1651 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1652 LOWORD(Msg
->wParam
),
1655 /* skip this message */
1656 co_HOOK_CallHooks( WH_CBT
,
1658 LOWORD(Msg
->wParam
),
1660 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1666 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1668 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1670 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1672 else if ( IS_KBD_MESSAGE(Msg
->message
))
1674 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1681 co_MsqPeekMouseMove(IN PTHREADINFO pti
,
1684 IN UINT MsgFilterLow
,
1685 IN UINT MsgFilterHigh
,
1690 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
1692 if(!(MessageQueue
->MouseMoved
))
1695 if (!MessageQueue
->ptiSysLock
)
1697 MessageQueue
->ptiSysLock
= pti
;
1698 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1701 if (MessageQueue
->ptiSysLock
!= pti
)
1703 ERR("MsqPeekMouseMove: Thread Q is locked to another pti!\n");
1707 msg
= MessageQueue
->MouseMoveMsg
;
1709 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1716 ClearMsgBitsMask(pti
, QS_MOUSEMOVE
);
1717 MessageQueue
->MouseMoved
= FALSE
;
1720 MessageQueue
->ptiSysLock
= NULL
;
1721 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1722 return AcceptMessage
;
1725 /* check whether a message filter contains at least one potential hardware message */
1727 filter_contains_hw_range( UINT first
, UINT last
)
1729 /* hardware message ranges are (in numerical order):
1730 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1731 * WM_KEYFIRST .. WM_KEYLAST
1732 * WM_MOUSEFIRST .. WM_MOUSELAST
1735 if (last
< WM_NCMOUSEFIRST
) return 0;
1736 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1737 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1738 if (first
> WM_MOUSELAST
) return 0;
1743 co_MsqPeekHardwareMessage(IN PTHREADINFO pti
,
1746 IN UINT MsgFilterLow
,
1747 IN UINT MsgFilterHigh
,
1753 PUSER_MESSAGE CurrentMessage
;
1754 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1757 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
1759 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1761 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1762 CurrentEntry
= ListHead
->Flink
;
1764 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1766 if (!MessageQueue
->ptiSysLock
)
1768 MessageQueue
->ptiSysLock
= pti
;
1769 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1772 if (MessageQueue
->ptiSysLock
!= pti
)
1774 ERR("MsqPeekHardwareMessage: Thread Q is locked to another pti!\n");
1778 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1782 if (IsListEmpty(CurrentEntry
)) break;
1783 if (!CurrentMessage
) break;
1784 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1785 if (!CurrentEntry
) break; //// Fix CORE-6734 reported crash.
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_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1794 ( Window
!= PWND_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 msg
= CurrentMessage
->Msg
;
1800 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
1801 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1805 RemoveEntryList(&CurrentMessage
->ListEntry
);
1806 ClearMsgBitsMask(pti
, CurrentMessage
->QS_Flags
);
1807 MsqDestroyMessage(CurrentMessage
);
1817 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
1819 while(CurrentEntry
!= ListHead
);
1821 MessageQueue
->ptiSysLock
= NULL
;
1822 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1827 MsqPeekMessage(IN PTHREADINFO pti
,
1830 IN UINT MsgFilterLow
,
1831 IN UINT MsgFilterHigh
,
1835 PLIST_ENTRY CurrentEntry
;
1836 PUSER_MESSAGE CurrentMessage
;
1837 PLIST_ENTRY ListHead
;
1840 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
1841 ListHead
= &pti
->PostedMessagesListHead
;
1843 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1845 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1849 if (IsListEmpty(CurrentEntry
)) break;
1850 if (!CurrentMessage
) break;
1851 CurrentEntry
= CurrentEntry
->Flink
;
1854 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1855 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1856 3: handle to the window whose messages are to be retrieved.
1858 if ( ( !Window
|| // 1
1859 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1860 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1861 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1862 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1864 *Message
= CurrentMessage
->Msg
;
1868 RemoveEntryList(&CurrentMessage
->ListEntry
);
1869 ClearMsgBitsMask(pti
, CurrentMessage
->QS_Flags
);
1870 MsqDestroyMessage(CurrentMessage
);
1875 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1878 while (CurrentEntry
!= ListHead
);
1884 co_MsqWaitForNewMessages(PTHREADINFO pti
, PWND WndFilter
,
1885 UINT MsgFilterMin
, UINT MsgFilterMax
)
1889 ret
= KeWaitForSingleObject( pti
->pEventQueueServer
,
1899 MsqIsHung(PTHREADINFO pti
)
1901 LARGE_INTEGER LargeTickCount
;
1903 KeQueryTickCount(&LargeTickCount
);
1904 return ((LargeTickCount
.u
.LowPart
- pti
->timeLast
) > MSQ_HUNG
);
1909 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1912 TRACE("HungAppSysTimerProc\n");
1913 // Process list of windows that are hung and waiting.
1917 MsqInitializeMessageQueue(PTHREADINFO pti
, PUSER_MESSAGE_QUEUE MessageQueue
)
1919 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1920 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
); // Keep here!
1921 MessageQueue
->spwndFocus
= NULL
;
1922 MessageQueue
->iCursorLevel
= 0;
1923 MessageQueue
->CursorObject
= NULL
;
1924 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
1925 MessageQueue
->ptiMouse
= pti
;
1926 MessageQueue
->ptiKeyboard
= pti
;
1927 MessageQueue
->cThreads
++;
1933 MsqCleanupThreadMsgs(PTHREADINFO pti
)
1935 PLIST_ENTRY CurrentEntry
;
1936 PUSER_MESSAGE CurrentMessage
;
1937 PUSER_SENT_MESSAGE CurrentSentMessage
;
1939 /* cleanup posted messages */
1940 while (!IsListEmpty(&pti
->PostedMessagesListHead
))
1942 CurrentEntry
= RemoveHeadList(&pti
->PostedMessagesListHead
);
1943 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1945 MsqDestroyMessage(CurrentMessage
);
1948 /* remove the messages that have not yet been dispatched */
1949 while (!IsListEmpty(&pti
->SentMessagesListHead
))
1951 CurrentEntry
= RemoveHeadList(&pti
->SentMessagesListHead
);
1952 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1955 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
1956 /* Only if the message has a sender was the message in the DispatchingList */
1957 if ((CurrentSentMessage
->ptiSender
)
1958 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1960 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1963 /* wake the sender's thread */
1964 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1966 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1969 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1971 if (CurrentSentMessage
->Msg
.lParam
)
1972 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1975 /* free the message */
1976 ExFreePool(CurrentSentMessage
);
1979 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1980 ExitThread() was called in a SendMessage() umode callback */
1981 while (!IsListEmpty(&pti
->LocalDispatchingMessagesHead
))
1983 CurrentEntry
= RemoveHeadList(&pti
->LocalDispatchingMessagesHead
);
1984 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1987 /* remove the message from the dispatching list */
1988 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1990 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1993 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
1995 /* wake the sender's thread */
1996 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1998 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2001 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
2003 if (CurrentSentMessage
->Msg
.lParam
)
2004 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2007 /* free the message */
2008 ExFreePool(CurrentSentMessage
);
2011 /* tell other threads not to bother returning any info to us */
2012 while (! IsListEmpty(&pti
->DispatchingMessagesHead
))
2014 CurrentEntry
= RemoveHeadList(&pti
->DispatchingMessagesHead
);
2015 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2016 DispatchingListEntry
);
2017 CurrentSentMessage
->CompletionEvent
= NULL
;
2018 CurrentSentMessage
->Result
= NULL
;
2020 /* do NOT dereference our message queue as it might get attempted to be
2024 // Clear it all out.
2027 pti
->pcti
->fsWakeBits
= 0;
2028 pti
->pcti
->fsChangeBits
= 0;
2031 pti
->nCntsQBits
[QSRosKey
] = 0;
2032 pti
->nCntsQBits
[QSRosMouseMove
] = 0;
2033 pti
->nCntsQBits
[QSRosMouseButton
] = 0;
2034 pti
->nCntsQBits
[QSRosPostMessage
] = 0;
2035 pti
->nCntsQBits
[QSRosSendMessage
] = 0;
2036 pti
->nCntsQBits
[QSRosHotKey
] = 0;
2037 pti
->nCntsQBits
[QSRosEvent
] = 0;
2041 MsqCleanupMessageQueue(PTHREADINFO pti
)
2043 PUSER_MESSAGE_QUEUE MessageQueue
;
2045 MessageQueue
= pti
->MessageQueue
;
2046 MessageQueue
->cThreads
--;
2048 if (MessageQueue
->cThreads
)
2050 if (MessageQueue
->ptiSysLock
== pti
) MessageQueue
->ptiSysLock
= NULL
;
2053 if (MessageQueue
->CursorObject
)
2055 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2057 /* Change to another cursor if we going to dereference current one
2058 Note: we can't use UserSetCursor because it uses current thread
2059 message queue instead of queue given for cleanup */
2060 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2064 /* Get the screen DC */
2065 hdcScreen
= IntGetScreenDC();
2067 GreMovePointer(hdcScreen
, -1, -1);
2068 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2071 ERR("DereferenceObject pCursor\n");
2072 UserDereferenceObject(pCursor
);
2075 if (gpqForeground
== MessageQueue
)
2077 IntSetFocusMessageQueue(NULL
);
2079 if (gpqForegroundPrev
== MessageQueue
)
2081 gpqForegroundPrev
= NULL
;
2083 if (gpqCursor
== MessageQueue
)
2089 PUSER_MESSAGE_QUEUE FASTCALL
2090 MsqCreateMessageQueue(PTHREADINFO pti
)
2092 PUSER_MESSAGE_QUEUE MessageQueue
;
2094 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2095 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2103 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2104 /* hold at least one reference until it'll be destroyed */
2105 IntReferenceMessageQueue(MessageQueue
);
2106 /* initialize the queue */
2107 if (!MsqInitializeMessageQueue(pti
, MessageQueue
))
2109 IntDereferenceMessageQueue(MessageQueue
);
2113 return MessageQueue
;
2117 MsqDestroyMessageQueue(PTHREADINFO pti
)
2120 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2122 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2124 /* remove the message queue from any desktops */
2125 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2127 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2128 IntDereferenceMessageQueue(MessageQueue
);
2132 MsqCleanupMessageQueue(pti
);
2134 /* decrease the reference counter, if it hits zero, the queue will be freed */
2135 IntDereferenceMessageQueue(MessageQueue
);
2139 MsqSetMessageExtraInfo(LPARAM lParam
)
2143 PUSER_MESSAGE_QUEUE MessageQueue
;
2145 pti
= PsGetCurrentThreadWin32Thread();
2146 MessageQueue
= pti
->MessageQueue
;
2152 Ret
= MessageQueue
->ExtraInfo
;
2153 MessageQueue
->ExtraInfo
= lParam
;
2159 MsqGetMessageExtraInfo(VOID
)
2162 PUSER_MESSAGE_QUEUE MessageQueue
;
2164 pti
= PsGetCurrentThreadWin32Thread();
2165 MessageQueue
= pti
->MessageQueue
;
2171 return MessageQueue
->ExtraInfo
;
2174 // ReplyMessage is called by the thread receiving the window message.
2176 co_MsqReplyMessage( LRESULT lResult
)
2178 PUSER_SENT_MESSAGE Message
;
2181 pti
= PsGetCurrentThreadWin32Thread();
2182 Message
= pti
->pusmCurrent
;
2184 if (!Message
) return FALSE
;
2186 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2188 // SendMessageXxx || Callback msg and not a notify msg
2189 if (Message
->ptiSender
|| Message
->CompletionCallback
)
2191 Message
->lResult
= lResult
;
2192 Message
->QS_Flags
|= QS_SMRESULT
;
2193 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2199 MsqSetStateWindow(PTHREADINFO pti
, ULONG Type
, HWND hWnd
)
2202 PUSER_MESSAGE_QUEUE MessageQueue
;
2204 MessageQueue
= pti
->MessageQueue
;
2208 case MSQ_STATE_CAPTURE
:
2209 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2210 MessageQueue
->spwndCapture
= ValidateHwndNoErr(hWnd
);
2212 case MSQ_STATE_ACTIVE
:
2213 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2214 MessageQueue
->spwndActive
= ValidateHwndNoErr(hWnd
);
2216 case MSQ_STATE_FOCUS
:
2217 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2218 MessageQueue
->spwndFocus
= ValidateHwndNoErr(hWnd
);
2220 case MSQ_STATE_MENUOWNER
:
2221 Prev
= MessageQueue
->MenuOwner
;
2222 MessageQueue
->MenuOwner
= hWnd
;
2224 case MSQ_STATE_MOVESIZE
:
2225 Prev
= MessageQueue
->MoveSize
;
2226 MessageQueue
->MoveSize
= hWnd
;
2228 case MSQ_STATE_CARET
:
2229 ASSERT(MessageQueue
->CaretInfo
);
2230 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2231 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2240 NtUserGetKeyState(INT key
)
2246 Ret
= UserGetKeyState(key
);
2256 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2258 DWORD i
, ret
= TRUE
;
2260 PUSER_MESSAGE_QUEUE MessageQueue
;
2264 pti
= PsGetCurrentThreadWin32Thread();
2265 MessageQueue
= pti
->MessageQueue
;
2269 /* Probe and copy key state to an array */
2270 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2271 for (i
= 0; i
< 256; ++i
)
2274 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2275 lpKeyState
[i
] |= KS_DOWN_BIT
;
2276 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2277 lpKeyState
[i
] |= KS_LOCK_BIT
;
2280 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2282 SetLastNtError(_SEH2_GetExceptionCode());
2294 NtUserSetKeyboardState(LPBYTE pKeyState
)
2299 PUSER_MESSAGE_QUEUE MessageQueue
;
2301 UserEnterExclusive();
2303 pti
= PsGetCurrentThreadWin32Thread();
2304 MessageQueue
= pti
->MessageQueue
;
2308 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2309 for (i
= 0; i
< 256; ++i
)
2311 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2312 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2315 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2317 SetLastNtError(_SEH2_GetExceptionCode());