2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Message queues
5 * FILE: win32ss/user/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
;
18 ULONG_PTR gdwMouseMoveExtraInfo
= 0;
19 DWORD gdwMouseMoveTimeStamp
= 0;
22 /* FUNCTIONS *****************************************************************/
27 MsqInitializeImpl(VOID
)
29 pgMessageLookasideList
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(PAGED_LOOKASIDE_LIST
), TAG_USRMSG
);
30 if(!pgMessageLookasideList
)
31 return STATUS_NO_MEMORY
;
32 ExInitializePagedLookasideList(pgMessageLookasideList
,
40 return(STATUS_SUCCESS
);
44 IntTopLevelWindowFromPoint(INT x
, INT y
)
46 PWND pWnd
, pwndDesktop
;
48 /* Get the desktop window */
49 pwndDesktop
= UserGetDesktopWindow();
53 /* Loop all top level windows */
54 for (pWnd
= pwndDesktop
->spwndChild
;
56 pWnd
= pWnd
->spwndNext
)
58 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
60 TRACE("The Window is in DESTROY!\n");
64 if ((pWnd
->style
& WS_VISIBLE
) && IntPtInWindow(pWnd
, x
, y
))
68 /* Window has not been found */
75 PCURICON_OBJECT NewCursor
,
78 PCURICON_OBJECT OldCursor
;
81 PUSER_MESSAGE_QUEUE MessageQueue
;
84 pti
= PsGetCurrentThreadWin32Thread();
85 MessageQueue
= pti
->MessageQueue
;
87 /* Get the screen DC */
88 if(!(hdcScreen
= IntGetScreenDC()))
93 OldCursor
= MessageQueue
->CursorObject
;
95 /* Check if cursors are different */
96 if (OldCursor
== NewCursor
)
99 /* Update cursor for this message queue */
100 MessageQueue
->CursorObject
= NewCursor
;
102 /* If cursor is not visible we have nothing to do */
103 if (MessageQueue
->iCursorLevel
< 0)
106 /* Update cursor if this message queue controls it */
107 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
108 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
112 /* Call GDI to set the new screen cursor */
113 #ifdef NEW_CURSORICON
114 PCURICON_OBJECT CursorFrame
= NewCursor
;
115 if(NewCursor
->CURSORF_flags
& CURSORF_ACON
)
117 FIXME("Should animate the cursor, using only the first frame now.\n");
118 CursorFrame
= ((PACON
)NewCursor
)->aspcur
[0];
120 GreSetPointerShape(hdcScreen
,
121 CursorFrame
->hbmAlpha
? NULL
: NewCursor
->hbmMask
,
122 CursorFrame
->hbmAlpha
? NewCursor
->hbmAlpha
: NewCursor
->hbmColor
,
123 CursorFrame
->xHotspot
,
124 CursorFrame
->yHotspot
,
127 CursorFrame
->hbmAlpha
? SPS_ALPHA
: 0);
129 GreSetPointerShape(hdcScreen
,
130 NewCursor
->IconInfo
.hbmMask
,
131 NewCursor
->IconInfo
.hbmColor
,
132 NewCursor
->IconInfo
.xHotspot
,
133 NewCursor
->IconInfo
.yHotspot
,
139 else /* Note: OldCursor != NewCursor so we have to hide cursor */
141 /* Remove the cursor */
142 GreMovePointer(hdcScreen
, -1, -1);
143 TRACE("Removing pointer!\n");
145 IntGetSysCursorInfo()->CurrentCursorObject
= NewCursor
;
148 /* Return the old cursor */
152 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
153 * User32 macro NtUserShowCursor */
154 int UserShowCursor(BOOL bShow
)
158 PUSER_MESSAGE_QUEUE MessageQueue
;
161 if (!(hdcScreen
= IntGetScreenDC()))
163 return -1; /* No mouse */
166 pti
= PsGetCurrentThreadWin32Thread();
167 MessageQueue
= pti
->MessageQueue
;
170 MessageQueue
->iCursorLevel
+= bShow
? 1 : -1;
171 pti
->iCursorLevel
+= bShow
? 1 : -1;
173 /* Check for trivial cases */
174 if ((bShow
&& MessageQueue
->iCursorLevel
!= 0) ||
175 (!bShow
&& MessageQueue
->iCursorLevel
!= -1))
177 /* Note: w don't update global info here because it is used only
178 internally to check if cursor is visible */
179 return MessageQueue
->iCursorLevel
;
182 /* Check if cursor is above window owned by this MessageQueue */
183 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
184 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
188 /* Show the pointer */
189 GreMovePointer(hdcScreen
, gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
190 TRACE("Showing pointer!\n");
194 /* Remove the pointer */
195 GreMovePointer(hdcScreen
, -1, -1);
196 TRACE("Removing pointer!\n");
199 /* Update global info */
200 IntGetSysCursorInfo()->ShowingCursor
= MessageQueue
->iCursorLevel
;
203 return MessageQueue
->iCursorLevel
;
207 UserGetKeyState(DWORD dwKey
)
211 PUSER_MESSAGE_QUEUE MessageQueue
;
213 pti
= PsGetCurrentThreadWin32Thread();
214 MessageQueue
= pti
->MessageQueue
;
218 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, dwKey
))
219 dwRet
|= 0xFF80; // If down, windows returns 0xFF80.
220 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, dwKey
))
225 EngSetLastError(ERROR_INVALID_PARAMETER
);
230 /* change the input key state for a given key */
232 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue
, WORD wVk
, BOOL bIsDown
)
234 TRACE("UpdateKeyState wVk: %u, bIsDown: %d\n", wVk
, bIsDown
);
238 /* If it's first key down event, xor lock bit */
239 if (!IS_KEY_DOWN(MessageQueue
->afKeyState
, wVk
))
240 SET_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
, !IS_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
));
242 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, TRUE
);
243 MessageQueue
->afKeyRecentDown
[wVk
/ 8] |= (1 << (wVk
% 8));
246 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, FALSE
);
249 /* update the input key state for a keyboard message */
251 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
256 TRACE("UpdateKeyStateFromMsg message:%u\n", msg
->message
);
258 switch (msg
->message
)
264 UpdateKeyState(MessageQueue
, VK_LBUTTON
, down
);
270 UpdateKeyState(MessageQueue
, VK_MBUTTON
, down
);
276 UpdateKeyState(MessageQueue
, VK_RBUTTON
, down
);
282 if (msg
->wParam
== XBUTTON1
)
283 UpdateKeyState(MessageQueue
, VK_XBUTTON1
, down
);
284 else if (msg
->wParam
== XBUTTON2
)
285 UpdateKeyState(MessageQueue
, VK_XBUTTON2
, down
);
293 key
= (UCHAR
)msg
->wParam
;
294 UpdateKeyState(MessageQueue
, key
, down
);
299 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LCONTROL
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RCONTROL
);
300 UpdateKeyState(MessageQueue
, VK_CONTROL
, down
);
304 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LMENU
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RMENU
);
305 UpdateKeyState(MessageQueue
, VK_MENU
, down
);
309 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LSHIFT
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RSHIFT
);
310 UpdateKeyState(MessageQueue
, VK_SHIFT
, down
);
318 Get down key states from the queue of prior processed input message key states.
320 This fixes the left button dragging on the desktop and release sticking outline issue.
321 USB Tablet pointer seems to stick the most and leaves the box outline displayed.
324 MsqGetDownKeyState(PUSER_MESSAGE_QUEUE MessageQueue
)
328 if (gspv
.bMouseBtnSwap
)
330 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RBUTTON
)) ret
|= MK_LBUTTON
;
331 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LBUTTON
)) ret
|= MK_RBUTTON
;
335 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LBUTTON
)) ret
|= MK_LBUTTON
;
336 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RBUTTON
)) ret
|= MK_RBUTTON
;
339 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_MBUTTON
)) ret
|= MK_MBUTTON
;
340 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_SHIFT
)) ret
|= MK_SHIFT
;
341 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_CONTROL
)) ret
|= MK_CONTROL
;
342 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_XBUTTON1
)) ret
|= MK_XBUTTON1
;
343 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_XBUTTON2
)) ret
|= MK_XBUTTON2
;
348 IntMsqSetWakeMask(DWORD WakeMask
)
350 PTHREADINFO Win32Thread
;
351 HANDLE MessageEventHandle
;
352 DWORD dwFlags
= HIWORD(WakeMask
);
354 Win32Thread
= PsGetCurrentThreadWin32Thread();
355 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
358 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
359 MessageEventHandle
= Win32Thread
->hEventQueueClient
;
361 if (Win32Thread
->pcti
)
363 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
364 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
366 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
367 KeSetEvent(Win32Thread
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
368 return MessageEventHandle
;
374 return MessageEventHandle
;
378 IntMsqClearWakeMask(VOID
)
380 PTHREADINFO Win32Thread
;
382 Win32Thread
= PsGetCurrentThreadWin32Thread();
383 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
385 // Very hacky, but that is what they do.
386 Win32Thread
->pcti
->fsWakeBits
= 0;
394 Due to the uncertainty of knowing what was set in our multilevel message queue,
395 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
396 I think this is the best solution... (jt) */
398 MsqWakeQueue(PTHREADINFO pti
, DWORD MessageBits
, BOOL KeyEvent
)
400 PUSER_MESSAGE_QUEUE Queue
;
402 Queue
= pti
->MessageQueue
;
404 if (Queue
->QF_flags
& QF_INDESTROY
)
406 ERR("This Message Queue is in Destroy!\n");
408 pti
->pcti
->fsWakeBits
|= MessageBits
;
409 pti
->pcti
->fsChangeBits
|= MessageBits
;
411 // Start bit accounting to help clear the main set of bits.
412 if (MessageBits
& QS_KEY
)
414 pti
->nCntsQBits
[QSRosKey
]++;
416 if (MessageBits
& QS_MOUSE
)
418 if (MessageBits
& QS_MOUSEMOVE
) pti
->nCntsQBits
[QSRosMouseMove
]++;
419 if (MessageBits
& QS_MOUSEBUTTON
) pti
->nCntsQBits
[QSRosMouseButton
]++;
421 if (MessageBits
& QS_POSTMESSAGE
) pti
->nCntsQBits
[QSRosPostMessage
]++;
422 if (MessageBits
& QS_SENDMESSAGE
) pti
->nCntsQBits
[QSRosSendMessage
]++;
423 if (MessageBits
& QS_HOTKEY
) pti
->nCntsQBits
[QSRosHotKey
]++;
424 if (MessageBits
& QS_EVENT
) pti
->nCntsQBits
[QSRosEvent
]++;
427 KeSetEvent(pti
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
);
431 ClearMsgBitsMask(PTHREADINFO pti
, UINT MessageBits
)
435 if (MessageBits
& QS_KEY
)
437 if (--pti
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
439 if (MessageBits
& QS_MOUSEMOVE
)
440 { // Account for tracking mouse moves..
441 if (pti
->nCntsQBits
[QSRosMouseMove
])
443 pti
->nCntsQBits
[QSRosMouseMove
] = 0; // Throttle down count. Up to > 3:1 entries are ignored.
444 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 Post the move or update the message still pending to be processed.
501 Do not overload the queue with mouse move messages.
504 MsqPostMouseMove(PTHREADINFO pti
, MSG
* Msg
, LONG_PTR ExtraInfo
)
506 PUSER_MESSAGE Message
;
507 PLIST_ENTRY ListHead
;
508 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
510 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
512 // Do nothing if empty.
513 if (!IsListEmpty(ListHead
->Flink
))
515 // Look at the end of the list,
516 Message
= CONTAINING_RECORD(ListHead
->Blink
, USER_MESSAGE
, ListEntry
);
518 // If the mouse move message is existing on the list,
519 if (Message
->Msg
.message
== WM_MOUSEMOVE
)
521 // Overwrite the message with updated data!
524 MsqWakeQueue(pti
, QS_MOUSEMOVE
, TRUE
);
529 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEMOVE
, 0, ExtraInfo
);
533 Bring together the mouse move message.
534 Named "Coalesce" from Amine email ;^) (jt).
537 IntCoalesceMouseMove(PTHREADINFO pti
)
540 LARGE_INTEGER LargeTickCount
;
542 // Force time stamp to update, keeping message time in sync.
543 if (gdwMouseMoveTimeStamp
== 0)
545 KeQueryTickCount(&LargeTickCount
);
546 gdwMouseMoveTimeStamp
= MsqCalculateMessageTime(&LargeTickCount
);
549 // Build mouse move message.
551 Msg
.message
= WM_MOUSEMOVE
;
553 Msg
.lParam
= MAKELONG(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
554 Msg
.time
= gdwMouseMoveTimeStamp
;
555 Msg
.pt
= gpsi
->ptCursor
;
558 MsqPostMouseMove(pti
, &Msg
, gdwMouseMoveExtraInfo
);
560 // Zero the time stamp.
561 gdwMouseMoveTimeStamp
= 0;
563 // Clear flag since the move was posted.
564 pti
->MessageQueue
->QF_flags
&= ~QF_MOUSEMOVED
;
568 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
570 LARGE_INTEGER LargeTickCount
;
571 MSLLHOOKSTRUCT MouseHookData
;
573 PWND pwnd
, pwndDesktop
;
576 PUSER_MESSAGE_QUEUE MessageQueue
;
577 PSYSTEM_CURSORINFO CurInfo
;
579 KeQueryTickCount(&LargeTickCount
);
580 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
582 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
583 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
584 switch (Msg
->message
)
587 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
591 case WM_XBUTTONDBLCLK
:
592 case WM_NCXBUTTONDOWN
:
594 case WM_NCXBUTTONDBLCLK
:
595 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
598 MouseHookData
.mouseData
= 0;
602 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
603 MouseHookData
.time
= Msg
->time
;
604 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
606 /* If the hook procedure returned non zero, dont send the message */
609 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
613 /* Get the desktop window */
614 pwndDesktop
= UserGetDesktopWindow();
615 if (!pwndDesktop
) return;
616 // pDesk = pwndDesktop->head.rpdesk;
618 /* Check if the mouse is captured */
619 Msg
->hwnd
= IntGetCaptureWindow();
620 if (Msg
->hwnd
!= NULL
)
622 pwnd
= UserGetWindowObject(Msg
->hwnd
);
626 pwnd
= IntTopLevelWindowFromPoint(Msg
->pt
.x
, Msg
->pt
.y
);
627 if (pwnd
) Msg
->hwnd
= pwnd
->head
.h
;
630 hdcScreen
= IntGetScreenDC();
631 CurInfo
= IntGetSysCursorInfo();
633 /* Check if we found a window */
634 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
636 pti
= pwnd
->head
.pti
;
637 MessageQueue
= pti
->MessageQueue
;
639 if (MessageQueue
->QF_flags
& QF_INDESTROY
)
641 ERR("Mouse is over a Window with a Dead Message Queue!\n");
645 MessageQueue
->ptiMouse
= pti
;
647 if (Msg
->message
== WM_MOUSEMOVE
)
649 /* Check if cursor should be visible */
651 MessageQueue
->CursorObject
&&
652 MessageQueue
->iCursorLevel
>= 0)
654 /* Check if shape has changed */
655 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
657 /* Call GDI to set the new screen cursor */
658 #ifdef NEW_CURSORICON
659 GreSetPointerShape(hdcScreen
,
660 MessageQueue
->CursorObject
->hbmAlpha
?
661 NULL
: MessageQueue
->CursorObject
->hbmMask
,
662 MessageQueue
->CursorObject
->hbmAlpha
?
663 MessageQueue
->CursorObject
->hbmAlpha
: MessageQueue
->CursorObject
->hbmColor
,
664 MessageQueue
->CursorObject
->xHotspot
,
665 MessageQueue
->CursorObject
->yHotspot
,
668 MessageQueue
->CursorObject
->hbmAlpha
? SPS_ALPHA
: 0);
670 GreSetPointerShape(hdcScreen
,
671 MessageQueue
->CursorObject
->IconInfo
.hbmMask
,
672 MessageQueue
->CursorObject
->IconInfo
.hbmColor
,
673 MessageQueue
->CursorObject
->IconInfo
.xHotspot
,
674 MessageQueue
->CursorObject
->IconInfo
.yHotspot
,
680 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
682 /* Check if w have to hide cursor */
683 else if (CurInfo
->ShowingCursor
>= 0)
684 GreMovePointer(hdcScreen
, -1, -1);
686 /* Update global cursor info */
687 CurInfo
->ShowingCursor
= MessageQueue
->iCursorLevel
;
688 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
689 gpqCursor
= MessageQueue
;
691 /* Mouse move is a special case */
692 MessageQueue
->QF_flags
|= QF_MOUSEMOVED
;
693 gdwMouseMoveExtraInfo
= dwExtraInfo
;
694 gdwMouseMoveTimeStamp
= Msg
->time
;
695 MsqWakeQueue(pti
, QS_MOUSEMOVE
, TRUE
);
699 if (!IntGetCaptureWindow())
701 // ERR("ptiLastInput is set\n");
702 // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
703 // Find all the Move Mouse calls and fix mouse set active focus issues......
706 // Post mouse move before posting mouse buttons, keep it in sync.
707 if (pti
->MessageQueue
->QF_flags
& QF_MOUSEMOVED
)
709 IntCoalesceMouseMove(pti
);
712 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd
));
713 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEBUTTON
, 0, dwExtraInfo
);
718 /* always show cursor on background; FIXME: set default pointer */
719 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
720 CurInfo
->ShowingCursor
= 0;
724 PUSER_MESSAGE FASTCALL
725 MsqCreateMessage(LPMSG Msg
)
727 PUSER_MESSAGE Message
;
729 Message
= ExAllocateFromPagedLookasideList(pgMessageLookasideList
);
735 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
741 MsqDestroyMessage(PUSER_MESSAGE Message
)
743 ExFreeToPagedLookasideList(pgMessageLookasideList
, Message
);
747 co_MsqDispatchOneSentMessage(PTHREADINFO pti
)
749 PUSER_SENT_MESSAGE SaveMsg
, Message
;
754 ASSERT(pti
== PsGetCurrentThreadWin32Thread());
756 if (IsListEmpty(&pti
->SentMessagesListHead
))
761 /* remove it from the list of pending messages */
762 Entry
= RemoveHeadList(&pti
->SentMessagesListHead
);
763 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
765 SaveMsg
= pti
->pusmCurrent
;
766 pti
->pusmCurrent
= Message
;
768 // Processing a message sent to it from another thread.
769 if ( ( Message
->ptiSender
&& pti
!= Message
->ptiSender
) ||
770 ( Message
->ptiCallBackSender
&& pti
!= Message
->ptiCallBackSender
))
771 { // most likely, but, to be sure.
772 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
775 /* insert it to the list of messages that are currently dispatched by this
777 InsertTailList(&pti
->LocalDispatchingMessagesHead
,
778 &Message
->ListEntry
);
780 ClearMsgBitsMask(pti
, Message
->QS_Flags
);
782 if (Message
->HookMessage
== MSQ_ISHOOK
)
783 { // Direct Hook Call processor
784 Result
= co_CallHook( Message
->Msg
.message
, // HookId
785 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
787 Message
->Msg
.lParam
);
789 else if (Message
->HookMessage
== MSQ_ISEVENT
)
790 { // Direct Event Call processor
791 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
794 Message
->Msg
.lParam
);
796 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
798 Result
= IntLoadHookModule(Message
->Msg
.message
,
799 (HHOOK
)Message
->Msg
.lParam
,
800 Message
->Msg
.wParam
);
802 else if ((Message
->CompletionCallback
) &&
803 (Message
->ptiCallBackSender
== pti
))
804 { /* Call the callback routine */
805 if (Message
->QS_Flags
& QS_SMRESULT
)
807 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
809 Message
->Msg
.message
,
810 Message
->CompletionCallbackContext
,
812 /* Set callback to NULL to prevent reentry */
813 Message
->CompletionCallback
= NULL
;
817 /* The message has not been processed yet, reinsert it. */
818 RemoveEntryList(&Message
->ListEntry
);
819 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
820 TRACE("Callback Message not processed yet. Requeuing the message\n");
826 { /* Call the window procedure. */
827 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
828 Message
->Msg
.message
,
830 Message
->Msg
.lParam
);
833 /* remove the message from the local dispatching list, because it doesn't need
834 to be cleaned up on thread termination anymore */
835 RemoveEntryList(&Message
->ListEntry
);
837 /* If the message is a callback, insert it in the callback senders MessageQueue */
838 if (Message
->CompletionCallback
)
840 if (Message
->ptiCallBackSender
)
842 Message
->lResult
= Result
;
843 Message
->QS_Flags
|= QS_SMRESULT
;
845 /* insert it in the callers message queue */
846 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
847 MsqWakeQueue(Message
->ptiCallBackSender
, QS_SENDMESSAGE
, TRUE
);
853 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
854 if (Message
->ptiSender
)
856 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
858 /* only remove it from the dispatching list if not already removed by a timeout */
859 RemoveEntryList(&Message
->DispatchingListEntry
);
862 /* still keep the sender's message queue locked, so the sender can't exit the
863 MsqSendMessage() function (if timed out) */
865 if (Message
->QS_Flags
& QS_SMRESULT
)
867 Result
= Message
->lResult
;
870 /* Let the sender know the result. */
871 if (Message
->Result
!= NULL
)
873 *Message
->Result
= Result
;
876 if (Message
->HasPackedLParam
)
878 if (Message
->Msg
.lParam
)
879 ExFreePool((PVOID
)Message
->Msg
.lParam
);
882 /* Notify the sender. */
883 if (Message
->CompletionEvent
!= NULL
)
885 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
888 /* free the message */
889 ExFreePoolWithTag(Message
, TAG_USRMSG
);
892 /* do not hangup on the user if this is reentering */
893 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
894 pti
->pusmCurrent
= SaveMsg
;
900 MsqRemoveWindowMessagesFromQueue(PWND Window
)
903 PUSER_SENT_MESSAGE SentMessage
;
904 PUSER_MESSAGE PostedMessage
;
905 PLIST_ENTRY CurrentEntry
, ListHead
;
909 pti
= Window
->head
.pti
;
911 /* remove the posted messages for this window */
912 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
913 ListHead
= &pti
->PostedMessagesListHead
;
914 while (CurrentEntry
!= ListHead
)
916 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
918 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
920 RemoveEntryList(&PostedMessage
->ListEntry
);
921 ClearMsgBitsMask(pti
, PostedMessage
->QS_Flags
);
922 MsqDestroyMessage(PostedMessage
);
923 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
927 CurrentEntry
= CurrentEntry
->Flink
;
931 /* remove the sent messages for this window */
932 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
933 ListHead
= &pti
->SentMessagesListHead
;
934 while (CurrentEntry
!= ListHead
)
936 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
938 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
940 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
942 RemoveEntryList(&SentMessage
->ListEntry
);
943 ClearMsgBitsMask(pti
, SentMessage
->QS_Flags
);
945 /* Only if the message has a sender was the queue referenced */
946 if ((SentMessage
->ptiSender
)
947 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
949 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
952 /* wake the sender's thread */
953 if (SentMessage
->CompletionEvent
!= NULL
)
955 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
958 if (SentMessage
->HasPackedLParam
)
960 if (SentMessage
->Msg
.lParam
)
961 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
964 /* free the message */
965 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
967 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
971 CurrentEntry
= CurrentEntry
->Flink
;
977 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
982 SENDASYNCPROC CompletionCallback
,
983 ULONG_PTR CompletionCallbackContext
,
984 BOOL HasPackedLParam
,
988 PTHREADINFO ptiSender
;
989 PUSER_SENT_MESSAGE Message
;
991 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
993 ERR("MsqSendMessage(): Not enough memory to allocate a message");
997 ptiSender
= PsGetCurrentThreadWin32Thread();
999 Message
->Msg
.hwnd
= hwnd
;
1000 Message
->Msg
.message
= Msg
;
1001 Message
->Msg
.wParam
= wParam
;
1002 Message
->Msg
.lParam
= lParam
;
1003 Message
->CompletionEvent
= NULL
;
1004 Message
->Result
= 0;
1005 Message
->lResult
= 0;
1006 Message
->ptiReceiver
= ptiReceiver
;
1007 Message
->ptiSender
= NULL
;
1008 Message
->ptiCallBackSender
= ptiSender
;
1009 Message
->DispatchingListEntry
.Flink
= NULL
;
1010 Message
->CompletionCallback
= CompletionCallback
;
1011 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
1012 Message
->HookMessage
= HookMessage
;
1013 Message
->HasPackedLParam
= HasPackedLParam
;
1014 Message
->QS_Flags
= QS_SENDMESSAGE
;
1016 InsertTailList(&ptiReceiver
->SentMessagesListHead
, &Message
->ListEntry
);
1017 MsqWakeQueue(ptiReceiver
, QS_SENDMESSAGE
, TRUE
);
1023 co_MsqSendMessage(PTHREADINFO ptirec
,
1024 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
1025 UINT uTimeout
, BOOL Block
, INT HookMessage
,
1029 PUSER_SENT_MESSAGE Message
;
1030 KEVENT CompletionEvent
;
1031 NTSTATUS WaitStatus
;
1032 LARGE_INTEGER Timeout
;
1035 LRESULT Result
= 0; //// Result could be trashed. ////
1037 pti
= PsGetCurrentThreadWin32Thread();
1038 ASSERT(pti
!= ptirec
);
1039 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
1041 /* Don't send from or to a dying thread */
1042 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
1044 // Unless we are dying and need to tell our parents.
1045 if (pti
->TIF_flags
& TIF_INCLEANUP
&& !(ptirec
->TIF_flags
& TIF_INCLEANUP
))
1047 // Parent notify is the big one. Fire and forget!
1048 TRACE("Send message from dying thread %d\n",Msg
);
1049 co_MsqSendMessageAsync(ptirec
, Wnd
, Msg
, wParam
, lParam
, NULL
, 0, FALSE
, HookMessage
);
1051 if (uResult
) *uResult
= -1;
1052 TRACE("MsqSM: Msg %d Current pti %lu or Rec pti %lu\n", Msg
, pti
->TIF_flags
& TIF_INCLEANUP
, ptirec
->TIF_flags
& TIF_INCLEANUP
);
1053 return STATUS_UNSUCCESSFUL
;
1056 if ( HookMessage
== MSQ_NORMAL
)
1058 pWnd
= ValidateHwndNoErr(Wnd
);
1060 // These can not cross International Border lines!
1061 if ( pti
->ppi
!= ptirec
->ppi
&& pWnd
)
1065 // Handle the special case when working with password transfers across bordering processes.
1067 case EM_SETPASSWORDCHAR
:
1069 // Look for edit controls setup for passwords.
1070 if ( gpsi
->atomSysClass
[ICLS_EDIT
] == pWnd
->pcls
->atomClassName
&& // Use atomNVClassName.
1071 pWnd
->style
& ES_PASSWORD
)
1073 if (uResult
) *uResult
= -1;
1074 ERR("Running across the border without a passport!\n");
1075 EngSetLastError(ERROR_ACCESS_DENIED
);
1076 return STATUS_UNSUCCESSFUL
;
1080 if (uResult
) *uResult
= -1;
1081 ERR("Running across the border without a passport!\n");
1082 return STATUS_UNSUCCESSFUL
;
1086 // These can not cross State lines!
1087 if ( Msg
== WM_CREATE
|| Msg
== WM_NCCREATE
)
1089 if (uResult
) *uResult
= -1;
1090 ERR("Can not tell the other State we have Create!\n");
1091 return STATUS_UNSUCCESSFUL
;
1095 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1097 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1098 return STATUS_INSUFFICIENT_RESOURCES
;
1101 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1103 Timeout
.QuadPart
= Int32x32To64(-10000,uTimeout
); // Pass SMTO test with a TO of 0x80000000.
1104 TRACE("Timeout val %lld\n",Timeout
.QuadPart
)
1106 /* FIXME: Increase reference counter of sender's message queue here */
1108 Message
->Msg
.hwnd
= Wnd
;
1109 Message
->Msg
.message
= Msg
;
1110 Message
->Msg
.wParam
= wParam
;
1111 Message
->Msg
.lParam
= lParam
;
1112 Message
->CompletionEvent
= &CompletionEvent
;
1113 Message
->Result
= &Result
;
1114 Message
->lResult
= 0;
1115 Message
->QS_Flags
= 0;
1116 Message
->ptiReceiver
= ptirec
;
1117 Message
->ptiSender
= pti
;
1118 Message
->ptiCallBackSender
= NULL
;
1119 Message
->CompletionCallback
= NULL
;
1120 Message
->CompletionCallbackContext
= 0;
1121 Message
->HookMessage
= HookMessage
;
1122 Message
->HasPackedLParam
= FALSE
;
1124 /* Add it to the list of pending messages */
1125 InsertTailList(&pti
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1127 /* Queue it in the destination's message queue */
1128 InsertTailList(&ptirec
->SentMessagesListHead
, &Message
->ListEntry
);
1130 Message
->QS_Flags
= QS_SENDMESSAGE
;
1131 MsqWakeQueue(ptirec
, QS_SENDMESSAGE
, TRUE
);
1133 /* We can't access the Message anymore since it could have already been deleted! */
1139 /* Don't process messages sent to the thread */
1140 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1141 FALSE
, (uTimeout
? &Timeout
: NULL
));
1145 if(WaitStatus
== STATUS_TIMEOUT
)
1147 /* Look up if the message has not yet dispatched, if so
1148 make sure it can't pass a result and it must not set the completion event anymore */
1149 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1150 while (Entry
!= &ptirec
->SentMessagesListHead
)
1152 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1155 /* We can access Message here, it's secure because the message queue is locked
1156 and the message is still hasn't been dispatched */
1157 Message
->CompletionEvent
= NULL
;
1158 Message
->Result
= NULL
;
1161 Entry
= Entry
->Flink
;
1164 /* Remove from the local dispatching list so the other thread knows,
1165 it can't pass a result and it must not set the completion event anymore */
1166 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1167 while (Entry
!= &pti
->DispatchingMessagesHead
)
1169 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1172 /* We can access Message here, it's secure because the sender's message is locked
1173 and the message has definitely not yet been destroyed, otherwise it would
1174 have been removed from this list by the dispatching routine right after
1175 dispatching the message */
1176 Message
->CompletionEvent
= NULL
;
1177 Message
->Result
= NULL
;
1178 RemoveEntryList(&Message
->DispatchingListEntry
);
1179 Message
->DispatchingListEntry
.Flink
= NULL
;
1182 Entry
= Entry
->Flink
;
1185 TRACE("MsqSendMessage (blocked) timed out 1\n");
1187 while (co_MsqDispatchOneSentMessage(pti
))
1192 PVOID WaitObjects
[3];
1194 WaitObjects
[0] = &CompletionEvent
; // Wait 0
1195 WaitObjects
[1] = pti
->pEventQueueServer
; // Wait 1
1196 WaitObjects
[2] = ptirec
->pEThread
; // Wait 2
1202 WaitStatus
= KeWaitForMultipleObjects(3, WaitObjects
, WaitAny
, UserRequest
,
1203 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1207 if(WaitStatus
== STATUS_TIMEOUT
)
1209 /* Look up if the message has not yet been dispatched, if so
1210 make sure it can't pass a result and it must not set the completion event anymore */
1211 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1212 while (Entry
!= &ptirec
->SentMessagesListHead
)
1214 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1217 /* We can access Message here, it's secure because the message queue is locked
1218 and the message is still hasn't been dispatched */
1219 Message
->CompletionEvent
= NULL
;
1220 Message
->Result
= NULL
;
1223 Entry
= Entry
->Flink
;
1226 /* Remove from the local dispatching list so the other thread knows,
1227 it can't pass a result and it must not set the completion event anymore */
1228 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1229 while (Entry
!= &pti
->DispatchingMessagesHead
)
1231 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1234 /* We can access Message here, it's secure because the sender's message is locked
1235 and the message has definitely not yet been destroyed, otherwise it would
1236 have been removed from this list by the dispatching routine right after
1237 dispatching the message */
1238 Message
->CompletionEvent
= NULL
;
1239 Message
->Result
= NULL
;
1240 RemoveEntryList(&Message
->DispatchingListEntry
);
1241 Message
->DispatchingListEntry
.Flink
= NULL
;
1244 Entry
= Entry
->Flink
;
1247 TRACE("MsqSendMessage timed out 2\n");
1250 // Receiving thread passed on and left us hanging with issues still pending.
1251 if ( WaitStatus
== STATUS_WAIT_2
)
1253 ERR("Receiving Thread woken up dead!\n");
1254 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1255 while (Entry
!= &pti
->DispatchingMessagesHead
)
1257 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1260 Message
->CompletionEvent
= NULL
;
1261 Message
->Result
= NULL
;
1262 RemoveEntryList(&Message
->DispatchingListEntry
);
1263 Message
->DispatchingListEntry
.Flink
= NULL
;
1266 Entry
= Entry
->Flink
;
1269 while (co_MsqDispatchOneSentMessage(pti
))
1272 while (NT_SUCCESS(WaitStatus
) && WaitStatus
== STATUS_WAIT_1
);
1275 if(WaitStatus
!= STATUS_TIMEOUT
)
1276 if (uResult
) *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1282 MsqPostMessage(PTHREADINFO pti
,
1284 BOOLEAN HardwareMessage
,
1289 PUSER_MESSAGE Message
;
1290 PUSER_MESSAGE_QUEUE MessageQueue
;
1292 if ( pti
->TIF_flags
& TIF_INCLEANUP
|| pti
->MessageQueue
->QF_flags
& QF_INDESTROY
)
1294 ERR("Post Msg; Thread or Q is Dead!\n");
1298 if(!(Message
= MsqCreateMessage(Msg
)))
1303 MessageQueue
= pti
->MessageQueue
;
1307 ERR("Post Msg; System Qeued Event Message!\n");
1308 InsertHeadList(&pti
->PostedMessagesListHead
,
1309 &Message
->ListEntry
);
1311 else if (!HardwareMessage
)
1313 InsertTailList(&pti
->PostedMessagesListHead
,
1314 &Message
->ListEntry
);
1318 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1319 &Message
->ListEntry
);
1322 if (Msg
->message
== WM_HOTKEY
) MessageBits
|= QS_HOTKEY
; // Justin Case, just set it.
1323 Message
->dwQEvent
= dwQEvent
;
1324 Message
->ExtraInfo
= ExtraInfo
;
1325 Message
->QS_Flags
= MessageBits
;
1327 MsqWakeQueue(pti
, MessageBits
, TRUE
);
1331 MsqPostQuitMessage(PTHREADINFO pti
, ULONG ExitCode
)
1333 pti
->QuitPosted
= TRUE
;
1334 pti
->exitCode
= ExitCode
;
1335 MsqWakeQueue(pti
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1338 /***********************************************************************
1339 * MsqSendParentNotify
1341 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1342 * the window has the WS_EX_NOPARENTNOTIFY style.
1344 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1346 PWND pwndDesktop
= UserGetDesktopWindow();
1348 /* pt has to be in the client coordinates of the parent window */
1349 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1350 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1356 if (!(pwnd
->style
& WS_CHILD
)) break;
1357 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1358 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1359 if (pwndParent
== pwndDesktop
) break;
1360 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1361 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1364 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1365 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1371 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1373 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1374 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
1376 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1377 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1378 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1380 TRACE("ITMM: Track Mouse Move!\n");
1382 /* Handle only the changing window track and mouse move across a border. */
1383 if ( pDesk
->spwndTrack
!= pwndTrack
||
1384 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1386 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1387 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1389 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1390 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1391 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1394 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1395 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1397 /* Clear the flags to sign a change. */
1398 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1400 /* Set the Track window and hit test. */
1401 pDesk
->spwndTrack
= pwndTrack
;
1402 pDesk
->htEx
= hittest
;
1405 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1406 if ( pDesk
->spwndTrack
== pwndTrack
&&
1407 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1408 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1410 TRACE("ITMM: Reset Hover points!\n");
1411 // Restart timer for the hover period.
1412 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1413 // Reset desktop mouse hover from the system default hover rectangle.
1414 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1415 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1416 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1417 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1418 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1422 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1429 MOUSEHOOKSTRUCT hook
;
1430 BOOL eatMsg
= FALSE
;
1432 PWND pwndMsg
, pwndDesktop
, pwndPopUP
;
1433 PUSER_MESSAGE_QUEUE MessageQueue
;
1435 PSYSTEM_CURSORINFO CurInfo
;
1437 DECLARE_RETURN(BOOL
);
1439 pti
= PsGetCurrentThreadWin32Thread();
1440 pwndDesktop
= UserGetDesktopWindow();
1441 MessageQueue
= pti
->MessageQueue
;
1442 CurInfo
= IntGetSysCursorInfo();
1443 pwndPopUP
= pwndMsg
= ValidateHwndNoErr(msg
->hwnd
);
1444 clk_msg
= MessageQueue
->msgDblClk
;
1445 pDesk
= pwndDesktop
->head
.rpdesk
;
1447 /* find the window to dispatch this mouse message to */
1448 if (MessageQueue
->spwndCapture
)
1451 pwndMsg
= MessageQueue
->spwndCapture
;
1452 if (pwndMsg
) UserReferenceObject(pwndMsg
);
1457 Start with null window. See wine win.c:test_mouse_input:WM_COMMAND tests.
1459 pwndMsg
= co_WinPosWindowFromPoint( NULL
, &msg
->pt
, &hittest
, FALSE
);
1461 // CORE-6129, Override if a diabled window with a visible popup was selected.
1463 if (pwndPopUP
&& pwndPopUP
->style
& WS_DISABLED
)
1465 TRACE("window disabled\n");
1466 pwndPopUP
= co_IntFindChildWindowToOwner(UserGetDesktopWindow(), pwndPopUP
);
1468 pwndPopUP
->style
& WS_POPUP
&&
1469 pwndPopUP
->style
& WS_VISIBLE
&&
1470 (pwndPopUP
->head
.pti
->MessageQueue
!= gpqForeground
||
1471 pwndPopUP
->head
.pti
->MessageQueue
->spwndActive
!= pwndPopUP
) &&
1472 //pwndPopUP != pwndPopUP->head.rpdesk->pDeskInfo->spwndShell needs testing.
1473 pwndPopUP
!= ValidateHwndNoErr(InputWindowStation
->ShellWindow
) )
1475 TRACE("Found Popup!\n");
1476 UserDereferenceObject(pwndMsg
);
1477 pwndMsg
= pwndPopUP
;
1478 UserReferenceObject(pwndMsg
);
1483 TRACE("Got mouse message for %p, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1485 // Null window or not the same "Hardware" message queue.
1486 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
->MessageQueue
!= pti
->MessageQueue
)
1488 /* Remove and ignore the message */
1489 *RemoveMessages
= TRUE
;
1493 if ( MessageQueue
== gpqCursor
) // Cursor must use the same Queue!
1495 IntTrackMouseMove(pwndMsg
, pDesk
, msg
, hittest
);
1499 ERR("Not the same cursor!\n");
1502 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1505 message
= msg
->message
;
1506 /* Note: windows has no concept of a non-client wheel message */
1507 if (message
!= WM_MOUSEWHEEL
)
1509 if (hittest
!= HTCLIENT
)
1511 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1512 msg
->wParam
= hittest
; // Caution! This might break wParam check in DblClk.
1516 /* coordinates don't get translated while tracking a menu */
1517 /* FIXME: should differentiate popups and top-level menus */
1518 if (!(MessageQueue
->MenuOwner
))
1520 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1521 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1525 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1527 /* translate double clicks */
1529 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1530 (msg
->message
== WM_RBUTTONDOWN
) ||
1531 (msg
->message
== WM_MBUTTONDOWN
) ||
1532 (msg
->message
== WM_XBUTTONDOWN
))
1534 BOOL update
= *RemoveMessages
;
1536 /* translate double clicks -
1537 * note that ...MOUSEMOVEs can slip in between
1538 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1540 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1541 hittest
!= HTCLIENT
||
1542 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1544 if ((msg
->message
== clk_msg
.message
) &&
1545 (msg
->hwnd
== clk_msg
.hwnd
) &&
1546 // Only worry about XButton wParam.
1547 (msg
->message
!= WM_XBUTTONDOWN
|| GET_XBUTTON_WPARAM(msg
->wParam
) == GET_XBUTTON_WPARAM(clk_msg
.wParam
)) &&
1548 ((msg
->time
- clk_msg
.time
) < (ULONG
)gspv
.iDblClickTime
) &&
1549 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1550 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1552 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1555 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1561 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1563 TRACE("Message out of range!!!\n");
1567 /* update static double click conditions */
1568 if (update
) MessageQueue
->msgDblClk
= *msg
;
1572 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1574 TRACE("Message out of range!!!\n");
1578 // Update mouse move down keys.
1579 if (message
== WM_MOUSEMOVE
)
1581 msg
->wParam
= MsqGetDownKeyState(MessageQueue
);
1585 if(gspv
.bMouseClickLock
)
1587 BOOL IsClkLck
= FALSE
;
1589 if(msg
->message
== WM_LBUTTONUP
)
1591 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1592 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1594 CurInfo
->ClickLockActive
= TRUE
;
1597 else if (msg
->message
== WM_LBUTTONDOWN
)
1599 if (CurInfo
->ClickLockActive
)
1602 CurInfo
->ClickLockActive
= FALSE
;
1605 CurInfo
->ClickLockTime
= msg
->time
;
1610 /* Remove and ignore the message */
1611 *RemoveMessages
= TRUE
;
1616 /* message is accepted now (but may still get dropped) */
1618 event
.message
= msg
->message
;
1619 event
.time
= msg
->time
;
1620 event
.hwnd
= msg
->hwnd
;
1621 event
.paramL
= msg
->pt
.x
;
1622 event
.paramH
= msg
->pt
.y
;
1623 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1626 hook
.hwnd
= msg
->hwnd
;
1627 hook
.wHitTestCode
= hittest
;
1628 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1629 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1630 message
, (LPARAM
)&hook
))
1633 hook
.hwnd
= msg
->hwnd
;
1634 hook
.wHitTestCode
= hittest
;
1635 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1636 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1638 ERR("WH_MOUSE dropped mouse message!\n");
1640 /* Remove and skip message */
1641 *RemoveMessages
= TRUE
;
1645 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1647 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1648 MAKELONG( hittest
, msg
->message
));
1650 /* Remove and skip message */
1651 *RemoveMessages
= TRUE
;
1655 if ((*RemoveMessages
== FALSE
) || MessageQueue
->spwndCapture
)
1657 /* Accept the message */
1658 msg
->message
= message
;
1662 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1663 (msg
->message
== WM_RBUTTONDOWN
) ||
1664 (msg
->message
== WM_MBUTTONDOWN
) ||
1665 (msg
->message
== WM_XBUTTONDOWN
))
1667 /* Send the WM_PARENTNOTIFY,
1668 * note that even for double/nonclient clicks
1669 * notification message is still WM_L/M/RBUTTONDOWN.
1671 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1673 /* Activate the window if needed */
1675 if (pwndMsg
!= MessageQueue
->spwndActive
)
1677 PWND pwndTop
= pwndMsg
;
1678 pwndTop
= IntGetNonChildAncestor(pwndTop
);
1680 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1682 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1684 (WPARAM
)UserHMGetHandle(pwndTop
),
1685 MAKELONG( hittest
, msg
->message
));
1688 case MA_NOACTIVATEANDEAT
:
1693 case MA_ACTIVATEANDEAT
:
1698 if (!co_IntMouseActivateWindow( pwndTop
)) eatMsg
= TRUE
;
1701 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1708 /* send the WM_SETCURSOR message */
1710 /* Windows sends the normal mouse message as the message parameter
1711 in the WM_SETCURSOR message even if it's non-client mouse message */
1712 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1714 msg
->message
= message
;
1719 UserDereferenceObject(pwndMsg
);
1724 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1728 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1729 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1731 switch (Msg
->wParam
)
1733 case VK_LSHIFT
: case VK_RSHIFT
:
1734 Msg
->wParam
= VK_SHIFT
;
1736 case VK_LCONTROL
: case VK_RCONTROL
:
1737 Msg
->wParam
= VK_CONTROL
;
1739 case VK_LMENU
: case VK_RMENU
:
1740 Msg
->wParam
= VK_MENU
;
1745 Event
.message
= Msg
->message
;
1746 Event
.hwnd
= Msg
->hwnd
;
1747 Event
.time
= Msg
->time
;
1748 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1749 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1750 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1751 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1753 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1754 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1755 LOWORD(Msg
->wParam
),
1758 /* skip this message */
1759 co_HOOK_CallHooks( WH_CBT
,
1761 LOWORD(Msg
->wParam
),
1763 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1769 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1771 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1773 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1775 else if ( IS_KBD_MESSAGE(Msg
->message
))
1777 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1783 /* check whether a message filter contains at least one potential hardware message */
1785 filter_contains_hw_range( UINT first
, UINT last
)
1787 /* hardware message ranges are (in numerical order):
1788 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1789 * WM_KEYFIRST .. WM_KEYLAST
1790 * WM_MOUSEFIRST .. WM_MOUSELAST
1793 if (last
< WM_NCMOUSEFIRST
) return 0;
1794 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1795 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1796 if (first
> WM_MOUSELAST
) return 0;
1801 co_MsqPeekHardwareMessage(IN PTHREADINFO pti
,
1804 IN UINT MsgFilterLow
,
1805 IN UINT MsgFilterHigh
,
1811 PUSER_MESSAGE CurrentMessage
;
1812 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1815 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
1817 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1819 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1820 CurrentEntry
= ListHead
->Flink
;
1822 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1824 if (!MessageQueue
->ptiSysLock
)
1826 MessageQueue
->ptiSysLock
= pti
;
1827 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1830 if (MessageQueue
->ptiSysLock
!= pti
)
1832 ERR("MsqPeekHardwareMessage: Thread Q is locked to another pti!\n");
1836 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1840 if (IsListEmpty(CurrentEntry
)) break;
1841 if (!CurrentMessage
) break;
1842 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1843 if (!CurrentEntry
) break; //// Fix CORE-6734 reported crash.
1846 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1847 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1848 3: handle to the window whose messages are to be retrieved.
1850 if ( ( !Window
|| // 1
1851 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1852 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) || // 3
1853 ( CurrentMessage
->Msg
.message
== WM_MOUSEMOVE
) ) && // Null window for mouse moves.
1854 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1855 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1857 msg
= CurrentMessage
->Msg
;
1859 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
1860 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1864 RemoveEntryList(&CurrentMessage
->ListEntry
);
1865 ClearMsgBitsMask(pti
, CurrentMessage
->QS_Flags
);
1866 MsqDestroyMessage(CurrentMessage
);
1876 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
1878 while(CurrentEntry
!= ListHead
);
1880 MessageQueue
->ptiSysLock
= NULL
;
1881 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1886 MsqPeekMessage(IN PTHREADINFO pti
,
1889 IN UINT MsgFilterLow
,
1890 IN UINT MsgFilterHigh
,
1894 PLIST_ENTRY CurrentEntry
;
1895 PUSER_MESSAGE CurrentMessage
;
1896 PLIST_ENTRY ListHead
;
1899 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
1900 ListHead
= &pti
->PostedMessagesListHead
;
1902 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1904 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1908 if (IsListEmpty(CurrentEntry
)) break;
1909 if (!CurrentMessage
) break;
1910 CurrentEntry
= CurrentEntry
->Flink
;
1913 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1914 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1915 3: handle to the window whose messages are to be retrieved.
1917 if ( ( !Window
|| // 1
1918 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1919 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1920 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1921 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1923 *Message
= CurrentMessage
->Msg
;
1927 RemoveEntryList(&CurrentMessage
->ListEntry
);
1928 ClearMsgBitsMask(pti
, CurrentMessage
->QS_Flags
);
1929 MsqDestroyMessage(CurrentMessage
);
1934 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1937 while (CurrentEntry
!= ListHead
);
1943 co_MsqWaitForNewMessages(PTHREADINFO pti
, PWND WndFilter
,
1944 UINT MsgFilterMin
, UINT MsgFilterMax
)
1948 ret
= KeWaitForSingleObject( pti
->pEventQueueServer
,
1958 MsqIsHung(PTHREADINFO pti
)
1960 LARGE_INTEGER LargeTickCount
;
1962 KeQueryTickCount(&LargeTickCount
);
1963 return ((LargeTickCount
.u
.LowPart
- pti
->timeLast
) > MSQ_HUNG
);
1968 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1971 TRACE("HungAppSysTimerProc\n");
1972 // Process list of windows that are hung and waiting.
1976 MsqInitializeMessageQueue(PTHREADINFO pti
, PUSER_MESSAGE_QUEUE MessageQueue
)
1978 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1979 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
); // Keep here!
1980 MessageQueue
->spwndFocus
= NULL
;
1981 MessageQueue
->iCursorLevel
= 0;
1982 MessageQueue
->CursorObject
= NULL
;
1983 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
1984 MessageQueue
->ptiMouse
= pti
;
1985 MessageQueue
->ptiKeyboard
= pti
;
1986 MessageQueue
->cThreads
++;
1992 MsqCleanupThreadMsgs(PTHREADINFO pti
)
1994 PLIST_ENTRY CurrentEntry
;
1995 PUSER_MESSAGE CurrentMessage
;
1996 PUSER_SENT_MESSAGE CurrentSentMessage
;
1998 /* cleanup posted messages */
1999 while (!IsListEmpty(&pti
->PostedMessagesListHead
))
2001 CurrentEntry
= RemoveHeadList(&pti
->PostedMessagesListHead
);
2002 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
2004 MsqDestroyMessage(CurrentMessage
);
2007 /* remove the messages that have not yet been dispatched */
2008 while (!IsListEmpty(&pti
->SentMessagesListHead
))
2010 CurrentEntry
= RemoveHeadList(&pti
->SentMessagesListHead
);
2011 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2014 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
2015 /* Only if the message has a sender was the message in the DispatchingList */
2016 if ((CurrentSentMessage
->ptiSender
)
2017 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
2019 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
2022 /* wake the sender's thread */
2023 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
2025 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2028 if (CurrentSentMessage
->HasPackedLParam
)
2030 if (CurrentSentMessage
->Msg
.lParam
)
2031 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2034 /* free the message */
2035 ExFreePool(CurrentSentMessage
);
2038 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
2039 ExitThread() was called in a SendMessage() umode callback */
2040 while (!IsListEmpty(&pti
->LocalDispatchingMessagesHead
))
2042 CurrentEntry
= RemoveHeadList(&pti
->LocalDispatchingMessagesHead
);
2043 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2046 /* remove the message from the dispatching list */
2047 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
2049 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
2052 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
2054 /* wake the sender's thread */
2055 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
2057 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2060 if (CurrentSentMessage
->HasPackedLParam
)
2062 if (CurrentSentMessage
->Msg
.lParam
)
2063 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2066 /* free the message */
2067 ExFreePool(CurrentSentMessage
);
2070 /* tell other threads not to bother returning any info to us */
2071 while (! IsListEmpty(&pti
->DispatchingMessagesHead
))
2073 CurrentEntry
= RemoveHeadList(&pti
->DispatchingMessagesHead
);
2074 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2075 DispatchingListEntry
);
2076 CurrentSentMessage
->CompletionEvent
= NULL
;
2077 CurrentSentMessage
->Result
= NULL
;
2079 /* do NOT dereference our message queue as it might get attempted to be
2083 // Clear it all out.
2086 pti
->pcti
->fsWakeBits
= 0;
2087 pti
->pcti
->fsChangeBits
= 0;
2090 pti
->nCntsQBits
[QSRosKey
] = 0;
2091 pti
->nCntsQBits
[QSRosMouseMove
] = 0;
2092 pti
->nCntsQBits
[QSRosMouseButton
] = 0;
2093 pti
->nCntsQBits
[QSRosPostMessage
] = 0;
2094 pti
->nCntsQBits
[QSRosSendMessage
] = 0;
2095 pti
->nCntsQBits
[QSRosHotKey
] = 0;
2096 pti
->nCntsQBits
[QSRosEvent
] = 0;
2100 MsqCleanupMessageQueue(PTHREADINFO pti
)
2102 PUSER_MESSAGE_QUEUE MessageQueue
;
2104 MessageQueue
= pti
->MessageQueue
;
2105 MessageQueue
->cThreads
--;
2107 if (MessageQueue
->cThreads
)
2109 if (MessageQueue
->ptiSysLock
== pti
) MessageQueue
->ptiSysLock
= NULL
;
2112 if (MessageQueue
->CursorObject
)
2114 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2116 /* Change to another cursor if we going to dereference current one
2117 Note: we can't use UserSetCursor because it uses current thread
2118 message queue instead of queue given for cleanup */
2119 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2123 /* Get the screen DC */
2124 hdcScreen
= IntGetScreenDC();
2126 GreMovePointer(hdcScreen
, -1, -1);
2127 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2130 TRACE("DereferenceObject pCursor\n");
2131 UserDereferenceObject(pCursor
);
2134 if (gpqForeground
== MessageQueue
)
2136 IntSetFocusMessageQueue(NULL
);
2138 if (gpqForegroundPrev
== MessageQueue
)
2140 gpqForegroundPrev
= NULL
;
2142 if (gpqCursor
== MessageQueue
)
2148 PUSER_MESSAGE_QUEUE FASTCALL
2149 MsqCreateMessageQueue(PTHREADINFO pti
)
2151 PUSER_MESSAGE_QUEUE MessageQueue
;
2153 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2154 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2162 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2163 /* hold at least one reference until it'll be destroyed */
2164 IntReferenceMessageQueue(MessageQueue
);
2165 /* initialize the queue */
2166 if (!MsqInitializeMessageQueue(pti
, MessageQueue
))
2168 IntDereferenceMessageQueue(MessageQueue
);
2172 return MessageQueue
;
2176 MsqDestroyMessageQueue(PTHREADINFO pti
)
2179 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2181 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2183 /* remove the message queue from any desktops */
2184 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2186 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2187 IntDereferenceMessageQueue(MessageQueue
);
2191 MsqCleanupMessageQueue(pti
);
2193 /* decrease the reference counter, if it hits zero, the queue will be freed */
2194 IntDereferenceMessageQueue(MessageQueue
);
2198 MsqSetMessageExtraInfo(LPARAM lParam
)
2202 PUSER_MESSAGE_QUEUE MessageQueue
;
2204 pti
= PsGetCurrentThreadWin32Thread();
2205 MessageQueue
= pti
->MessageQueue
;
2211 Ret
= MessageQueue
->ExtraInfo
;
2212 MessageQueue
->ExtraInfo
= lParam
;
2218 MsqGetMessageExtraInfo(VOID
)
2221 PUSER_MESSAGE_QUEUE MessageQueue
;
2223 pti
= PsGetCurrentThreadWin32Thread();
2224 MessageQueue
= pti
->MessageQueue
;
2230 return MessageQueue
->ExtraInfo
;
2233 // ReplyMessage is called by the thread receiving the window message.
2235 co_MsqReplyMessage( LRESULT lResult
)
2237 PUSER_SENT_MESSAGE Message
;
2240 pti
= PsGetCurrentThreadWin32Thread();
2241 Message
= pti
->pusmCurrent
;
2243 if (!Message
) return FALSE
;
2245 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2247 // SendMessageXxx || Callback msg and not a notify msg
2248 if (Message
->ptiSender
|| Message
->CompletionCallback
)
2250 Message
->lResult
= lResult
;
2251 Message
->QS_Flags
|= QS_SMRESULT
;
2252 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2258 MsqSetStateWindow(PTHREADINFO pti
, ULONG Type
, HWND hWnd
)
2261 PUSER_MESSAGE_QUEUE MessageQueue
;
2263 MessageQueue
= pti
->MessageQueue
;
2267 case MSQ_STATE_CAPTURE
:
2268 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2269 MessageQueue
->spwndCapture
= ValidateHwndNoErr(hWnd
);
2271 case MSQ_STATE_ACTIVE
:
2272 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2273 MessageQueue
->spwndActive
= ValidateHwndNoErr(hWnd
);
2275 case MSQ_STATE_FOCUS
:
2276 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2277 MessageQueue
->spwndFocus
= ValidateHwndNoErr(hWnd
);
2279 case MSQ_STATE_MENUOWNER
:
2280 Prev
= MessageQueue
->MenuOwner
;
2281 MessageQueue
->MenuOwner
= hWnd
;
2283 case MSQ_STATE_MOVESIZE
:
2284 Prev
= MessageQueue
->MoveSize
;
2285 MessageQueue
->MoveSize
= hWnd
;
2287 case MSQ_STATE_CARET
:
2288 ASSERT(MessageQueue
->CaretInfo
);
2289 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2290 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2299 NtUserGetKeyState(INT key
)
2305 Ret
= UserGetKeyState(key
);
2315 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2317 DWORD i
, ret
= TRUE
;
2319 PUSER_MESSAGE_QUEUE MessageQueue
;
2323 pti
= PsGetCurrentThreadWin32Thread();
2324 MessageQueue
= pti
->MessageQueue
;
2328 /* Probe and copy key state to an array */
2329 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2330 for (i
= 0; i
< 256; ++i
)
2333 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2334 lpKeyState
[i
] |= KS_DOWN_BIT
;
2335 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2336 lpKeyState
[i
] |= KS_LOCK_BIT
;
2339 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2341 SetLastNtError(_SEH2_GetExceptionCode());
2353 NtUserSetKeyboardState(LPBYTE pKeyState
)
2358 PUSER_MESSAGE_QUEUE MessageQueue
;
2360 UserEnterExclusive();
2362 pti
= PsGetCurrentThreadWin32Thread();
2363 MessageQueue
= pti
->MessageQueue
;
2367 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2368 for (i
= 0; i
< 256; ++i
)
2370 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2371 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2374 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2376 SetLastNtError(_SEH2_GetExceptionCode());