2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Message queues
5 * FILE: subsystems/win32/win32k/ntuser/msgqueue.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
10 * 06-06-2001 CSH Created
13 /* INCLUDES ******************************************************************/
20 /* GLOBALS *******************************************************************/
22 static PAGED_LOOKASIDE_LIST MessageLookasideList
;
23 MOUSEMOVEPOINT MouseHistoryOfMoves
[64];
26 /* FUNCTIONS *****************************************************************/
31 MsqInitializeImpl(VOID
)
33 ExInitializePagedLookasideList(&MessageLookasideList
,
41 return(STATUS_SUCCESS
);
44 DWORD FASTCALL
UserGetKeyState(DWORD key
)
48 PUSER_MESSAGE_QUEUE MessageQueue
;
50 pti
= PsGetCurrentThreadWin32Thread();
51 MessageQueue
= pti
->MessageQueue
;
55 ret
= ((DWORD
)(MessageQueue
->KeyState
[key
] & KS_DOWN_BIT
) << 8 ) |
56 (MessageQueue
->KeyState
[key
] & KS_LOCK_BIT
);
62 /* change the input key state for a given key */
63 static void set_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue
, UCHAR key
, BOOL down
)
67 if (!(MessageQueue
->KeyState
[key
] & KS_DOWN_BIT
))
69 MessageQueue
->KeyState
[key
] ^= KS_LOCK_BIT
;
71 MessageQueue
->KeyState
[key
] |= KS_DOWN_BIT
;
75 MessageQueue
->KeyState
[key
] &= ~KS_DOWN_BIT
;
79 /* update the input key state for a keyboard message */
80 static void update_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
91 set_input_key_state( MessageQueue
, VK_LBUTTON
, down
);
97 set_input_key_state( MessageQueue
, VK_MBUTTON
, down
);
103 set_input_key_state( MessageQueue
, VK_RBUTTON
, down
);
109 if (msg
->wParam
== XBUTTON1
)
110 set_input_key_state( MessageQueue
, VK_XBUTTON1
, down
);
111 else if (msg
->wParam
== XBUTTON2
)
112 set_input_key_state( MessageQueue
, VK_XBUTTON2
, down
);
120 key
= (UCHAR
)msg
->wParam
;
121 set_input_key_state( MessageQueue
, key
, down
);
126 down
= (MessageQueue
->KeyState
[VK_LCONTROL
] | MessageQueue
->KeyState
[VK_RCONTROL
]) & KS_DOWN_BIT
;
127 set_input_key_state( MessageQueue
, VK_CONTROL
, down
);
131 down
= (MessageQueue
->KeyState
[VK_LMENU
] | MessageQueue
->KeyState
[VK_RMENU
]) & KS_DOWN_BIT
;
132 set_input_key_state( MessageQueue
, VK_MENU
, down
);
136 down
= (MessageQueue
->KeyState
[VK_LSHIFT
] | MessageQueue
->KeyState
[VK_RSHIFT
]) & KS_DOWN_BIT
;
137 set_input_key_state( MessageQueue
, VK_SHIFT
, down
);
145 IntMsqSetWakeMask(DWORD WakeMask
)
147 PTHREADINFO Win32Thread
;
148 PUSER_MESSAGE_QUEUE MessageQueue
;
149 HANDLE MessageEventHandle
;
150 DWORD dwFlags
= HIWORD(WakeMask
);
152 Win32Thread
= PsGetCurrentThreadWin32Thread();
153 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
156 MessageQueue
= Win32Thread
->MessageQueue
;
157 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
158 MessageEventHandle
= MessageQueue
->NewMessagesHandle
;
160 if (Win32Thread
->pcti
)
162 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
163 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
165 DPRINT1("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
166 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
167 return MessageEventHandle
;
173 return MessageEventHandle
;
177 IntMsqClearWakeMask(VOID
)
179 PTHREADINFO Win32Thread
;
181 Win32Thread
= PsGetCurrentThreadWin32Thread();
182 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
184 // Very hacky, but that is what they do.
185 Win32Thread
->pcti
->fsWakeBits
= 0;
193 Due to the uncertainty of knowing what was set in our multilevel message queue,
194 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
195 I think this is the best solution... (jt) */
197 MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue
, DWORD MessageBits
, BOOL KeyEvent
)
201 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
202 pti
->pcti
->fsWakeBits
|= MessageBits
;
203 pti
->pcti
->fsChangeBits
|= MessageBits
;
205 // Start bit accounting to help clear the main set of bits.
206 if (MessageBits
& QS_KEY
) Queue
->nCntsQBits
[QSRosKey
]++;
207 if (MessageBits
& QS_MOUSEMOVE
) Queue
->nCntsQBits
[QSRosMouseMove
]++;
208 if (MessageBits
& QS_MOUSEBUTTON
) Queue
->nCntsQBits
[QSRosMouseButton
]++;
209 if (MessageBits
& QS_POSTMESSAGE
) Queue
->nCntsQBits
[QSRosPostMessage
]++;
210 if (MessageBits
& QS_SENDMESSAGE
) Queue
->nCntsQBits
[QSRosSendMessage
]++;
211 if (MessageBits
& QS_HOTKEY
) Queue
->nCntsQBits
[QSRosHotKey
]++;
214 KeSetEvent(Queue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
218 ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue
, UINT MessageBits
)
223 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
225 if (MessageBits
& QS_KEY
)
227 if (--Queue
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
229 if (MessageBits
& QS_MOUSEMOVE
) // ReactOS hard coded.
230 { // Account for tracking mouse moves..
231 if (--Queue
->nCntsQBits
[QSRosMouseMove
] == 0) ClrMask
|= QS_MOUSEMOVE
;
232 // Handle mouse move bits here.
233 if (Queue
->MouseMoved
) ClrMask
|= QS_MOUSEMOVE
;
235 if (MessageBits
& QS_MOUSEBUTTON
)
237 if (--Queue
->nCntsQBits
[QSRosMouseButton
] == 0) ClrMask
|= QS_MOUSEBUTTON
;
239 if (MessageBits
& QS_POSTMESSAGE
)
241 if (--Queue
->nCntsQBits
[QSRosPostMessage
] == 0) ClrMask
|= QS_POSTMESSAGE
;
243 if (MessageBits
& QS_TIMER
) // ReactOS hard coded.
244 { // Handle timer bits here.
245 if ( pti
->cTimersReady
)
247 if (--pti
->cTimersReady
== 0) ClrMask
|= QS_TIMER
;
250 if (MessageBits
& QS_PAINT
) // ReactOS hard coded.
251 { // Handle paint bits here.
252 if ( pti
->cPaintsReady
)
254 if (--pti
->cPaintsReady
== 0) ClrMask
|= QS_PAINT
;
257 if (MessageBits
& QS_SENDMESSAGE
)
259 if (--Queue
->nCntsQBits
[QSRosSendMessage
] == 0) ClrMask
|= QS_SENDMESSAGE
;
261 if (MessageBits
& QS_HOTKEY
)
263 if (--Queue
->nCntsQBits
[QSRosHotKey
] == 0) ClrMask
|= QS_HOTKEY
;
266 pti
->pcti
->fsWakeBits
&= ~ClrMask
;
267 pti
->pcti
->fsChangeBits
&= ~ClrMask
;
271 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
274 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
276 MsqWakeQueue(Queue
, QS_PAINT
, TRUE
);
280 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
282 ClearMsgBitsMask(Queue
, QS_PAINT
);
286 MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
)
288 MessageQueue
->MouseMoveMsg
= *Msg
;
289 MessageQueue
->MouseMoved
= TRUE
;
290 MsqWakeQueue(MessageQueue
, QS_MOUSEMOVE
, TRUE
);
294 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
296 LARGE_INTEGER LargeTickCount
;
297 MSLLHOOKSTRUCT MouseHookData
;
299 PWND pwnd
, pwndDesktop
;
301 KeQueryTickCount(&LargeTickCount
);
302 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
304 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
305 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
309 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
313 case WM_XBUTTONDBLCLK
:
314 case WM_NCXBUTTONDOWN
:
316 case WM_NCXBUTTONDBLCLK
:
317 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
320 MouseHookData
.mouseData
= 0;
324 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
325 MouseHookData
.time
= Msg
->time
;
326 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
328 /* If the hook procedure returned non zero, dont send the message */
331 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
335 /* Get the desktop window */
336 pwndDesktop
= UserGetDesktopWindow();
340 /* Set hit somewhere on the desktop */
341 pDesk
= pwndDesktop
->head
.rpdesk
;
342 pDesk
->htEx
= HTNOWHERE
;
343 pDesk
->spwndTrack
= pwndDesktop
;
345 /* Check if the mouse is captured */
346 Msg
->hwnd
= IntGetCaptureWindow();
347 if(Msg
->hwnd
!= NULL
)
349 pwnd
= UserGetWindowObject(Msg
->hwnd
);
350 if ((pwnd
->style
& WS_VISIBLE
) &&
351 IntPtInWindow(pwnd
, Msg
->pt
.x
, Msg
->pt
.y
))
353 pDesk
->htEx
= HTCLIENT
;
354 pDesk
->spwndTrack
= pwnd
;
359 /* Loop all top level windows to find which one should receive input */
360 for( pwnd
= pwndDesktop
->spwndChild
;
362 pwnd
= pwnd
->spwndNext
)
364 if ( pwnd
->state2
& WNDS2_INDESTROY
|| pwnd
->state
& WNDS_DESTROYED
)
366 DPRINT("The Window is in DESTROY!\n");
370 if((pwnd
->style
& WS_VISIBLE
) &&
371 IntPtInWindow(pwnd
, Msg
->pt
.x
, Msg
->pt
.y
))
373 Msg
->hwnd
= pwnd
->head
.h
;
374 pDesk
->htEx
= HTCLIENT
;
375 pDesk
->spwndTrack
= pwnd
;
381 /* Check if we found a window */
382 if(Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
384 if(Msg
->message
== WM_MOUSEMOVE
)
386 /* Mouse move is a special case*/
387 MsqPostMouseMove(pwnd
->head
.pti
->MessageQueue
, Msg
);
391 DPRINT("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd
));
392 MsqPostMessage(pwnd
->head
.pti
->MessageQueue
, Msg
, TRUE
, QS_MOUSEBUTTON
);
396 /* Do GetMouseMovePointsEx FIFO. */
397 MouseHistoryOfMoves
[gcur_count
].x
= Msg
->pt
.x
;
398 MouseHistoryOfMoves
[gcur_count
].y
= Msg
->pt
.y
;
399 MouseHistoryOfMoves
[gcur_count
].time
= Msg
->time
;
400 MouseHistoryOfMoves
[gcur_count
].dwExtraInfo
= dwExtraInfo
;
401 if (gcur_count
++ == 64) gcur_count
= 0; // 0 - 63 is 64, FIFO forwards.
405 // Note: Only called from input.c.
408 co_MsqPostKeyboardMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
410 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
412 LARGE_INTEGER LargeTickCount
;
413 KBDLLHOOKSTRUCT KbdHookData
;
415 DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
416 uMsg
, wParam
, lParam
);
418 // Condition may arise when calling MsqPostMessage and waiting for an event.
419 ASSERT(UserIsEntered());
421 FocusMessageQueue
= IntGetFocusMessageQueue();
425 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
426 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
432 KeQueryTickCount(&LargeTickCount
);
433 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
435 /* We can't get the Msg.pt point here since we don't know thread
436 (and thus the window station) the message will end up in yet. */
438 KbdHookData
.vkCode
= Msg
.wParam
;
439 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
440 KbdHookData
.flags
= (0 == (Msg
.lParam
& 0x01000000) ? 0 : LLKHF_EXTENDED
) |
441 (0 == (Msg
.lParam
& 0x20000000) ? 0 : LLKHF_ALTDOWN
) |
442 (0 == (Msg
.lParam
& 0x80000000) ? 0 : LLKHF_UP
);
443 KbdHookData
.time
= Msg
.time
;
444 KbdHookData
.dwExtraInfo
= 0;
445 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
447 DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
448 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
452 if (FocusMessageQueue
== NULL
)
454 DPRINT("No focus message queue\n");
458 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
460 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
461 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
463 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
465 Msg
.pt
= gpsi
->ptCursor
;
466 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
470 DPRINT("Invalid focus window handle\n");
477 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
480 PTHREADINFO Win32Thread
;
482 LARGE_INTEGER LargeTickCount
;
485 Status
= ObReferenceObjectByPointer (Thread
,
489 if (!NT_SUCCESS(Status
))
492 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
493 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
495 ObDereferenceObject ((PETHREAD
)Thread
);
499 Window
= IntGetWindowObject(hWnd
);
502 ObDereferenceObject ((PETHREAD
)Thread
);
507 Mesg
.message
= WM_HOTKEY
;
508 Mesg
.wParam
= wParam
;
509 Mesg
.lParam
= lParam
;
510 KeQueryTickCount(&LargeTickCount
);
511 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
512 Mesg
.pt
= gpsi
->ptCursor
;
513 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
514 UserDereferenceObject(Window
);
515 ObDereferenceObject (Thread
);
519 PUSER_MESSAGE FASTCALL
520 MsqCreateMessage(LPMSG Msg
)
522 PUSER_MESSAGE Message
;
524 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
530 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
536 MsqDestroyMessage(PUSER_MESSAGE Message
)
538 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
542 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
544 PUSER_SENT_MESSAGE SaveMsg
, Message
;
549 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
554 /* remove it from the list of pending messages */
555 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
556 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
558 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
560 SaveMsg
= pti
->pusmCurrent
;
561 pti
->pusmCurrent
= Message
;
563 // Processing a message sent to it from another thread.
564 if ( ( Message
->SenderQueue
&& MessageQueue
!= Message
->SenderQueue
) ||
565 ( Message
->CallBackSenderQueue
&& MessageQueue
!= Message
->CallBackSenderQueue
))
566 { // most likely, but, to be sure.
567 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
570 /* insert it to the list of messages that are currently dispatched by this
572 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
573 &Message
->ListEntry
);
575 ClearMsgBitsMask(MessageQueue
, Message
->QS_Flags
);
577 if (Message
->HookMessage
== MSQ_ISHOOK
)
578 { // Direct Hook Call processor
579 Result
= co_CallHook( Message
->Msg
.message
, // HookId
580 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
582 Message
->Msg
.lParam
);
584 else if (Message
->HookMessage
== MSQ_ISEVENT
)
585 { // Direct Event Call processor
586 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
589 Message
->Msg
.lParam
);
591 else if ((Message
->CompletionCallback
)
592 && (Message
->CallBackSenderQueue
== MessageQueue
))
593 { /* Call the callback routine */
594 if (Message
->QS_Flags
& QS_SMRESULT
)
596 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
598 Message
->Msg
.message
,
599 Message
->CompletionCallbackContext
,
601 /* Set callback to NULL to prevent reentry */
602 Message
->CompletionCallback
= NULL
;
606 /* The message has not been processed yet, reinsert it. */
607 RemoveEntryList(&Message
->ListEntry
);
608 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
609 DPRINT("Callback Message not processed yet. Requeuing the message\n");
614 { /* Call the window procedure. */
615 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
616 Message
->Msg
.message
,
618 Message
->Msg
.lParam
);
621 /* remove the message from the local dispatching list, because it doesn't need
622 to be cleaned up on thread termination anymore */
623 RemoveEntryList(&Message
->ListEntry
);
625 /* If the message is a callback, insert it in the callback senders MessageQueue */
626 if (Message
->CompletionCallback
)
628 if (Message
->CallBackSenderQueue
)
630 Message
->lResult
= Result
;
631 Message
->QS_Flags
|= QS_SMRESULT
;
633 /* insert it in the callers message queue */
634 InsertTailList(&Message
->CallBackSenderQueue
->SentMessagesListHead
, &Message
->ListEntry
);
635 MsqWakeQueue(Message
->CallBackSenderQueue
, QS_SENDMESSAGE
, TRUE
);
636 IntDereferenceMessageQueue(Message
->CallBackSenderQueue
);
641 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
642 if (Message
->SenderQueue
)
644 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
646 /* only remove it from the dispatching list if not already removed by a timeout */
647 RemoveEntryList(&Message
->DispatchingListEntry
);
650 /* still keep the sender's message queue locked, so the sender can't exit the
651 MsqSendMessage() function (if timed out) */
653 if (Message
->QS_Flags
& QS_SMRESULT
)
655 Result
= Message
->lResult
;
658 /* Let the sender know the result. */
659 if (Message
->Result
!= NULL
)
661 *Message
->Result
= Result
;
664 if (Message
->HasPackedLParam
== TRUE
)
666 if (Message
->Msg
.lParam
)
667 ExFreePool((PVOID
)Message
->Msg
.lParam
);
670 /* Notify the sender. */
671 if (Message
->CompletionEvent
!= NULL
)
673 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
676 /* if the message has a sender */
677 if (Message
->SenderQueue
)
679 /* dereference our and the sender's message queue */
680 IntDereferenceMessageQueue(Message
->SenderQueue
);
681 IntDereferenceMessageQueue(MessageQueue
);
684 /* free the message */
685 ExFreePoolWithTag(Message
, TAG_USRMSG
);
687 /* do not hangup on the user if this is reentering */
688 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
689 pti
->pusmCurrent
= SaveMsg
;
695 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
697 PUSER_SENT_MESSAGE SentMessage
;
698 PUSER_MESSAGE PostedMessage
;
699 PUSER_MESSAGE_QUEUE MessageQueue
;
700 PLIST_ENTRY CurrentEntry
, ListHead
;
701 PWND Window
= pWindow
;
705 MessageQueue
= Window
->head
.pti
->MessageQueue
;
706 ASSERT(MessageQueue
);
708 /* remove the posted messages for this window */
709 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
710 ListHead
= &MessageQueue
->PostedMessagesListHead
;
711 while (CurrentEntry
!= ListHead
)
713 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
715 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
717 RemoveEntryList(&PostedMessage
->ListEntry
);
718 ClearMsgBitsMask(MessageQueue
, PostedMessage
->QS_Flags
);
719 MsqDestroyMessage(PostedMessage
);
720 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
724 CurrentEntry
= CurrentEntry
->Flink
;
728 /* remove the sent messages for this window */
729 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
730 ListHead
= &MessageQueue
->SentMessagesListHead
;
731 while (CurrentEntry
!= ListHead
)
733 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
735 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
737 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
739 RemoveEntryList(&SentMessage
->ListEntry
);
740 ClearMsgBitsMask(MessageQueue
, SentMessage
->QS_Flags
);
742 /* if it is a callback and this queue is not the sender queue, dereference queue */
743 if ((SentMessage
->CompletionCallback
) && (SentMessage
->CallBackSenderQueue
!= MessageQueue
))
745 IntDereferenceMessageQueue(SentMessage
->CallBackSenderQueue
);
747 /* Only if the message has a sender was the queue referenced */
748 if ((SentMessage
->SenderQueue
)
749 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
751 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
754 /* wake the sender's thread */
755 if (SentMessage
->CompletionEvent
!= NULL
)
757 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
760 if (SentMessage
->HasPackedLParam
== TRUE
)
762 if (SentMessage
->Msg
.lParam
)
763 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
766 /* if the message has a sender */
767 if (SentMessage
->SenderQueue
)
769 /* dereference our and the sender's message queue */
770 IntDereferenceMessageQueue(MessageQueue
);
771 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
774 /* free the message */
775 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
777 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
781 CurrentEntry
= CurrentEntry
->Flink
;
787 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
788 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
789 UINT uTimeout
, BOOL Block
, INT HookMessage
,
792 PTHREADINFO pti
, ptirec
;
793 PUSER_SENT_MESSAGE Message
;
794 KEVENT CompletionEvent
;
796 PUSER_MESSAGE_QUEUE ThreadQueue
;
797 LARGE_INTEGER Timeout
;
799 LRESULT Result
= 0; //// Result could be trashed. ////
801 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
803 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
804 return STATUS_INSUFFICIENT_RESOURCES
;
807 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
809 pti
= PsGetCurrentThreadWin32Thread();
810 ThreadQueue
= pti
->MessageQueue
;
811 ptirec
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
812 ASSERT(ThreadQueue
!= MessageQueue
);
813 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
815 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
817 /* FIXME - increase reference counter of sender's message queue here */
819 Message
->Msg
.hwnd
= Wnd
;
820 Message
->Msg
.message
= Msg
;
821 Message
->Msg
.wParam
= wParam
;
822 Message
->Msg
.lParam
= lParam
;
823 Message
->CompletionEvent
= &CompletionEvent
;
824 Message
->Result
= &Result
;
825 Message
->lResult
= 0;
826 Message
->QS_Flags
= 0;
827 Message
->SenderQueue
= ThreadQueue
;
828 Message
->CallBackSenderQueue
= NULL
;
829 IntReferenceMessageQueue(ThreadQueue
);
830 Message
->CompletionCallback
= NULL
;
831 Message
->CompletionCallbackContext
= 0;
832 Message
->HookMessage
= HookMessage
;
833 Message
->HasPackedLParam
= FALSE
;
835 IntReferenceMessageQueue(MessageQueue
);
837 /* add it to the list of pending messages */
838 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
840 /* queue it in the destination's message queue */
841 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
843 Message
->QS_Flags
= QS_SENDMESSAGE
;
844 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
, TRUE
);
846 /* we can't access the Message anymore since it could have already been deleted! */
852 /* don't process messages sent to the thread */
853 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
854 FALSE
, (uTimeout
? &Timeout
: NULL
));
858 if(WaitStatus
== STATUS_TIMEOUT
)
860 /* look up if the message has not yet dispatched, if so
861 make sure it can't pass a result and it must not set the completion event anymore */
862 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
863 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
865 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
868 /* we can access Message here, it's secure because the message queue is locked
869 and the message is still hasn't been dispatched */
870 Message
->CompletionEvent
= NULL
;
871 Message
->Result
= NULL
;
874 Entry
= Entry
->Flink
;
877 /* remove from the local dispatching list so the other thread knows,
878 it can't pass a result and it must not set the completion event anymore */
879 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
880 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
882 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
885 /* we can access Message here, it's secure because the sender's message is locked
886 and the message has definitely not yet been destroyed, otherwise it would
887 have been removed from this list by the dispatching routine right after
888 dispatching the message */
889 Message
->CompletionEvent
= NULL
;
890 Message
->Result
= NULL
;
891 RemoveEntryList(&Message
->DispatchingListEntry
);
892 Message
->DispatchingListEntry
.Flink
= NULL
;
895 Entry
= Entry
->Flink
;
898 DPRINT("MsqSendMessage (blocked) timed out 1\n");
900 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
905 PVOID WaitObjects
[2];
907 WaitObjects
[0] = &CompletionEvent
;
908 WaitObjects
[1] = ThreadQueue
->NewMessages
;
913 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
914 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
918 if(WaitStatus
== STATUS_TIMEOUT
)
920 /* look up if the message has not yet been dispatched, if so
921 make sure it can't pass a result and it must not set the completion event anymore */
922 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
923 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
925 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
928 /* we can access Message here, it's secure because the message queue is locked
929 and the message is still hasn't been dispatched */
930 Message
->CompletionEvent
= NULL
;
931 Message
->Result
= NULL
;
934 Entry
= Entry
->Flink
;
937 /* remove from the local dispatching list so the other thread knows,
938 it can't pass a result and it must not set the completion event anymore */
939 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
940 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
942 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
945 /* we can access Message here, it's secure because the sender's message is locked
946 and the message has definitely not yet been destroyed, otherwise it would
947 have been removed from this list by the dispatching routine right after
948 dispatching the message */
949 Message
->CompletionEvent
= NULL
;
950 Message
->Result
= NULL
;
951 RemoveEntryList(&Message
->DispatchingListEntry
);
952 Message
->DispatchingListEntry
.Flink
= NULL
;
955 Entry
= Entry
->Flink
;
958 DPRINT("MsqSendMessage timed out 2\n");
961 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
964 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
967 if(WaitStatus
!= STATUS_TIMEOUT
)
968 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
974 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
977 PUSER_MESSAGE Message
;
979 if(!(Message
= MsqCreateMessage(Msg
)))
986 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
987 &Message
->ListEntry
);
991 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
992 &Message
->ListEntry
);
995 Message
->QS_Flags
= MessageBits
;
996 MsqWakeQueue(MessageQueue
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
1000 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1002 MessageQueue
->QuitPosted
= TRUE
;
1003 MessageQueue
->QuitExitCode
= ExitCode
;
1004 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1007 /***********************************************************************
1008 * MsqSendParentNotify
1010 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1011 * the window has the WS_EX_NOPARENTNOTIFY style.
1013 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1015 PWND pwndDesktop
= UserGetWindowObject(IntGetDesktopWindow());
1017 /* pt has to be in the client coordinates of the parent window */
1018 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1019 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1025 if (!(pwnd
->style
& WS_CHILD
)) break;
1026 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1027 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1028 if (pwndParent
== pwndDesktop
) break;
1029 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1030 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1033 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1034 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1038 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1045 MOUSEHOOKSTRUCT hook
;
1048 PWND pwndMsg
, pwndDesktop
;
1049 PUSER_MESSAGE_QUEUE MessageQueue
;
1051 PSYSTEM_CURSORINFO CurInfo
;
1052 DECLARE_RETURN(BOOL
);
1054 pti
= PsGetCurrentThreadWin32Thread();
1055 pwndDesktop
= UserGetDesktopWindow();
1056 MessageQueue
= pti
->MessageQueue
;
1057 CurInfo
= IntGetSysCursorInfo();
1058 pwndMsg
= UserGetWindowObject(msg
->hwnd
);
1059 clk_msg
= MessageQueue
->msgDblClk
;
1061 /* find the window to dispatch this mouse message to */
1062 if (MessageQueue
->CaptureWindow
)
1065 pwndMsg
= IntGetWindowObject(MessageQueue
->CaptureWindow
);
1069 pwndMsg
= co_WinPosWindowFromPoint(pwndMsg
, &msg
->pt
, &hittest
);
1072 DPRINT("Got mouse message for 0x%x, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1074 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
1076 /* Remove and ignore the message */
1077 *RemoveMessages
= TRUE
;
1081 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1084 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
1088 message
= msg
->message
;
1089 /* Note: windows has no concept of a non-client wheel message */
1090 if (message
!= WM_MOUSEWHEEL
)
1092 if (hittest
!= HTCLIENT
)
1094 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1095 msg
->wParam
= hittest
;
1099 /* coordinates don't get translated while tracking a menu */
1100 /* FIXME: should differentiate popups and top-level menus */
1101 if (!(MessageQueue
->MenuOwner
))
1103 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1104 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1108 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1110 /* translate double clicks */
1112 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1113 (msg
->message
== WM_RBUTTONDOWN
) ||
1114 (msg
->message
== WM_MBUTTONDOWN
) ||
1115 (msg
->message
== WM_XBUTTONDOWN
))
1117 BOOL update
= *RemoveMessages
;
1119 /* translate double clicks -
1120 * note that ...MOUSEMOVEs can slip in between
1121 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1123 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1124 hittest
!= HTCLIENT
||
1125 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1127 if ((msg
->message
== clk_msg
.message
) &&
1128 (msg
->hwnd
== clk_msg
.hwnd
) &&
1129 (msg
->wParam
== clk_msg
.wParam
) &&
1130 (msg
->time
- clk_msg
.time
< gspv
.iDblClickTime
) &&
1131 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1132 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1134 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1137 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1143 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1145 DPRINT("Message out of range!!!\n");
1149 /* update static double click conditions */
1150 if (update
) MessageQueue
->msgDblClk
= *msg
;
1154 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1156 DPRINT("Message out of range!!!\n");
1161 if(gspv
.bMouseClickLock
)
1163 BOOL IsClkLck
= FALSE
;
1165 if(msg
->message
== WM_LBUTTONUP
)
1167 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1168 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1170 CurInfo
->ClickLockActive
= TRUE
;
1173 else if (msg
->message
== WM_LBUTTONDOWN
)
1175 if (CurInfo
->ClickLockActive
)
1178 CurInfo
->ClickLockActive
= FALSE
;
1181 CurInfo
->ClickLockTime
= msg
->time
;
1186 /* Remove and ignore the message */
1187 *RemoveMessages
= TRUE
;
1192 /* message is accepted now (but may still get dropped) */
1194 event
.message
= msg
->message
;
1195 event
.time
= msg
->time
;
1196 event
.hwnd
= msg
->hwnd
;
1197 event
.paramL
= msg
->pt
.x
;
1198 event
.paramH
= msg
->pt
.y
;
1199 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1202 hook
.hwnd
= msg
->hwnd
;
1203 hook
.wHitTestCode
= hittest
;
1204 hook
.dwExtraInfo
= 0/*extra_info*/;
1205 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1206 message
, (LPARAM
)&hook
))
1209 hook
.hwnd
= msg
->hwnd
;
1210 hook
.wHitTestCode
= hittest
;
1211 hook
.dwExtraInfo
= 0/*extra_info*/;
1212 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1214 DPRINT1("WH_MOUSE dorpped mouse message!\n");
1216 /* Remove and skip message */
1217 *RemoveMessages
= TRUE
;
1221 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1223 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1224 MAKELONG( hittest
, msg
->message
));
1226 /* Remove and skip message */
1227 *RemoveMessages
= TRUE
;
1231 if ((*RemoveMessages
== FALSE
) || MessageQueue
->CaptureWindow
)
1233 /* Accept the message */
1234 msg
->message
= message
;
1240 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1241 (msg
->message
== WM_RBUTTONDOWN
) ||
1242 (msg
->message
== WM_MBUTTONDOWN
) ||
1243 (msg
->message
== WM_XBUTTONDOWN
))
1245 /* Send the WM_PARENTNOTIFY,
1246 * note that even for double/nonclient clicks
1247 * notification message is still WM_L/M/RBUTTONDOWN.
1249 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1251 /* Activate the window if needed */
1253 if (msg
->hwnd
!= UserGetForegroundWindow())
1255 PWND pwndTop
= pwndMsg
;
1258 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
1259 pwndTop
= IntGetParent( pwndTop
);
1262 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1264 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1266 (WPARAM
)UserHMGetHandle(pwndTop
),
1267 MAKELONG( hittest
, msg
->message
));
1270 case MA_NOACTIVATEANDEAT
:
1275 case MA_ACTIVATEANDEAT
:
1280 if(!co_IntMouseActivateWindow(pwndMsg
)) eatMsg
= TRUE
;
1283 DPRINT1( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1290 /* send the WM_SETCURSOR message */
1292 /* Windows sends the normal mouse message as the message parameter
1293 in the WM_SETCURSOR message even if it's non-client mouse message */
1294 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1296 msg
->message
= message
;
1301 UserDereferenceObject(pwndMsg
);
1306 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1310 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1311 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1313 switch (Msg
->wParam
)
1315 case VK_LSHIFT
: case VK_RSHIFT
:
1316 Msg
->wParam
= VK_SHIFT
;
1318 case VK_LCONTROL
: case VK_RCONTROL
:
1319 Msg
->wParam
= VK_CONTROL
;
1321 case VK_LMENU
: case VK_RMENU
:
1322 Msg
->wParam
= VK_MENU
;
1327 Event
.message
= Msg
->message
;
1328 Event
.hwnd
= Msg
->hwnd
;
1329 Event
.time
= Msg
->time
;
1330 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1331 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1332 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1333 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1335 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1336 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1337 LOWORD(Msg
->wParam
),
1340 /* skip this message */
1341 co_HOOK_CallHooks( WH_CBT
,
1343 LOWORD(Msg
->wParam
),
1345 DPRINT1("KeyboardMessage WH_CBT Call Hook return!\n");
1351 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1353 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1355 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1357 else if ( IS_KBD_MESSAGE(Msg
->message
))
1359 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1366 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1369 IN UINT MsgFilterLow
,
1370 IN UINT MsgFilterHigh
,
1376 if(!(MessageQueue
->MouseMoved
))
1379 msg
= MessageQueue
->MouseMoveMsg
;
1381 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1388 ClearMsgBitsMask(MessageQueue
, QS_MOUSEMOVE
);
1389 MessageQueue
->MouseMoved
= FALSE
;
1392 return AcceptMessage
;
1395 /* check whether a message filter contains at least one potential hardware message */
1397 filter_contains_hw_range( UINT first
, UINT last
)
1399 /* hardware message ranges are (in numerical order):
1400 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1401 * WM_KEYFIRST .. WM_KEYLAST
1402 * WM_MOUSEFIRST .. WM_MOUSELAST
1405 if (last
< WM_NCMOUSEFIRST
) return 0;
1406 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1407 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1408 if (first
> WM_MOUSELAST
) return 0;
1413 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1416 IN UINT MsgFilterLow
,
1417 IN UINT MsgFilterHigh
,
1423 PUSER_MESSAGE CurrentMessage
;
1424 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1427 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1429 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1430 CurrentEntry
= ListHead
->Flink
;
1432 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1434 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1438 if (IsListEmpty(CurrentEntry
)) break;
1439 if (!CurrentMessage
) break;
1440 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1442 if ( (( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && (CurrentMessage
->QS_Flags
& QSflags
)) ||
1443 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) )
1445 msg
= CurrentMessage
->Msg
;
1447 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1451 update_input_key_state(MessageQueue
, pMsg
);
1452 RemoveEntryList(&CurrentMessage
->ListEntry
);
1453 ClearMsgBitsMask(MessageQueue
, QS_INPUT
);
1454 MsqDestroyMessage(CurrentMessage
);
1463 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1466 while(CurrentEntry
!= ListHead
);
1472 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1475 IN UINT MsgFilterLow
,
1476 IN UINT MsgFilterHigh
,
1480 PLIST_ENTRY CurrentEntry
;
1481 PUSER_MESSAGE CurrentMessage
;
1482 PLIST_ENTRY ListHead
;
1484 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1485 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1487 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1489 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1493 if (IsListEmpty(CurrentEntry
)) break;
1494 if (!CurrentMessage
) break;
1495 CurrentEntry
= CurrentEntry
->Flink
;
1498 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1499 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1500 3: handle to the window whose messages are to be retrieved.
1502 if ( ( !Window
|| // 1
1503 ( Window
== HWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1504 ( Window
!= HWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1505 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1506 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1508 *Message
= CurrentMessage
->Msg
;
1512 RemoveEntryList(&CurrentMessage
->ListEntry
);
1513 ClearMsgBitsMask(MessageQueue
, QS_POSTMESSAGE
);
1514 MsqDestroyMessage(CurrentMessage
);
1518 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1521 while (CurrentEntry
!= ListHead
);
1527 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1528 UINT MsgFilterMin
, UINT MsgFilterMax
)
1532 ret
= KeWaitForSingleObject( MessageQueue
->NewMessages
,
1542 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1544 LARGE_INTEGER LargeTickCount
;
1546 KeQueryTickCount(&LargeTickCount
);
1547 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1552 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1554 //DoTheScreenSaver();
1555 DPRINT("HungAppSysTimerProc\n");
1556 // Process list of windows that are hung and waiting.
1560 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1562 LARGE_INTEGER LargeTickCount
;
1565 MessageQueue
->Thread
= Thread
;
1566 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1567 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1568 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1569 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1570 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1571 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1572 KeInitializeMutex(&MessageQueue
->HardwareLock
, 0);
1573 MessageQueue
->QuitPosted
= FALSE
;
1574 MessageQueue
->QuitExitCode
= 0;
1575 KeQueryTickCount(&LargeTickCount
);
1576 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1577 MessageQueue
->FocusWindow
= NULL
;
1578 MessageQueue
->NewMessagesHandle
= NULL
;
1580 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1581 NULL
, SynchronizationEvent
, FALSE
);
1582 if (!NT_SUCCESS(Status
))
1587 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1588 ExEventObjectType
, KernelMode
,
1589 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1590 if (!NT_SUCCESS(Status
))
1592 ZwClose(MessageQueue
->NewMessagesHandle
);
1593 MessageQueue
->NewMessagesHandle
= NULL
;
1601 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1603 PLIST_ENTRY CurrentEntry
;
1604 PUSER_MESSAGE CurrentMessage
;
1605 PUSER_SENT_MESSAGE CurrentSentMessage
;
1608 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1611 /* cleanup posted messages */
1612 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1614 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1615 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1617 MsqDestroyMessage(CurrentMessage
);
1620 /* remove the messages that have not yet been dispatched */
1621 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1623 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1624 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1627 /* if it is a callback and this queue is not the sender queue, dereference queue */
1628 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
1630 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
1633 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1634 /* Only if the message has a sender was the message in the DispatchingList */
1635 if ((CurrentSentMessage
->SenderQueue
)
1636 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1638 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1641 /* wake the sender's thread */
1642 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1644 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1647 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1649 if (CurrentSentMessage
->Msg
.lParam
)
1650 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1653 /* if the message has a sender */
1654 if (CurrentSentMessage
->SenderQueue
)
1656 /* dereference our and the sender's message queue */
1657 IntDereferenceMessageQueue(MessageQueue
);
1658 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1661 /* free the message */
1662 ExFreePool(CurrentSentMessage
);
1665 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1666 ExitThread() was called in a SendMessage() umode callback */
1667 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1669 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1670 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1673 /* if it is a callback and this queue is not the sender queue, dereference queue */
1674 if ((CurrentSentMessage
->CompletionCallback
) && (CurrentSentMessage
->CallBackSenderQueue
!= MessageQueue
))
1676 IntDereferenceMessageQueue(CurrentSentMessage
->CallBackSenderQueue
);
1679 /* remove the message from the dispatching list */
1680 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1682 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1685 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1687 /* wake the sender's thread */
1688 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1690 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1693 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1695 if (CurrentSentMessage
->Msg
.lParam
)
1696 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1699 /* if the message has a sender */
1700 if (CurrentSentMessage
->SenderQueue
)
1702 /* dereference our and the sender's message queue */
1703 IntDereferenceMessageQueue(MessageQueue
);
1704 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1707 /* free the message */
1708 ExFreePool(CurrentSentMessage
);
1711 /* tell other threads not to bother returning any info to us */
1712 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
1714 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
1715 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1716 DispatchingListEntry
);
1717 CurrentSentMessage
->CompletionEvent
= NULL
;
1718 CurrentSentMessage
->Result
= NULL
;
1720 /* do NOT dereference our message queue as it might get attempted to be
1724 // Clear it all out.
1725 pti
->pcti
->fsWakeBits
= 0;
1726 pti
->pcti
->fsChangeBits
= 0;
1728 MessageQueue
->nCntsQBits
[QSRosKey
] = 0;
1729 MessageQueue
->nCntsQBits
[QSRosMouseMove
] = 0;
1730 MessageQueue
->nCntsQBits
[QSRosMouseButton
] = 0;
1731 MessageQueue
->nCntsQBits
[QSRosPostMessage
] = 0;
1732 MessageQueue
->nCntsQBits
[QSRosSendMessage
] = 0;
1733 MessageQueue
->nCntsQBits
[QSRosHotKey
] = 0;
1736 PUSER_MESSAGE_QUEUE FASTCALL
1737 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
1739 PUSER_MESSAGE_QUEUE MessageQueue
;
1741 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
1742 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
1750 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
1751 /* hold at least one reference until it'll be destroyed */
1752 IntReferenceMessageQueue(MessageQueue
);
1753 /* initialize the queue */
1754 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
1756 IntDereferenceMessageQueue(MessageQueue
);
1760 return MessageQueue
;
1764 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1768 MessageQueue
->QF_flags
|= QF_INDESTROY
;
1770 /* remove the message queue from any desktops */
1771 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
1773 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
1774 IntDereferenceMessageQueue(MessageQueue
);
1778 MsqCleanupMessageQueue(MessageQueue
);
1780 if (MessageQueue
->NewMessagesHandle
!= NULL
)
1781 ZwClose(MessageQueue
->NewMessagesHandle
);
1782 MessageQueue
->NewMessagesHandle
= NULL
;
1783 /* decrease the reference counter, if it hits zero, the queue will be freed */
1784 IntDereferenceMessageQueue(MessageQueue
);
1788 MsqSetMessageExtraInfo(LPARAM lParam
)
1792 PUSER_MESSAGE_QUEUE MessageQueue
;
1794 pti
= PsGetCurrentThreadWin32Thread();
1795 MessageQueue
= pti
->MessageQueue
;
1801 Ret
= MessageQueue
->ExtraInfo
;
1802 MessageQueue
->ExtraInfo
= lParam
;
1808 MsqGetMessageExtraInfo(VOID
)
1811 PUSER_MESSAGE_QUEUE MessageQueue
;
1813 pti
= PsGetCurrentThreadWin32Thread();
1814 MessageQueue
= pti
->MessageQueue
;
1820 return MessageQueue
->ExtraInfo
;
1823 // ReplyMessage is called by the thread receiving the window message.
1825 co_MsqReplyMessage( LRESULT lResult
)
1827 PUSER_SENT_MESSAGE Message
;
1830 pti
= PsGetCurrentThreadWin32Thread();
1831 Message
= pti
->pusmCurrent
;
1833 if (!Message
) return FALSE
;
1835 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
1837 // SendMessageXxx || Callback msg and not a notify msg
1838 if (Message
->SenderQueue
|| Message
->CompletionCallback
)
1840 Message
->lResult
= lResult
;
1841 Message
->QS_Flags
|= QS_SMRESULT
;
1842 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
1848 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
1854 case MSQ_STATE_CAPTURE
:
1855 Prev
= MessageQueue
->CaptureWindow
;
1856 MessageQueue
->CaptureWindow
= hWnd
;
1858 case MSQ_STATE_ACTIVE
:
1859 Prev
= MessageQueue
->ActiveWindow
;
1860 MessageQueue
->ActiveWindow
= hWnd
;
1862 case MSQ_STATE_FOCUS
:
1863 Prev
= MessageQueue
->FocusWindow
;
1864 MessageQueue
->FocusWindow
= hWnd
;
1866 case MSQ_STATE_MENUOWNER
:
1867 Prev
= MessageQueue
->MenuOwner
;
1868 MessageQueue
->MenuOwner
= hWnd
;
1870 case MSQ_STATE_MOVESIZE
:
1871 Prev
= MessageQueue
->MoveSize
;
1872 MessageQueue
->MoveSize
= hWnd
;
1874 case MSQ_STATE_CARET
:
1875 ASSERT(MessageQueue
->CaretInfo
);
1876 Prev
= MessageQueue
->CaretInfo
->hWnd
;
1877 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
1886 NtUserGetKeyState(INT key
)
1890 UserEnterExclusive();
1892 Ret
= UserGetKeyState(key
);
1902 NtUserGetKeyboardState(LPBYTE lpKeyState
)
1906 PUSER_MESSAGE_QUEUE MessageQueue
;
1910 pti
= PsGetCurrentThreadWin32Thread();
1911 MessageQueue
= pti
->MessageQueue
;
1915 ProbeForWrite(lpKeyState
,sizeof(MessageQueue
->KeyState
) ,1);
1916 RtlCopyMemory(lpKeyState
,MessageQueue
->KeyState
,sizeof(MessageQueue
->KeyState
));
1918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1920 SetLastNtError(_SEH2_GetExceptionCode());
1932 NtUserSetKeyboardState(LPBYTE lpKeyState
)
1936 PUSER_MESSAGE_QUEUE MessageQueue
;
1938 UserEnterExclusive();
1940 pti
= PsGetCurrentThreadWin32Thread();
1941 MessageQueue
= pti
->MessageQueue
;
1945 ProbeForRead(lpKeyState
,sizeof(MessageQueue
->KeyState
) ,1);
1946 RtlCopyMemory(MessageQueue
->KeyState
,lpKeyState
,sizeof(MessageQueue
->KeyState
));
1948 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1950 SetLastNtError(_SEH2_GetExceptionCode());