2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * PURPOSE: Message queues
23 * FILE: subsystems/win32/win32k/ntuser/msgqueue.c
24 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * 06-06-2001 CSH Created
29 /* INCLUDES ******************************************************************/
36 /* GLOBALS *******************************************************************/
38 #define SYSTEM_MESSAGE_QUEUE_SIZE (256)
40 static MSG SystemMessageQueue
[SYSTEM_MESSAGE_QUEUE_SIZE
];
41 static ULONG SystemMessageQueueHead
= 0;
42 static ULONG SystemMessageQueueTail
= 0;
43 static ULONG SystemMessageQueueCount
= 0;
44 static KSPIN_LOCK SystemMessageQueueLock
;
46 static ULONG
volatile HardwareMessageQueueStamp
= 0;
47 static LIST_ENTRY HardwareMessageQueueHead
;
48 static KMUTANT HardwareMessageQueueLock
;
50 static KEVENT HardwareMessageEvent
;
52 static PAGED_LOOKASIDE_LIST MessageLookasideList
;
54 #define IntLockSystemMessageQueue(OldIrql) \
55 KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql)
57 #define IntUnLockSystemMessageQueue(OldIrql) \
58 KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql)
60 #define IntUnLockSystemHardwareMessageQueueLock(Wait) \
61 KeReleaseMutant(&HardwareMessageQueueLock, IO_NO_INCREMENT, FALSE, Wait)
63 /* FUNCTIONS *****************************************************************/
66 // Wakeup any thread/process waiting on idle input.
73 PPROCESSINFO W32d
= PsGetCurrentProcessWin32Process();
75 hWnd
= UserGetForegroundWindow();
77 Window
= UserGetWindowObject(hWnd
);
79 if (Window
&& Window
->head
.pti
)
81 if (Window
->head
.pti
->fsHooks
& HOOKID_TO_FLAG(WH_FOREGROUNDIDLE
))
83 co_HOOK_CallHooks(WH_FOREGROUNDIDLE
,HC_ACTION
,0,0);
87 if (W32d
&& W32d
->InputIdleEvent
)
88 KePulseEvent( W32d
->InputIdleEvent
, EVENT_INCREMENT
, TRUE
);
92 IntMsqSetWakeMask(DWORD WakeMask
)
94 PTHREADINFO Win32Thread
;
95 PUSER_MESSAGE_QUEUE MessageQueue
;
96 HANDLE MessageEventHandle
;
98 Win32Thread
= PsGetCurrentThreadWin32Thread();
99 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
102 MessageQueue
= Win32Thread
->MessageQueue
;
103 MessageQueue
->WakeMask
= WakeMask
;
104 MessageEventHandle
= MessageQueue
->NewMessagesHandle
;
106 return MessageEventHandle
;
110 IntMsqClearWakeMask(VOID
)
112 PTHREADINFO Win32Thread
;
113 PUSER_MESSAGE_QUEUE MessageQueue
;
115 Win32Thread
= PsGetCurrentThreadWin32Thread();
116 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
119 MessageQueue
= Win32Thread
->MessageQueue
;
120 // HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt)
121 MessageQueue
->WakeMask
= ~0;
127 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
130 Queue
->QueueBits
|= QS_PAINT
;
131 Queue
->ChangedBits
|= QS_PAINT
;
132 if (Queue
->WakeMask
& QS_PAINT
)
133 KeSetEvent(Queue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
137 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
144 MsqInitializeImpl(VOID
)
146 /*CurrentFocusMessageQueue = NULL;*/
147 InitializeListHead(&HardwareMessageQueueHead
);
148 KeInitializeEvent(&HardwareMessageEvent
, NotificationEvent
, 0);
149 KeInitializeSpinLock(&SystemMessageQueueLock
);
150 KeInitializeMutant(&HardwareMessageQueueLock
, 0);
152 ExInitializePagedLookasideList(&MessageLookasideList
,
156 sizeof(USER_MESSAGE
),
160 return(STATUS_SUCCESS
);
164 MsqInsertSystemMessage(MSG
* Msg
)
166 LARGE_INTEGER LargeTickCount
;
169 MSLLHOOKSTRUCT MouseHookData
;
171 KeQueryTickCount(&LargeTickCount
);
172 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
174 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
175 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
179 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
183 case WM_XBUTTONDBLCLK
:
184 case WM_NCXBUTTONDOWN
:
186 case WM_NCXBUTTONDBLCLK
:
187 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
190 MouseHookData
.mouseData
= 0;
194 MouseHookData
.flags
= 0;
195 MouseHookData
.time
= Msg
->time
;
196 MouseHookData
.dwExtraInfo
= 0;
198 /* If the hook procedure returned non zero, dont send the message */
199 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
203 * If we got WM_MOUSEMOVE and there are already messages in the
204 * system message queue, check if the last message is mouse move
205 * and if it is then just overwrite it.
207 IntLockSystemMessageQueue(OldIrql
);
210 * Bail out if the queue is full. FIXME: We should handle this case
214 if (SystemMessageQueueCount
== SYSTEM_MESSAGE_QUEUE_SIZE
)
216 IntUnLockSystemMessageQueue(OldIrql
);
220 if (Msg
->message
== WM_MOUSEMOVE
&& SystemMessageQueueCount
)
222 if (SystemMessageQueueTail
== 0)
223 Prev
= SYSTEM_MESSAGE_QUEUE_SIZE
- 1;
225 Prev
= SystemMessageQueueTail
- 1;
226 if (SystemMessageQueue
[Prev
].message
== WM_MOUSEMOVE
)
228 SystemMessageQueueTail
= Prev
;
229 SystemMessageQueueCount
--;
234 * Actually insert the message into the system message queue.
237 SystemMessageQueue
[SystemMessageQueueTail
] = *Msg
;
238 SystemMessageQueueTail
=
239 (SystemMessageQueueTail
+ 1) % SYSTEM_MESSAGE_QUEUE_SIZE
;
240 SystemMessageQueueCount
++;
242 IntUnLockSystemMessageQueue(OldIrql
);
244 KeSetEvent(&HardwareMessageEvent
, IO_NO_INCREMENT
, FALSE
);
248 MsqIsClkLck(LPMSG Msg
, BOOL Remove
)
251 PSYSTEM_CURSORINFO CurInfo
;
254 pti
= PsGetCurrentThreadWin32Thread();
255 if (pti
->rpdesk
== NULL
)
260 CurInfo
= IntGetSysCursorInfo();
262 switch (Msg
->message
)
265 Res
= ((Msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
266 if (Res
&& (!CurInfo
->ClickLockActive
))
268 CurInfo
->ClickLockActive
= TRUE
;
272 if (CurInfo
->ClickLockActive
)
275 CurInfo
->ClickLockActive
= FALSE
;
276 CurInfo
->ClickLockTime
= 0;
280 CurInfo
->ClickLockTime
= Msg
->time
;
288 MsqIsDblClk(LPMSG Msg
, BOOL Remove
)
291 PSYSTEM_CURSORINFO CurInfo
;
295 pti
= PsGetCurrentThreadWin32Thread();
296 if (pti
->rpdesk
== NULL
)
301 CurInfo
= IntGetSysCursorInfo();
302 Res
= (Msg
->hwnd
== (HWND
)CurInfo
->LastClkWnd
) &&
303 ((Msg
->time
- CurInfo
->LastBtnDown
) < gspv
.iDblClickTime
);
307 dX
= CurInfo
->LastBtnDownX
- Msg
->pt
.x
;
308 dY
= CurInfo
->LastBtnDownY
- Msg
->pt
.y
;
314 Res
= (dX
<= gspv
.iDblClickWidth
) &&
315 (dY
<= gspv
.iDblClickHeight
);
319 if(CurInfo
->ButtonsDown
)
320 Res
= (CurInfo
->ButtonsDown
== Msg
->message
);
326 CurInfo
->LastBtnDownX
= Msg
->pt
.x
;
327 CurInfo
->LastBtnDownY
= Msg
->pt
.y
;
328 CurInfo
->ButtonsDown
= Msg
->message
;
331 CurInfo
->LastBtnDown
= 0;
332 CurInfo
->LastClkWnd
= NULL
;
336 CurInfo
->LastClkWnd
= (HANDLE
)Msg
->hwnd
;
337 CurInfo
->LastBtnDown
= Msg
->time
;
345 co_MsqTranslateMouseMessage(PUSER_MESSAGE_QUEUE MessageQueue
, PWND Window
, UINT FilterLow
, UINT FilterHigh
,
346 PUSER_MESSAGE Message
, BOOL Remove
, PBOOL Freed
,
347 PWND ScopeWin
, PPOINT ScreenPoint
, BOOL FromGlobalQueue
, PLIST_ENTRY
*Next
)
349 USHORT Msg
= Message
->Msg
.message
;
350 PWND CaptureWindow
= NULL
;
353 /* FIXME: Mouse message can be sent before the Desktop is up and running in which case ScopeWin (Desktop) is 0.
354 Is this the best fix? */
355 if (ScopeWin
== 0) return FALSE
;
357 ASSERT_REFS_CO(ScopeWin
);
360 co_WinPosWindowFromPoint can return a Window, and in that case
361 that window has a ref that we need to deref. Thats why we add "dummy"
362 refs in all other cases.
365 hCaptureWin
= IntGetCaptureWindow();
366 if (hCaptureWin
== NULL
)
368 if (Msg
== WM_MOUSEWHEEL
)
370 CaptureWindow
= UserGetWindowObject(IntGetFocusWindow());
371 if (CaptureWindow
) UserReferenceObject(CaptureWindow
);
375 co_WinPosWindowFromPoint(ScopeWin
, NULL
, &Message
->Msg
.pt
, &CaptureWindow
);
376 if(CaptureWindow
== NULL
)
378 CaptureWindow
= ScopeWin
;
379 if (CaptureWindow
) UserReferenceObject(CaptureWindow
);
383 /* this is the one case where we dont add a ref, since the returned
384 window is already referenced */
390 /* FIXME - window messages should go to the right window if no buttons are
392 CaptureWindow
= UserGetWindowObject(hCaptureWin
);
393 if (CaptureWindow
) UserReferenceObject(CaptureWindow
);
398 if (CaptureWindow
== NULL
)
402 RemoveEntryList(&Message
->ListEntry
);
403 if(MessageQueue
->MouseMoveMsg
== Message
)
405 MessageQueue
->MouseMoveMsg
= NULL
;
408 // when FromGlobalQueue is true, the caller has already removed the Message
414 if (CaptureWindow
->head
.pti
->MessageQueue
!= MessageQueue
)
416 if (! FromGlobalQueue
)
418 DPRINT("Moving msg between private queues\n");
419 /* This message is already queued in a private queue, but we need
420 * to move it to a different queue, perhaps because a new window
421 * was created which now covers the screen area previously taken
422 * by another window. To move it, we need to take it out of the
423 * old queue. Note that we're already holding the lock mutexes of the
425 RemoveEntryList(&Message
->ListEntry
);
427 /* remove the pointer for the current WM_MOUSEMOVE message in case we
429 if(MessageQueue
->MouseMoveMsg
== Message
)
431 MessageQueue
->MouseMoveMsg
= NULL
;
435 /* lock the destination message queue, so we don't get in trouble with other
436 threads, messing with it at the same time */
437 IntLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
438 InsertTailList(&CaptureWindow
->head
.pti
->MessageQueue
->HardwareMessagesListHead
,
439 &Message
->ListEntry
);
440 if(Message
->Msg
.message
== WM_MOUSEMOVE
)
442 if(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
)
444 /* remove the old WM_MOUSEMOVE message, we're processing a more recent
446 RemoveEntryList(&CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
->ListEntry
);
447 ExFreePool(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
);
449 /* save the pointer to the WM_MOUSEMOVE message in the new queue */
450 CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
= Message
;
452 CaptureWindow
->head
.pti
->MessageQueue
->QueueBits
|= QS_MOUSEMOVE
;
453 CaptureWindow
->head
.pti
->MessageQueue
->ChangedBits
|= QS_MOUSEMOVE
;
454 if (CaptureWindow
->head
.pti
->MessageQueue
->WakeMask
& QS_MOUSEMOVE
)
455 KeSetEvent(CaptureWindow
->head
.pti
->MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
459 CaptureWindow
->head
.pti
->MessageQueue
->QueueBits
|= QS_MOUSEBUTTON
;
460 CaptureWindow
->head
.pti
->MessageQueue
->ChangedBits
|= QS_MOUSEBUTTON
;
461 if (CaptureWindow
->head
.pti
->MessageQueue
->WakeMask
& QS_MOUSEBUTTON
)
462 KeSetEvent(CaptureWindow
->head
.pti
->MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
464 IntUnLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
467 UserDereferenceObject(CaptureWindow
);
471 /* From here on, we're in the same message queue as the caller! */
473 *ScreenPoint
= Message
->Msg
.pt
;
475 if((Window
!= NULL
&& PtrToInt(Window
) != 1 && CaptureWindow
->head
.h
!= Window
->head
.h
) ||
476 ((FilterLow
!= 0 || FilterHigh
!= 0) && (Msg
< FilterLow
|| Msg
> FilterHigh
)))
478 /* Reject the message because it doesn't match the filter */
482 /* Lock the message queue so no other thread can mess with it.
483 Our own message queue is not locked while fetching from the global
484 queue, so we have to make sure nothing interferes! */
485 IntLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
486 /* if we're from the global queue, we need to add our message to our
487 private queue so we don't loose it! */
488 InsertTailList(&CaptureWindow
->head
.pti
->MessageQueue
->HardwareMessagesListHead
,
489 &Message
->ListEntry
);
492 if (Message
->Msg
.message
== WM_MOUSEMOVE
)
494 if(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
&&
495 (CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
!= Message
))
497 /* delete the old message */
498 RemoveEntryList(&CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
->ListEntry
);
499 ExFreePool(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
);
500 if (!FromGlobalQueue
)
502 // We might have deleted the next one in our queue, so fix next
503 *Next
= Message
->ListEntry
.Flink
;
506 /* always save a pointer to this WM_MOUSEMOVE message here because we're
507 sure that the message is in the private queue */
508 CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
= Message
;
512 IntUnLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
515 UserDereferenceObject(CaptureWindow
);
520 /* FIXME - only assign if removing? */
521 Message
->Msg
.hwnd
= CaptureWindow
->head
.h
;
522 Message
->Msg
.message
= Msg
;
523 Message
->Msg
.lParam
= MAKELONG(Message
->Msg
.pt
.x
, Message
->Msg
.pt
.y
);
525 /* remove the reference to the current WM_(NC)MOUSEMOVE message, if this message
527 if (Message
->Msg
.message
== WM_MOUSEMOVE
||
528 Message
->Msg
.message
== WM_NCMOUSEMOVE
)
532 /* Lock the message queue so no other thread can mess with it.
533 Our own message queue is not locked while fetching from the global
534 queue, so we have to make sure nothing interferes! */
535 IntLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
536 if(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
)
538 /* delete the WM_(NC)MOUSEMOVE message in the private queue, we're dealing
539 with one that's been sent later */
540 RemoveEntryList(&CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
->ListEntry
);
541 ExFreePool(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
);
542 /* our message is not in the private queue so we can remove the pointer
543 instead of setting it to the current message we're processing */
544 CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
= NULL
;
546 IntUnLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
548 else if (CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
== Message
)
550 CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
= NULL
;
554 UserDereferenceObject(CaptureWindow
);
560 co_MsqPeekHardwareMessage(PUSER_MESSAGE_QUEUE MessageQueue
, PWND Window
,
561 UINT FilterLow
, UINT FilterHigh
, BOOL Remove
,
562 PUSER_MESSAGE
* Message
)
567 PLIST_ENTRY CurrentEntry
;
568 PWND DesktopWindow
= NULL
;
569 PVOID WaitObjects
[2];
571 DECLARE_RETURN(BOOL
);
572 USER_REFERENCE_ENTRY Ref
;
573 PDESKTOPINFO Desk
= NULL
;
575 WaitObjects
[1] = MessageQueue
->NewMessages
;
576 WaitObjects
[0] = &HardwareMessageQueueLock
;
583 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
584 UserMode
, FALSE
, NULL
, NULL
);
588 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
590 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
594 UserRefObjectCo(DesktopWindow
, &Ref
);
595 Desk
= DesktopWindow
->head
.pti
->pDeskInfo
;
598 /* Process messages in the message queue itself. */
599 IntLockHardwareMessageQueue(MessageQueue
);
600 CurrentEntry
= MessageQueue
->HardwareMessagesListHead
.Flink
;
601 while (CurrentEntry
!= &MessageQueue
->HardwareMessagesListHead
)
603 PUSER_MESSAGE Current
=
604 CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
605 CurrentEntry
= CurrentEntry
->Flink
;
606 if (Current
->Msg
.message
>= WM_MOUSEFIRST
&&
607 Current
->Msg
.message
<= WM_MOUSELAST
)
611 Accept
= co_MsqTranslateMouseMessage(MessageQueue
, Window
, FilterLow
, FilterHigh
,
612 Current
, Remove
, &Freed
,
613 DesktopWindow
, &ScreenPoint
, FALSE
, &CurrentEntry
);
618 RemoveEntryList(&Current
->ListEntry
);
620 IntUnLockHardwareMessageQueue(MessageQueue
);
621 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
625 Desk
->LastInputWasKbd
= FALSE
;
635 RemoveEntryList(&Current
->ListEntry
);
637 IntUnLockHardwareMessageQueue(MessageQueue
);
638 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
644 IntUnLockHardwareMessageQueue(MessageQueue
);
646 /* Now try the global queue. */
648 /* Transfer all messages from the DPC accessible queue to the main queue. */
649 IntLockSystemMessageQueue(OldIrql
);
650 while (SystemMessageQueueCount
> 0)
652 PUSER_MESSAGE UserMsg
;
655 ASSERT(SystemMessageQueueHead
< SYSTEM_MESSAGE_QUEUE_SIZE
);
656 Msg
= SystemMessageQueue
[SystemMessageQueueHead
];
657 SystemMessageQueueHead
=
658 (SystemMessageQueueHead
+ 1) % SYSTEM_MESSAGE_QUEUE_SIZE
;
659 SystemMessageQueueCount
--;
660 IntUnLockSystemMessageQueue(OldIrql
);
662 UserMsg
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
663 /* What to do if out of memory? For now we just panic a bit in debug */
666 InsertTailList(&HardwareMessageQueueHead
, &UserMsg
->ListEntry
);
668 IntLockSystemMessageQueue(OldIrql
);
670 HardwareMessageQueueStamp
++;
671 IntUnLockSystemMessageQueue(OldIrql
);
673 /* Process messages in the queue until we find one to return. */
674 CurrentEntry
= HardwareMessageQueueHead
.Flink
;
675 while (CurrentEntry
!= &HardwareMessageQueueHead
)
677 PUSER_MESSAGE Current
=
678 CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
679 CurrentEntry
= CurrentEntry
->Flink
;
680 RemoveEntryList(&Current
->ListEntry
);
681 HardwareMessageQueueStamp
++;
682 if (Current
->Msg
.message
>= WM_MOUSEFIRST
&&
683 Current
->Msg
.message
<= WM_MOUSELAST
)
685 const ULONG ActiveStamp
= HardwareMessageQueueStamp
;
686 /* Translate the message. */
687 Accept
= co_MsqTranslateMouseMessage(MessageQueue
, Window
, FilterLow
, FilterHigh
,
688 Current
, Remove
, &Freed
,
689 DesktopWindow
, &ScreenPoint
, TRUE
, NULL
);
692 /* Check for no more messages in the system queue. */
693 IntLockSystemMessageQueue(OldIrql
);
694 if (SystemMessageQueueCount
== 0 &&
695 IsListEmpty(&HardwareMessageQueueHead
))
697 KeClearEvent(&HardwareMessageEvent
);
699 IntUnLockSystemMessageQueue(OldIrql
);
702 If we aren't removing the message then add it to the private
707 IntLockHardwareMessageQueue(MessageQueue
);
708 if(Current
->Msg
.message
== WM_MOUSEMOVE
)
710 if(MessageQueue
->MouseMoveMsg
)
712 RemoveEntryList(&MessageQueue
->MouseMoveMsg
->ListEntry
);
713 ExFreePool(MessageQueue
->MouseMoveMsg
);
715 MessageQueue
->MouseMoveMsg
= Current
;
717 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
718 &Current
->ListEntry
);
719 IntUnLockHardwareMessageQueue(MessageQueue
);
721 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
726 /* If the contents of the queue changed then restart processing. */
727 if (HardwareMessageQueueStamp
!= ActiveStamp
)
729 CurrentEntry
= HardwareMessageQueueHead
.Flink
;
735 /* Check if the system message queue is now empty. */
736 IntLockSystemMessageQueue(OldIrql
);
737 if (SystemMessageQueueCount
== 0 && IsListEmpty(&HardwareMessageQueueHead
))
739 KeClearEvent(&HardwareMessageEvent
);
741 IntUnLockSystemMessageQueue(OldIrql
);
742 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
747 if (DesktopWindow
) UserDerefObjectCo(DesktopWindow
);
753 // Note: Only called from input.c.
756 co_MsqPostKeyboardMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
758 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
760 LARGE_INTEGER LargeTickCount
;
761 KBDLLHOOKSTRUCT KbdHookData
;
762 BOOLEAN Entered
= FALSE
;
764 DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
765 uMsg
, wParam
, lParam
);
767 // Condition may arise when calling MsqPostMessage and waiting for an event.
768 if (!UserIsEntered())
770 // Fixme: Not sure ATM if this thread is locked.
771 UserEnterExclusive();
775 FocusMessageQueue
= IntGetFocusMessageQueue();
779 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
780 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
786 KeQueryTickCount(&LargeTickCount
);
787 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
789 /* We can't get the Msg.pt point here since we don't know thread
790 (and thus the window station) the message will end up in yet. */
792 KbdHookData
.vkCode
= Msg
.wParam
;
793 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
794 KbdHookData
.flags
= (0 == (Msg
.lParam
& 0x01000000) ? 0 : LLKHF_EXTENDED
) |
795 (0 == (Msg
.lParam
& 0x20000000) ? 0 : LLKHF_ALTDOWN
) |
796 (0 == (Msg
.lParam
& 0x80000000) ? 0 : LLKHF_UP
);
797 KbdHookData
.time
= Msg
.time
;
798 KbdHookData
.dwExtraInfo
= 0;
799 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
801 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
802 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
803 if (Entered
) UserLeave();
807 if (FocusMessageQueue
== NULL
)
809 DPRINT("No focus message queue\n");
810 if (Entered
) UserLeave();
814 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
816 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
817 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
819 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
821 Msg
.pt
= gpsi
->ptCursor
;
822 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
826 DPRINT("Invalid focus window handle\n");
829 if (Entered
) UserLeave();
834 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
837 PTHREADINFO Win32Thread
;
839 LARGE_INTEGER LargeTickCount
;
842 Status
= ObReferenceObjectByPointer (Thread
,
846 if (!NT_SUCCESS(Status
))
849 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
850 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
852 ObDereferenceObject ((PETHREAD
)Thread
);
856 Window
= IntGetWindowObject(hWnd
);
859 ObDereferenceObject ((PETHREAD
)Thread
);
864 Mesg
.message
= WM_HOTKEY
;
865 Mesg
.wParam
= wParam
;
866 Mesg
.lParam
= lParam
;
867 KeQueryTickCount(&LargeTickCount
);
868 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
869 Mesg
.pt
= gpsi
->ptCursor
;
870 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
871 UserDereferenceObject(Window
);
872 ObDereferenceObject (Thread
);
874 // InsertHeadList(&pThread->MessageQueue->PostedMessagesListHead,
875 // &Message->ListEntry);
876 // KeSetEvent(pThread->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
879 PUSER_MESSAGE FASTCALL
880 MsqCreateMessage(LPMSG Msg
)
882 PUSER_MESSAGE Message
;
884 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
890 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
896 MsqDestroyMessage(PUSER_MESSAGE Message
)
898 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
902 co_MsqDispatchSentNotifyMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
904 PLIST_ENTRY ListEntry
;
905 PUSER_SENT_MESSAGE_NOTIFY Message
;
907 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
909 ListEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
910 Message
= CONTAINING_RECORD(ListEntry
, USER_SENT_MESSAGE_NOTIFY
,
913 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
916 Message
->CompletionCallbackContext
,
924 MsqPeekSentMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
926 return(!IsListEmpty(&MessageQueue
->SentMessagesListHead
));
930 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
932 PUSER_SENT_MESSAGE Message
;
936 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
941 /* remove it from the list of pending messages */
942 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
943 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
945 /* insert it to the list of messages that are currently dispatched by this
947 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
948 &Message
->ListEntry
);
950 if (Message
->HookMessage
== MSQ_ISHOOK
)
952 Result
= co_HOOK_CallHooks(Message
->Msg
.message
,
953 (INT
)(INT_PTR
)Message
->Msg
.hwnd
,
955 Message
->Msg
.lParam
);
957 else if (Message
->HookMessage
== MSQ_ISEVENT
)
959 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
962 Message
->Msg
.lParam
);
966 /* Call the window procedure. */
967 Result
= co_IntSendMessage(Message
->Msg
.hwnd
,
968 Message
->Msg
.message
,
970 Message
->Msg
.lParam
);
973 /* remove the message from the local dispatching list, because it doesn't need
974 to be cleaned up on thread termination anymore */
975 RemoveEntryList(&Message
->ListEntry
);
977 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
978 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
980 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
982 /* only remove it from the dispatching list if not already removed by a timeout */
983 RemoveEntryList(&Message
->DispatchingListEntry
);
986 /* still keep the sender's message queue locked, so the sender can't exit the
987 MsqSendMessage() function (if timed out) */
989 /* Let the sender know the result. */
990 if (Message
->Result
!= NULL
)
992 *Message
->Result
= Result
;
995 if (Message
->HasPackedLParam
== TRUE
)
997 if (Message
->Msg
.lParam
)
998 ExFreePool((PVOID
)Message
->Msg
.lParam
);
1001 /* Notify the sender. */
1002 if (Message
->CompletionEvent
!= NULL
)
1004 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1007 /* Call the callback if the message was sent with SendMessageCallback */
1008 if (Message
->CompletionCallback
!= NULL
)
1010 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
1012 Message
->Msg
.message
,
1013 Message
->CompletionCallbackContext
,
1017 /* Only if it is not a no wait message */
1018 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
1020 IntDereferenceMessageQueue(Message
->SenderQueue
);
1021 IntDereferenceMessageQueue(MessageQueue
);
1024 /* free the message */
1025 ExFreePoolWithTag(Message
, TAG_USRMSG
);
1030 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
1032 PUSER_SENT_MESSAGE SentMessage
;
1033 PUSER_MESSAGE PostedMessage
;
1034 PUSER_MESSAGE_QUEUE MessageQueue
;
1035 PLIST_ENTRY CurrentEntry
, ListHead
;
1036 PWND Window
= pWindow
;
1040 MessageQueue
= Window
->head
.pti
->MessageQueue
;
1041 ASSERT(MessageQueue
);
1043 /* remove the posted messages for this window */
1044 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1045 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1046 while (CurrentEntry
!= ListHead
)
1048 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1050 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
1052 RemoveEntryList(&PostedMessage
->ListEntry
);
1053 MsqDestroyMessage(PostedMessage
);
1054 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1058 CurrentEntry
= CurrentEntry
->Flink
;
1062 /* remove the sent messages for this window */
1063 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
1064 ListHead
= &MessageQueue
->SentMessagesListHead
;
1065 while (CurrentEntry
!= ListHead
)
1067 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1069 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
1071 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1073 RemoveEntryList(&SentMessage
->ListEntry
);
1075 /* remove the message from the dispatching list if neede */
1076 if ((!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1077 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1079 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
1082 /* wake the sender's thread */
1083 if (SentMessage
->CompletionEvent
!= NULL
)
1085 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1088 if (SentMessage
->HasPackedLParam
== TRUE
)
1090 if (SentMessage
->Msg
.lParam
)
1091 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
1094 /* Only if it is not a no wait message */
1095 if (!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1097 /* dereference our and the sender's message queue */
1098 IntDereferenceMessageQueue(MessageQueue
);
1099 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
1102 /* free the message */
1103 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
1105 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
1109 CurrentEntry
= CurrentEntry
->Flink
;
1115 MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1116 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage
)
1118 InsertTailList(&MessageQueue
->NotifyMessagesListHead
,
1119 &NotifyMessage
->ListEntry
);
1120 MessageQueue
->QueueBits
|= QS_SENDMESSAGE
;
1121 MessageQueue
->ChangedBits
|= QS_SENDMESSAGE
;
1122 if (MessageQueue
->WakeMask
& QS_SENDMESSAGE
)
1123 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1127 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1128 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
1129 UINT uTimeout
, BOOL Block
, INT HookMessage
,
1133 PUSER_SENT_MESSAGE Message
;
1134 KEVENT CompletionEvent
;
1135 NTSTATUS WaitStatus
;
1137 PUSER_MESSAGE_QUEUE ThreadQueue
;
1138 LARGE_INTEGER Timeout
;
1141 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1143 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1144 return STATUS_INSUFFICIENT_RESOURCES
;
1147 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1149 pti
= PsGetCurrentThreadWin32Thread();
1150 ThreadQueue
= pti
->MessageQueue
;
1151 ASSERT(ThreadQueue
!= MessageQueue
);
1153 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1155 /* FIXME - increase reference counter of sender's message queue here */
1158 Message
->Msg
.hwnd
= Wnd
;
1159 Message
->Msg
.message
= Msg
;
1160 Message
->Msg
.wParam
= wParam
;
1161 Message
->Msg
.lParam
= lParam
;
1162 Message
->CompletionEvent
= &CompletionEvent
;
1163 Message
->Result
= &Result
;
1164 Message
->SenderQueue
= ThreadQueue
;
1165 IntReferenceMessageQueue(ThreadQueue
);
1166 Message
->CompletionCallback
= NULL
;
1167 Message
->HookMessage
= HookMessage
;
1168 Message
->HasPackedLParam
= FALSE
;
1170 IntReferenceMessageQueue(MessageQueue
);
1172 /* add it to the list of pending messages */
1173 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1175 /* queue it in the destination's message queue */
1176 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1178 MessageQueue
->QueueBits
|= QS_SENDMESSAGE
;
1179 MessageQueue
->ChangedBits
|= QS_SENDMESSAGE
;
1180 if (MessageQueue
->WakeMask
& QS_SENDMESSAGE
)
1181 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1183 /* we can't access the Message anymore since it could have already been deleted! */
1191 /* don't process messages sent to the thread */
1192 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1193 FALSE
, (uTimeout
? &Timeout
: NULL
));
1197 if(WaitStatus
== STATUS_TIMEOUT
)
1199 /* look up if the message has not yet dispatched, if so
1200 make sure it can't pass a result and it must not set the completion event anymore */
1201 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1202 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1204 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1207 /* we can access Message here, it's secure because the message queue is locked
1208 and the message is still hasn't been dispatched */
1209 Message
->CompletionEvent
= NULL
;
1210 Message
->Result
= NULL
;
1213 Entry
= Entry
->Flink
;
1216 /* remove from the local dispatching list so the other thread knows,
1217 it can't pass a result and it must not set the completion event anymore */
1218 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1219 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1221 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1224 /* we can access Message here, it's secure because the sender's message is locked
1225 and the message has definitely not yet been destroyed, otherwise it would
1226 have been removed from this list by the dispatching routine right after
1227 dispatching the message */
1228 Message
->CompletionEvent
= NULL
;
1229 Message
->Result
= NULL
;
1230 RemoveEntryList(&Message
->DispatchingListEntry
);
1231 Message
->DispatchingListEntry
.Flink
= NULL
;
1234 Entry
= Entry
->Flink
;
1237 DPRINT("MsqSendMessage (blocked) timed out\n");
1239 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1244 PVOID WaitObjects
[2];
1246 WaitObjects
[0] = &CompletionEvent
;
1247 WaitObjects
[1] = ThreadQueue
->NewMessages
;
1254 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1255 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1259 if(WaitStatus
== STATUS_TIMEOUT
)
1261 /* look up if the message has not yet been dispatched, if so
1262 make sure it can't pass a result and it must not set the completion event anymore */
1263 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1264 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1266 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1269 /* we can access Message here, it's secure because the message queue is locked
1270 and the message is still hasn't been dispatched */
1271 Message
->CompletionEvent
= NULL
;
1272 Message
->Result
= NULL
;
1275 Entry
= Entry
->Flink
;
1278 /* remove from the local dispatching list so the other thread knows,
1279 it can't pass a result and it must not set the completion event anymore */
1280 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1281 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1283 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1286 /* we can access Message here, it's secure because the sender's message is locked
1287 and the message has definitely not yet been destroyed, otherwise it would
1288 have been removed from this list by the dispatching routine right after
1289 dispatching the message */
1290 Message
->CompletionEvent
= NULL
;
1291 Message
->Result
= NULL
;
1292 RemoveEntryList(&Message
->DispatchingListEntry
);
1293 Message
->DispatchingListEntry
.Flink
= NULL
;
1296 Entry
= Entry
->Flink
;
1299 DPRINT("MsqSendMessage timed out\n");
1302 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1305 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
1308 if(WaitStatus
!= STATUS_TIMEOUT
)
1309 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1315 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
1318 PUSER_MESSAGE Message
;
1320 if(!(Message
= MsqCreateMessage(Msg
)))
1325 if(!HardwareMessage
)
1327 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1328 &Message
->ListEntry
);
1332 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1333 &Message
->ListEntry
);
1335 MessageQueue
->QueueBits
|= MessageBits
;
1336 MessageQueue
->ChangedBits
|= MessageBits
;
1337 if (MessageQueue
->WakeMask
& MessageBits
)
1338 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1342 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1344 MessageQueue
->QuitPosted
= TRUE
;
1345 MessageQueue
->QuitExitCode
= ExitCode
;
1346 MessageQueue
->QueueBits
|= QS_POSTMESSAGE
;
1347 MessageQueue
->ChangedBits
|= QS_POSTMESSAGE
;
1348 if (MessageQueue
->WakeMask
& QS_POSTMESSAGE
)
1349 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1353 co_MsqFindMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1354 IN BOOLEAN Hardware
,
1357 IN UINT MsgFilterLow
,
1358 IN UINT MsgFilterHigh
,
1359 OUT PUSER_MESSAGE
* Message
)
1361 PLIST_ENTRY CurrentEntry
;
1362 PUSER_MESSAGE CurrentMessage
;
1363 PLIST_ENTRY ListHead
;
1367 return(co_MsqPeekHardwareMessage( MessageQueue
,
1375 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1376 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1377 while (CurrentEntry
!= ListHead
)
1379 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1382 PtrToInt(Window
) == 1 ||
1383 Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) &&
1384 ( (MsgFilterLow
== 0 && MsgFilterHigh
== 0) ||
1385 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&&
1386 MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1390 RemoveEntryList(&CurrentMessage
->ListEntry
);
1393 *Message
= CurrentMessage
;
1396 CurrentEntry
= CurrentEntry
->Flink
;
1403 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1404 UINT MsgFilterMin
, UINT MsgFilterMax
)
1406 PVOID WaitObjects
[2] = {MessageQueue
->NewMessages
, &HardwareMessageEvent
};
1409 IdlePing(); // Going to wait so send Idle ping.
1413 ret
= KeWaitForMultipleObjects(2,
1426 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1428 LARGE_INTEGER LargeTickCount
;
1430 KeQueryTickCount(&LargeTickCount
);
1431 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1435 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1437 LARGE_INTEGER LargeTickCount
;
1440 MessageQueue
->Thread
= Thread
;
1441 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1442 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1443 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1444 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1445 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1446 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1447 KeInitializeMutex(&MessageQueue
->HardwareLock
, 0);
1448 MessageQueue
->QuitPosted
= FALSE
;
1449 MessageQueue
->QuitExitCode
= 0;
1450 KeQueryTickCount(&LargeTickCount
);
1451 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1452 MessageQueue
->FocusWindow
= NULL
;
1453 MessageQueue
->PaintCount
= 0;
1454 // HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt)
1455 MessageQueue
->WakeMask
= ~0;
1456 MessageQueue
->NewMessagesHandle
= NULL
;
1458 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1459 NULL
, SynchronizationEvent
, FALSE
);
1460 if (!NT_SUCCESS(Status
))
1465 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1466 ExEventObjectType
, KernelMode
,
1467 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1468 if (!NT_SUCCESS(Status
))
1470 ZwClose(MessageQueue
->NewMessagesHandle
);
1471 MessageQueue
->NewMessagesHandle
= NULL
;
1479 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1481 PLIST_ENTRY CurrentEntry
;
1482 PUSER_MESSAGE CurrentMessage
;
1483 PUSER_SENT_MESSAGE CurrentSentMessage
;
1485 /* cleanup posted messages */
1486 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1488 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1489 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1491 MsqDestroyMessage(CurrentMessage
);
1494 /* remove the messages that have not yet been dispatched */
1495 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1497 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1498 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1501 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1503 /* remove the message from the dispatching list if needed */
1504 if ((!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1505 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1507 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1510 /* wake the sender's thread */
1511 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1513 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1516 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1518 if (CurrentSentMessage
->Msg
.lParam
)
1519 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1522 /* Only if it is not a no wait message */
1523 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1525 /* dereference our and the sender's message queue */
1526 IntDereferenceMessageQueue(MessageQueue
);
1527 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1530 /* free the message */
1531 ExFreePool(CurrentSentMessage
);
1534 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1535 ExitThread() was called in a SendMessage() umode callback */
1536 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1538 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1539 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1542 /* remove the message from the dispatching list */
1543 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1545 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1548 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1550 /* wake the sender's thread */
1551 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1553 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1556 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1558 if (CurrentSentMessage
->Msg
.lParam
)
1559 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1562 /* Only if it is not a no wait message */
1563 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1565 /* dereference our and the sender's message queue */
1566 IntDereferenceMessageQueue(MessageQueue
);
1567 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1570 /* free the message */
1571 ExFreePool(CurrentSentMessage
);
1574 /* tell other threads not to bother returning any info to us */
1575 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
1577 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
1578 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1579 DispatchingListEntry
);
1580 CurrentSentMessage
->CompletionEvent
= NULL
;
1581 CurrentSentMessage
->Result
= NULL
;
1583 /* do NOT dereference our message queue as it might get attempted to be
1589 PUSER_MESSAGE_QUEUE FASTCALL
1590 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
1592 PUSER_MESSAGE_QUEUE MessageQueue
;
1594 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
1595 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
1603 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
1604 /* hold at least one reference until it'll be destroyed */
1605 IntReferenceMessageQueue(MessageQueue
);
1606 /* initialize the queue */
1607 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
1609 IntDereferenceMessageQueue(MessageQueue
);
1613 return MessageQueue
;
1617 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1621 /* remove the message queue from any desktops */
1622 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
1624 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
1625 IntDereferenceMessageQueue(MessageQueue
);
1629 MsqCleanupMessageQueue(MessageQueue
);
1631 /* decrease the reference counter, if it hits zero, the queue will be freed */
1632 IntDereferenceMessageQueue(MessageQueue
);
1636 MsqGetHooks(PUSER_MESSAGE_QUEUE Queue
)
1638 return Queue
->Hooks
;
1642 MsqSetHooks(PUSER_MESSAGE_QUEUE Queue
, PHOOKTABLE Hooks
)
1644 Queue
->Hooks
= Hooks
;
1648 MsqSetMessageExtraInfo(LPARAM lParam
)
1652 PUSER_MESSAGE_QUEUE MessageQueue
;
1654 pti
= PsGetCurrentThreadWin32Thread();
1655 MessageQueue
= pti
->MessageQueue
;
1661 Ret
= MessageQueue
->ExtraInfo
;
1662 MessageQueue
->ExtraInfo
= lParam
;
1668 MsqGetMessageExtraInfo(VOID
)
1671 PUSER_MESSAGE_QUEUE MessageQueue
;
1673 pti
= PsGetCurrentThreadWin32Thread();
1674 MessageQueue
= pti
->MessageQueue
;
1680 return MessageQueue
->ExtraInfo
;
1684 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
1690 case MSQ_STATE_CAPTURE
:
1691 Prev
= MessageQueue
->CaptureWindow
;
1692 MessageQueue
->CaptureWindow
= hWnd
;
1694 case MSQ_STATE_ACTIVE
:
1695 Prev
= MessageQueue
->ActiveWindow
;
1696 MessageQueue
->ActiveWindow
= hWnd
;
1698 case MSQ_STATE_FOCUS
:
1699 Prev
= MessageQueue
->FocusWindow
;
1700 MessageQueue
->FocusWindow
= hWnd
;
1702 case MSQ_STATE_MENUOWNER
:
1703 Prev
= MessageQueue
->MenuOwner
;
1704 MessageQueue
->MenuOwner
= hWnd
;
1706 case MSQ_STATE_MOVESIZE
:
1707 Prev
= MessageQueue
->MoveSize
;
1708 MessageQueue
->MoveSize
= hWnd
;
1710 case MSQ_STATE_CARET
:
1711 ASSERT(MessageQueue
->CaretInfo
);
1712 Prev
= MessageQueue
->CaretInfo
->hWnd
;
1713 MessageQueue
->CaretInfo
->hWnd
= hWnd
;