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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Message queues
24 * FILE: subsys/win32k/ntuser/msgqueue.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH Created
30 /* INCLUDES ******************************************************************/
35 #include <win32k/debug1.h>
38 /* GLOBALS *******************************************************************/
40 #define SYSTEM_MESSAGE_QUEUE_SIZE (256)
42 static MSG SystemMessageQueue
[SYSTEM_MESSAGE_QUEUE_SIZE
];
43 static ULONG SystemMessageQueueHead
= 0;
44 static ULONG SystemMessageQueueTail
= 0;
45 static ULONG SystemMessageQueueCount
= 0;
46 static ULONG SystemMessageQueueMouseMove
= -1;
47 static KSPIN_LOCK SystemMessageQueueLock
;
49 static ULONG
volatile HardwareMessageQueueStamp
= 0;
50 static LIST_ENTRY HardwareMessageQueueHead
;
51 static KMUTEX HardwareMessageQueueLock
;
53 static KEVENT HardwareMessageEvent
;
55 static PAGED_LOOKASIDE_LIST MessageLookasideList
;
56 static PAGED_LOOKASIDE_LIST TimerLookasideList
;
58 #define IntLockSystemMessageQueue(OldIrql) \
59 KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql)
61 #define IntUnLockSystemMessageQueue(OldIrql) \
62 KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql)
64 #define IntUnLockSystemHardwareMessageQueueLock(Wait) \
65 KeReleaseMutex(&HardwareMessageQueueLock, Wait)
67 /* FUNCTIONS *****************************************************************/
70 IntMsqSetWakeMask(DWORD WakeMask
)
72 PW32THREAD Win32Thread
;
73 PUSER_MESSAGE_QUEUE MessageQueue
;
74 HANDLE MessageEventHandle
;
76 Win32Thread
= PsGetWin32Thread();
77 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
80 MessageQueue
= Win32Thread
->MessageQueue
;
81 IntLockMessageQueue(MessageQueue
);
82 MessageQueue
->WakeMask
= WakeMask
;
83 MessageEventHandle
= MessageQueue
->NewMessagesHandle
;
84 IntUnLockMessageQueue(MessageQueue
);
86 return MessageEventHandle
;
90 IntMsqClearWakeMask(VOID
)
92 PW32THREAD Win32Thread
;
93 PUSER_MESSAGE_QUEUE MessageQueue
;
95 Win32Thread
= PsGetWin32Thread();
96 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
99 MessageQueue
= Win32Thread
->MessageQueue
;
100 IntLockMessageQueue(MessageQueue
);
101 MessageQueue
->WakeMask
= ~0;
102 IntUnLockMessageQueue(MessageQueue
);
108 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
110 IntLockMessageQueue(Queue
);
112 Queue
->PaintPosted
= TRUE
;
113 Queue
->QueueBits
|= QS_PAINT
;
114 Queue
->ChangedBits
|= QS_PAINT
;
115 if (Queue
->WakeMask
& QS_PAINT
)
116 KeSetEvent(Queue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
117 IntUnLockMessageQueue(Queue
);
121 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
123 IntLockMessageQueue(Queue
);
125 if (Queue
->PaintCount
== 0)
127 Queue
->PaintPosted
= FALSE
;
129 IntUnLockMessageQueue(Queue
);
134 MsqInitializeImpl(VOID
)
136 /*CurrentFocusMessageQueue = NULL;*/
137 InitializeListHead(&HardwareMessageQueueHead
);
138 KeInitializeEvent(&HardwareMessageEvent
, NotificationEvent
, 0);
139 KeInitializeSpinLock(&SystemMessageQueueLock
);
140 KeInitializeMutex(&HardwareMessageQueueLock
, 0);
142 ExInitializePagedLookasideList(&MessageLookasideList
,
146 sizeof(USER_MESSAGE
),
149 ExInitializePagedLookasideList(&TimerLookasideList
,
157 return(STATUS_SUCCESS
);
161 MsqInsertSystemMessage(MSG
* Msg
)
163 LARGE_INTEGER LargeTickCount
;
165 ULONG mmov
= (ULONG
)-1;
167 KeQueryTickCount(&LargeTickCount
);
168 Msg
->time
= LargeTickCount
.u
.LowPart
;
170 IntLockSystemMessageQueue(OldIrql
);
172 /* only insert WM_MOUSEMOVE messages if not already in system message queue */
173 if(Msg
->message
== WM_MOUSEMOVE
)
174 mmov
= SystemMessageQueueMouseMove
;
176 if(mmov
!= (ULONG
)-1)
178 /* insert message at the queue head */
179 while (mmov
!= SystemMessageQueueHead
)
181 ULONG prev
= mmov
? mmov
- 1 : SYSTEM_MESSAGE_QUEUE_SIZE
- 1;
182 ASSERT((LONG
) mmov
>= 0);
183 ASSERT(mmov
< SYSTEM_MESSAGE_QUEUE_SIZE
);
184 SystemMessageQueue
[mmov
] = SystemMessageQueue
[prev
];
187 SystemMessageQueue
[SystemMessageQueueHead
] = *Msg
;
191 if (SystemMessageQueueCount
== SYSTEM_MESSAGE_QUEUE_SIZE
)
193 IntUnLockSystemMessageQueue(OldIrql
);
196 SystemMessageQueue
[SystemMessageQueueTail
] = *Msg
;
197 if(Msg
->message
== WM_MOUSEMOVE
)
198 SystemMessageQueueMouseMove
= SystemMessageQueueTail
;
199 SystemMessageQueueTail
=
200 (SystemMessageQueueTail
+ 1) % SYSTEM_MESSAGE_QUEUE_SIZE
;
201 SystemMessageQueueCount
++;
203 IntUnLockSystemMessageQueue(OldIrql
);
204 KeSetEvent(&HardwareMessageEvent
, IO_NO_INCREMENT
, FALSE
);
208 MsqIsDblClk(LPMSG Msg
, BOOL Remove
)
210 PWINSTATION_OBJECT WinStaObject
;
211 PSYSTEM_CURSORINFO CurInfo
;
215 if (PsGetWin32Thread()->Desktop
== NULL
)
219 WinStaObject
= PsGetWin32Thread()->Desktop
->WindowStation
;
221 CurInfo
= IntGetSysCursorInfo(WinStaObject
);
222 Res
= (Msg
->hwnd
== (HWND
)CurInfo
->LastClkWnd
) &&
223 ((Msg
->time
- CurInfo
->LastBtnDown
) < CurInfo
->DblClickSpeed
);
227 dX
= CurInfo
->LastBtnDownX
- Msg
->pt
.x
;
228 dY
= CurInfo
->LastBtnDownY
- Msg
->pt
.y
;
232 Res
= (dX
<= CurInfo
->DblClickWidth
) &&
233 (dY
<= CurInfo
->DblClickHeight
);
240 CurInfo
->LastBtnDown
= 0;
241 CurInfo
->LastBtnDownX
= Msg
->pt
.x
;
242 CurInfo
->LastBtnDownY
= Msg
->pt
.y
;
243 CurInfo
->LastClkWnd
= NULL
;
247 CurInfo
->LastBtnDownX
= Msg
->pt
.x
;
248 CurInfo
->LastBtnDownY
= Msg
->pt
.y
;
249 CurInfo
->LastClkWnd
= (HANDLE
)Msg
->hwnd
;
250 CurInfo
->LastBtnDown
= Msg
->time
;
258 MsqTranslateMouseMessage(PUSER_MESSAGE_QUEUE MessageQueue
, HWND hWnd
, UINT FilterLow
, UINT FilterHigh
,
259 PUSER_MESSAGE Message
, BOOL Remove
, PBOOL Freed
,
260 PWINDOW_OBJECT ScopeWin
, PPOINT ScreenPoint
, BOOL FromGlobalQueue
)
262 USHORT Msg
= Message
->Msg
.message
;
263 PWINDOW_OBJECT Window
= NULL
;
266 CaptureWin
= IntGetCaptureWindow();
267 if (CaptureWin
== NULL
)
269 if(Msg
== WM_MOUSEWHEEL
)
271 Window
= IntGetWindowObject(IntGetFocusWindow());
275 WinPosWindowFromPoint(ScopeWin
, NULL
, &Message
->Msg
.pt
, &Window
);
279 IntReferenceWindowObject(Window
);
285 /* FIXME - window messages should go to the right window if no buttons are
287 Window
= IntGetWindowObject(CaptureWin
);
294 RemoveEntryList(&Message
->ListEntry
);
295 if(MessageQueue
->MouseMoveMsg
== Message
)
297 MessageQueue
->MouseMoveMsg
= NULL
;
305 if (Window
->MessageQueue
!= MessageQueue
)
307 if (! FromGlobalQueue
)
309 DPRINT("Moving msg between private queues\n");
310 /* This message is already queued in a private queue, but we need
311 * to move it to a different queue, perhaps because a new window
312 * was created which now covers the screen area previously taken
313 * by another window. To move it, we need to take it out of the
314 * old queue. Note that we're already holding the lock mutexes of the
316 RemoveEntryList(&Message
->ListEntry
);
318 /* remove the pointer for the current WM_MOUSEMOVE message in case we
320 if(MessageQueue
->MouseMoveMsg
== Message
)
322 MessageQueue
->MouseMoveMsg
= NULL
;
326 /* lock the destination message queue, so we don't get in trouble with other
327 threads, messing with it at the same time */
328 IntLockHardwareMessageQueue(Window
->MessageQueue
);
329 InsertTailList(&Window
->MessageQueue
->HardwareMessagesListHead
,
330 &Message
->ListEntry
);
331 if(Message
->Msg
.message
== WM_MOUSEMOVE
)
333 if(Window
->MessageQueue
->MouseMoveMsg
)
335 /* remove the old WM_MOUSEMOVE message, we're processing a more recent
337 RemoveEntryList(&Window
->MessageQueue
->MouseMoveMsg
->ListEntry
);
338 ExFreePool(Window
->MessageQueue
->MouseMoveMsg
);
340 /* save the pointer to the WM_MOUSEMOVE message in the new queue */
341 Window
->MessageQueue
->MouseMoveMsg
= Message
;
343 Window
->MessageQueue
->QueueBits
|= QS_MOUSEMOVE
;
344 Window
->MessageQueue
->ChangedBits
|= QS_MOUSEMOVE
;
345 if (Window
->MessageQueue
->WakeMask
& QS_MOUSEMOVE
)
346 KeSetEvent(Window
->MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
350 Window
->MessageQueue
->QueueBits
|= QS_MOUSEBUTTON
;
351 Window
->MessageQueue
->ChangedBits
|= QS_MOUSEBUTTON
;
352 if (Window
->MessageQueue
->WakeMask
& QS_MOUSEBUTTON
)
353 KeSetEvent(Window
->MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
355 IntUnLockHardwareMessageQueue(Window
->MessageQueue
);
358 IntReleaseWindowObject(Window
);
362 /* From here on, we're in the same message queue as the caller! */
364 *ScreenPoint
= Message
->Msg
.pt
;
366 if((hWnd
!= NULL
&& Window
->Self
!= hWnd
) ||
367 ((FilterLow
!= 0 || FilterLow
!= 0) && (Msg
< FilterLow
|| Msg
> FilterHigh
)))
369 /* Reject the message because it doesn't match the filter */
373 /* Lock the message queue so no other thread can mess with it.
374 Our own message queue is not locked while fetching from the global
375 queue, so we have to make sure nothing interferes! */
376 IntLockHardwareMessageQueue(Window
->MessageQueue
);
377 /* if we're from the global queue, we need to add our message to our
378 private queue so we don't loose it! */
379 InsertTailList(&Window
->MessageQueue
->HardwareMessagesListHead
,
380 &Message
->ListEntry
);
383 if (Message
->Msg
.message
== WM_MOUSEMOVE
)
385 if(Window
->MessageQueue
->MouseMoveMsg
&&
386 (Window
->MessageQueue
->MouseMoveMsg
!= Message
))
388 /* delete the old message */
389 RemoveEntryList(&Window
->MessageQueue
->MouseMoveMsg
->ListEntry
);
390 ExFreePool(Window
->MessageQueue
->MouseMoveMsg
);
392 /* always save a pointer to this WM_MOUSEMOVE message here because we're
393 sure that the message is in the private queue */
394 Window
->MessageQueue
->MouseMoveMsg
= Message
;
398 IntUnLockHardwareMessageQueue(Window
->MessageQueue
);
401 IntReleaseWindowObject(Window
);
406 /* FIXME - only assign if removing? */
407 Message
->Msg
.hwnd
= Window
->Self
;
408 Message
->Msg
.message
= Msg
;
409 Message
->Msg
.lParam
= MAKELONG(Message
->Msg
.pt
.x
, Message
->Msg
.pt
.y
);
411 /* remove the reference to the current WM_(NC)MOUSEMOVE message, if this message
413 if (Message
->Msg
.message
== WM_MOUSEMOVE
||
414 Message
->Msg
.message
== WM_NCMOUSEMOVE
)
418 /* Lock the message queue so no other thread can mess with it.
419 Our own message queue is not locked while fetching from the global
420 queue, so we have to make sure nothing interferes! */
421 IntLockHardwareMessageQueue(Window
->MessageQueue
);
422 if(Window
->MessageQueue
->MouseMoveMsg
)
424 /* delete the WM_(NC)MOUSEMOVE message in the private queue, we're dealing
425 with one that's been sent later */
426 RemoveEntryList(&Window
->MessageQueue
->MouseMoveMsg
->ListEntry
);
427 ExFreePool(Window
->MessageQueue
->MouseMoveMsg
);
428 /* our message is not in the private queue so we can remove the pointer
429 instead of setting it to the current message we're processing */
430 Window
->MessageQueue
->MouseMoveMsg
= NULL
;
432 IntUnLockHardwareMessageQueue(Window
->MessageQueue
);
434 else if(Window
->MessageQueue
->MouseMoveMsg
== Message
)
436 Window
->MessageQueue
->MouseMoveMsg
= NULL
;
440 IntReleaseWindowObject(Window
);
446 MsqPeekHardwareMessage(PUSER_MESSAGE_QUEUE MessageQueue
, HWND hWnd
,
447 UINT FilterLow
, UINT FilterHigh
, BOOL Remove
,
448 PUSER_MESSAGE
* Message
)
453 PLIST_ENTRY CurrentEntry
;
454 PWINDOW_OBJECT DesktopWindow
;
455 PVOID WaitObjects
[2];
458 if( !IntGetScreenDC() ||
459 PsGetWin32Thread()->MessageQueue
== W32kGetPrimitiveMessageQueue() )
464 WaitObjects
[1] = MessageQueue
->NewMessages
;
465 WaitObjects
[0] = &HardwareMessageQueueLock
;
468 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
469 UserMode
, FALSE
, NULL
, NULL
);
470 while (MsqDispatchOneSentMessage(MessageQueue
))
475 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
477 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
479 /* Process messages in the message queue itself. */
480 IntLockHardwareMessageQueue(MessageQueue
);
481 CurrentEntry
= MessageQueue
->HardwareMessagesListHead
.Flink
;
482 while (CurrentEntry
!= &MessageQueue
->HardwareMessagesListHead
)
484 PUSER_MESSAGE Current
=
485 CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
486 CurrentEntry
= CurrentEntry
->Flink
;
487 if (Current
->Msg
.message
>= WM_MOUSEFIRST
&&
488 Current
->Msg
.message
<= WM_MOUSELAST
)
490 Accept
= MsqTranslateMouseMessage(MessageQueue
, hWnd
, FilterLow
, FilterHigh
,
491 Current
, Remove
, &Freed
,
492 DesktopWindow
, &ScreenPoint
, FALSE
);
497 RemoveEntryList(&Current
->ListEntry
);
499 IntUnLockHardwareMessageQueue(MessageQueue
);
500 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
502 IntReleaseWindowObject(DesktopWindow
);
508 IntUnLockHardwareMessageQueue(MessageQueue
);
510 /* Now try the global queue. */
512 /* Transfer all messages from the DPC accessible queue to the main queue. */
513 IntLockSystemMessageQueue(OldIrql
);
514 while (SystemMessageQueueCount
> 0)
516 PUSER_MESSAGE UserMsg
;
520 ASSERT(SystemMessageQueueHead
< SYSTEM_MESSAGE_QUEUE_SIZE
);
521 Msg
= SystemMessageQueue
[SystemMessageQueueHead
];
522 SystemMessageQueueHead
=
523 (SystemMessageQueueHead
+ 1) % SYSTEM_MESSAGE_QUEUE_SIZE
;
524 SystemMessageQueueCount
--;
525 IntUnLockSystemMessageQueue(OldIrql
);
526 if (WM_MOUSEFIRST
<= Msg
.message
&& Msg
.message
<= WM_MOUSELAST
)
528 MSLLHOOKSTRUCT MouseHookData
;
530 MouseHookData
.pt
.x
= GET_X_LPARAM(Msg
.lParam
);
531 MouseHookData
.pt
.y
= GET_Y_LPARAM(Msg
.lParam
);
535 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
.wParam
));
539 case WM_XBUTTONDBLCLK
:
540 case WM_NCXBUTTONDOWN
:
542 case WM_NCXBUTTONDBLCLK
:
543 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
.wParam
));
546 MouseHookData
.mouseData
= 0;
549 MouseHookData
.flags
= 0;
550 MouseHookData
.time
= Msg
.time
;
551 MouseHookData
.dwExtraInfo
= 0;
552 ProcessMessage
= (0 == HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
,
553 Msg
.message
, (LPARAM
) &MouseHookData
));
557 ProcessMessage
= TRUE
;
561 UserMsg
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
562 /* What to do if out of memory? For now we just panic a bit in debug */
564 UserMsg
->FreeLParam
= FALSE
;
566 InsertTailList(&HardwareMessageQueueHead
, &UserMsg
->ListEntry
);
568 IntLockSystemMessageQueue(OldIrql
);
571 * we could set this to -1 conditionally if we find one, but
572 * this is more efficient and just as effective.
574 SystemMessageQueueMouseMove
= -1;
575 HardwareMessageQueueStamp
++;
576 IntUnLockSystemMessageQueue(OldIrql
);
578 /* Process messages in the queue until we find one to return. */
579 CurrentEntry
= HardwareMessageQueueHead
.Flink
;
580 while (CurrentEntry
!= &HardwareMessageQueueHead
)
582 PUSER_MESSAGE Current
=
583 CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
584 CurrentEntry
= CurrentEntry
->Flink
;
585 RemoveEntryList(&Current
->ListEntry
);
586 HardwareMessageQueueStamp
++;
587 if (Current
->Msg
.message
>= WM_MOUSEFIRST
&&
588 Current
->Msg
.message
<= WM_MOUSELAST
)
590 const ULONG ActiveStamp
= HardwareMessageQueueStamp
;
591 /* Translate the message. */
592 Accept
= MsqTranslateMouseMessage(MessageQueue
, hWnd
, FilterLow
, FilterHigh
,
593 Current
, Remove
, &Freed
,
594 DesktopWindow
, &ScreenPoint
, TRUE
);
597 /* Check for no more messages in the system queue. */
598 IntLockSystemMessageQueue(OldIrql
);
599 if (SystemMessageQueueCount
== 0 &&
600 IsListEmpty(&HardwareMessageQueueHead
))
602 KeClearEvent(&HardwareMessageEvent
);
604 IntUnLockSystemMessageQueue(OldIrql
);
607 If we aren't removing the message then add it to the private
612 IntLockHardwareMessageQueue(MessageQueue
);
613 if(Current
->Msg
.message
== WM_MOUSEMOVE
)
615 if(MessageQueue
->MouseMoveMsg
)
617 RemoveEntryList(&MessageQueue
->MouseMoveMsg
->ListEntry
);
618 ExFreePool(MessageQueue
->MouseMoveMsg
);
620 MessageQueue
->MouseMoveMsg
= Current
;
622 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
623 &Current
->ListEntry
);
624 IntUnLockHardwareMessageQueue(MessageQueue
);
626 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
628 IntReleaseWindowObject(DesktopWindow
);
631 /* If the contents of the queue changed then restart processing. */
632 if (HardwareMessageQueueStamp
!= ActiveStamp
)
634 CurrentEntry
= HardwareMessageQueueHead
.Flink
;
639 IntReleaseWindowObject(DesktopWindow
);
640 /* Check if the system message queue is now empty. */
641 IntLockSystemMessageQueue(OldIrql
);
642 if (SystemMessageQueueCount
== 0 && IsListEmpty(&HardwareMessageQueueHead
))
644 KeClearEvent(&HardwareMessageEvent
);
646 IntUnLockSystemMessageQueue(OldIrql
);
647 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
653 MsqPostKeyboardMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
655 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
657 LARGE_INTEGER LargeTickCount
;
658 KBDLLHOOKSTRUCT KbdHookData
;
660 DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
661 uMsg
, wParam
, lParam
);
668 KeQueryTickCount(&LargeTickCount
);
669 Msg
.time
= LargeTickCount
.u
.LowPart
;
670 /* We can't get the Msg.pt point here since we don't know thread
671 (and thus the window station) the message will end up in yet. */
673 KbdHookData
.vkCode
= Msg
.wParam
;
674 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
675 KbdHookData
.flags
= (0 == (Msg
.lParam
& 0x01000000) ? 0 : LLKHF_EXTENDED
) |
676 (0 == (Msg
.lParam
& 0x20000000) ? 0 : LLKHF_ALTDOWN
) |
677 (0 == (Msg
.lParam
& 0x80000000) ? 0 : LLKHF_UP
);
678 KbdHookData
.time
= Msg
.time
;
679 KbdHookData
.dwExtraInfo
= 0;
680 if (HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
682 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
683 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
687 FocusMessageQueue
= IntGetFocusMessageQueue();
688 if( !IntGetScreenDC() ) {
689 /* FIXME: What to do about Msg.pt here? */
690 if( W32kGetPrimitiveMessageQueue() ) {
691 MsqPostMessage(W32kGetPrimitiveMessageQueue(), &Msg
, FALSE
, QS_KEY
);
694 if (FocusMessageQueue
== NULL
)
696 DPRINT("No focus message queue\n");
700 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
702 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
703 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
704 IntGetCursorLocation(FocusMessageQueue
->Desktop
->WindowStation
,
706 MsqPostMessage(FocusMessageQueue
, &Msg
, FALSE
, QS_KEY
);
710 DPRINT("Invalid focus window handle\n");
716 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
718 PWINDOW_OBJECT Window
;
719 PW32THREAD Win32Thread
;
720 PWINSTATION_OBJECT WinSta
;
722 LARGE_INTEGER LargeTickCount
;
725 Status
= ObReferenceObjectByPointer (Thread
,
729 if (!NT_SUCCESS(Status
))
732 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
733 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
735 ObDereferenceObject ((PETHREAD
)Thread
);
739 WinSta
= Win32Thread
->Desktop
->WindowStation
;
740 Status
= ObmReferenceObjectByHandle(WinSta
->HandleTable
,
741 hWnd
, otWindow
, (PVOID
*)&Window
);
742 if (!NT_SUCCESS(Status
))
744 ObDereferenceObject ((PETHREAD
)Thread
);
749 Mesg
.message
= WM_HOTKEY
;
750 Mesg
.wParam
= wParam
;
751 Mesg
.lParam
= lParam
;
752 KeQueryTickCount(&LargeTickCount
);
753 Mesg
.time
= LargeTickCount
.u
.LowPart
;
754 IntGetCursorLocation(WinSta
, &Mesg
.pt
);
755 MsqPostMessage(Window
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
756 ObmDereferenceObject(Window
);
757 ObDereferenceObject (Thread
);
759 // IntLockMessageQueue(pThread->MessageQueue);
760 // InsertHeadList(&pThread->MessageQueue->PostedMessagesListHead,
761 // &Message->ListEntry);
762 // KeSetEvent(pThread->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
763 // IntUnLockMessageQueue(pThread->MessageQueue);
767 PUSER_MESSAGE FASTCALL
768 MsqCreateMessage(LPMSG Msg
, BOOLEAN FreeLParam
)
770 PUSER_MESSAGE Message
;
772 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
778 Message
->FreeLParam
= FreeLParam
;
779 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
785 MsqDestroyMessage(PUSER_MESSAGE Message
)
787 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
791 MsqDispatchSentNotifyMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
793 PLIST_ENTRY ListEntry
;
794 PUSER_SENT_MESSAGE_NOTIFY Message
;
796 IntLockMessageQueue(MessageQueue
);
797 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
799 ListEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
800 Message
= CONTAINING_RECORD(ListEntry
, USER_SENT_MESSAGE_NOTIFY
,
802 IntUnLockMessageQueue(MessageQueue
);
804 IntCallSentMessageCallback(Message
->CompletionCallback
,
807 Message
->CompletionCallbackContext
,
810 IntLockMessageQueue(MessageQueue
);
812 IntUnLockMessageQueue(MessageQueue
);
816 MsqPeekSentMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
818 return(!IsListEmpty(&MessageQueue
->SentMessagesListHead
));
822 MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
824 PUSER_SENT_MESSAGE Message
;
828 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage
;
830 IntLockMessageQueue(MessageQueue
);
831 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
833 IntUnLockMessageQueue(MessageQueue
);
837 /* remove it from the list of pending messages */
838 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
839 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
841 /* insert it to the list of messages that are currently dispatched by this
843 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
844 &Message
->ListEntry
);
846 IntUnLockMessageQueue(MessageQueue
);
848 if (Message
->HookMessage
)
850 Result
= HOOK_CallHooks(Message
->Msg
.message
,
851 (INT
) Message
->Msg
.hwnd
,
853 Message
->Msg
.lParam
);
857 /* Call the window procedure. */
858 Result
= IntSendMessage(Message
->Msg
.hwnd
,
859 Message
->Msg
.message
,
861 Message
->Msg
.lParam
);
864 /* remove the message from the local dispatching list, because it doesn't need
865 to be cleaned up on thread termination anymore */
866 IntLockMessageQueue(MessageQueue
);
867 RemoveEntryList(&Message
->ListEntry
);
868 IntUnLockMessageQueue(MessageQueue
);
870 /* remove the message from the dispatching list, so lock the sender's message queue */
871 IntLockMessageQueue(Message
->SenderQueue
);
873 SenderReturned
= (Message
->DispatchingListEntry
.Flink
== NULL
);
876 /* only remove it from the dispatching list if not already removed by a timeout */
877 RemoveEntryList(&Message
->DispatchingListEntry
);
879 /* still keep the sender's message queue locked, so the sender can't exit the
880 MsqSendMessage() function (if timed out) */
882 /* Let the sender know the result. */
883 if (Message
->Result
!= NULL
)
885 *Message
->Result
= Result
;
888 /* Notify the sender. */
889 if (Message
->CompletionEvent
!= NULL
)
891 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
894 /* unlock the sender's message queue, the safe operation is done */
895 IntUnLockMessageQueue(Message
->SenderQueue
);
897 /* Notify the sender if they specified a callback. */
898 if (!SenderReturned
&& Message
->CompletionCallback
!= NULL
)
900 if(!(NotifyMessage
= ExAllocatePoolWithTag(NonPagedPool
,
901 sizeof(USER_SENT_MESSAGE_NOTIFY
), TAG_USRMSG
)))
903 DPRINT1("MsqDispatchOneSentMessage(): Not enough memory to create a callback notify message\n");
906 NotifyMessage
->CompletionCallback
=
907 Message
->CompletionCallback
;
908 NotifyMessage
->CompletionCallbackContext
=
909 Message
->CompletionCallbackContext
;
910 NotifyMessage
->Result
= Result
;
911 NotifyMessage
->hWnd
= Message
->Msg
.hwnd
;
912 NotifyMessage
->Msg
= Message
->Msg
.message
;
913 MsqSendNotifyMessage(Message
->SenderQueue
, NotifyMessage
);
918 /* dereference both sender and our queue */
919 IntDereferenceMessageQueue(MessageQueue
);
920 IntDereferenceMessageQueue(Message
->SenderQueue
);
922 /* free the message */
928 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
930 PUSER_SENT_MESSAGE SentMessage
;
931 PUSER_MESSAGE PostedMessage
;
932 PUSER_MESSAGE_QUEUE MessageQueue
;
933 PLIST_ENTRY CurrentEntry
, ListHead
;
934 PWINDOW_OBJECT Window
= pWindow
;
938 MessageQueue
= Window
->MessageQueue
;
939 ASSERT(MessageQueue
);
941 IntLockMessageQueue(MessageQueue
);
943 /* remove the posted messages for this window */
944 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
945 ListHead
= &MessageQueue
->PostedMessagesListHead
;
946 while (CurrentEntry
!= ListHead
)
948 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
950 if (PostedMessage
->Msg
.hwnd
== Window
->Self
)
952 RemoveEntryList(&PostedMessage
->ListEntry
);
953 MsqDestroyMessage(PostedMessage
);
954 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
958 CurrentEntry
= CurrentEntry
->Flink
;
962 /* remove the sent messages for this window */
963 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
964 ListHead
= &MessageQueue
->SentMessagesListHead
;
965 while (CurrentEntry
!= ListHead
)
967 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
968 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
970 if(SentMessage
->Msg
.hwnd
== Window
->Self
)
972 IntLockMessageQueue(SentMessage
->SenderQueue
);
973 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
975 /* remove the message from the dispatching list */
976 if(SentMessage
->DispatchingListEntry
.Flink
!= NULL
)
978 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
981 /* wake the sender's thread */
982 if (SentMessage
->CompletionEvent
!= NULL
)
984 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
986 IntUnLockMessageQueue(SentMessage
->SenderQueue
);
988 /* dereference our and the sender's message queue */
989 IntDereferenceMessageQueue(MessageQueue
);
990 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
992 /* free the message */
993 ExFreePool(SentMessage
);
995 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
999 CurrentEntry
= CurrentEntry
->Flink
;
1002 IntUnLockMessageQueue(MessageQueue
);
1006 MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1007 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage
)
1009 IntLockMessageQueue(MessageQueue
);
1010 InsertTailList(&MessageQueue
->NotifyMessagesListHead
,
1011 &NotifyMessage
->ListEntry
);
1012 MessageQueue
->QueueBits
|= QS_SENDMESSAGE
;
1013 MessageQueue
->ChangedBits
|= QS_SENDMESSAGE
;
1014 if (MessageQueue
->WakeMask
& QS_SENDMESSAGE
)
1015 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1016 IntUnLockMessageQueue(MessageQueue
);
1020 MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1021 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
1022 UINT uTimeout
, BOOL Block
, BOOL HookMessage
,
1025 PUSER_SENT_MESSAGE Message
;
1026 KEVENT CompletionEvent
;
1027 NTSTATUS WaitStatus
;
1029 PUSER_MESSAGE_QUEUE ThreadQueue
;
1030 LARGE_INTEGER Timeout
;
1033 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1035 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1036 return STATUS_INSUFFICIENT_RESOURCES
;
1039 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1041 ThreadQueue
= PsGetWin32Thread()->MessageQueue
;
1042 ASSERT(ThreadQueue
!= MessageQueue
);
1044 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1046 /* FIXME - increase reference counter of sender's message queue here */
1049 Message
->Msg
.hwnd
= Wnd
;
1050 Message
->Msg
.message
= Msg
;
1051 Message
->Msg
.wParam
= wParam
;
1052 Message
->Msg
.lParam
= lParam
;
1053 Message
->CompletionEvent
= &CompletionEvent
;
1054 Message
->Result
= &Result
;
1055 Message
->SenderQueue
= ThreadQueue
;
1056 IntReferenceMessageQueue(ThreadQueue
);
1057 Message
->CompletionCallback
= NULL
;
1058 Message
->HookMessage
= HookMessage
;
1060 IntReferenceMessageQueue(MessageQueue
);
1062 /* add it to the list of pending messages */
1063 IntLockMessageQueue(ThreadQueue
);
1064 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1065 IntUnLockMessageQueue(ThreadQueue
);
1067 /* queue it in the destination's message queue */
1068 IntLockMessageQueue(MessageQueue
);
1069 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1070 IntUnLockMessageQueue(MessageQueue
);
1072 MessageQueue
->QueueBits
|= QS_SENDMESSAGE
;
1073 MessageQueue
->ChangedBits
|= QS_SENDMESSAGE
;
1074 if (MessageQueue
->WakeMask
& QS_SENDMESSAGE
)
1075 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1077 /* we can't access the Message anymore since it could have already been deleted! */
1081 /* don't process messages sent to the thread */
1082 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1083 FALSE
, (uTimeout
? &Timeout
: NULL
));
1084 if(WaitStatus
== STATUS_TIMEOUT
)
1086 /* look up if the message has not yet dispatched, if so
1087 make sure it can't pass a result and it must not set the completion event anymore */
1088 IntLockMessageQueue(MessageQueue
);
1089 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1090 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1092 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1095 /* we can access Message here, it's secure because the message queue is locked
1096 and the message is still hasn't been dispatched */
1097 Message
->CompletionEvent
= NULL
;
1098 Message
->Result
= NULL
;
1101 Entry
= Entry
->Flink
;
1103 IntUnLockMessageQueue(MessageQueue
);
1105 /* remove from the local dispatching list so the other thread knows,
1106 it can't pass a result and it must not set the completion event anymore */
1107 IntLockMessageQueue(ThreadQueue
);
1108 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1109 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1111 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1114 /* we can access Message here, it's secure because the sender's message is locked
1115 and the message has definitely not yet been destroyed, otherwise it would
1116 have been removed from this list by the dispatching routine right after
1117 dispatching the message */
1118 Message
->CompletionEvent
= NULL
;
1119 Message
->Result
= NULL
;
1120 RemoveEntryList(&Message
->DispatchingListEntry
);
1123 Entry
= Entry
->Flink
;
1125 IntUnLockMessageQueue(ThreadQueue
);
1127 DPRINT("MsqSendMessage (blocked) timed out\n");
1129 while (MsqDispatchOneSentMessage(ThreadQueue
));
1133 PVOID WaitObjects
[2];
1135 WaitObjects
[0] = &CompletionEvent
;
1136 WaitObjects
[1] = ThreadQueue
->NewMessages
;
1139 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1140 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1141 if(WaitStatus
== STATUS_TIMEOUT
)
1143 /* look up if the message has not yet been dispatched, if so
1144 make sure it can't pass a result and it must not set the completion event anymore */
1145 IntLockMessageQueue(MessageQueue
);
1146 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1147 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1149 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1152 /* we can access Message here, it's secure because the message queue is locked
1153 and the message is still hasn't been dispatched */
1154 Message
->CompletionEvent
= NULL
;
1155 Message
->Result
= NULL
;
1158 Entry
= Entry
->Flink
;
1160 IntUnLockMessageQueue(MessageQueue
);
1162 /* remove from the local dispatching list so the other thread knows,
1163 it can't pass a result and it must not set the completion event anymore */
1164 IntLockMessageQueue(ThreadQueue
);
1165 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1166 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1168 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1171 /* we can access Message here, it's secure because the sender's message is locked
1172 and the message has definitely not yet been destroyed, otherwise it would
1173 have been removed from this list by the dispatching routine right after
1174 dispatching the message */
1175 Message
->CompletionEvent
= NULL
;
1176 Message
->Result
= NULL
;
1177 RemoveEntryList(&Message
->DispatchingListEntry
);
1180 Entry
= Entry
->Flink
;
1182 IntUnLockMessageQueue(ThreadQueue
);
1184 DPRINT("MsqSendMessage timed out\n");
1187 while (MsqDispatchOneSentMessage(ThreadQueue
));
1189 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
1192 if(WaitStatus
!= STATUS_TIMEOUT
)
1193 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1199 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN FreeLParam
,
1202 PUSER_MESSAGE Message
;
1204 if(!(Message
= MsqCreateMessage(Msg
, FreeLParam
)))
1208 IntLockMessageQueue(MessageQueue
);
1209 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1210 &Message
->ListEntry
);
1211 MessageQueue
->QueueBits
|= MessageBits
;
1212 MessageQueue
->ChangedBits
|= MessageBits
;
1213 if (MessageQueue
->WakeMask
& MessageBits
)
1214 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1215 IntUnLockMessageQueue(MessageQueue
);
1219 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1221 IntLockMessageQueue(MessageQueue
);
1222 MessageQueue
->QuitPosted
= TRUE
;
1223 MessageQueue
->QuitExitCode
= ExitCode
;
1224 MessageQueue
->QueueBits
|= QS_POSTMESSAGE
;
1225 MessageQueue
->ChangedBits
|= QS_POSTMESSAGE
;
1226 if (MessageQueue
->WakeMask
& QS_POSTMESSAGE
)
1227 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1228 IntUnLockMessageQueue(MessageQueue
);
1232 MsqFindMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1233 IN BOOLEAN Hardware
,
1236 IN UINT MsgFilterLow
,
1237 IN UINT MsgFilterHigh
,
1238 OUT PUSER_MESSAGE
* Message
)
1240 PLIST_ENTRY CurrentEntry
;
1241 PUSER_MESSAGE CurrentMessage
;
1242 PLIST_ENTRY ListHead
;
1246 return(MsqPeekHardwareMessage(MessageQueue
, Wnd
,
1247 MsgFilterLow
, MsgFilterHigh
,
1251 IntLockMessageQueue(MessageQueue
);
1252 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1253 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1254 while (CurrentEntry
!= ListHead
)
1256 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1258 if ((Wnd
== 0 || Wnd
== CurrentMessage
->Msg
.hwnd
) &&
1259 ((MsgFilterLow
== 0 && MsgFilterHigh
== 0) ||
1260 (MsgFilterLow
<= CurrentMessage
->Msg
.message
&&
1261 MsgFilterHigh
>= CurrentMessage
->Msg
.message
)))
1265 RemoveEntryList(&CurrentMessage
->ListEntry
);
1267 IntUnLockMessageQueue(MessageQueue
);
1268 *Message
= CurrentMessage
;
1271 CurrentEntry
= CurrentEntry
->Flink
;
1273 IntUnLockMessageQueue(MessageQueue
);
1278 MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, HWND WndFilter
,
1279 UINT MsgFilterMin
, UINT MsgFilterMax
)
1281 PVOID WaitObjects
[2] = {MessageQueue
->NewMessages
, &HardwareMessageEvent
};
1282 LARGE_INTEGER TimerExpiry
;
1283 PLARGE_INTEGER Timeout
;
1285 if (MsqGetFirstTimerExpiry(MessageQueue
, WndFilter
, MsgFilterMin
, MsgFilterMax
, &TimerExpiry
))
1287 Timeout
= &TimerExpiry
;
1294 return(KeWaitForMultipleObjects(2,
1305 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1307 LARGE_INTEGER LargeTickCount
;
1309 KeQueryTickCount(&LargeTickCount
);
1310 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1314 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1316 LARGE_INTEGER LargeTickCount
;
1319 MessageQueue
->Thread
= Thread
;
1320 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1321 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1322 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1323 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1324 InitializeListHead(&MessageQueue
->TimerListHead
);
1325 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1326 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1327 KeInitializeMutex(&MessageQueue
->HardwareLock
, 0);
1328 ExInitializeFastMutex(&MessageQueue
->Lock
);
1329 MessageQueue
->QuitPosted
= FALSE
;
1330 MessageQueue
->QuitExitCode
= 0;
1331 KeQueryTickCount(&LargeTickCount
);
1332 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1333 MessageQueue
->FocusWindow
= NULL
;
1334 MessageQueue
->PaintPosted
= FALSE
;
1335 MessageQueue
->PaintCount
= 0;
1336 MessageQueue
->WakeMask
= ~0;
1337 MessageQueue
->NewMessagesHandle
= NULL
;
1339 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1340 NULL
, SynchronizationEvent
, FALSE
);
1341 if (!NT_SUCCESS(Status
))
1346 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1347 ExEventObjectType
, KernelMode
,
1348 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1349 if (!NT_SUCCESS(Status
))
1351 ZwClose(MessageQueue
->NewMessagesHandle
);
1352 MessageQueue
->NewMessagesHandle
= NULL
;
1360 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1362 PLIST_ENTRY CurrentEntry
;
1363 PUSER_MESSAGE CurrentMessage
;
1364 PTIMER_ENTRY CurrentTimer
;
1365 PUSER_SENT_MESSAGE CurrentSentMessage
;
1367 IntLockMessageQueue(MessageQueue
);
1369 /* cleanup posted messages */
1370 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1372 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1373 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1375 MsqDestroyMessage(CurrentMessage
);
1378 /* remove the messages that have not yet been dispatched */
1379 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1381 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1382 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1385 IntLockMessageQueue(CurrentSentMessage
->SenderQueue
);
1386 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1388 /* remove the message from the dispatching list */
1389 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1391 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1394 /* wake the sender's thread */
1395 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1397 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1399 IntUnLockMessageQueue(CurrentSentMessage
->SenderQueue
);
1401 /* dereference our and the sender's message queue */
1402 IntDereferenceMessageQueue(MessageQueue
);
1403 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1405 /* free the message */
1406 ExFreePool(CurrentSentMessage
);
1409 /* cleanup timers */
1410 while (! IsListEmpty(&MessageQueue
->TimerListHead
))
1412 CurrentEntry
= RemoveHeadList(&MessageQueue
->TimerListHead
);
1413 CurrentTimer
= CONTAINING_RECORD(CurrentEntry
, TIMER_ENTRY
, ListEntry
);
1414 ExFreeToPagedLookasideList(&TimerLookasideList
, CurrentTimer
);
1417 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1418 ExitThread() was called in a SendMessage() umode callback */
1419 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1421 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1422 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1425 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1427 /* wake the sender's thread */
1428 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1430 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1433 /* dereference our and the sender's message queue */
1434 IntDereferenceMessageQueue(MessageQueue
);
1435 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1437 /* free the message */
1438 ExFreePool(CurrentSentMessage
);
1441 /* tell other threads not to bother returning any info to us */
1442 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
1444 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
1445 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1446 DispatchingListEntry
);
1447 CurrentSentMessage
->CompletionEvent
= NULL
;
1448 CurrentSentMessage
->Result
= NULL
;
1450 /* do NOT dereference our message queue as it might get attempted to be
1454 IntUnLockMessageQueue(MessageQueue
);
1457 PUSER_MESSAGE_QUEUE FASTCALL
1458 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
1460 PUSER_MESSAGE_QUEUE MessageQueue
;
1462 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(PagedPool
,
1463 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
1471 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
1472 /* hold at least one reference until it'll be destroyed */
1473 IntReferenceMessageQueue(MessageQueue
);
1474 /* initialize the queue */
1475 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
1477 IntDereferenceMessageQueue(MessageQueue
);
1481 return MessageQueue
;
1485 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1487 PDESKTOP_OBJECT desk
;
1489 /* remove the message queue from any desktops */
1490 if ((desk
= (PDESKTOP_OBJECT
)InterlockedExchange((LONG
*)&MessageQueue
->Desktop
, 0)))
1492 InterlockedExchange((LONG
*)&desk
->ActiveMessageQueue
, 0);
1493 IntDereferenceMessageQueue(MessageQueue
);
1496 /* if this is the primitive message queue, deregister it */
1497 if (MessageQueue
== W32kGetPrimitiveMessageQueue())
1498 W32kUnregisterPrimitiveMessageQueue();
1501 MsqCleanupMessageQueue(MessageQueue
);
1503 /* decrease the reference counter, if it hits zero, the queue will be freed */
1504 IntDereferenceMessageQueue(MessageQueue
);
1508 MsqGetHooks(PUSER_MESSAGE_QUEUE Queue
)
1510 return Queue
->Hooks
;
1514 MsqSetHooks(PUSER_MESSAGE_QUEUE Queue
, PHOOKTABLE Hooks
)
1516 Queue
->Hooks
= Hooks
;
1520 MsqSetMessageExtraInfo(LPARAM lParam
)
1523 PUSER_MESSAGE_QUEUE MessageQueue
;
1525 MessageQueue
= PsGetWin32Thread()->MessageQueue
;
1531 Ret
= MessageQueue
->ExtraInfo
;
1532 MessageQueue
->ExtraInfo
= lParam
;
1538 MsqGetMessageExtraInfo(VOID
)
1540 PUSER_MESSAGE_QUEUE MessageQueue
;
1542 MessageQueue
= PsGetWin32Thread()->MessageQueue
;
1548 return MessageQueue
->ExtraInfo
;
1552 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
1558 case MSQ_STATE_CAPTURE
:
1559 Prev
= MessageQueue
->CaptureWindow
;
1560 MessageQueue
->CaptureWindow
= hWnd
;
1562 case MSQ_STATE_ACTIVE
:
1563 Prev
= MessageQueue
->ActiveWindow
;
1564 MessageQueue
->ActiveWindow
= hWnd
;
1566 case MSQ_STATE_FOCUS
:
1567 Prev
= MessageQueue
->FocusWindow
;
1568 MessageQueue
->FocusWindow
= hWnd
;
1570 case MSQ_STATE_MENUOWNER
:
1571 Prev
= MessageQueue
->MenuOwner
;
1572 MessageQueue
->MenuOwner
= hWnd
;
1574 case MSQ_STATE_MOVESIZE
:
1575 Prev
= MessageQueue
->MoveSize
;
1576 MessageQueue
->MoveSize
= hWnd
;
1578 case MSQ_STATE_CARET
:
1579 ASSERT(MessageQueue
->CaretInfo
);
1580 Prev
= MessageQueue
->CaretInfo
->hWnd
;
1581 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
1589 static VOID FASTCALL
1590 DumpTimerList(PUSER_MESSAGE_QUEUE MessageQueue
)
1592 PLIST_ENTRY Current
;
1595 Current
= MessageQueue
->TimerListHead
.Flink
;
1596 if (Current
== &MessageQueue
->TimerListHead
)
1598 DPRINT("timer list is empty for queue %p\n", MessageQueue
);
1600 while (Current
!= &MessageQueue
->TimerListHead
)
1602 Timer
= CONTAINING_RECORD(Current
, TIMER_ENTRY
, ListEntry
);
1603 DPRINT("queue %p timer %p expiry %I64d wnd %x id %p period %u timerproc %p msg %u\n",
1604 MessageQueue
, Timer
, Timer
->ExpiryTime
.QuadPart
, Timer
->Wnd
, Timer
->IDEvent
,
1605 Timer
->Period
, Timer
->TimerFunc
, Timer
->Msg
);
1606 Current
= Current
->Flink
;
1609 #endif /* ! defined(NDEBUG) */
1611 /* Must have the message queue locked while calling this */
1612 static VOID FASTCALL
1613 InsertTimer(PUSER_MESSAGE_QUEUE MessageQueue
, PTIMER_ENTRY NewTimer
)
1615 PLIST_ENTRY Current
;
1617 Current
= MessageQueue
->TimerListHead
.Flink
;
1618 while (Current
!= &MessageQueue
->TimerListHead
)
1620 if (NewTimer
->ExpiryTime
.QuadPart
<
1621 CONTAINING_RECORD(Current
, TIMER_ENTRY
, ListEntry
)->ExpiryTime
.QuadPart
)
1625 Current
= Current
->Flink
;
1628 InsertTailList(Current
, &NewTimer
->ListEntry
);
1631 /* Must have the message queue locked while calling this */
1632 static PTIMER_ENTRY FASTCALL
1633 RemoveTimer(PUSER_MESSAGE_QUEUE MessageQueue
, HWND Wnd
, UINT_PTR IDEvent
, UINT Msg
)
1636 PLIST_ENTRY EnumEntry
;
1638 /* Remove timer if already in the queue */
1639 EnumEntry
= MessageQueue
->TimerListHead
.Flink
;
1640 while (EnumEntry
!= &MessageQueue
->TimerListHead
)
1642 Timer
= CONTAINING_RECORD(EnumEntry
, TIMER_ENTRY
, ListEntry
);
1643 EnumEntry
= EnumEntry
->Flink
;
1645 if (Timer
->Wnd
== Wnd
&&
1646 Timer
->IDEvent
== IDEvent
&&
1649 RemoveEntryList(&Timer
->ListEntry
);
1658 MsqSetTimer(PUSER_MESSAGE_QUEUE MessageQueue
, HWND Wnd
,
1659 UINT_PTR IDEvent
, UINT Period
, TIMERPROC TimerFunc
,
1663 LARGE_INTEGER CurrentTime
;
1665 DPRINT("MsqSetTimer queue %p wnd %x id %p period %u timerproc %p msg %d\n",
1666 MessageQueue
, Wnd
, IDEvent
, Period
, TimerFunc
, Msg
);
1668 IntLockMessageQueue(MessageQueue
);
1669 Timer
= RemoveTimer(MessageQueue
, Wnd
, IDEvent
, Msg
);
1672 Timer
= ExAllocateFromPagedLookasideList(&TimerLookasideList
);
1675 IntUnLockMessageQueue(MessageQueue
);
1676 DPRINT1("Failed to allocate timer entry\n");
1679 DPRINT("Allocated new timer entry %p\n", Timer
);
1681 Timer
->IDEvent
= IDEvent
;
1686 DPRINT("Updating existing timer entry %p\n", Timer
);
1689 KeQuerySystemTime(&CurrentTime
);
1690 Timer
->ExpiryTime
.QuadPart
= CurrentTime
.QuadPart
+
1691 (ULONGLONG
) Period
* (ULONGLONG
) 10000;
1692 Timer
->Period
= Period
;
1693 Timer
->TimerFunc
= TimerFunc
;
1694 DPRINT("Insert timer now %I64d expiry %I64d\n", CurrentTime
.QuadPart
,
1695 Timer
->ExpiryTime
.QuadPart
);
1697 InsertTimer(MessageQueue
, Timer
);
1700 DumpTimerList(MessageQueue
);
1701 #endif /* ! defined(NDEBUG) */
1703 IntUnLockMessageQueue(MessageQueue
);
1709 MsqKillTimer(PUSER_MESSAGE_QUEUE MessageQueue
, HWND Wnd
,
1710 UINT_PTR IDEvent
, UINT Msg
)
1714 DPRINT("MsqKillTimer queue %p wnd %x id %p msg %d\n",
1715 MessageQueue
, Wnd
, IDEvent
, Msg
);
1717 IntLockMessageQueue(MessageQueue
);
1718 Timer
= RemoveTimer(MessageQueue
, Wnd
, IDEvent
, Msg
);
1722 DPRINT("Failed to remove timer from list, not found\n");
1726 ExFreeToPagedLookasideList(&TimerLookasideList
, Timer
);
1730 DumpTimerList(MessageQueue
);
1731 #endif /* ! defined(NDEBUG) */
1733 IntUnLockMessageQueue(MessageQueue
);
1735 return NULL
!= Timer
;
1739 MsqGetTimerMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1740 HWND WndFilter
, UINT MsgFilterMin
, UINT MsgFilterMax
,
1741 MSG
*Msg
, BOOLEAN Restart
)
1744 LARGE_INTEGER CurrentTime
;
1745 PLIST_ENTRY EnumEntry
;
1748 DPRINT("MsqGetTimerMessage queue %p msg %p restart %s\n",
1749 MessageQueue
, Msg
, Restart
? "TRUE" : "FALSE");
1751 IntLockMessageQueue(MessageQueue
);
1752 KeQuerySystemTime(&CurrentTime
);
1753 DPRINT("Current time %I64d\n", CurrentTime
.QuadPart
);
1754 EnumEntry
= MessageQueue
->TimerListHead
.Flink
;
1756 while (EnumEntry
!= &MessageQueue
->TimerListHead
)
1758 Timer
= CONTAINING_RECORD(MessageQueue
->TimerListHead
.Flink
,
1759 TIMER_ENTRY
, ListEntry
);
1760 DPRINT("Checking timer %p wnd %x expiry %I64d\n", Timer
, Timer
->Wnd
,
1761 Timer
->ExpiryTime
.QuadPart
);
1762 EnumEntry
= EnumEntry
->Flink
;
1763 if ((NULL
== WndFilter
|| Timer
->Wnd
== WndFilter
) &&
1764 ((MsgFilterMin
== 0 && MsgFilterMax
== 0) ||
1765 (MsgFilterMin
<= Timer
->Msg
&&
1766 Timer
->Msg
<= MsgFilterMax
)))
1768 if (Timer
->ExpiryTime
.QuadPart
<= CurrentTime
.QuadPart
)
1770 DPRINT("Timer is expired\n");
1776 DPRINT("No need to check later timers\n");
1782 DPRINT("timer %p (wnd %x msg %d) failed filter wnd %x msgmin %d msgmax %d\n",
1783 Timer
, Timer
->Wnd
, Timer
->Msg
, WndFilter
, MsgFilterMin
, MsgFilterMax
);
1789 DPRINT("No timer pending\n");
1790 IntUnLockMessageQueue(MessageQueue
);
1794 Msg
->hwnd
= Timer
->Wnd
;
1795 Msg
->message
= Timer
->Msg
;
1796 Msg
->wParam
= (WPARAM
) Timer
->IDEvent
;
1797 Msg
->lParam
= (LPARAM
) Timer
->TimerFunc
;
1801 RemoveEntryList(&Timer
->ListEntry
);
1802 Timer
->ExpiryTime
.QuadPart
= CurrentTime
.QuadPart
+
1803 (ULONGLONG
) Timer
->Period
* (ULONGLONG
) 10000;
1804 DPRINT("Restarting timer %p expires %I64d\n", Timer
, Timer
->ExpiryTime
.QuadPart
);
1805 InsertTimer(MessageQueue
, Timer
);
1808 DumpTimerList(MessageQueue
);
1809 #endif /* ! defined(NDEBUG) */
1812 IntUnLockMessageQueue(MessageQueue
);
1814 DPRINT("Created message wnd %x msg %d wParam %u lParam %u\n", Msg
->hwnd
, Msg
->message
,
1815 Msg
->wParam
, Msg
->lParam
);
1821 MsqRemoveTimersWindow(PUSER_MESSAGE_QUEUE MessageQueue
, HWND Wnd
)
1824 PLIST_ENTRY EnumEntry
;
1826 DPRINT("MsqRemoveTimersWindow queue %p wnd %x\n", MessageQueue
, Wnd
);
1828 IntLockMessageQueue(MessageQueue
);
1829 EnumEntry
= MessageQueue
->TimerListHead
.Flink
;
1830 while (EnumEntry
!= &MessageQueue
->TimerListHead
)
1832 Timer
= CONTAINING_RECORD(EnumEntry
, TIMER_ENTRY
, ListEntry
);
1833 EnumEntry
= EnumEntry
->Flink
;
1834 if (Timer
->Wnd
== Wnd
)
1836 DPRINT("Removing timer %p because its window is going away\n", Timer
);
1837 RemoveEntryList(&Timer
->ListEntry
);
1838 ExFreeToPagedLookasideList(&TimerLookasideList
, Timer
);
1843 DumpTimerList(MessageQueue
);
1844 #endif /* ! defined(NDEBUG) */
1846 IntUnLockMessageQueue(MessageQueue
);
1850 MsqGetFirstTimerExpiry(PUSER_MESSAGE_QUEUE MessageQueue
,
1851 HWND WndFilter
, UINT MsgFilterMin
, UINT MsgFilterMax
,
1852 PLARGE_INTEGER FirstTimerExpiry
)
1855 PLIST_ENTRY EnumEntry
;
1857 DPRINT("MsqGetFirstTimerExpiry queue %p wndfilter %x msgfiltermin %d msgfiltermax %d expiry %p\n",
1858 MessageQueue
, WndFilter
, MsgFilterMin
, MsgFilterMax
, FirstTimerExpiry
);
1860 IntLockMessageQueue(MessageQueue
);
1861 EnumEntry
= MessageQueue
->TimerListHead
.Flink
;
1862 while (EnumEntry
!= &MessageQueue
->TimerListHead
)
1864 Timer
= CONTAINING_RECORD(MessageQueue
->TimerListHead
.Flink
,
1865 TIMER_ENTRY
, ListEntry
);
1866 EnumEntry
= EnumEntry
->Flink
;
1867 if ((NULL
== WndFilter
|| Timer
->Wnd
== WndFilter
) &&
1868 ((MsgFilterMin
== 0 && MsgFilterMax
== 0) ||
1869 (MsgFilterMin
<= Timer
->Msg
&&
1870 Timer
->Msg
<= MsgFilterMax
)))
1872 *FirstTimerExpiry
= Timer
->ExpiryTime
;
1873 DPRINT("First timer expires %I64d\n", Timer
->ExpiryTime
);
1874 IntUnLockMessageQueue(MessageQueue
);
1879 IntUnLockMessageQueue(MessageQueue
);