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
);//can DesktopWindow be NULL?
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
;
632 IntUnLockHardwareMessageQueue(MessageQueue
);
634 /* Now try the global queue. */
636 /* Transfer all messages from the DPC accessible queue to the main queue. */
637 IntLockSystemMessageQueue(OldIrql
);
638 while (SystemMessageQueueCount
> 0)
640 PUSER_MESSAGE UserMsg
;
643 ASSERT(SystemMessageQueueHead
< SYSTEM_MESSAGE_QUEUE_SIZE
);
644 Msg
= SystemMessageQueue
[SystemMessageQueueHead
];
645 SystemMessageQueueHead
=
646 (SystemMessageQueueHead
+ 1) % SYSTEM_MESSAGE_QUEUE_SIZE
;
647 SystemMessageQueueCount
--;
648 IntUnLockSystemMessageQueue(OldIrql
);
650 UserMsg
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
651 /* What to do if out of memory? For now we just panic a bit in debug */
653 UserMsg
->FreeLParam
= FALSE
;
655 InsertTailList(&HardwareMessageQueueHead
, &UserMsg
->ListEntry
);
657 IntLockSystemMessageQueue(OldIrql
);
659 HardwareMessageQueueStamp
++;
660 IntUnLockSystemMessageQueue(OldIrql
);
662 /* Process messages in the queue until we find one to return. */
663 CurrentEntry
= HardwareMessageQueueHead
.Flink
;
664 while (CurrentEntry
!= &HardwareMessageQueueHead
)
666 PUSER_MESSAGE Current
=
667 CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
668 CurrentEntry
= CurrentEntry
->Flink
;
669 RemoveEntryList(&Current
->ListEntry
);
670 HardwareMessageQueueStamp
++;
671 if (Current
->Msg
.message
>= WM_MOUSEFIRST
&&
672 Current
->Msg
.message
<= WM_MOUSELAST
)
674 const ULONG ActiveStamp
= HardwareMessageQueueStamp
;
675 /* Translate the message. */
676 Accept
= co_MsqTranslateMouseMessage(MessageQueue
, Window
, FilterLow
, FilterHigh
,
677 Current
, Remove
, &Freed
,
678 DesktopWindow
, &ScreenPoint
, TRUE
, NULL
);
681 /* Check for no more messages in the system queue. */
682 IntLockSystemMessageQueue(OldIrql
);
683 if (SystemMessageQueueCount
== 0 &&
684 IsListEmpty(&HardwareMessageQueueHead
))
686 KeClearEvent(&HardwareMessageEvent
);
688 IntUnLockSystemMessageQueue(OldIrql
);
691 If we aren't removing the message then add it to the private
696 IntLockHardwareMessageQueue(MessageQueue
);
697 if(Current
->Msg
.message
== WM_MOUSEMOVE
)
699 if(MessageQueue
->MouseMoveMsg
)
701 RemoveEntryList(&MessageQueue
->MouseMoveMsg
->ListEntry
);
702 ExFreePool(MessageQueue
->MouseMoveMsg
);
704 MessageQueue
->MouseMoveMsg
= Current
;
706 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
707 &Current
->ListEntry
);
708 IntUnLockHardwareMessageQueue(MessageQueue
);
710 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
715 /* If the contents of the queue changed then restart processing. */
716 if (HardwareMessageQueueStamp
!= ActiveStamp
)
718 CurrentEntry
= HardwareMessageQueueHead
.Flink
;
724 /* Check if the system message queue is now empty. */
725 IntLockSystemMessageQueue(OldIrql
);
726 if (SystemMessageQueueCount
== 0 && IsListEmpty(&HardwareMessageQueueHead
))
728 KeClearEvent(&HardwareMessageEvent
);
730 IntUnLockSystemMessageQueue(OldIrql
);
731 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
736 if (DesktopWindow
) UserDerefObjectCo(DesktopWindow
);
742 // Note: Only called from input.c.
745 co_MsqPostKeyboardMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
747 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
749 LARGE_INTEGER LargeTickCount
;
750 KBDLLHOOKSTRUCT KbdHookData
;
751 BOOLEAN Entered
= FALSE
;
753 DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
754 uMsg
, wParam
, lParam
);
756 // Condition may arise when calling MsqPostMessage and waiting for an event.
757 if (!UserIsEntered())
759 // Fixme: Not sure ATM if this thread is locked.
760 UserEnterExclusive();
764 FocusMessageQueue
= IntGetFocusMessageQueue();
768 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
769 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
775 KeQueryTickCount(&LargeTickCount
);
776 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
778 /* We can't get the Msg.pt point here since we don't know thread
779 (and thus the window station) the message will end up in yet. */
781 KbdHookData
.vkCode
= Msg
.wParam
;
782 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
783 KbdHookData
.flags
= (0 == (Msg
.lParam
& 0x01000000) ? 0 : LLKHF_EXTENDED
) |
784 (0 == (Msg
.lParam
& 0x20000000) ? 0 : LLKHF_ALTDOWN
) |
785 (0 == (Msg
.lParam
& 0x80000000) ? 0 : LLKHF_UP
);
786 KbdHookData
.time
= Msg
.time
;
787 KbdHookData
.dwExtraInfo
= 0;
788 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
790 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
791 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
792 if (Entered
) UserLeave();
796 if (FocusMessageQueue
== NULL
)
798 DPRINT("No focus message queue\n");
799 if (Entered
) UserLeave();
803 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
805 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
806 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
808 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
810 Msg
.pt
= gpsi
->ptCursor
;
811 MsqPostMessage(FocusMessageQueue
, &Msg
, FALSE
, QS_KEY
);
815 DPRINT("Invalid focus window handle\n");
818 if (Entered
) UserLeave();
823 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
826 PTHREADINFO Win32Thread
;
828 LARGE_INTEGER LargeTickCount
;
831 Status
= ObReferenceObjectByPointer (Thread
,
835 if (!NT_SUCCESS(Status
))
838 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
839 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
841 ObDereferenceObject ((PETHREAD
)Thread
);
845 Window
= IntGetWindowObject(hWnd
);
848 ObDereferenceObject ((PETHREAD
)Thread
);
853 Mesg
.message
= WM_HOTKEY
;
854 Mesg
.wParam
= wParam
;
855 Mesg
.lParam
= lParam
;
856 KeQueryTickCount(&LargeTickCount
);
857 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
858 Mesg
.pt
= gpsi
->ptCursor
;
859 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
860 UserDereferenceObject(Window
);
861 ObDereferenceObject (Thread
);
863 // InsertHeadList(&pThread->MessageQueue->PostedMessagesListHead,
864 // &Message->ListEntry);
865 // KeSetEvent(pThread->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
868 PUSER_MESSAGE FASTCALL
869 MsqCreateMessage(LPMSG Msg
, BOOLEAN FreeLParam
)
871 PUSER_MESSAGE Message
;
873 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
879 Message
->FreeLParam
= FreeLParam
;
880 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
886 MsqDestroyMessage(PUSER_MESSAGE Message
)
888 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
892 co_MsqDispatchSentNotifyMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
894 PLIST_ENTRY ListEntry
;
895 PUSER_SENT_MESSAGE_NOTIFY Message
;
897 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
899 ListEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
900 Message
= CONTAINING_RECORD(ListEntry
, USER_SENT_MESSAGE_NOTIFY
,
903 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
906 Message
->CompletionCallbackContext
,
914 MsqPeekSentMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
916 return(!IsListEmpty(&MessageQueue
->SentMessagesListHead
));
920 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
922 PUSER_SENT_MESSAGE Message
;
926 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
931 /* remove it from the list of pending messages */
932 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
933 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
935 /* insert it to the list of messages that are currently dispatched by this
937 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
938 &Message
->ListEntry
);
940 if (Message
->HookMessage
== MSQ_ISHOOK
)
942 Result
= co_HOOK_CallHooks(Message
->Msg
.message
,
943 (INT
)(INT_PTR
)Message
->Msg
.hwnd
,
945 Message
->Msg
.lParam
);
947 else if (Message
->HookMessage
== MSQ_ISEVENT
)
949 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
952 Message
->Msg
.lParam
);
956 /* Call the window procedure. */
957 Result
= co_IntSendMessage(Message
->Msg
.hwnd
,
958 Message
->Msg
.message
,
960 Message
->Msg
.lParam
);
963 /* remove the message from the local dispatching list, because it doesn't need
964 to be cleaned up on thread termination anymore */
965 RemoveEntryList(&Message
->ListEntry
);
967 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
968 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
970 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
972 /* only remove it from the dispatching list if not already removed by a timeout */
973 RemoveEntryList(&Message
->DispatchingListEntry
);
976 /* still keep the sender's message queue locked, so the sender can't exit the
977 MsqSendMessage() function (if timed out) */
979 /* Let the sender know the result. */
980 if (Message
->Result
!= NULL
)
982 *Message
->Result
= Result
;
985 if (Message
->HasPackedLParam
== TRUE
)
987 if (Message
->Msg
.lParam
)
988 ExFreePool((PVOID
)Message
->Msg
.lParam
);
991 /* Notify the sender. */
992 if (Message
->CompletionEvent
!= NULL
)
994 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
997 /* Call the callback if the message was sent with SendMessageCallback */
998 if (Message
->CompletionCallback
!= NULL
)
1000 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
1002 Message
->Msg
.message
,
1003 Message
->CompletionCallbackContext
,
1007 /* Only if it is not a no wait message */
1008 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
1010 IntDereferenceMessageQueue(Message
->SenderQueue
);
1011 IntDereferenceMessageQueue(MessageQueue
);
1014 /* free the message */
1015 ExFreePoolWithTag(Message
, TAG_USRMSG
);
1020 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
1022 PUSER_SENT_MESSAGE SentMessage
;
1023 PUSER_MESSAGE PostedMessage
;
1024 PUSER_MESSAGE_QUEUE MessageQueue
;
1025 PLIST_ENTRY CurrentEntry
, ListHead
;
1026 PWND Window
= pWindow
;
1030 MessageQueue
= Window
->head
.pti
->MessageQueue
;
1031 ASSERT(MessageQueue
);
1033 /* remove the posted messages for this window */
1034 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1035 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1036 while (CurrentEntry
!= ListHead
)
1038 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1040 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
1042 RemoveEntryList(&PostedMessage
->ListEntry
);
1043 MsqDestroyMessage(PostedMessage
);
1044 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1048 CurrentEntry
= CurrentEntry
->Flink
;
1052 /* remove the sent messages for this window */
1053 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
1054 ListHead
= &MessageQueue
->SentMessagesListHead
;
1055 while (CurrentEntry
!= ListHead
)
1057 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1059 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
1061 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1063 RemoveEntryList(&SentMessage
->ListEntry
);
1065 /* remove the message from the dispatching list if neede */
1066 if ((!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1067 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1069 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
1072 /* wake the sender's thread */
1073 if (SentMessage
->CompletionEvent
!= NULL
)
1075 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1078 if (SentMessage
->HasPackedLParam
== TRUE
)
1080 if (SentMessage
->Msg
.lParam
)
1081 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
1084 /* Only if it is not a no wait message */
1085 if (!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1087 /* dereference our and the sender's message queue */
1088 IntDereferenceMessageQueue(MessageQueue
);
1089 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
1092 /* free the message */
1093 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
1095 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
1099 CurrentEntry
= CurrentEntry
->Flink
;
1105 MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1106 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage
)
1108 InsertTailList(&MessageQueue
->NotifyMessagesListHead
,
1109 &NotifyMessage
->ListEntry
);
1110 MessageQueue
->QueueBits
|= QS_SENDMESSAGE
;
1111 MessageQueue
->ChangedBits
|= QS_SENDMESSAGE
;
1112 if (MessageQueue
->WakeMask
& QS_SENDMESSAGE
)
1113 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1117 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1118 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
1119 UINT uTimeout
, BOOL Block
, INT HookMessage
,
1123 PUSER_SENT_MESSAGE Message
;
1124 KEVENT CompletionEvent
;
1125 NTSTATUS WaitStatus
;
1127 PUSER_MESSAGE_QUEUE ThreadQueue
;
1128 LARGE_INTEGER Timeout
;
1131 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1133 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1134 return STATUS_INSUFFICIENT_RESOURCES
;
1137 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1139 pti
= PsGetCurrentThreadWin32Thread();
1140 ThreadQueue
= pti
->MessageQueue
;
1141 ASSERT(ThreadQueue
!= MessageQueue
);
1143 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1145 /* FIXME - increase reference counter of sender's message queue here */
1148 Message
->Msg
.hwnd
= Wnd
;
1149 Message
->Msg
.message
= Msg
;
1150 Message
->Msg
.wParam
= wParam
;
1151 Message
->Msg
.lParam
= lParam
;
1152 Message
->CompletionEvent
= &CompletionEvent
;
1153 Message
->Result
= &Result
;
1154 Message
->SenderQueue
= ThreadQueue
;
1155 IntReferenceMessageQueue(ThreadQueue
);
1156 Message
->CompletionCallback
= NULL
;
1157 Message
->HookMessage
= HookMessage
;
1158 Message
->HasPackedLParam
= FALSE
;
1160 IntReferenceMessageQueue(MessageQueue
);
1162 /* add it to the list of pending messages */
1163 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1165 /* queue it in the destination's message queue */
1166 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1168 MessageQueue
->QueueBits
|= QS_SENDMESSAGE
;
1169 MessageQueue
->ChangedBits
|= QS_SENDMESSAGE
;
1170 if (MessageQueue
->WakeMask
& QS_SENDMESSAGE
)
1171 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1173 /* we can't access the Message anymore since it could have already been deleted! */
1181 /* don't process messages sent to the thread */
1182 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1183 FALSE
, (uTimeout
? &Timeout
: NULL
));
1187 if(WaitStatus
== STATUS_TIMEOUT
)
1189 /* look up if the message has not yet dispatched, if so
1190 make sure it can't pass a result and it must not set the completion event anymore */
1191 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1192 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1194 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1197 /* we can access Message here, it's secure because the message queue is locked
1198 and the message is still hasn't been dispatched */
1199 Message
->CompletionEvent
= NULL
;
1200 Message
->Result
= NULL
;
1203 Entry
= Entry
->Flink
;
1206 /* remove from the local dispatching list so the other thread knows,
1207 it can't pass a result and it must not set the completion event anymore */
1208 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1209 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1211 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1214 /* we can access Message here, it's secure because the sender's message is locked
1215 and the message has definitely not yet been destroyed, otherwise it would
1216 have been removed from this list by the dispatching routine right after
1217 dispatching the message */
1218 Message
->CompletionEvent
= NULL
;
1219 Message
->Result
= NULL
;
1220 RemoveEntryList(&Message
->DispatchingListEntry
);
1221 Message
->DispatchingListEntry
.Flink
= NULL
;
1224 Entry
= Entry
->Flink
;
1227 DPRINT("MsqSendMessage (blocked) timed out\n");
1229 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1234 PVOID WaitObjects
[2];
1236 WaitObjects
[0] = &CompletionEvent
;
1237 WaitObjects
[1] = ThreadQueue
->NewMessages
;
1244 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1245 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1249 if(WaitStatus
== STATUS_TIMEOUT
)
1251 /* look up if the message has not yet been dispatched, if so
1252 make sure it can't pass a result and it must not set the completion event anymore */
1253 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1254 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1256 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1259 /* we can access Message here, it's secure because the message queue is locked
1260 and the message is still hasn't been dispatched */
1261 Message
->CompletionEvent
= NULL
;
1262 Message
->Result
= NULL
;
1265 Entry
= Entry
->Flink
;
1268 /* remove from the local dispatching list so the other thread knows,
1269 it can't pass a result and it must not set the completion event anymore */
1270 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1271 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1273 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1276 /* we can access Message here, it's secure because the sender's message is locked
1277 and the message has definitely not yet been destroyed, otherwise it would
1278 have been removed from this list by the dispatching routine right after
1279 dispatching the message */
1280 Message
->CompletionEvent
= NULL
;
1281 Message
->Result
= NULL
;
1282 RemoveEntryList(&Message
->DispatchingListEntry
);
1283 Message
->DispatchingListEntry
.Flink
= NULL
;
1286 Entry
= Entry
->Flink
;
1289 DPRINT("MsqSendMessage timed out\n");
1292 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1295 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
1298 if(WaitStatus
!= STATUS_TIMEOUT
)
1299 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1305 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN FreeLParam
,
1308 PUSER_MESSAGE Message
;
1310 if(!(Message
= MsqCreateMessage(Msg
, FreeLParam
)))
1314 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1315 &Message
->ListEntry
);
1316 MessageQueue
->QueueBits
|= MessageBits
;
1317 MessageQueue
->ChangedBits
|= MessageBits
;
1318 if (MessageQueue
->WakeMask
& MessageBits
)
1319 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1323 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1325 MessageQueue
->QuitPosted
= TRUE
;
1326 MessageQueue
->QuitExitCode
= ExitCode
;
1327 MessageQueue
->QueueBits
|= QS_POSTMESSAGE
;
1328 MessageQueue
->ChangedBits
|= QS_POSTMESSAGE
;
1329 if (MessageQueue
->WakeMask
& QS_POSTMESSAGE
)
1330 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1334 co_MsqFindMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1335 IN BOOLEAN Hardware
,
1338 IN UINT MsgFilterLow
,
1339 IN UINT MsgFilterHigh
,
1340 OUT PUSER_MESSAGE
* Message
)
1342 PLIST_ENTRY CurrentEntry
;
1343 PUSER_MESSAGE CurrentMessage
;
1344 PLIST_ENTRY ListHead
;
1348 return(co_MsqPeekHardwareMessage( MessageQueue
,
1356 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1357 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1358 while (CurrentEntry
!= ListHead
)
1360 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1363 PtrToInt(Window
) == 1 ||
1364 Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) &&
1365 ( (MsgFilterLow
== 0 && MsgFilterHigh
== 0) ||
1366 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&&
1367 MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1371 RemoveEntryList(&CurrentMessage
->ListEntry
);
1374 *Message
= CurrentMessage
;
1377 CurrentEntry
= CurrentEntry
->Flink
;
1384 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1385 UINT MsgFilterMin
, UINT MsgFilterMax
)
1387 PVOID WaitObjects
[2] = {MessageQueue
->NewMessages
, &HardwareMessageEvent
};
1390 IdlePing(); // Going to wait so send Idle ping.
1394 ret
= KeWaitForMultipleObjects(2,
1407 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1409 LARGE_INTEGER LargeTickCount
;
1411 KeQueryTickCount(&LargeTickCount
);
1412 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1416 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1418 LARGE_INTEGER LargeTickCount
;
1421 MessageQueue
->Thread
= Thread
;
1422 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1423 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1424 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1425 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1426 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1427 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1428 KeInitializeMutex(&MessageQueue
->HardwareLock
, 0);
1429 MessageQueue
->QuitPosted
= FALSE
;
1430 MessageQueue
->QuitExitCode
= 0;
1431 KeQueryTickCount(&LargeTickCount
);
1432 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1433 MessageQueue
->FocusWindow
= NULL
;
1434 MessageQueue
->PaintCount
= 0;
1435 // HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt)
1436 MessageQueue
->WakeMask
= ~0;
1437 MessageQueue
->NewMessagesHandle
= NULL
;
1439 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1440 NULL
, SynchronizationEvent
, FALSE
);
1441 if (!NT_SUCCESS(Status
))
1446 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1447 ExEventObjectType
, KernelMode
,
1448 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1449 if (!NT_SUCCESS(Status
))
1451 ZwClose(MessageQueue
->NewMessagesHandle
);
1452 MessageQueue
->NewMessagesHandle
= NULL
;
1460 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1462 PLIST_ENTRY CurrentEntry
;
1463 PUSER_MESSAGE CurrentMessage
;
1464 PUSER_SENT_MESSAGE CurrentSentMessage
;
1466 /* cleanup posted messages */
1467 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1469 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1470 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1472 MsqDestroyMessage(CurrentMessage
);
1475 /* remove the messages that have not yet been dispatched */
1476 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1478 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1479 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1482 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1484 /* remove the message from the dispatching list if needed */
1485 if ((!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1486 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1488 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1491 /* wake the sender's thread */
1492 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1494 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1497 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1499 if (CurrentSentMessage
->Msg
.lParam
)
1500 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1503 /* Only if it is not a no wait message */
1504 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1506 /* dereference our and the sender's message queue */
1507 IntDereferenceMessageQueue(MessageQueue
);
1508 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1511 /* free the message */
1512 ExFreePool(CurrentSentMessage
);
1515 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1516 ExitThread() was called in a SendMessage() umode callback */
1517 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1519 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1520 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1523 /* remove the message from the dispatching list */
1524 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1526 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1529 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1531 /* wake the sender's thread */
1532 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1534 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1537 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1539 if (CurrentSentMessage
->Msg
.lParam
)
1540 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1543 /* Only if it is not a no wait message */
1544 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1546 /* dereference our and the sender's message queue */
1547 IntDereferenceMessageQueue(MessageQueue
);
1548 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1551 /* free the message */
1552 ExFreePool(CurrentSentMessage
);
1555 /* tell other threads not to bother returning any info to us */
1556 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
1558 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
1559 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1560 DispatchingListEntry
);
1561 CurrentSentMessage
->CompletionEvent
= NULL
;
1562 CurrentSentMessage
->Result
= NULL
;
1564 /* do NOT dereference our message queue as it might get attempted to be
1570 PUSER_MESSAGE_QUEUE FASTCALL
1571 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
1573 PUSER_MESSAGE_QUEUE MessageQueue
;
1575 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
1576 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
1584 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
1585 /* hold at least one reference until it'll be destroyed */
1586 IntReferenceMessageQueue(MessageQueue
);
1587 /* initialize the queue */
1588 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
1590 IntDereferenceMessageQueue(MessageQueue
);
1594 return MessageQueue
;
1598 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1602 /* remove the message queue from any desktops */
1603 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
1605 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
1606 IntDereferenceMessageQueue(MessageQueue
);
1610 MsqCleanupMessageQueue(MessageQueue
);
1612 /* decrease the reference counter, if it hits zero, the queue will be freed */
1613 IntDereferenceMessageQueue(MessageQueue
);
1617 MsqGetHooks(PUSER_MESSAGE_QUEUE Queue
)
1619 return Queue
->Hooks
;
1623 MsqSetHooks(PUSER_MESSAGE_QUEUE Queue
, PHOOKTABLE Hooks
)
1625 Queue
->Hooks
= Hooks
;
1629 MsqSetMessageExtraInfo(LPARAM lParam
)
1633 PUSER_MESSAGE_QUEUE MessageQueue
;
1635 pti
= PsGetCurrentThreadWin32Thread();
1636 MessageQueue
= pti
->MessageQueue
;
1642 Ret
= MessageQueue
->ExtraInfo
;
1643 MessageQueue
->ExtraInfo
= lParam
;
1649 MsqGetMessageExtraInfo(VOID
)
1652 PUSER_MESSAGE_QUEUE MessageQueue
;
1654 pti
= PsGetCurrentThreadWin32Thread();
1655 MessageQueue
= pti
->MessageQueue
;
1661 return MessageQueue
->ExtraInfo
;
1665 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
1671 case MSQ_STATE_CAPTURE
:
1672 Prev
= MessageQueue
->CaptureWindow
;
1673 MessageQueue
->CaptureWindow
= hWnd
;
1675 case MSQ_STATE_ACTIVE
:
1676 Prev
= MessageQueue
->ActiveWindow
;
1677 MessageQueue
->ActiveWindow
= hWnd
;
1679 case MSQ_STATE_FOCUS
:
1680 Prev
= MessageQueue
->FocusWindow
;
1681 MessageQueue
->FocusWindow
= hWnd
;
1683 case MSQ_STATE_MENUOWNER
:
1684 Prev
= MessageQueue
->MenuOwner
;
1685 MessageQueue
->MenuOwner
= hWnd
;
1687 case MSQ_STATE_MOVESIZE
:
1688 Prev
= MessageQueue
->MoveSize
;
1689 MessageQueue
->MoveSize
= hWnd
;
1691 case MSQ_STATE_CARET
:
1692 ASSERT(MessageQueue
->CaretInfo
);
1693 Prev
= MessageQueue
->CaretInfo
->hWnd
;
1694 MessageQueue
->CaretInfo
->hWnd
= hWnd
;