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.
72 PWINDOW_OBJECT Window
;
73 PPROCESSINFO W32d
= PsGetCurrentProcessWin32Process();
75 hWnd
= UserGetForegroundWindow();
77 Window
= UserGetWindowObject(hWnd
);
79 if (Window
&& Window
->pti
)
81 if (Window
->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
, PWINDOW_OBJECT Window
, UINT FilterLow
, UINT FilterHigh
,
346 PUSER_MESSAGE Message
, BOOL Remove
, PBOOL Freed
,
347 PWINDOW_OBJECT ScopeWin
, PPOINT ScreenPoint
, BOOL FromGlobalQueue
, PLIST_ENTRY
*Next
)
349 USHORT Msg
= Message
->Msg
.message
;
350 PWINDOW_OBJECT CaptureWindow
= NULL
;
353 ASSERT_REFS_CO(ScopeWin
);
356 co_WinPosWindowFromPoint can return a Window, and in that case
357 that window has a ref that we need to deref. Thats why we add "dummy"
358 refs in all other cases.
361 hCaptureWin
= IntGetCaptureWindow();
362 if (hCaptureWin
== NULL
)
364 if (Msg
== WM_MOUSEWHEEL
)
366 CaptureWindow
= UserGetWindowObject(IntGetFocusWindow());
367 if (CaptureWindow
) UserReferenceObject(CaptureWindow
);
371 co_WinPosWindowFromPoint(ScopeWin
, NULL
, &Message
->Msg
.pt
, &CaptureWindow
);
372 if(CaptureWindow
== NULL
)
374 CaptureWindow
= ScopeWin
;
375 if (CaptureWindow
) UserReferenceObject(CaptureWindow
);
379 /* this is the one case where we dont add a ref, since the returned
380 window is already referenced */
386 /* FIXME - window messages should go to the right window if no buttons are
388 CaptureWindow
= UserGetWindowObject(hCaptureWin
);
389 if (CaptureWindow
) UserReferenceObject(CaptureWindow
);
394 if (CaptureWindow
== NULL
)
398 RemoveEntryList(&Message
->ListEntry
);
399 if(MessageQueue
->MouseMoveMsg
== Message
)
401 MessageQueue
->MouseMoveMsg
= NULL
;
404 // when FromGlobalQueue is true, the caller has already removed the Message
410 if (CaptureWindow
->pti
->MessageQueue
!= MessageQueue
)
412 if (! FromGlobalQueue
)
414 DPRINT("Moving msg between private queues\n");
415 /* This message is already queued in a private queue, but we need
416 * to move it to a different queue, perhaps because a new window
417 * was created which now covers the screen area previously taken
418 * by another window. To move it, we need to take it out of the
419 * old queue. Note that we're already holding the lock mutexes of the
421 RemoveEntryList(&Message
->ListEntry
);
423 /* remove the pointer for the current WM_MOUSEMOVE message in case we
425 if(MessageQueue
->MouseMoveMsg
== Message
)
427 MessageQueue
->MouseMoveMsg
= NULL
;
431 /* lock the destination message queue, so we don't get in trouble with other
432 threads, messing with it at the same time */
433 IntLockHardwareMessageQueue(CaptureWindow
->pti
->MessageQueue
);
434 InsertTailList(&CaptureWindow
->pti
->MessageQueue
->HardwareMessagesListHead
,
435 &Message
->ListEntry
);
436 if(Message
->Msg
.message
== WM_MOUSEMOVE
)
438 if(CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
)
440 /* remove the old WM_MOUSEMOVE message, we're processing a more recent
442 RemoveEntryList(&CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
->ListEntry
);
443 ExFreePool(CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
);
445 /* save the pointer to the WM_MOUSEMOVE message in the new queue */
446 CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
= Message
;
448 CaptureWindow
->pti
->MessageQueue
->QueueBits
|= QS_MOUSEMOVE
;
449 CaptureWindow
->pti
->MessageQueue
->ChangedBits
|= QS_MOUSEMOVE
;
450 if (CaptureWindow
->pti
->MessageQueue
->WakeMask
& QS_MOUSEMOVE
)
451 KeSetEvent(CaptureWindow
->pti
->MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
455 CaptureWindow
->pti
->MessageQueue
->QueueBits
|= QS_MOUSEBUTTON
;
456 CaptureWindow
->pti
->MessageQueue
->ChangedBits
|= QS_MOUSEBUTTON
;
457 if (CaptureWindow
->pti
->MessageQueue
->WakeMask
& QS_MOUSEBUTTON
)
458 KeSetEvent(CaptureWindow
->pti
->MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
460 IntUnLockHardwareMessageQueue(CaptureWindow
->pti
->MessageQueue
);
463 UserDereferenceObject(CaptureWindow
);
467 /* From here on, we're in the same message queue as the caller! */
469 *ScreenPoint
= Message
->Msg
.pt
;
471 if((Window
!= NULL
&& PtrToInt(Window
) != 1 && CaptureWindow
->hSelf
!= Window
->hSelf
) ||
472 ((FilterLow
!= 0 || FilterHigh
!= 0) && (Msg
< FilterLow
|| Msg
> FilterHigh
)))
474 /* Reject the message because it doesn't match the filter */
478 /* Lock the message queue so no other thread can mess with it.
479 Our own message queue is not locked while fetching from the global
480 queue, so we have to make sure nothing interferes! */
481 IntLockHardwareMessageQueue(CaptureWindow
->pti
->MessageQueue
);
482 /* if we're from the global queue, we need to add our message to our
483 private queue so we don't loose it! */
484 InsertTailList(&CaptureWindow
->pti
->MessageQueue
->HardwareMessagesListHead
,
485 &Message
->ListEntry
);
488 if (Message
->Msg
.message
== WM_MOUSEMOVE
)
490 if(CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
&&
491 (CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
!= Message
))
493 /* delete the old message */
494 RemoveEntryList(&CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
->ListEntry
);
495 ExFreePool(CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
);
496 if (!FromGlobalQueue
)
498 // We might have deleted the next one in our queue, so fix next
499 *Next
= Message
->ListEntry
.Flink
;
502 /* always save a pointer to this WM_MOUSEMOVE message here because we're
503 sure that the message is in the private queue */
504 CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
= Message
;
508 IntUnLockHardwareMessageQueue(CaptureWindow
->pti
->MessageQueue
);
511 UserDereferenceObject(CaptureWindow
);
516 /* FIXME - only assign if removing? */
517 Message
->Msg
.hwnd
= CaptureWindow
->hSelf
;
518 Message
->Msg
.message
= Msg
;
519 Message
->Msg
.lParam
= MAKELONG(Message
->Msg
.pt
.x
, Message
->Msg
.pt
.y
);
521 /* remove the reference to the current WM_(NC)MOUSEMOVE message, if this message
523 if (Message
->Msg
.message
== WM_MOUSEMOVE
||
524 Message
->Msg
.message
== WM_NCMOUSEMOVE
)
528 /* Lock the message queue so no other thread can mess with it.
529 Our own message queue is not locked while fetching from the global
530 queue, so we have to make sure nothing interferes! */
531 IntLockHardwareMessageQueue(CaptureWindow
->pti
->MessageQueue
);
532 if(CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
)
534 /* delete the WM_(NC)MOUSEMOVE message in the private queue, we're dealing
535 with one that's been sent later */
536 RemoveEntryList(&CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
->ListEntry
);
537 ExFreePool(CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
);
538 /* our message is not in the private queue so we can remove the pointer
539 instead of setting it to the current message we're processing */
540 CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
= NULL
;
542 IntUnLockHardwareMessageQueue(CaptureWindow
->pti
->MessageQueue
);
544 else if (CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
== Message
)
546 CaptureWindow
->pti
->MessageQueue
->MouseMoveMsg
= NULL
;
550 UserDereferenceObject(CaptureWindow
);
556 co_MsqPeekHardwareMessage(PUSER_MESSAGE_QUEUE MessageQueue
, PWINDOW_OBJECT Window
,
557 UINT FilterLow
, UINT FilterHigh
, BOOL Remove
,
558 PUSER_MESSAGE
* Message
)
563 PLIST_ENTRY CurrentEntry
;
564 PWINDOW_OBJECT DesktopWindow
= NULL
;
565 PVOID WaitObjects
[2];
567 DECLARE_RETURN(BOOL
);
568 USER_REFERENCE_ENTRY Ref
;
569 PDESKTOPINFO Desk
= NULL
;
571 WaitObjects
[1] = MessageQueue
->NewMessages
;
572 WaitObjects
[0] = &HardwareMessageQueueLock
;
579 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
580 UserMode
, FALSE
, NULL
, NULL
);
584 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
586 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
590 UserRefObjectCo(DesktopWindow
, &Ref
);//can DesktopWindow be NULL?
591 Desk
= DesktopWindow
->pti
->pDeskInfo
;
594 /* Process messages in the message queue itself. */
595 IntLockHardwareMessageQueue(MessageQueue
);
596 CurrentEntry
= MessageQueue
->HardwareMessagesListHead
.Flink
;
597 while (CurrentEntry
!= &MessageQueue
->HardwareMessagesListHead
)
599 PUSER_MESSAGE Current
=
600 CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
601 CurrentEntry
= CurrentEntry
->Flink
;
602 if (Current
->Msg
.message
>= WM_MOUSEFIRST
&&
603 Current
->Msg
.message
<= WM_MOUSELAST
)
607 Accept
= co_MsqTranslateMouseMessage(MessageQueue
, Window
, FilterLow
, FilterHigh
,
608 Current
, Remove
, &Freed
,
609 DesktopWindow
, &ScreenPoint
, FALSE
, &CurrentEntry
);
614 RemoveEntryList(&Current
->ListEntry
);
616 IntUnLockHardwareMessageQueue(MessageQueue
);
617 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
621 Desk
->LastInputWasKbd
= FALSE
;
628 IntUnLockHardwareMessageQueue(MessageQueue
);
630 /* Now try the global queue. */
632 /* Transfer all messages from the DPC accessible queue to the main queue. */
633 IntLockSystemMessageQueue(OldIrql
);
634 while (SystemMessageQueueCount
> 0)
636 PUSER_MESSAGE UserMsg
;
639 ASSERT(SystemMessageQueueHead
< SYSTEM_MESSAGE_QUEUE_SIZE
);
640 Msg
= SystemMessageQueue
[SystemMessageQueueHead
];
641 SystemMessageQueueHead
=
642 (SystemMessageQueueHead
+ 1) % SYSTEM_MESSAGE_QUEUE_SIZE
;
643 SystemMessageQueueCount
--;
644 IntUnLockSystemMessageQueue(OldIrql
);
646 UserMsg
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
647 /* What to do if out of memory? For now we just panic a bit in debug */
649 UserMsg
->FreeLParam
= FALSE
;
651 InsertTailList(&HardwareMessageQueueHead
, &UserMsg
->ListEntry
);
653 IntLockSystemMessageQueue(OldIrql
);
655 HardwareMessageQueueStamp
++;
656 IntUnLockSystemMessageQueue(OldIrql
);
658 /* Process messages in the queue until we find one to return. */
659 CurrentEntry
= HardwareMessageQueueHead
.Flink
;
660 while (CurrentEntry
!= &HardwareMessageQueueHead
)
662 PUSER_MESSAGE Current
=
663 CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
664 CurrentEntry
= CurrentEntry
->Flink
;
665 RemoveEntryList(&Current
->ListEntry
);
666 HardwareMessageQueueStamp
++;
667 if (Current
->Msg
.message
>= WM_MOUSEFIRST
&&
668 Current
->Msg
.message
<= WM_MOUSELAST
)
670 const ULONG ActiveStamp
= HardwareMessageQueueStamp
;
671 /* Translate the message. */
672 Accept
= co_MsqTranslateMouseMessage(MessageQueue
, Window
, FilterLow
, FilterHigh
,
673 Current
, Remove
, &Freed
,
674 DesktopWindow
, &ScreenPoint
, TRUE
, NULL
);
677 /* Check for no more messages in the system queue. */
678 IntLockSystemMessageQueue(OldIrql
);
679 if (SystemMessageQueueCount
== 0 &&
680 IsListEmpty(&HardwareMessageQueueHead
))
682 KeClearEvent(&HardwareMessageEvent
);
684 IntUnLockSystemMessageQueue(OldIrql
);
687 If we aren't removing the message then add it to the private
692 IntLockHardwareMessageQueue(MessageQueue
);
693 if(Current
->Msg
.message
== WM_MOUSEMOVE
)
695 if(MessageQueue
->MouseMoveMsg
)
697 RemoveEntryList(&MessageQueue
->MouseMoveMsg
->ListEntry
);
698 ExFreePool(MessageQueue
->MouseMoveMsg
);
700 MessageQueue
->MouseMoveMsg
= Current
;
702 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
703 &Current
->ListEntry
);
704 IntUnLockHardwareMessageQueue(MessageQueue
);
706 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
711 /* If the contents of the queue changed then restart processing. */
712 if (HardwareMessageQueueStamp
!= ActiveStamp
)
714 CurrentEntry
= HardwareMessageQueueHead
.Flink
;
720 /* Check if the system message queue is now empty. */
721 IntLockSystemMessageQueue(OldIrql
);
722 if (SystemMessageQueueCount
== 0 && IsListEmpty(&HardwareMessageQueueHead
))
724 KeClearEvent(&HardwareMessageEvent
);
726 IntUnLockSystemMessageQueue(OldIrql
);
727 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
732 if (DesktopWindow
) UserDerefObjectCo(DesktopWindow
);
738 // Note: Only called from input.c.
741 co_MsqPostKeyboardMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
743 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
745 LARGE_INTEGER LargeTickCount
;
746 KBDLLHOOKSTRUCT KbdHookData
;
747 BOOLEAN Entered
= FALSE
;
749 DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
750 uMsg
, wParam
, lParam
);
752 // Condition may arise when calling MsqPostMessage and waiting for an event.
753 if (!UserIsEntered())
755 // Fixme: Not sure ATM if this thread is locked.
756 UserEnterExclusive();
760 FocusMessageQueue
= IntGetFocusMessageQueue();
764 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
765 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
771 KeQueryTickCount(&LargeTickCount
);
772 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
774 /* We can't get the Msg.pt point here since we don't know thread
775 (and thus the window station) the message will end up in yet. */
777 KbdHookData
.vkCode
= Msg
.wParam
;
778 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
779 KbdHookData
.flags
= (0 == (Msg
.lParam
& 0x01000000) ? 0 : LLKHF_EXTENDED
) |
780 (0 == (Msg
.lParam
& 0x20000000) ? 0 : LLKHF_ALTDOWN
) |
781 (0 == (Msg
.lParam
& 0x80000000) ? 0 : LLKHF_UP
);
782 KbdHookData
.time
= Msg
.time
;
783 KbdHookData
.dwExtraInfo
= 0;
784 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
786 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
787 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
788 if (Entered
) UserLeave();
792 if (FocusMessageQueue
== NULL
)
794 DPRINT("No focus message queue\n");
795 if (Entered
) UserLeave();
799 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
801 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
802 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
804 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
806 Msg
.pt
= gpsi
->ptCursor
;
807 MsqPostMessage(FocusMessageQueue
, &Msg
, FALSE
, QS_KEY
);
811 DPRINT("Invalid focus window handle\n");
814 if (Entered
) UserLeave();
819 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
821 PWINDOW_OBJECT Window
;
822 PTHREADINFO Win32Thread
;
824 LARGE_INTEGER LargeTickCount
;
827 Status
= ObReferenceObjectByPointer (Thread
,
831 if (!NT_SUCCESS(Status
))
834 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
835 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
837 ObDereferenceObject ((PETHREAD
)Thread
);
841 Window
= IntGetWindowObject(hWnd
);
844 ObDereferenceObject ((PETHREAD
)Thread
);
849 Mesg
.message
= WM_HOTKEY
;
850 Mesg
.wParam
= wParam
;
851 Mesg
.lParam
= lParam
;
852 KeQueryTickCount(&LargeTickCount
);
853 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
854 Mesg
.pt
= gpsi
->ptCursor
;
855 MsqPostMessage(Window
->pti
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
856 UserDereferenceObject(Window
);
857 ObDereferenceObject (Thread
);
859 // InsertHeadList(&pThread->MessageQueue->PostedMessagesListHead,
860 // &Message->ListEntry);
861 // KeSetEvent(pThread->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
864 PUSER_MESSAGE FASTCALL
865 MsqCreateMessage(LPMSG Msg
, BOOLEAN FreeLParam
)
867 PUSER_MESSAGE Message
;
869 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
875 Message
->FreeLParam
= FreeLParam
;
876 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
882 MsqDestroyMessage(PUSER_MESSAGE Message
)
884 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
888 co_MsqDispatchSentNotifyMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
890 PLIST_ENTRY ListEntry
;
891 PUSER_SENT_MESSAGE_NOTIFY Message
;
893 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
895 ListEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
896 Message
= CONTAINING_RECORD(ListEntry
, USER_SENT_MESSAGE_NOTIFY
,
899 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
902 Message
->CompletionCallbackContext
,
910 MsqPeekSentMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
912 return(!IsListEmpty(&MessageQueue
->SentMessagesListHead
));
916 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
918 PUSER_SENT_MESSAGE Message
;
922 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
927 /* remove it from the list of pending messages */
928 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
929 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
931 /* insert it to the list of messages that are currently dispatched by this
933 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
934 &Message
->ListEntry
);
936 if (Message
->HookMessage
== MSQ_ISHOOK
)
938 Result
= co_HOOK_CallHooks(Message
->Msg
.message
,
939 (INT
)(INT_PTR
)Message
->Msg
.hwnd
,
941 Message
->Msg
.lParam
);
943 else if (Message
->HookMessage
== MSQ_ISEVENT
)
945 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
948 Message
->Msg
.lParam
);
952 /* Call the window procedure. */
953 Result
= co_IntSendMessage(Message
->Msg
.hwnd
,
954 Message
->Msg
.message
,
956 Message
->Msg
.lParam
);
959 /* remove the message from the local dispatching list, because it doesn't need
960 to be cleaned up on thread termination anymore */
961 RemoveEntryList(&Message
->ListEntry
);
963 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
964 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
966 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
968 /* only remove it from the dispatching list if not already removed by a timeout */
969 RemoveEntryList(&Message
->DispatchingListEntry
);
972 /* still keep the sender's message queue locked, so the sender can't exit the
973 MsqSendMessage() function (if timed out) */
975 /* Let the sender know the result. */
976 if (Message
->Result
!= NULL
)
978 *Message
->Result
= Result
;
981 if (Message
->HasPackedLParam
== TRUE
)
983 if (Message
->Msg
.lParam
)
984 ExFreePool((PVOID
)Message
->Msg
.lParam
);
987 /* Notify the sender. */
988 if (Message
->CompletionEvent
!= NULL
)
990 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
993 /* Call the callback if the message was sent with SendMessageCallback */
994 if (Message
->CompletionCallback
!= NULL
)
996 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
998 Message
->Msg
.message
,
999 Message
->CompletionCallbackContext
,
1003 /* Only if it is not a no wait message */
1004 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
1006 IntDereferenceMessageQueue(Message
->SenderQueue
);
1007 IntDereferenceMessageQueue(MessageQueue
);
1010 /* free the message */
1011 ExFreePoolWithTag(Message
, TAG_USRMSG
);
1016 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
1018 PUSER_SENT_MESSAGE SentMessage
;
1019 PUSER_MESSAGE PostedMessage
;
1020 PUSER_MESSAGE_QUEUE MessageQueue
;
1021 PLIST_ENTRY CurrentEntry
, ListHead
;
1022 PWINDOW_OBJECT Window
= pWindow
;
1026 MessageQueue
= Window
->pti
->MessageQueue
;
1027 ASSERT(MessageQueue
);
1029 /* remove the posted messages for this window */
1030 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1031 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1032 while (CurrentEntry
!= ListHead
)
1034 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1036 if (PostedMessage
->Msg
.hwnd
== Window
->hSelf
)
1038 RemoveEntryList(&PostedMessage
->ListEntry
);
1039 MsqDestroyMessage(PostedMessage
);
1040 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1044 CurrentEntry
= CurrentEntry
->Flink
;
1048 /* remove the sent messages for this window */
1049 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
1050 ListHead
= &MessageQueue
->SentMessagesListHead
;
1051 while (CurrentEntry
!= ListHead
)
1053 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1055 if(SentMessage
->Msg
.hwnd
== Window
->hSelf
)
1057 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1059 RemoveEntryList(&SentMessage
->ListEntry
);
1061 /* remove the message from the dispatching list if neede */
1062 if ((!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1063 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1065 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
1068 /* wake the sender's thread */
1069 if (SentMessage
->CompletionEvent
!= NULL
)
1071 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1074 if (SentMessage
->HasPackedLParam
== TRUE
)
1076 if (SentMessage
->Msg
.lParam
)
1077 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
1080 /* Only if it is not a no wait message */
1081 if (!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1083 /* dereference our and the sender's message queue */
1084 IntDereferenceMessageQueue(MessageQueue
);
1085 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
1088 /* free the message */
1089 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
1091 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
1095 CurrentEntry
= CurrentEntry
->Flink
;
1101 MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1102 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage
)
1104 InsertTailList(&MessageQueue
->NotifyMessagesListHead
,
1105 &NotifyMessage
->ListEntry
);
1106 MessageQueue
->QueueBits
|= QS_SENDMESSAGE
;
1107 MessageQueue
->ChangedBits
|= QS_SENDMESSAGE
;
1108 if (MessageQueue
->WakeMask
& QS_SENDMESSAGE
)
1109 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1113 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1114 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
1115 UINT uTimeout
, BOOL Block
, INT HookMessage
,
1119 PUSER_SENT_MESSAGE Message
;
1120 KEVENT CompletionEvent
;
1121 NTSTATUS WaitStatus
;
1123 PUSER_MESSAGE_QUEUE ThreadQueue
;
1124 LARGE_INTEGER Timeout
;
1127 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1129 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1130 return STATUS_INSUFFICIENT_RESOURCES
;
1133 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1135 pti
= PsGetCurrentThreadWin32Thread();
1136 ThreadQueue
= pti
->MessageQueue
;
1137 ASSERT(ThreadQueue
!= MessageQueue
);
1139 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1141 /* FIXME - increase reference counter of sender's message queue here */
1144 Message
->Msg
.hwnd
= Wnd
;
1145 Message
->Msg
.message
= Msg
;
1146 Message
->Msg
.wParam
= wParam
;
1147 Message
->Msg
.lParam
= lParam
;
1148 Message
->CompletionEvent
= &CompletionEvent
;
1149 Message
->Result
= &Result
;
1150 Message
->SenderQueue
= ThreadQueue
;
1151 IntReferenceMessageQueue(ThreadQueue
);
1152 Message
->CompletionCallback
= NULL
;
1153 Message
->HookMessage
= HookMessage
;
1154 Message
->HasPackedLParam
= FALSE
;
1156 IntReferenceMessageQueue(MessageQueue
);
1158 /* add it to the list of pending messages */
1159 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1161 /* queue it in the destination's message queue */
1162 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1164 MessageQueue
->QueueBits
|= QS_SENDMESSAGE
;
1165 MessageQueue
->ChangedBits
|= QS_SENDMESSAGE
;
1166 if (MessageQueue
->WakeMask
& QS_SENDMESSAGE
)
1167 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1169 /* we can't access the Message anymore since it could have already been deleted! */
1177 /* don't process messages sent to the thread */
1178 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1179 FALSE
, (uTimeout
? &Timeout
: NULL
));
1183 if(WaitStatus
== STATUS_TIMEOUT
)
1185 /* look up if the message has not yet dispatched, if so
1186 make sure it can't pass a result and it must not set the completion event anymore */
1187 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1188 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1190 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1193 /* we can access Message here, it's secure because the message queue is locked
1194 and the message is still hasn't been dispatched */
1195 Message
->CompletionEvent
= NULL
;
1196 Message
->Result
= NULL
;
1199 Entry
= Entry
->Flink
;
1202 /* remove from the local dispatching list so the other thread knows,
1203 it can't pass a result and it must not set the completion event anymore */
1204 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1205 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1207 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1210 /* we can access Message here, it's secure because the sender's message is locked
1211 and the message has definitely not yet been destroyed, otherwise it would
1212 have been removed from this list by the dispatching routine right after
1213 dispatching the message */
1214 Message
->CompletionEvent
= NULL
;
1215 Message
->Result
= NULL
;
1216 RemoveEntryList(&Message
->DispatchingListEntry
);
1217 Message
->DispatchingListEntry
.Flink
= NULL
;
1220 Entry
= Entry
->Flink
;
1223 DPRINT("MsqSendMessage (blocked) timed out\n");
1225 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1230 PVOID WaitObjects
[2];
1232 WaitObjects
[0] = &CompletionEvent
;
1233 WaitObjects
[1] = ThreadQueue
->NewMessages
;
1240 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1241 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1245 if(WaitStatus
== STATUS_TIMEOUT
)
1247 /* look up if the message has not yet been dispatched, if so
1248 make sure it can't pass a result and it must not set the completion event anymore */
1249 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1250 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1252 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1255 /* we can access Message here, it's secure because the message queue is locked
1256 and the message is still hasn't been dispatched */
1257 Message
->CompletionEvent
= NULL
;
1258 Message
->Result
= NULL
;
1261 Entry
= Entry
->Flink
;
1264 /* remove from the local dispatching list so the other thread knows,
1265 it can't pass a result and it must not set the completion event anymore */
1266 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1267 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1269 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1272 /* we can access Message here, it's secure because the sender's message is locked
1273 and the message has definitely not yet been destroyed, otherwise it would
1274 have been removed from this list by the dispatching routine right after
1275 dispatching the message */
1276 Message
->CompletionEvent
= NULL
;
1277 Message
->Result
= NULL
;
1278 RemoveEntryList(&Message
->DispatchingListEntry
);
1279 Message
->DispatchingListEntry
.Flink
= NULL
;
1282 Entry
= Entry
->Flink
;
1285 DPRINT("MsqSendMessage timed out\n");
1288 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1291 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
1294 if(WaitStatus
!= STATUS_TIMEOUT
)
1295 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1301 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN FreeLParam
,
1304 PUSER_MESSAGE Message
;
1306 if(!(Message
= MsqCreateMessage(Msg
, FreeLParam
)))
1310 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1311 &Message
->ListEntry
);
1312 MessageQueue
->QueueBits
|= MessageBits
;
1313 MessageQueue
->ChangedBits
|= MessageBits
;
1314 if (MessageQueue
->WakeMask
& MessageBits
)
1315 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1319 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1321 MessageQueue
->QuitPosted
= TRUE
;
1322 MessageQueue
->QuitExitCode
= ExitCode
;
1323 MessageQueue
->QueueBits
|= QS_POSTMESSAGE
;
1324 MessageQueue
->ChangedBits
|= QS_POSTMESSAGE
;
1325 if (MessageQueue
->WakeMask
& QS_POSTMESSAGE
)
1326 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1330 co_MsqFindMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1331 IN BOOLEAN Hardware
,
1333 IN PWINDOW_OBJECT Window
,
1334 IN UINT MsgFilterLow
,
1335 IN UINT MsgFilterHigh
,
1336 OUT PUSER_MESSAGE
* Message
)
1338 PLIST_ENTRY CurrentEntry
;
1339 PUSER_MESSAGE CurrentMessage
;
1340 PLIST_ENTRY ListHead
;
1344 return(co_MsqPeekHardwareMessage( MessageQueue
,
1352 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1353 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1354 while (CurrentEntry
!= ListHead
)
1356 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1359 PtrToInt(Window
) == 1 ||
1360 Window
->hSelf
== CurrentMessage
->Msg
.hwnd
) &&
1361 ( (MsgFilterLow
== 0 && MsgFilterHigh
== 0) ||
1362 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&&
1363 MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1367 RemoveEntryList(&CurrentMessage
->ListEntry
);
1370 *Message
= CurrentMessage
;
1373 CurrentEntry
= CurrentEntry
->Flink
;
1380 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWINDOW_OBJECT WndFilter
,
1381 UINT MsgFilterMin
, UINT MsgFilterMax
)
1383 PVOID WaitObjects
[2] = {MessageQueue
->NewMessages
, &HardwareMessageEvent
};
1386 IdlePing(); // Going to wait so send Idle ping.
1390 ret
= KeWaitForMultipleObjects(2,
1403 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1405 LARGE_INTEGER LargeTickCount
;
1407 KeQueryTickCount(&LargeTickCount
);
1408 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1412 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1414 LARGE_INTEGER LargeTickCount
;
1417 MessageQueue
->Thread
= Thread
;
1418 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1419 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1420 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1421 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1422 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1423 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1424 KeInitializeMutex(&MessageQueue
->HardwareLock
, 0);
1425 MessageQueue
->QuitPosted
= FALSE
;
1426 MessageQueue
->QuitExitCode
= 0;
1427 KeQueryTickCount(&LargeTickCount
);
1428 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1429 MessageQueue
->FocusWindow
= NULL
;
1430 MessageQueue
->PaintCount
= 0;
1431 // HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt)
1432 MessageQueue
->WakeMask
= ~0;
1433 MessageQueue
->NewMessagesHandle
= NULL
;
1435 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1436 NULL
, SynchronizationEvent
, FALSE
);
1437 if (!NT_SUCCESS(Status
))
1442 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1443 ExEventObjectType
, KernelMode
,
1444 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1445 if (!NT_SUCCESS(Status
))
1447 ZwClose(MessageQueue
->NewMessagesHandle
);
1448 MessageQueue
->NewMessagesHandle
= NULL
;
1456 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1458 PLIST_ENTRY CurrentEntry
;
1459 PUSER_MESSAGE CurrentMessage
;
1460 PUSER_SENT_MESSAGE CurrentSentMessage
;
1462 /* cleanup posted messages */
1463 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1465 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1466 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1468 MsqDestroyMessage(CurrentMessage
);
1471 /* remove the messages that have not yet been dispatched */
1472 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1474 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1475 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1478 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1480 /* remove the message from the dispatching list if needed */
1481 if ((!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1482 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1484 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1487 /* wake the sender's thread */
1488 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1490 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1493 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1495 if (CurrentSentMessage
->Msg
.lParam
)
1496 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1499 /* Only if it is not a no wait message */
1500 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1502 /* dereference our and the sender's message queue */
1503 IntDereferenceMessageQueue(MessageQueue
);
1504 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1507 /* free the message */
1508 ExFreePool(CurrentSentMessage
);
1511 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1512 ExitThread() was called in a SendMessage() umode callback */
1513 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1515 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1516 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1519 /* remove the message from the dispatching list */
1520 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1522 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1525 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1527 /* wake the sender's thread */
1528 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1530 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1533 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1535 if (CurrentSentMessage
->Msg
.lParam
)
1536 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1539 /* Only if it is not a no wait message */
1540 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1542 /* dereference our and the sender's message queue */
1543 IntDereferenceMessageQueue(MessageQueue
);
1544 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1547 /* free the message */
1548 ExFreePool(CurrentSentMessage
);
1551 /* tell other threads not to bother returning any info to us */
1552 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
1554 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
1555 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1556 DispatchingListEntry
);
1557 CurrentSentMessage
->CompletionEvent
= NULL
;
1558 CurrentSentMessage
->Result
= NULL
;
1560 /* do NOT dereference our message queue as it might get attempted to be
1566 PUSER_MESSAGE_QUEUE FASTCALL
1567 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
1569 PUSER_MESSAGE_QUEUE MessageQueue
;
1571 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
1572 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
1580 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
1581 /* hold at least one reference until it'll be destroyed */
1582 IntReferenceMessageQueue(MessageQueue
);
1583 /* initialize the queue */
1584 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
1586 IntDereferenceMessageQueue(MessageQueue
);
1590 return MessageQueue
;
1594 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1598 /* remove the message queue from any desktops */
1599 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
1601 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
1602 IntDereferenceMessageQueue(MessageQueue
);
1606 MsqCleanupMessageQueue(MessageQueue
);
1608 /* decrease the reference counter, if it hits zero, the queue will be freed */
1609 IntDereferenceMessageQueue(MessageQueue
);
1613 MsqGetHooks(PUSER_MESSAGE_QUEUE Queue
)
1615 return Queue
->Hooks
;
1619 MsqSetHooks(PUSER_MESSAGE_QUEUE Queue
, PHOOKTABLE Hooks
)
1621 Queue
->Hooks
= Hooks
;
1625 MsqSetMessageExtraInfo(LPARAM lParam
)
1629 PUSER_MESSAGE_QUEUE MessageQueue
;
1631 pti
= PsGetCurrentThreadWin32Thread();
1632 MessageQueue
= pti
->MessageQueue
;
1638 Ret
= MessageQueue
->ExtraInfo
;
1639 MessageQueue
->ExtraInfo
= lParam
;
1645 MsqGetMessageExtraInfo(VOID
)
1648 PUSER_MESSAGE_QUEUE MessageQueue
;
1650 pti
= PsGetCurrentThreadWin32Thread();
1651 MessageQueue
= pti
->MessageQueue
;
1657 return MessageQueue
->ExtraInfo
;
1661 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
1667 case MSQ_STATE_CAPTURE
:
1668 Prev
= MessageQueue
->CaptureWindow
;
1669 MessageQueue
->CaptureWindow
= hWnd
;
1671 case MSQ_STATE_ACTIVE
:
1672 Prev
= MessageQueue
->ActiveWindow
;
1673 MessageQueue
->ActiveWindow
= hWnd
;
1675 case MSQ_STATE_FOCUS
:
1676 Prev
= MessageQueue
->FocusWindow
;
1677 MessageQueue
->FocusWindow
= hWnd
;
1679 case MSQ_STATE_MENUOWNER
:
1680 Prev
= MessageQueue
->MenuOwner
;
1681 MessageQueue
->MenuOwner
= hWnd
;
1683 case MSQ_STATE_MOVESIZE
:
1684 Prev
= MessageQueue
->MoveSize
;
1685 MessageQueue
->MoveSize
= hWnd
;
1687 case MSQ_STATE_CARET
:
1688 ASSERT(MessageQueue
->CaretInfo
);
1689 Prev
= MessageQueue
->CaretInfo
->hWnd
;
1690 MessageQueue
->CaretInfo
->hWnd
= hWnd
;