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
;
579 if ( pti
->TIF_flags
& TIF_INCLEANUP
|| MessageQueue
->QF_flags
& QF_INDESTROY
)
581 ERR("Mouse is over the Window Thread is Dead!\n");
585 if (Msg
->message
== WM_MOUSEMOVE
)
587 /* Check if cursor should be visible */
589 MessageQueue
->CursorObject
&&
590 MessageQueue
->iCursorLevel
>= 0)
592 /* Check if shape has changed */
593 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
595 /* Call GDI to set the new screen cursor */
596 #ifdef NEW_CURSORICON
597 GreSetPointerShape(hdcScreen
,
598 MessageQueue
->CursorObject
->hbmAlpha
?
599 NULL
: MessageQueue
->CursorObject
->hbmMask
,
600 MessageQueue
->CursorObject
->hbmAlpha
?
601 MessageQueue
->CursorObject
->hbmAlpha
: MessageQueue
->CursorObject
->hbmColor
,
602 MessageQueue
->CursorObject
->xHotspot
,
603 MessageQueue
->CursorObject
->yHotspot
,
606 MessageQueue
->CursorObject
->hbmAlpha
? SPS_ALPHA
: 0);
608 GreSetPointerShape(hdcScreen
,
609 MessageQueue
->CursorObject
->IconInfo
.hbmMask
,
610 MessageQueue
->CursorObject
->IconInfo
.hbmColor
,
611 MessageQueue
->CursorObject
->IconInfo
.xHotspot
,
612 MessageQueue
->CursorObject
->IconInfo
.yHotspot
,
618 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
620 /* Check if w have to hide cursor */
621 else if (CurInfo
->ShowingCursor
>= 0)
622 GreMovePointer(hdcScreen
, -1, -1);
624 /* Update global cursor info */
625 CurInfo
->ShowingCursor
= MessageQueue
->iCursorLevel
;
626 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
627 gpqCursor
= MessageQueue
;
629 /* Mouse move is a special case */
630 MsqPostMouseMove(pti
, Msg
);
634 if (!IntGetCaptureWindow())
636 // ERR("ptiLastInput is set\n");
637 // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
639 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd
));
640 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEBUTTON
, 0);
645 /* always show cursor on background; FIXME: set default pointer */
646 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
647 CurInfo
->ShowingCursor
= 0;
651 PUSER_MESSAGE FASTCALL
652 MsqCreateMessage(LPMSG Msg
)
654 PUSER_MESSAGE Message
;
656 Message
= ExAllocateFromPagedLookasideList(pgMessageLookasideList
);
662 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
668 MsqDestroyMessage(PUSER_MESSAGE Message
)
670 ExFreeToPagedLookasideList(pgMessageLookasideList
, Message
);
674 co_MsqDispatchOneSentMessage(PTHREADINFO pti
)
676 PUSER_SENT_MESSAGE SaveMsg
, Message
;
681 if (IsListEmpty(&pti
->SentMessagesListHead
))
686 /* remove it from the list of pending messages */
687 Entry
= RemoveHeadList(&pti
->SentMessagesListHead
);
688 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
690 SaveMsg
= pti
->pusmCurrent
;
691 pti
->pusmCurrent
= Message
;
693 // Processing a message sent to it from another thread.
694 if ( ( Message
->ptiSender
&& pti
!= Message
->ptiSender
) ||
695 ( Message
->ptiCallBackSender
&& pti
!= Message
->ptiCallBackSender
))
696 { // most likely, but, to be sure.
697 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
700 /* insert it to the list of messages that are currently dispatched by this
702 InsertTailList(&pti
->LocalDispatchingMessagesHead
,
703 &Message
->ListEntry
);
705 ClearMsgBitsMask(pti
, Message
->QS_Flags
);
707 if (Message
->HookMessage
== MSQ_ISHOOK
)
708 { // Direct Hook Call processor
709 Result
= co_CallHook( Message
->Msg
.message
, // HookId
710 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
712 Message
->Msg
.lParam
);
714 else if (Message
->HookMessage
== MSQ_ISEVENT
)
715 { // Direct Event Call processor
716 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
719 Message
->Msg
.lParam
);
721 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
723 Result
= IntLoadHookModule(Message
->Msg
.message
,
724 (HHOOK
)Message
->Msg
.lParam
,
725 Message
->Msg
.wParam
);
727 else if ((Message
->CompletionCallback
) &&
728 (Message
->ptiCallBackSender
== pti
))
729 { /* Call the callback routine */
730 if (Message
->QS_Flags
& QS_SMRESULT
)
732 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
734 Message
->Msg
.message
,
735 Message
->CompletionCallbackContext
,
737 /* Set callback to NULL to prevent reentry */
738 Message
->CompletionCallback
= NULL
;
742 /* The message has not been processed yet, reinsert it. */
743 RemoveEntryList(&Message
->ListEntry
);
744 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
745 TRACE("Callback Message not processed yet. Requeuing the message\n");
751 { /* Call the window procedure. */
752 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
753 Message
->Msg
.message
,
755 Message
->Msg
.lParam
);
758 /* remove the message from the local dispatching list, because it doesn't need
759 to be cleaned up on thread termination anymore */
760 RemoveEntryList(&Message
->ListEntry
);
762 /* If the message is a callback, insert it in the callback senders MessageQueue */
763 if (Message
->CompletionCallback
)
765 if (Message
->ptiCallBackSender
)
767 Message
->lResult
= Result
;
768 Message
->QS_Flags
|= QS_SMRESULT
;
770 /* insert it in the callers message queue */
771 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
772 MsqWakeQueue(Message
->ptiCallBackSender
, QS_SENDMESSAGE
, TRUE
);
778 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
779 if (Message
->ptiSender
)
781 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
783 /* only remove it from the dispatching list if not already removed by a timeout */
784 RemoveEntryList(&Message
->DispatchingListEntry
);
787 /* still keep the sender's message queue locked, so the sender can't exit the
788 MsqSendMessage() function (if timed out) */
790 if (Message
->QS_Flags
& QS_SMRESULT
)
792 Result
= Message
->lResult
;
795 /* Let the sender know the result. */
796 if (Message
->Result
!= NULL
)
798 *Message
->Result
= Result
;
801 if (Message
->HasPackedLParam
== TRUE
)
803 if (Message
->Msg
.lParam
)
804 ExFreePool((PVOID
)Message
->Msg
.lParam
);
807 /* Notify the sender. */
808 if (Message
->CompletionEvent
!= NULL
)
810 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
813 /* free the message */
814 ExFreePoolWithTag(Message
, TAG_USRMSG
);
817 /* do not hangup on the user if this is reentering */
818 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
819 pti
->pusmCurrent
= SaveMsg
;
825 MsqRemoveWindowMessagesFromQueue(PWND Window
)
828 PUSER_SENT_MESSAGE SentMessage
;
829 PUSER_MESSAGE PostedMessage
;
830 PLIST_ENTRY CurrentEntry
, ListHead
;
834 pti
= Window
->head
.pti
;
836 /* remove the posted messages for this window */
837 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
838 ListHead
= &pti
->PostedMessagesListHead
;
839 while (CurrentEntry
!= ListHead
)
841 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
843 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
845 RemoveEntryList(&PostedMessage
->ListEntry
);
846 ClearMsgBitsMask(pti
, PostedMessage
->QS_Flags
);
847 MsqDestroyMessage(PostedMessage
);
848 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
852 CurrentEntry
= CurrentEntry
->Flink
;
856 /* remove the sent messages for this window */
857 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
858 ListHead
= &pti
->SentMessagesListHead
;
859 while (CurrentEntry
!= ListHead
)
861 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
863 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
865 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
867 RemoveEntryList(&SentMessage
->ListEntry
);
868 ClearMsgBitsMask(pti
, SentMessage
->QS_Flags
);
870 /* Only if the message has a sender was the queue referenced */
871 if ((SentMessage
->ptiSender
)
872 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
874 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
877 /* wake the sender's thread */
878 if (SentMessage
->CompletionEvent
!= NULL
)
880 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
883 if (SentMessage
->HasPackedLParam
== TRUE
)
885 if (SentMessage
->Msg
.lParam
)
886 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
889 /* free the message */
890 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
892 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
896 CurrentEntry
= CurrentEntry
->Flink
;
902 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
907 SENDASYNCPROC CompletionCallback
,
908 ULONG_PTR CompletionCallbackContext
,
909 BOOL HasPackedLParam
,
913 PTHREADINFO ptiSender
;
914 PUSER_SENT_MESSAGE Message
;
916 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
918 ERR("MsqSendMessage(): Not enough memory to allocate a message");
922 ptiSender
= PsGetCurrentThreadWin32Thread();
924 Message
->Msg
.hwnd
= hwnd
;
925 Message
->Msg
.message
= Msg
;
926 Message
->Msg
.wParam
= wParam
;
927 Message
->Msg
.lParam
= lParam
;
928 Message
->CompletionEvent
= NULL
;
930 Message
->lResult
= 0;
931 Message
->ptiReceiver
= ptiReceiver
;
932 Message
->ptiSender
= NULL
;
933 Message
->ptiCallBackSender
= ptiSender
;
934 Message
->DispatchingListEntry
.Flink
= NULL
;
935 Message
->CompletionCallback
= CompletionCallback
;
936 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
937 Message
->HookMessage
= HookMessage
;
938 Message
->HasPackedLParam
= HasPackedLParam
;
939 Message
->QS_Flags
= QS_SENDMESSAGE
;
941 InsertTailList(&ptiReceiver
->SentMessagesListHead
, &Message
->ListEntry
);
942 MsqWakeQueue(ptiReceiver
, QS_SENDMESSAGE
, TRUE
);
948 co_MsqSendMessage(PTHREADINFO ptirec
,
949 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
950 UINT uTimeout
, BOOL Block
, INT HookMessage
,
954 PUSER_SENT_MESSAGE Message
;
955 KEVENT CompletionEvent
;
957 LARGE_INTEGER Timeout
;
960 LRESULT Result
= 0; //// Result could be trashed. ////
962 pti
= PsGetCurrentThreadWin32Thread();
963 ASSERT(pti
!= ptirec
);
964 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
966 /* Don't send from or to a dying thread */
967 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
969 if (uResult
) *uResult
= -1;
970 ERR("MsqSM: Current pti %lu or Rec pti %lu\n", pti
->TIF_flags
& TIF_INCLEANUP
, ptirec
->TIF_flags
& TIF_INCLEANUP
);
971 return STATUS_UNSUCCESSFUL
;
974 if ( HookMessage
== MSQ_NORMAL
)
976 pWnd
= ValidateHwndNoErr(Wnd
);
978 // These can not cross International Border lines!
979 if ( pti
->ppi
!= ptirec
->ppi
&& pWnd
)
983 // Handle the special case when working with password transfers across bordering processes.
985 case EM_SETPASSWORDCHAR
:
987 // Look for edit controls setup for passwords.
988 if ( gpsi
->atomSysClass
[ICLS_EDIT
] == pWnd
->pcls
->atomClassName
&& // Use atomNVClassName.
989 pWnd
->style
& ES_PASSWORD
)
991 if (uResult
) *uResult
= -1;
992 ERR("Running across the border without a passport!\n");
993 EngSetLastError(ERROR_ACCESS_DENIED
);
994 return STATUS_UNSUCCESSFUL
;
998 if (uResult
) *uResult
= -1;
999 ERR("Running across the border without a passport!\n");
1000 return STATUS_UNSUCCESSFUL
;
1004 // These can not cross State lines!
1005 if ( Msg
== WM_CREATE
|| Msg
== WM_NCCREATE
)
1007 if (uResult
) *uResult
= -1;
1008 ERR("Can not tell the other State we have Create!\n");
1009 return STATUS_UNSUCCESSFUL
;
1013 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1015 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1016 return STATUS_INSUFFICIENT_RESOURCES
;
1019 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1021 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1023 /* FIXME: Increase reference counter of sender's message queue here */
1025 Message
->Msg
.hwnd
= Wnd
;
1026 Message
->Msg
.message
= Msg
;
1027 Message
->Msg
.wParam
= wParam
;
1028 Message
->Msg
.lParam
= lParam
;
1029 Message
->CompletionEvent
= &CompletionEvent
;
1030 Message
->Result
= &Result
;
1031 Message
->lResult
= 0;
1032 Message
->QS_Flags
= 0;
1033 Message
->ptiReceiver
= ptirec
;
1034 Message
->ptiSender
= pti
;
1035 Message
->ptiCallBackSender
= NULL
;
1036 Message
->CompletionCallback
= NULL
;
1037 Message
->CompletionCallbackContext
= 0;
1038 Message
->HookMessage
= HookMessage
;
1039 Message
->HasPackedLParam
= FALSE
;
1041 /* Add it to the list of pending messages */
1042 InsertTailList(&pti
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1044 /* Queue it in the destination's message queue */
1045 InsertTailList(&ptirec
->SentMessagesListHead
, &Message
->ListEntry
);
1047 Message
->QS_Flags
= QS_SENDMESSAGE
;
1048 MsqWakeQueue(ptirec
, QS_SENDMESSAGE
, TRUE
);
1050 /* We can't access the Message anymore since it could have already been deleted! */
1056 /* Don't process messages sent to the thread */
1057 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1058 FALSE
, (uTimeout
? &Timeout
: NULL
));
1062 if(WaitStatus
== STATUS_TIMEOUT
)
1064 /* Look up if the message has not yet dispatched, if so
1065 make sure it can't pass a result and it must not set the completion event anymore */
1066 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1067 while (Entry
!= &ptirec
->SentMessagesListHead
)
1069 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1072 /* We can access Message here, it's secure because the message queue is locked
1073 and the message is still hasn't been dispatched */
1074 Message
->CompletionEvent
= NULL
;
1075 Message
->Result
= NULL
;
1078 Entry
= Entry
->Flink
;
1081 /* Remove from the local dispatching list so the other thread knows,
1082 it can't pass a result and it must not set the completion event anymore */
1083 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1084 while (Entry
!= &pti
->DispatchingMessagesHead
)
1086 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1089 /* We can access Message here, it's secure because the sender's message is locked
1090 and the message has definitely not yet been destroyed, otherwise it would
1091 have been removed from this list by the dispatching routine right after
1092 dispatching the message */
1093 Message
->CompletionEvent
= NULL
;
1094 Message
->Result
= NULL
;
1095 RemoveEntryList(&Message
->DispatchingListEntry
);
1096 Message
->DispatchingListEntry
.Flink
= NULL
;
1099 Entry
= Entry
->Flink
;
1102 TRACE("MsqSendMessage (blocked) timed out 1\n");
1104 while (co_MsqDispatchOneSentMessage(ptirec
))
1109 PVOID WaitObjects
[3];
1111 WaitObjects
[0] = &CompletionEvent
; // Wait 0
1112 WaitObjects
[1] = pti
->pEventQueueServer
; // Wait 1
1113 WaitObjects
[2] = ptirec
->pEThread
; // Wait 2
1119 WaitStatus
= KeWaitForMultipleObjects(3, WaitObjects
, WaitAny
, UserRequest
,
1120 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1124 if(WaitStatus
== STATUS_TIMEOUT
)
1126 /* Look up if the message has not yet been dispatched, if so
1127 make sure it can't pass a result and it must not set the completion event anymore */
1128 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1129 while (Entry
!= &ptirec
->SentMessagesListHead
)
1131 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1134 /* We can access Message here, it's secure because the message queue is locked
1135 and the message is still hasn't been dispatched */
1136 Message
->CompletionEvent
= NULL
;
1137 Message
->Result
= NULL
;
1140 Entry
= Entry
->Flink
;
1143 /* Remove from the local dispatching list so the other thread knows,
1144 it can't pass a result and it must not set the completion event anymore */
1145 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1146 while (Entry
!= &pti
->DispatchingMessagesHead
)
1148 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1151 /* We can access Message here, it's secure because the sender's message is locked
1152 and the message has definitely not yet been destroyed, otherwise it would
1153 have been removed from this list by the dispatching routine right after
1154 dispatching the message */
1155 Message
->CompletionEvent
= NULL
;
1156 Message
->Result
= NULL
;
1157 RemoveEntryList(&Message
->DispatchingListEntry
);
1158 Message
->DispatchingListEntry
.Flink
= NULL
;
1161 Entry
= Entry
->Flink
;
1164 TRACE("MsqSendMessage timed out 2\n");
1167 // Receiving thread passed on and left us hanging with issues still pending.
1168 if ( WaitStatus
== STATUS_WAIT_2
)
1170 ERR("Receiving Thread woken up dead!\n");
1171 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1172 while (Entry
!= &pti
->DispatchingMessagesHead
)
1174 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1177 Message
->CompletionEvent
= NULL
;
1178 Message
->Result
= NULL
;
1179 RemoveEntryList(&Message
->DispatchingListEntry
);
1180 Message
->DispatchingListEntry
.Flink
= NULL
;
1183 Entry
= Entry
->Flink
;
1186 while (co_MsqDispatchOneSentMessage(pti
))
1189 while (NT_SUCCESS(WaitStatus
) && WaitStatus
== STATUS_WAIT_1
);
1192 if(WaitStatus
!= STATUS_TIMEOUT
)
1193 if (uResult
) *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1199 MsqPostMessage(PTHREADINFO pti
,
1201 BOOLEAN HardwareMessage
,
1205 PUSER_MESSAGE Message
;
1206 PUSER_MESSAGE_QUEUE MessageQueue
;
1208 if ( pti
->TIF_flags
& TIF_INCLEANUP
|| pti
->MessageQueue
->QF_flags
& QF_INDESTROY
)
1210 ERR("Post Msg; Thread or Q is Dead!\n");
1214 if(!(Message
= MsqCreateMessage(Msg
)))
1219 MessageQueue
= pti
->MessageQueue
;
1223 ERR("Post Msg; System Qeued Event Message!\n");
1224 InsertHeadList(&pti
->PostedMessagesListHead
,
1225 &Message
->ListEntry
);
1227 else if (!HardwareMessage
)
1229 InsertTailList(&pti
->PostedMessagesListHead
,
1230 &Message
->ListEntry
);
1234 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1235 &Message
->ListEntry
);
1238 if (Msg
->message
== WM_HOTKEY
) MessageBits
|= QS_HOTKEY
; // Justin Case, just set it.
1239 Message
->dwQEvent
= dwQEvent
;
1240 Message
->QS_Flags
= MessageBits
;
1242 MsqWakeQueue(pti
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
1246 MsqPostQuitMessage(PTHREADINFO pti
, ULONG ExitCode
)
1248 pti
->QuitPosted
= TRUE
;
1249 pti
->exitCode
= ExitCode
;
1250 MsqWakeQueue(pti
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1253 /***********************************************************************
1254 * MsqSendParentNotify
1256 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1257 * the window has the WS_EX_NOPARENTNOTIFY style.
1259 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1261 PWND pwndDesktop
= UserGetDesktopWindow();
1263 /* pt has to be in the client coordinates of the parent window */
1264 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1265 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1271 if (!(pwnd
->style
& WS_CHILD
)) break;
1272 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1273 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1274 if (pwndParent
== pwndDesktop
) break;
1275 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1276 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1279 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1280 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1286 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1288 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1289 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
1291 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1292 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1293 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1295 TRACE("ITMM: Track Mouse Move!\n");
1297 /* Handle only the changing window track and mouse move across a border. */
1298 if ( pDesk
->spwndTrack
!= pwndTrack
||
1299 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1301 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1302 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1304 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1305 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1306 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1309 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1310 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1312 /* Clear the flags to sign a change. */
1313 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1315 /* Set the Track window and hit test. */
1316 pDesk
->spwndTrack
= pwndTrack
;
1317 pDesk
->htEx
= hittest
;
1320 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1321 if ( pDesk
->spwndTrack
== pwndTrack
&&
1322 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1323 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1325 TRACE("ITMM: Reset Hover points!\n");
1326 // Restart timer for the hover period.
1327 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1328 // Reset desktop mouse hover from the system default hover rectangle.
1329 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1330 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1331 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1332 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1333 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1337 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1344 MOUSEHOOKSTRUCT hook
;
1347 PWND pwndMsg
, pwndDesktop
;
1348 PUSER_MESSAGE_QUEUE MessageQueue
;
1350 PSYSTEM_CURSORINFO CurInfo
;
1352 DECLARE_RETURN(BOOL
);
1354 pti
= PsGetCurrentThreadWin32Thread();
1355 pwndDesktop
= UserGetDesktopWindow();
1356 MessageQueue
= pti
->MessageQueue
;
1357 CurInfo
= IntGetSysCursorInfo();
1358 pwndMsg
= ValidateHwndNoErr(msg
->hwnd
);
1359 clk_msg
= MessageQueue
->msgDblClk
;
1360 pDesk
= pwndDesktop
->head
.rpdesk
;
1362 /* find the window to dispatch this mouse message to */
1363 if (MessageQueue
->spwndCapture
)
1366 pwndMsg
= MessageQueue
->spwndCapture
;
1367 if (pwndMsg
) UserReferenceObject(pwndMsg
);
1370 { // Fix wine Msg test_HTTRANSPARENT. Start with a NULL window.
1371 // http://www.winehq.org/pipermail/wine-patches/2012-August/116776.html
1372 pwndMsg
= co_WinPosWindowFromPoint(NULL
, &msg
->pt
, &hittest
);
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 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
1400 message
= msg
->message
;
1401 /* Note: windows has no concept of a non-client wheel message */
1402 if (message
!= WM_MOUSEWHEEL
)
1404 if (hittest
!= HTCLIENT
)
1406 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1407 msg
->wParam
= hittest
;
1411 /* coordinates don't get translated while tracking a menu */
1412 /* FIXME: should differentiate popups and top-level menus */
1413 if (!(MessageQueue
->MenuOwner
))
1415 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1416 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1420 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1422 /* translate double clicks */
1424 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1425 (msg
->message
== WM_RBUTTONDOWN
) ||
1426 (msg
->message
== WM_MBUTTONDOWN
) ||
1427 (msg
->message
== WM_XBUTTONDOWN
))
1429 BOOL update
= *RemoveMessages
;
1431 /* translate double clicks -
1432 * note that ...MOUSEMOVEs can slip in between
1433 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1435 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1436 hittest
!= HTCLIENT
||
1437 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1439 if ((msg
->message
== clk_msg
.message
) &&
1440 (msg
->hwnd
== clk_msg
.hwnd
) &&
1441 (msg
->wParam
== clk_msg
.wParam
) &&
1442 ((msg
->time
- clk_msg
.time
) < (ULONG
)gspv
.iDblClickTime
) &&
1443 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1444 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1446 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1449 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1455 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1457 TRACE("Message out of range!!!\n");
1461 /* update static double click conditions */
1462 if (update
) MessageQueue
->msgDblClk
= *msg
;
1466 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1468 TRACE("Message out of range!!!\n");
1473 if(gspv
.bMouseClickLock
)
1475 BOOL IsClkLck
= FALSE
;
1477 if(msg
->message
== WM_LBUTTONUP
)
1479 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1480 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1482 CurInfo
->ClickLockActive
= TRUE
;
1485 else if (msg
->message
== WM_LBUTTONDOWN
)
1487 if (CurInfo
->ClickLockActive
)
1490 CurInfo
->ClickLockActive
= FALSE
;
1493 CurInfo
->ClickLockTime
= msg
->time
;
1498 /* Remove and ignore the message */
1499 *RemoveMessages
= TRUE
;
1504 /* message is accepted now (but may still get dropped) */
1506 event
.message
= msg
->message
;
1507 event
.time
= msg
->time
;
1508 event
.hwnd
= msg
->hwnd
;
1509 event
.paramL
= msg
->pt
.x
;
1510 event
.paramH
= msg
->pt
.y
;
1511 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1514 hook
.hwnd
= msg
->hwnd
;
1515 hook
.wHitTestCode
= hittest
;
1516 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1517 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1518 message
, (LPARAM
)&hook
))
1521 hook
.hwnd
= msg
->hwnd
;
1522 hook
.wHitTestCode
= hittest
;
1523 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1524 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1526 ERR("WH_MOUSE dropped mouse message!\n");
1528 /* Remove and skip message */
1529 *RemoveMessages
= TRUE
;
1533 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1535 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1536 MAKELONG( hittest
, msg
->message
));
1538 /* Remove and skip message */
1539 *RemoveMessages
= TRUE
;
1543 if ((*RemoveMessages
== FALSE
) || MessageQueue
->spwndCapture
)
1545 /* Accept the message */
1546 msg
->message
= message
;
1552 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1553 (msg
->message
== WM_RBUTTONDOWN
) ||
1554 (msg
->message
== WM_MBUTTONDOWN
) ||
1555 (msg
->message
== WM_XBUTTONDOWN
))
1557 /* Send the WM_PARENTNOTIFY,
1558 * note that even for double/nonclient clicks
1559 * notification message is still WM_L/M/RBUTTONDOWN.
1561 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1563 /* Activate the window if needed */
1565 if (pwndMsg
!= MessageQueue
->spwndActive
)
1567 PWND pwndTop
= pwndMsg
;
1568 while (pwndTop
&& ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
))
1570 pwndTop
= pwndTop
->spwndParent
;
1573 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1575 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1577 (WPARAM
)UserHMGetHandle(pwndTop
),
1578 MAKELONG( hittest
, msg
->message
));
1581 case MA_NOACTIVATEANDEAT
:
1586 case MA_ACTIVATEANDEAT
:
1591 if (!co_IntMouseActivateWindow( pwndTop
)) eatMsg
= TRUE
;
1594 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1601 /* send the WM_SETCURSOR message */
1603 /* Windows sends the normal mouse message as the message parameter
1604 in the WM_SETCURSOR message even if it's non-client mouse message */
1605 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1607 msg
->message
= message
;
1612 UserDereferenceObject(pwndMsg
);
1617 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1621 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1622 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1624 switch (Msg
->wParam
)
1626 case VK_LSHIFT
: case VK_RSHIFT
:
1627 Msg
->wParam
= VK_SHIFT
;
1629 case VK_LCONTROL
: case VK_RCONTROL
:
1630 Msg
->wParam
= VK_CONTROL
;
1632 case VK_LMENU
: case VK_RMENU
:
1633 Msg
->wParam
= VK_MENU
;
1638 Event
.message
= Msg
->message
;
1639 Event
.hwnd
= Msg
->hwnd
;
1640 Event
.time
= Msg
->time
;
1641 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1642 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1643 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1644 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1646 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1647 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1648 LOWORD(Msg
->wParam
),
1651 /* skip this message */
1652 co_HOOK_CallHooks( WH_CBT
,
1654 LOWORD(Msg
->wParam
),
1656 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1662 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1664 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1666 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1668 else if ( IS_KBD_MESSAGE(Msg
->message
))
1670 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1677 co_MsqPeekMouseMove(IN PTHREADINFO pti
,
1680 IN UINT MsgFilterLow
,
1681 IN UINT MsgFilterHigh
,
1686 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
1688 if(!(MessageQueue
->MouseMoved
))
1691 if (!MessageQueue
->ptiSysLock
)
1693 MessageQueue
->ptiSysLock
= pti
;
1694 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1697 if (MessageQueue
->ptiSysLock
!= pti
)
1699 ERR("MsqPeekMouseMove: Thread Q is locked to another pti!\n");
1703 msg
= MessageQueue
->MouseMoveMsg
;
1705 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1712 ClearMsgBitsMask(pti
, QS_MOUSEMOVE
);
1713 MessageQueue
->MouseMoved
= FALSE
;
1716 MessageQueue
->ptiSysLock
= NULL
;
1717 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1718 return AcceptMessage
;
1721 /* check whether a message filter contains at least one potential hardware message */
1723 filter_contains_hw_range( UINT first
, UINT last
)
1725 /* hardware message ranges are (in numerical order):
1726 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1727 * WM_KEYFIRST .. WM_KEYLAST
1728 * WM_MOUSEFIRST .. WM_MOUSELAST
1731 if (last
< WM_NCMOUSEFIRST
) return 0;
1732 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1733 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1734 if (first
> WM_MOUSELAST
) return 0;
1739 co_MsqPeekHardwareMessage(IN PTHREADINFO pti
,
1742 IN UINT MsgFilterLow
,
1743 IN UINT MsgFilterHigh
,
1749 PUSER_MESSAGE CurrentMessage
;
1750 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1753 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
1755 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1757 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1758 CurrentEntry
= ListHead
->Flink
;
1760 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1762 if (!MessageQueue
->ptiSysLock
)
1764 MessageQueue
->ptiSysLock
= pti
;
1765 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1768 if (MessageQueue
->ptiSysLock
!= pti
)
1770 ERR("MsqPeekHardwareMessage: Thread Q is locked to another pti!\n");
1774 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1778 if (IsListEmpty(CurrentEntry
)) break;
1779 if (!CurrentMessage
) break;
1780 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1783 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1784 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1785 3: handle to the window whose messages are to be retrieved.
1787 if ( ( !Window
|| // 1
1788 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1789 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1790 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1791 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1793 msg
= CurrentMessage
->Msg
;
1795 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
1796 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1800 RemoveEntryList(&CurrentMessage
->ListEntry
);
1801 ClearMsgBitsMask(pti
, CurrentMessage
->QS_Flags
);
1802 MsqDestroyMessage(CurrentMessage
);
1812 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1815 while(CurrentEntry
!= ListHead
);
1817 MessageQueue
->ptiSysLock
= NULL
;
1818 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1823 MsqPeekMessage(IN PTHREADINFO pti
,
1826 IN UINT MsgFilterLow
,
1827 IN UINT MsgFilterHigh
,
1831 PLIST_ENTRY CurrentEntry
;
1832 PUSER_MESSAGE CurrentMessage
;
1833 PLIST_ENTRY ListHead
;
1836 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
1837 ListHead
= &pti
->PostedMessagesListHead
;
1839 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1841 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1845 if (IsListEmpty(CurrentEntry
)) break;
1846 if (!CurrentMessage
) break;
1847 CurrentEntry
= CurrentEntry
->Flink
;
1850 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1851 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1852 3: handle to the window whose messages are to be retrieved.
1854 if ( ( !Window
|| // 1
1855 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1856 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1857 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1858 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1860 *Message
= CurrentMessage
->Msg
;
1864 RemoveEntryList(&CurrentMessage
->ListEntry
);
1865 ClearMsgBitsMask(pti
, CurrentMessage
->QS_Flags
);
1866 MsqDestroyMessage(CurrentMessage
);
1871 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1874 while (CurrentEntry
!= ListHead
);
1880 co_MsqWaitForNewMessages(PTHREADINFO pti
, PWND WndFilter
,
1881 UINT MsgFilterMin
, UINT MsgFilterMax
)
1885 ret
= KeWaitForSingleObject( pti
->pEventQueueServer
,
1895 MsqIsHung(PTHREADINFO pti
)
1897 LARGE_INTEGER LargeTickCount
;
1899 KeQueryTickCount(&LargeTickCount
);
1900 return ((LargeTickCount
.u
.LowPart
- pti
->timeLast
) > MSQ_HUNG
);
1905 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1908 TRACE("HungAppSysTimerProc\n");
1909 // Process list of windows that are hung and waiting.
1913 MsqInitializeMessageQueue(PTHREADINFO pti
, PUSER_MESSAGE_QUEUE MessageQueue
)
1915 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1916 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
); // Keep here!
1917 MessageQueue
->spwndFocus
= NULL
;
1918 MessageQueue
->iCursorLevel
= 0;
1919 MessageQueue
->CursorObject
= NULL
;
1920 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
1921 MessageQueue
->ptiMouse
= pti
;
1922 MessageQueue
->ptiKeyboard
= pti
;
1923 MessageQueue
->cThreads
++;
1929 MsqCleanupThreadMsgs(PTHREADINFO pti
)
1931 PLIST_ENTRY CurrentEntry
;
1932 PUSER_MESSAGE CurrentMessage
;
1933 PUSER_SENT_MESSAGE CurrentSentMessage
;
1935 /* cleanup posted messages */
1936 while (!IsListEmpty(&pti
->PostedMessagesListHead
))
1938 CurrentEntry
= RemoveHeadList(&pti
->PostedMessagesListHead
);
1939 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1941 MsqDestroyMessage(CurrentMessage
);
1944 /* remove the messages that have not yet been dispatched */
1945 while (!IsListEmpty(&pti
->SentMessagesListHead
))
1947 CurrentEntry
= RemoveHeadList(&pti
->SentMessagesListHead
);
1948 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1951 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
1952 /* Only if the message has a sender was the message in the DispatchingList */
1953 if ((CurrentSentMessage
->ptiSender
)
1954 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1956 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1959 /* wake the sender's thread */
1960 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1962 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1965 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1967 if (CurrentSentMessage
->Msg
.lParam
)
1968 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1971 /* free the message */
1972 ExFreePool(CurrentSentMessage
);
1975 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1976 ExitThread() was called in a SendMessage() umode callback */
1977 while (!IsListEmpty(&pti
->LocalDispatchingMessagesHead
))
1979 CurrentEntry
= RemoveHeadList(&pti
->LocalDispatchingMessagesHead
);
1980 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1983 /* remove the message from the dispatching list */
1984 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1986 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1989 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
1991 /* wake the sender's thread */
1992 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1994 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1997 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1999 if (CurrentSentMessage
->Msg
.lParam
)
2000 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2003 /* free the message */
2004 ExFreePool(CurrentSentMessage
);
2007 /* tell other threads not to bother returning any info to us */
2008 while (! IsListEmpty(&pti
->DispatchingMessagesHead
))
2010 CurrentEntry
= RemoveHeadList(&pti
->DispatchingMessagesHead
);
2011 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2012 DispatchingListEntry
);
2013 CurrentSentMessage
->CompletionEvent
= NULL
;
2014 CurrentSentMessage
->Result
= NULL
;
2016 /* do NOT dereference our message queue as it might get attempted to be
2020 // Clear it all out.
2023 pti
->pcti
->fsWakeBits
= 0;
2024 pti
->pcti
->fsChangeBits
= 0;
2027 pti
->nCntsQBits
[QSRosKey
] = 0;
2028 pti
->nCntsQBits
[QSRosMouseMove
] = 0;
2029 pti
->nCntsQBits
[QSRosMouseButton
] = 0;
2030 pti
->nCntsQBits
[QSRosPostMessage
] = 0;
2031 pti
->nCntsQBits
[QSRosSendMessage
] = 0;
2032 pti
->nCntsQBits
[QSRosHotKey
] = 0;
2033 pti
->nCntsQBits
[QSRosEvent
] = 0;
2037 MsqCleanupMessageQueue(PTHREADINFO pti
)
2039 PUSER_MESSAGE_QUEUE MessageQueue
;
2041 MessageQueue
= pti
->MessageQueue
;
2042 MessageQueue
->cThreads
--;
2044 if (MessageQueue
->cThreads
)
2046 if (MessageQueue
->ptiSysLock
== pti
) MessageQueue
->ptiSysLock
= NULL
;
2049 if (MessageQueue
->CursorObject
)
2051 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2053 /* Change to another cursor if we going to dereference current one
2054 Note: we can't use UserSetCursor because it uses current thread
2055 message queue instead of queue given for cleanup */
2056 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2060 /* Get the screen DC */
2061 hdcScreen
= IntGetScreenDC();
2063 GreMovePointer(hdcScreen
, -1, -1);
2064 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2067 ERR("DereferenceObject pCursor\n");
2068 UserDereferenceObject(pCursor
);
2071 if (gpqForeground
== MessageQueue
)
2073 IntSetFocusMessageQueue(NULL
);
2075 if (gpqForegroundPrev
== MessageQueue
)
2077 gpqForegroundPrev
= NULL
;
2079 if (gpqCursor
== MessageQueue
)
2085 PUSER_MESSAGE_QUEUE FASTCALL
2086 MsqCreateMessageQueue(PTHREADINFO pti
)
2088 PUSER_MESSAGE_QUEUE MessageQueue
;
2090 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2091 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2099 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2100 /* hold at least one reference until it'll be destroyed */
2101 IntReferenceMessageQueue(MessageQueue
);
2102 /* initialize the queue */
2103 if (!MsqInitializeMessageQueue(pti
, MessageQueue
))
2105 IntDereferenceMessageQueue(MessageQueue
);
2109 return MessageQueue
;
2113 MsqDestroyMessageQueue(PTHREADINFO pti
)
2116 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2118 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2120 /* remove the message queue from any desktops */
2121 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2123 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2124 IntDereferenceMessageQueue(MessageQueue
);
2128 MsqCleanupMessageQueue(pti
);
2130 /* decrease the reference counter, if it hits zero, the queue will be freed */
2131 IntDereferenceMessageQueue(MessageQueue
);
2135 MsqSetMessageExtraInfo(LPARAM lParam
)
2139 PUSER_MESSAGE_QUEUE MessageQueue
;
2141 pti
= PsGetCurrentThreadWin32Thread();
2142 MessageQueue
= pti
->MessageQueue
;
2148 Ret
= MessageQueue
->ExtraInfo
;
2149 MessageQueue
->ExtraInfo
= lParam
;
2155 MsqGetMessageExtraInfo(VOID
)
2158 PUSER_MESSAGE_QUEUE MessageQueue
;
2160 pti
= PsGetCurrentThreadWin32Thread();
2161 MessageQueue
= pti
->MessageQueue
;
2167 return MessageQueue
->ExtraInfo
;
2170 // ReplyMessage is called by the thread receiving the window message.
2172 co_MsqReplyMessage( LRESULT lResult
)
2174 PUSER_SENT_MESSAGE Message
;
2177 pti
= PsGetCurrentThreadWin32Thread();
2178 Message
= pti
->pusmCurrent
;
2180 if (!Message
) return FALSE
;
2182 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2184 // SendMessageXxx || Callback msg and not a notify msg
2185 if (Message
->ptiSender
|| Message
->CompletionCallback
)
2187 Message
->lResult
= lResult
;
2188 Message
->QS_Flags
|= QS_SMRESULT
;
2189 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2195 MsqSetStateWindow(PTHREADINFO pti
, ULONG Type
, HWND hWnd
)
2198 PUSER_MESSAGE_QUEUE MessageQueue
;
2200 MessageQueue
= pti
->MessageQueue
;
2204 case MSQ_STATE_CAPTURE
:
2205 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2206 MessageQueue
->spwndCapture
= ValidateHwndNoErr(hWnd
);
2208 case MSQ_STATE_ACTIVE
:
2209 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2210 MessageQueue
->spwndActive
= ValidateHwndNoErr(hWnd
);
2212 case MSQ_STATE_FOCUS
:
2213 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2214 MessageQueue
->spwndFocus
= ValidateHwndNoErr(hWnd
);
2216 case MSQ_STATE_MENUOWNER
:
2217 Prev
= MessageQueue
->MenuOwner
;
2218 MessageQueue
->MenuOwner
= hWnd
;
2220 case MSQ_STATE_MOVESIZE
:
2221 Prev
= MessageQueue
->MoveSize
;
2222 MessageQueue
->MoveSize
= hWnd
;
2224 case MSQ_STATE_CARET
:
2225 ASSERT(MessageQueue
->CaretInfo
);
2226 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2227 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2236 NtUserGetKeyState(INT key
)
2242 Ret
= UserGetKeyState(key
);
2252 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2254 DWORD i
, ret
= TRUE
;
2256 PUSER_MESSAGE_QUEUE MessageQueue
;
2260 pti
= PsGetCurrentThreadWin32Thread();
2261 MessageQueue
= pti
->MessageQueue
;
2265 /* Probe and copy key state to an array */
2266 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2267 for (i
= 0; i
< 256; ++i
)
2270 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2271 lpKeyState
[i
] |= KS_DOWN_BIT
;
2272 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2273 lpKeyState
[i
] |= KS_LOCK_BIT
;
2276 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2278 SetLastNtError(_SEH2_GetExceptionCode());
2290 NtUserSetKeyboardState(LPBYTE pKeyState
)
2295 PUSER_MESSAGE_QUEUE MessageQueue
;
2297 UserEnterExclusive();
2299 pti
= PsGetCurrentThreadWin32Thread();
2300 MessageQueue
= pti
->MessageQueue
;
2304 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2305 for (i
= 0; i
< 256; ++i
)
2307 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2308 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2311 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2313 SetLastNtError(_SEH2_GetExceptionCode());