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()) ptiLastInput = pti;
635 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd
));
636 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEBUTTON
, 0);
641 /* always show cursor on background; FIXME: set default pointer */
642 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
643 CurInfo
->ShowingCursor
= 0;
647 PUSER_MESSAGE FASTCALL
648 MsqCreateMessage(LPMSG Msg
)
650 PUSER_MESSAGE Message
;
652 Message
= ExAllocateFromPagedLookasideList(pgMessageLookasideList
);
658 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
664 MsqDestroyMessage(PUSER_MESSAGE Message
)
666 ExFreeToPagedLookasideList(pgMessageLookasideList
, Message
);
670 co_MsqDispatchOneSentMessage(PTHREADINFO pti
)
672 PUSER_SENT_MESSAGE SaveMsg
, Message
;
677 if (IsListEmpty(&pti
->SentMessagesListHead
))
682 /* remove it from the list of pending messages */
683 Entry
= RemoveHeadList(&pti
->SentMessagesListHead
);
684 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
686 SaveMsg
= pti
->pusmCurrent
;
687 pti
->pusmCurrent
= Message
;
689 // Processing a message sent to it from another thread.
690 if ( ( Message
->ptiSender
&& pti
!= Message
->ptiSender
) ||
691 ( Message
->ptiCallBackSender
&& pti
!= Message
->ptiCallBackSender
))
692 { // most likely, but, to be sure.
693 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
696 /* insert it to the list of messages that are currently dispatched by this
698 InsertTailList(&pti
->LocalDispatchingMessagesHead
,
699 &Message
->ListEntry
);
701 ClearMsgBitsMask(pti
, Message
->QS_Flags
);
703 if (Message
->HookMessage
== MSQ_ISHOOK
)
704 { // Direct Hook Call processor
705 Result
= co_CallHook( Message
->Msg
.message
, // HookId
706 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
708 Message
->Msg
.lParam
);
710 else if (Message
->HookMessage
== MSQ_ISEVENT
)
711 { // Direct Event Call processor
712 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
715 Message
->Msg
.lParam
);
717 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
719 Result
= IntLoadHookModule(Message
->Msg
.message
,
720 (HHOOK
)Message
->Msg
.lParam
,
721 Message
->Msg
.wParam
);
723 else if ((Message
->CompletionCallback
) &&
724 (Message
->ptiCallBackSender
== pti
))
725 { /* Call the callback routine */
726 if (Message
->QS_Flags
& QS_SMRESULT
)
728 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
730 Message
->Msg
.message
,
731 Message
->CompletionCallbackContext
,
733 /* Set callback to NULL to prevent reentry */
734 Message
->CompletionCallback
= NULL
;
738 /* The message has not been processed yet, reinsert it. */
739 RemoveEntryList(&Message
->ListEntry
);
740 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
741 TRACE("Callback Message not processed yet. Requeuing the message\n");
747 { /* Call the window procedure. */
748 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
749 Message
->Msg
.message
,
751 Message
->Msg
.lParam
);
754 /* remove the message from the local dispatching list, because it doesn't need
755 to be cleaned up on thread termination anymore */
756 RemoveEntryList(&Message
->ListEntry
);
758 /* If the message is a callback, insert it in the callback senders MessageQueue */
759 if (Message
->CompletionCallback
)
761 if (Message
->ptiCallBackSender
)
763 Message
->lResult
= Result
;
764 Message
->QS_Flags
|= QS_SMRESULT
;
766 /* insert it in the callers message queue */
767 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
768 MsqWakeQueue(Message
->ptiCallBackSender
, QS_SENDMESSAGE
, TRUE
);
774 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
775 if (Message
->ptiSender
)
777 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
779 /* only remove it from the dispatching list if not already removed by a timeout */
780 RemoveEntryList(&Message
->DispatchingListEntry
);
783 /* still keep the sender's message queue locked, so the sender can't exit the
784 MsqSendMessage() function (if timed out) */
786 if (Message
->QS_Flags
& QS_SMRESULT
)
788 Result
= Message
->lResult
;
791 /* Let the sender know the result. */
792 if (Message
->Result
!= NULL
)
794 *Message
->Result
= Result
;
797 if (Message
->HasPackedLParam
== TRUE
)
799 if (Message
->Msg
.lParam
)
800 ExFreePool((PVOID
)Message
->Msg
.lParam
);
803 /* Notify the sender. */
804 if (Message
->CompletionEvent
!= NULL
)
806 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
809 /* free the message */
810 ExFreePoolWithTag(Message
, TAG_USRMSG
);
813 /* do not hangup on the user if this is reentering */
814 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
815 pti
->pusmCurrent
= SaveMsg
;
821 MsqRemoveWindowMessagesFromQueue(PWND Window
)
824 PUSER_SENT_MESSAGE SentMessage
;
825 PUSER_MESSAGE PostedMessage
;
826 PLIST_ENTRY CurrentEntry
, ListHead
;
830 pti
= Window
->head
.pti
;
832 /* remove the posted messages for this window */
833 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
834 ListHead
= &pti
->PostedMessagesListHead
;
835 while (CurrentEntry
!= ListHead
)
837 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
839 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
841 RemoveEntryList(&PostedMessage
->ListEntry
);
842 ClearMsgBitsMask(pti
, PostedMessage
->QS_Flags
);
843 MsqDestroyMessage(PostedMessage
);
844 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
848 CurrentEntry
= CurrentEntry
->Flink
;
852 /* remove the sent messages for this window */
853 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
854 ListHead
= &pti
->SentMessagesListHead
;
855 while (CurrentEntry
!= ListHead
)
857 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
859 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
861 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
863 RemoveEntryList(&SentMessage
->ListEntry
);
864 ClearMsgBitsMask(pti
, SentMessage
->QS_Flags
);
866 /* Only if the message has a sender was the queue referenced */
867 if ((SentMessage
->ptiSender
)
868 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
870 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
873 /* wake the sender's thread */
874 if (SentMessage
->CompletionEvent
!= NULL
)
876 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
879 if (SentMessage
->HasPackedLParam
== TRUE
)
881 if (SentMessage
->Msg
.lParam
)
882 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
885 /* free the message */
886 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
888 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
892 CurrentEntry
= CurrentEntry
->Flink
;
898 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
903 SENDASYNCPROC CompletionCallback
,
904 ULONG_PTR CompletionCallbackContext
,
905 BOOL HasPackedLParam
,
909 PTHREADINFO ptiSender
;
910 PUSER_SENT_MESSAGE Message
;
912 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
914 ERR("MsqSendMessage(): Not enough memory to allocate a message");
918 ptiSender
= PsGetCurrentThreadWin32Thread();
920 Message
->Msg
.hwnd
= hwnd
;
921 Message
->Msg
.message
= Msg
;
922 Message
->Msg
.wParam
= wParam
;
923 Message
->Msg
.lParam
= lParam
;
924 Message
->CompletionEvent
= NULL
;
926 Message
->lResult
= 0;
927 Message
->ptiReceiver
= ptiReceiver
;
928 Message
->ptiSender
= NULL
;
929 Message
->ptiCallBackSender
= ptiSender
;
930 Message
->DispatchingListEntry
.Flink
= NULL
;
931 Message
->CompletionCallback
= CompletionCallback
;
932 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
933 Message
->HookMessage
= HookMessage
;
934 Message
->HasPackedLParam
= HasPackedLParam
;
935 Message
->QS_Flags
= QS_SENDMESSAGE
;
937 InsertTailList(&ptiReceiver
->SentMessagesListHead
, &Message
->ListEntry
);
938 MsqWakeQueue(ptiReceiver
, QS_SENDMESSAGE
, TRUE
);
944 co_MsqSendMessage(PTHREADINFO ptirec
,
945 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
946 UINT uTimeout
, BOOL Block
, INT HookMessage
,
950 PUSER_SENT_MESSAGE Message
;
951 KEVENT CompletionEvent
;
953 LARGE_INTEGER Timeout
;
956 LRESULT Result
= 0; //// Result could be trashed. ////
958 pti
= PsGetCurrentThreadWin32Thread();
959 ASSERT(pti
!= ptirec
);
960 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
962 /* Don't send from or to a dying thread */
963 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
965 if (uResult
) *uResult
= -1;
966 ERR("MsqSM: Current pti %lu or Rec pti %lu\n", pti
->TIF_flags
& TIF_INCLEANUP
, ptirec
->TIF_flags
& TIF_INCLEANUP
);
967 return STATUS_UNSUCCESSFUL
;
970 if ( HookMessage
== MSQ_NORMAL
)
972 pWnd
= ValidateHwndNoErr(Wnd
);
974 // These can not cross International Border lines!
975 if ( pti
->ppi
!= ptirec
->ppi
&& pWnd
)
979 // Handle the special case when working with password transfers across bordering processes.
981 case EM_SETPASSWORDCHAR
:
983 // Look for edit controls setup for passwords.
984 if ( gpsi
->atomSysClass
[ICLS_EDIT
] == pWnd
->pcls
->atomClassName
&& // Use atomNVClassName.
985 pWnd
->style
& ES_PASSWORD
)
987 if (uResult
) *uResult
= -1;
988 ERR("Running across the border without a passport!\n");
989 EngSetLastError(ERROR_ACCESS_DENIED
);
990 return STATUS_UNSUCCESSFUL
;
994 if (uResult
) *uResult
= -1;
995 ERR("Running across the border without a passport!\n");
996 return STATUS_UNSUCCESSFUL
;
1000 // These can not cross State lines!
1001 if ( Msg
== WM_CREATE
|| Msg
== WM_NCCREATE
)
1003 if (uResult
) *uResult
= -1;
1004 ERR("Can not tell the other State we have Create!\n");
1005 return STATUS_UNSUCCESSFUL
;
1009 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1011 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1012 return STATUS_INSUFFICIENT_RESOURCES
;
1015 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1017 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1019 /* FIXME: Increase reference counter of sender's message queue here */
1021 Message
->Msg
.hwnd
= Wnd
;
1022 Message
->Msg
.message
= Msg
;
1023 Message
->Msg
.wParam
= wParam
;
1024 Message
->Msg
.lParam
= lParam
;
1025 Message
->CompletionEvent
= &CompletionEvent
;
1026 Message
->Result
= &Result
;
1027 Message
->lResult
= 0;
1028 Message
->QS_Flags
= 0;
1029 Message
->ptiReceiver
= ptirec
;
1030 Message
->ptiSender
= pti
;
1031 Message
->ptiCallBackSender
= NULL
;
1032 Message
->CompletionCallback
= NULL
;
1033 Message
->CompletionCallbackContext
= 0;
1034 Message
->HookMessage
= HookMessage
;
1035 Message
->HasPackedLParam
= FALSE
;
1037 /* Add it to the list of pending messages */
1038 InsertTailList(&pti
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1040 /* Queue it in the destination's message queue */
1041 InsertTailList(&ptirec
->SentMessagesListHead
, &Message
->ListEntry
);
1043 Message
->QS_Flags
= QS_SENDMESSAGE
;
1044 MsqWakeQueue(ptirec
, QS_SENDMESSAGE
, TRUE
);
1046 /* We can't access the Message anymore since it could have already been deleted! */
1052 /* Don't process messages sent to the thread */
1053 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1054 FALSE
, (uTimeout
? &Timeout
: NULL
));
1058 if(WaitStatus
== STATUS_TIMEOUT
)
1060 /* Look up if the message has not yet dispatched, if so
1061 make sure it can't pass a result and it must not set the completion event anymore */
1062 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1063 while (Entry
!= &ptirec
->SentMessagesListHead
)
1065 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1068 /* We can access Message here, it's secure because the message queue is locked
1069 and the message is still hasn't been dispatched */
1070 Message
->CompletionEvent
= NULL
;
1071 Message
->Result
= NULL
;
1074 Entry
= Entry
->Flink
;
1077 /* Remove from the local dispatching list so the other thread knows,
1078 it can't pass a result and it must not set the completion event anymore */
1079 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1080 while (Entry
!= &pti
->DispatchingMessagesHead
)
1082 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1085 /* We can access Message here, it's secure because the sender's message is locked
1086 and the message has definitely not yet been destroyed, otherwise it would
1087 have been removed from this list by the dispatching routine right after
1088 dispatching the message */
1089 Message
->CompletionEvent
= NULL
;
1090 Message
->Result
= NULL
;
1091 RemoveEntryList(&Message
->DispatchingListEntry
);
1092 Message
->DispatchingListEntry
.Flink
= NULL
;
1095 Entry
= Entry
->Flink
;
1098 TRACE("MsqSendMessage (blocked) timed out 1\n");
1100 while (co_MsqDispatchOneSentMessage(ptirec
))
1105 PVOID WaitObjects
[3];
1107 ObReferenceObject(ptirec
->pEThread
);
1109 WaitObjects
[0] = &CompletionEvent
; // Wait 0
1110 WaitObjects
[1] = pti
->pEventQueueServer
; // Wait 1
1111 WaitObjects
[2] = ptirec
->pEThread
; // Wait 2
1117 WaitStatus
= KeWaitForMultipleObjects(3, WaitObjects
, WaitAny
, UserRequest
,
1118 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1122 if(WaitStatus
== STATUS_TIMEOUT
)
1124 /* Look up if the message has not yet been dispatched, if so
1125 make sure it can't pass a result and it must not set the completion event anymore */
1126 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1127 while (Entry
!= &ptirec
->SentMessagesListHead
)
1129 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1132 /* We can access Message here, it's secure because the message queue is locked
1133 and the message is still hasn't been dispatched */
1134 Message
->CompletionEvent
= NULL
;
1135 Message
->Result
= NULL
;
1138 Entry
= Entry
->Flink
;
1141 /* Remove from the local dispatching list so the other thread knows,
1142 it can't pass a result and it must not set the completion event anymore */
1143 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1144 while (Entry
!= &pti
->DispatchingMessagesHead
)
1146 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1149 /* We can access Message here, it's secure because the sender's message is locked
1150 and the message has definitely not yet been destroyed, otherwise it would
1151 have been removed from this list by the dispatching routine right after
1152 dispatching the message */
1153 Message
->CompletionEvent
= NULL
;
1154 Message
->Result
= NULL
;
1155 RemoveEntryList(&Message
->DispatchingListEntry
);
1156 Message
->DispatchingListEntry
.Flink
= NULL
;
1159 Entry
= Entry
->Flink
;
1162 TRACE("MsqSendMessage timed out 2\n");
1165 /*if (WaitStatus == STATUS_WAIT_1)
1169 // Receiving thread passed on and left us hanging with issues still pending.
1170 if (WaitStatus
== STATUS_WAIT_2
)
1172 ERR("Thread woken up dead!\n");
1173 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1174 while (Entry
!= &pti
->DispatchingMessagesHead
)
1176 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1179 Message
->CompletionEvent
= NULL
;
1180 Message
->Result
= NULL
;
1181 RemoveEntryList(&Message
->DispatchingListEntry
);
1182 Message
->DispatchingListEntry
.Flink
= NULL
;
1185 Entry
= Entry
->Flink
;
1188 while (co_MsqDispatchOneSentMessage(pti
))
1191 while (NT_SUCCESS(WaitStatus
) && WaitStatus
== STATUS_WAIT_1
);
1192 ObDereferenceObject(ptirec
->pEThread
);
1195 if(WaitStatus
!= STATUS_TIMEOUT
)
1196 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1202 MsqPostMessage(PTHREADINFO pti
,
1204 BOOLEAN HardwareMessage
,
1208 PUSER_MESSAGE Message
;
1209 PUSER_MESSAGE_QUEUE MessageQueue
;
1211 if ( pti
->TIF_flags
& TIF_INCLEANUP
|| pti
->MessageQueue
->QF_flags
& QF_INDESTROY
)
1213 ERR("Post Msg; Thread or Q is Dead!\n");
1217 if(!(Message
= MsqCreateMessage(Msg
)))
1222 MessageQueue
= pti
->MessageQueue
;
1226 ERR("Post Msg; System Qeued Event Message!\n");
1227 InsertHeadList(&pti
->PostedMessagesListHead
,
1228 &Message
->ListEntry
);
1230 else if (!HardwareMessage
)
1232 InsertTailList(&pti
->PostedMessagesListHead
,
1233 &Message
->ListEntry
);
1237 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1238 &Message
->ListEntry
);
1241 if (Msg
->message
== WM_HOTKEY
) MessageBits
|= QS_HOTKEY
; // Justin Case, just set it.
1242 Message
->dwQEvent
= dwQEvent
;
1243 Message
->QS_Flags
= MessageBits
;
1245 MsqWakeQueue(pti
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
1249 MsqPostQuitMessage(PTHREADINFO pti
, ULONG ExitCode
)
1251 pti
->QuitPosted
= TRUE
;
1252 pti
->exitCode
= ExitCode
;
1253 MsqWakeQueue(pti
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1256 /***********************************************************************
1257 * MsqSendParentNotify
1259 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1260 * the window has the WS_EX_NOPARENTNOTIFY style.
1262 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1264 PWND pwndDesktop
= UserGetDesktopWindow();
1266 /* pt has to be in the client coordinates of the parent window */
1267 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1268 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1274 if (!(pwnd
->style
& WS_CHILD
)) break;
1275 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1276 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1277 if (pwndParent
== pwndDesktop
) break;
1278 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1279 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1282 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1283 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1289 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1291 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1292 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
1294 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1295 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1296 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1298 TRACE("ITMM: Track Mouse Move!\n");
1300 /* Handle only the changing window track and mouse move across a border. */
1301 if ( pDesk
->spwndTrack
!= pwndTrack
||
1302 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1304 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1305 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1307 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1308 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1309 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1312 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1313 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1315 /* Clear the flags to sign a change. */
1316 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1318 /* Set the Track window and hit test. */
1319 pDesk
->spwndTrack
= pwndTrack
;
1320 pDesk
->htEx
= hittest
;
1323 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1324 if ( pDesk
->spwndTrack
== pwndTrack
&&
1325 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1326 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1328 TRACE("ITMM: Reset Hover points!\n");
1329 // Restart timer for the hover period.
1330 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1331 // Reset desktop mouse hover from the system default hover rectangle.
1332 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1333 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1334 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1335 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1336 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1340 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1347 MOUSEHOOKSTRUCT hook
;
1350 PWND pwndMsg
, pwndDesktop
;
1351 PUSER_MESSAGE_QUEUE MessageQueue
;
1353 PSYSTEM_CURSORINFO CurInfo
;
1355 DECLARE_RETURN(BOOL
);
1357 pti
= PsGetCurrentThreadWin32Thread();
1358 pwndDesktop
= UserGetDesktopWindow();
1359 MessageQueue
= pti
->MessageQueue
;
1360 CurInfo
= IntGetSysCursorInfo();
1361 pwndMsg
= ValidateHwndNoErr(msg
->hwnd
);
1362 clk_msg
= MessageQueue
->msgDblClk
;
1363 pDesk
= pwndDesktop
->head
.rpdesk
;
1365 /* find the window to dispatch this mouse message to */
1366 if (MessageQueue
->spwndCapture
)
1369 pwndMsg
= MessageQueue
->spwndCapture
;
1370 if (pwndMsg
) UserReferenceObject(pwndMsg
);
1373 { // Fix wine Msg test_HTTRANSPARENT. Start with a NULL window.
1374 // http://www.winehq.org/pipermail/wine-patches/2012-August/116776.html
1375 pwndMsg
= co_WinPosWindowFromPoint(NULL
, &msg
->pt
, &hittest
);
1378 TRACE("Got mouse message for %p, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1380 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
1382 /* Remove and ignore the message */
1383 *RemoveMessages
= TRUE
;
1387 if ( MessageQueue
== gpqCursor
) // Cursor must use the same Queue!
1389 IntTrackMouseMove(pwndMsg
, pDesk
, msg
, hittest
);
1393 ERR("Not the same cursor!\n");
1396 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1399 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
1403 message
= msg
->message
;
1404 /* Note: windows has no concept of a non-client wheel message */
1405 if (message
!= WM_MOUSEWHEEL
)
1407 if (hittest
!= HTCLIENT
)
1409 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1410 msg
->wParam
= hittest
;
1414 /* coordinates don't get translated while tracking a menu */
1415 /* FIXME: should differentiate popups and top-level menus */
1416 if (!(MessageQueue
->MenuOwner
))
1418 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1419 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1423 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1425 /* translate double clicks */
1427 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1428 (msg
->message
== WM_RBUTTONDOWN
) ||
1429 (msg
->message
== WM_MBUTTONDOWN
) ||
1430 (msg
->message
== WM_XBUTTONDOWN
))
1432 BOOL update
= *RemoveMessages
;
1434 /* translate double clicks -
1435 * note that ...MOUSEMOVEs can slip in between
1436 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1438 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1439 hittest
!= HTCLIENT
||
1440 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1442 if ((msg
->message
== clk_msg
.message
) &&
1443 (msg
->hwnd
== clk_msg
.hwnd
) &&
1444 (msg
->wParam
== clk_msg
.wParam
) &&
1445 ((msg
->time
- clk_msg
.time
) < (ULONG
)gspv
.iDblClickTime
) &&
1446 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1447 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1449 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1452 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1458 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1460 TRACE("Message out of range!!!\n");
1464 /* update static double click conditions */
1465 if (update
) MessageQueue
->msgDblClk
= *msg
;
1469 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1471 TRACE("Message out of range!!!\n");
1476 if(gspv
.bMouseClickLock
)
1478 BOOL IsClkLck
= FALSE
;
1480 if(msg
->message
== WM_LBUTTONUP
)
1482 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1483 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1485 CurInfo
->ClickLockActive
= TRUE
;
1488 else if (msg
->message
== WM_LBUTTONDOWN
)
1490 if (CurInfo
->ClickLockActive
)
1493 CurInfo
->ClickLockActive
= FALSE
;
1496 CurInfo
->ClickLockTime
= msg
->time
;
1501 /* Remove and ignore the message */
1502 *RemoveMessages
= TRUE
;
1507 /* message is accepted now (but may still get dropped) */
1509 event
.message
= msg
->message
;
1510 event
.time
= msg
->time
;
1511 event
.hwnd
= msg
->hwnd
;
1512 event
.paramL
= msg
->pt
.x
;
1513 event
.paramH
= msg
->pt
.y
;
1514 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1517 hook
.hwnd
= msg
->hwnd
;
1518 hook
.wHitTestCode
= hittest
;
1519 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1520 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1521 message
, (LPARAM
)&hook
))
1524 hook
.hwnd
= msg
->hwnd
;
1525 hook
.wHitTestCode
= hittest
;
1526 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1527 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1529 ERR("WH_MOUSE dropped mouse message!\n");
1531 /* Remove and skip message */
1532 *RemoveMessages
= TRUE
;
1536 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1538 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1539 MAKELONG( hittest
, msg
->message
));
1541 /* Remove and skip message */
1542 *RemoveMessages
= TRUE
;
1546 if ((*RemoveMessages
== FALSE
) || MessageQueue
->spwndCapture
)
1548 /* Accept the message */
1549 msg
->message
= message
;
1555 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1556 (msg
->message
== WM_RBUTTONDOWN
) ||
1557 (msg
->message
== WM_MBUTTONDOWN
) ||
1558 (msg
->message
== WM_XBUTTONDOWN
))
1560 /* Send the WM_PARENTNOTIFY,
1561 * note that even for double/nonclient clicks
1562 * notification message is still WM_L/M/RBUTTONDOWN.
1564 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1566 /* Activate the window if needed */
1568 if (pwndMsg
!= MessageQueue
->spwndActive
)
1570 PWND pwndTop
= pwndMsg
;
1571 while (pwndTop
&& ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
))
1573 pwndTop
= pwndTop
->spwndParent
;
1576 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1578 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1580 (WPARAM
)UserHMGetHandle(pwndTop
),
1581 MAKELONG( hittest
, msg
->message
));
1584 case MA_NOACTIVATEANDEAT
:
1589 case MA_ACTIVATEANDEAT
:
1594 if (!co_IntMouseActivateWindow( pwndTop
)) eatMsg
= TRUE
;
1597 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1604 /* send the WM_SETCURSOR message */
1606 /* Windows sends the normal mouse message as the message parameter
1607 in the WM_SETCURSOR message even if it's non-client mouse message */
1608 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1610 msg
->message
= message
;
1615 UserDereferenceObject(pwndMsg
);
1620 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1624 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1625 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1627 switch (Msg
->wParam
)
1629 case VK_LSHIFT
: case VK_RSHIFT
:
1630 Msg
->wParam
= VK_SHIFT
;
1632 case VK_LCONTROL
: case VK_RCONTROL
:
1633 Msg
->wParam
= VK_CONTROL
;
1635 case VK_LMENU
: case VK_RMENU
:
1636 Msg
->wParam
= VK_MENU
;
1641 Event
.message
= Msg
->message
;
1642 Event
.hwnd
= Msg
->hwnd
;
1643 Event
.time
= Msg
->time
;
1644 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1645 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1646 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1647 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1649 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1650 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1651 LOWORD(Msg
->wParam
),
1654 /* skip this message */
1655 co_HOOK_CallHooks( WH_CBT
,
1657 LOWORD(Msg
->wParam
),
1659 ERR("KeyboardMessage WH_CBT Call Hook return!\n");
1665 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1667 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1669 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1671 else if ( IS_KBD_MESSAGE(Msg
->message
))
1673 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1680 co_MsqPeekMouseMove(IN PTHREADINFO pti
,
1683 IN UINT MsgFilterLow
,
1684 IN UINT MsgFilterHigh
,
1689 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
1691 if(!(MessageQueue
->MouseMoved
))
1694 if (!MessageQueue
->ptiSysLock
)
1696 MessageQueue
->ptiSysLock
= pti
;
1697 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1700 if (MessageQueue
->ptiSysLock
!= pti
)
1702 ERR("MsqPeekMouseMove: Thread Q is locked to another pti!\n");
1706 msg
= MessageQueue
->MouseMoveMsg
;
1708 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1715 ClearMsgBitsMask(pti
, QS_MOUSEMOVE
);
1716 MessageQueue
->MouseMoved
= FALSE
;
1719 MessageQueue
->ptiSysLock
= NULL
;
1720 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1721 return AcceptMessage
;
1724 /* check whether a message filter contains at least one potential hardware message */
1726 filter_contains_hw_range( UINT first
, UINT last
)
1728 /* hardware message ranges are (in numerical order):
1729 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1730 * WM_KEYFIRST .. WM_KEYLAST
1731 * WM_MOUSEFIRST .. WM_MOUSELAST
1734 if (last
< WM_NCMOUSEFIRST
) return 0;
1735 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1736 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1737 if (first
> WM_MOUSELAST
) return 0;
1742 co_MsqPeekHardwareMessage(IN PTHREADINFO pti
,
1745 IN UINT MsgFilterLow
,
1746 IN UINT MsgFilterHigh
,
1752 PUSER_MESSAGE CurrentMessage
;
1753 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1756 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
1758 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1760 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1761 CurrentEntry
= ListHead
->Flink
;
1763 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1765 if (!MessageQueue
->ptiSysLock
)
1767 MessageQueue
->ptiSysLock
= pti
;
1768 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1771 if (MessageQueue
->ptiSysLock
!= pti
)
1773 ERR("MsqPeekHardwareMessage: Thread Q is locked to another pti!\n");
1777 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1781 if (IsListEmpty(CurrentEntry
)) break;
1782 if (!CurrentMessage
) break;
1783 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1786 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1787 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1788 3: handle to the window whose messages are to be retrieved.
1790 if ( ( !Window
|| // 1
1791 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1792 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1793 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1794 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1796 msg
= CurrentMessage
->Msg
;
1798 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
1799 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1803 RemoveEntryList(&CurrentMessage
->ListEntry
);
1804 ClearMsgBitsMask(pti
, CurrentMessage
->QS_Flags
);
1805 MsqDestroyMessage(CurrentMessage
);
1815 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1818 while(CurrentEntry
!= ListHead
);
1820 MessageQueue
->ptiSysLock
= NULL
;
1821 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
1826 MsqPeekMessage(IN PTHREADINFO pti
,
1829 IN UINT MsgFilterLow
,
1830 IN UINT MsgFilterHigh
,
1834 PLIST_ENTRY CurrentEntry
;
1835 PUSER_MESSAGE CurrentMessage
;
1836 PLIST_ENTRY ListHead
;
1839 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
1840 ListHead
= &pti
->PostedMessagesListHead
;
1842 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1844 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1848 if (IsListEmpty(CurrentEntry
)) break;
1849 if (!CurrentMessage
) break;
1850 CurrentEntry
= CurrentEntry
->Flink
;
1853 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1854 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1855 3: handle to the window whose messages are to be retrieved.
1857 if ( ( !Window
|| // 1
1858 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1859 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1860 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1861 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1863 *Message
= CurrentMessage
->Msg
;
1867 RemoveEntryList(&CurrentMessage
->ListEntry
);
1868 ClearMsgBitsMask(pti
, CurrentMessage
->QS_Flags
);
1869 MsqDestroyMessage(CurrentMessage
);
1874 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1877 while (CurrentEntry
!= ListHead
);
1883 co_MsqWaitForNewMessages(PTHREADINFO pti
, PWND WndFilter
,
1884 UINT MsgFilterMin
, UINT MsgFilterMax
)
1888 ret
= KeWaitForSingleObject( pti
->pEventQueueServer
,
1898 MsqIsHung(PTHREADINFO pti
)
1900 LARGE_INTEGER LargeTickCount
;
1902 KeQueryTickCount(&LargeTickCount
);
1903 return ((LargeTickCount
.u
.LowPart
- pti
->timeLast
) > MSQ_HUNG
);
1908 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1911 TRACE("HungAppSysTimerProc\n");
1912 // Process list of windows that are hung and waiting.
1916 MsqInitializeMessageQueue(PTHREADINFO pti
, PUSER_MESSAGE_QUEUE MessageQueue
)
1918 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1919 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
); // Keep here!
1920 MessageQueue
->spwndFocus
= NULL
;
1921 MessageQueue
->iCursorLevel
= 0;
1922 MessageQueue
->CursorObject
= NULL
;
1923 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
1924 MessageQueue
->ptiMouse
= pti
;
1925 MessageQueue
->ptiKeyboard
= pti
;
1926 MessageQueue
->cThreads
++;
1932 MsqCleanupThreadMsgs(PTHREADINFO pti
)
1934 PLIST_ENTRY CurrentEntry
;
1935 PUSER_MESSAGE CurrentMessage
;
1936 PUSER_SENT_MESSAGE CurrentSentMessage
;
1938 /* cleanup posted messages */
1939 while (!IsListEmpty(&pti
->PostedMessagesListHead
))
1941 CurrentEntry
= RemoveHeadList(&pti
->PostedMessagesListHead
);
1942 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1944 MsqDestroyMessage(CurrentMessage
);
1947 /* remove the messages that have not yet been dispatched */
1948 while (!IsListEmpty(&pti
->SentMessagesListHead
))
1950 CurrentEntry
= RemoveHeadList(&pti
->SentMessagesListHead
);
1951 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1954 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
1955 /* Only if the message has a sender was the message in the DispatchingList */
1956 if ((CurrentSentMessage
->ptiSender
)
1957 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1959 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1962 /* wake the sender's thread */
1963 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1965 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1968 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1970 if (CurrentSentMessage
->Msg
.lParam
)
1971 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1974 /* free the message */
1975 ExFreePool(CurrentSentMessage
);
1978 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1979 ExitThread() was called in a SendMessage() umode callback */
1980 while (!IsListEmpty(&pti
->LocalDispatchingMessagesHead
))
1982 CurrentEntry
= RemoveHeadList(&pti
->LocalDispatchingMessagesHead
);
1983 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1986 /* remove the message from the dispatching list */
1987 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1989 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1992 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
1994 /* wake the sender's thread */
1995 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1997 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2000 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
2002 if (CurrentSentMessage
->Msg
.lParam
)
2003 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2006 /* free the message */
2007 ExFreePool(CurrentSentMessage
);
2010 /* tell other threads not to bother returning any info to us */
2011 while (! IsListEmpty(&pti
->DispatchingMessagesHead
))
2013 CurrentEntry
= RemoveHeadList(&pti
->DispatchingMessagesHead
);
2014 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2015 DispatchingListEntry
);
2016 CurrentSentMessage
->CompletionEvent
= NULL
;
2017 CurrentSentMessage
->Result
= NULL
;
2019 /* do NOT dereference our message queue as it might get attempted to be
2023 // Clear it all out.
2026 pti
->pcti
->fsWakeBits
= 0;
2027 pti
->pcti
->fsChangeBits
= 0;
2030 pti
->nCntsQBits
[QSRosKey
] = 0;
2031 pti
->nCntsQBits
[QSRosMouseMove
] = 0;
2032 pti
->nCntsQBits
[QSRosMouseButton
] = 0;
2033 pti
->nCntsQBits
[QSRosPostMessage
] = 0;
2034 pti
->nCntsQBits
[QSRosSendMessage
] = 0;
2035 pti
->nCntsQBits
[QSRosHotKey
] = 0;
2036 pti
->nCntsQBits
[QSRosEvent
] = 0;
2040 MsqCleanupMessageQueue(PTHREADINFO pti
)
2042 PUSER_MESSAGE_QUEUE MessageQueue
;
2044 MessageQueue
= pti
->MessageQueue
;
2045 MessageQueue
->cThreads
--;
2047 if (MessageQueue
->cThreads
)
2049 if (MessageQueue
->ptiSysLock
== pti
) MessageQueue
->ptiSysLock
= NULL
;
2052 if (MessageQueue
->CursorObject
)
2054 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2056 /* Change to another cursor if we going to dereference current one
2057 Note: we can't use UserSetCursor because it uses current thread
2058 message queue instead of queue given for cleanup */
2059 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2063 /* Get the screen DC */
2064 hdcScreen
= IntGetScreenDC();
2066 GreMovePointer(hdcScreen
, -1, -1);
2067 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2070 ERR("DereferenceObject pCursor\n");
2071 UserDereferenceObject(pCursor
);
2074 if (gpqForeground
== MessageQueue
)
2076 IntSetFocusMessageQueue(NULL
);
2078 if (gpqForegroundPrev
== MessageQueue
)
2080 gpqForegroundPrev
= NULL
;
2082 if (gpqCursor
== MessageQueue
)
2088 PUSER_MESSAGE_QUEUE FASTCALL
2089 MsqCreateMessageQueue(PTHREADINFO pti
)
2091 PUSER_MESSAGE_QUEUE MessageQueue
;
2093 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2094 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2102 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2103 /* hold at least one reference until it'll be destroyed */
2104 IntReferenceMessageQueue(MessageQueue
);
2105 /* initialize the queue */
2106 if (!MsqInitializeMessageQueue(pti
, MessageQueue
))
2108 IntDereferenceMessageQueue(MessageQueue
);
2112 return MessageQueue
;
2116 MsqDestroyMessageQueue(PTHREADINFO pti
)
2119 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2121 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2123 /* remove the message queue from any desktops */
2124 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2126 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2127 IntDereferenceMessageQueue(MessageQueue
);
2131 MsqCleanupMessageQueue(pti
);
2133 /* decrease the reference counter, if it hits zero, the queue will be freed */
2134 IntDereferenceMessageQueue(MessageQueue
);
2138 MsqSetMessageExtraInfo(LPARAM lParam
)
2142 PUSER_MESSAGE_QUEUE MessageQueue
;
2144 pti
= PsGetCurrentThreadWin32Thread();
2145 MessageQueue
= pti
->MessageQueue
;
2151 Ret
= MessageQueue
->ExtraInfo
;
2152 MessageQueue
->ExtraInfo
= lParam
;
2158 MsqGetMessageExtraInfo(VOID
)
2161 PUSER_MESSAGE_QUEUE MessageQueue
;
2163 pti
= PsGetCurrentThreadWin32Thread();
2164 MessageQueue
= pti
->MessageQueue
;
2170 return MessageQueue
->ExtraInfo
;
2173 // ReplyMessage is called by the thread receiving the window message.
2175 co_MsqReplyMessage( LRESULT lResult
)
2177 PUSER_SENT_MESSAGE Message
;
2180 pti
= PsGetCurrentThreadWin32Thread();
2181 Message
= pti
->pusmCurrent
;
2183 if (!Message
) return FALSE
;
2185 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2187 // SendMessageXxx || Callback msg and not a notify msg
2188 if (Message
->ptiSender
|| Message
->CompletionCallback
)
2190 Message
->lResult
= lResult
;
2191 Message
->QS_Flags
|= QS_SMRESULT
;
2192 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2198 MsqSetStateWindow(PTHREADINFO pti
, ULONG Type
, HWND hWnd
)
2201 PUSER_MESSAGE_QUEUE MessageQueue
;
2203 MessageQueue
= pti
->MessageQueue
;
2207 case MSQ_STATE_CAPTURE
:
2208 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2209 MessageQueue
->spwndCapture
= ValidateHwndNoErr(hWnd
);
2211 case MSQ_STATE_ACTIVE
:
2212 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2213 MessageQueue
->spwndActive
= ValidateHwndNoErr(hWnd
);
2215 case MSQ_STATE_FOCUS
:
2216 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2217 MessageQueue
->spwndFocus
= ValidateHwndNoErr(hWnd
);
2219 case MSQ_STATE_MENUOWNER
:
2220 Prev
= MessageQueue
->MenuOwner
;
2221 MessageQueue
->MenuOwner
= hWnd
;
2223 case MSQ_STATE_MOVESIZE
:
2224 Prev
= MessageQueue
->MoveSize
;
2225 MessageQueue
->MoveSize
= hWnd
;
2227 case MSQ_STATE_CARET
:
2228 ASSERT(MessageQueue
->CaretInfo
);
2229 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2230 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2239 NtUserGetKeyState(INT key
)
2245 Ret
= UserGetKeyState(key
);
2255 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2257 DWORD i
, ret
= TRUE
;
2259 PUSER_MESSAGE_QUEUE MessageQueue
;
2263 pti
= PsGetCurrentThreadWin32Thread();
2264 MessageQueue
= pti
->MessageQueue
;
2268 /* Probe and copy key state to an array */
2269 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2270 for (i
= 0; i
< 256; ++i
)
2273 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2274 lpKeyState
[i
] |= KS_DOWN_BIT
;
2275 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2276 lpKeyState
[i
] |= KS_LOCK_BIT
;
2279 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2281 SetLastNtError(_SEH2_GetExceptionCode());
2293 NtUserSetKeyboardState(LPBYTE pKeyState
)
2298 PUSER_MESSAGE_QUEUE MessageQueue
;
2300 UserEnterExclusive();
2302 pti
= PsGetCurrentThreadWin32Thread();
2303 MessageQueue
= pti
->MessageQueue
;
2307 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2308 for (i
= 0; i
< 256; ++i
)
2310 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2311 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2314 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2316 SetLastNtError(_SEH2_GetExceptionCode());