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 IntMsqSetWakeMask(DWORD WakeMask
)
68 PTHREADINFO Win32Thread
;
69 PUSER_MESSAGE_QUEUE MessageQueue
;
70 HANDLE MessageEventHandle
;
72 Win32Thread
= PsGetCurrentThreadWin32Thread();
73 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
76 MessageQueue
= Win32Thread
->MessageQueue
;
77 MessageQueue
->WakeMask
= WakeMask
;
78 MessageEventHandle
= MessageQueue
->NewMessagesHandle
;
80 return MessageEventHandle
;
84 IntMsqClearWakeMask(VOID
)
86 PTHREADINFO Win32Thread
;
87 PUSER_MESSAGE_QUEUE MessageQueue
;
89 Win32Thread
= PsGetCurrentThreadWin32Thread();
90 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
93 MessageQueue
= Win32Thread
->MessageQueue
;
94 // HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt)
95 MessageQueue
->WakeMask
= ~0;
101 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
104 Queue
->QueueBits
|= QS_PAINT
;
105 Queue
->ChangedBits
|= QS_PAINT
;
106 if (Queue
->WakeMask
& QS_PAINT
)
107 KeSetEvent(Queue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
111 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
120 MsqInitializeImpl(VOID
)
122 /*CurrentFocusMessageQueue = NULL;*/
123 InitializeListHead(&HardwareMessageQueueHead
);
124 KeInitializeEvent(&HardwareMessageEvent
, NotificationEvent
, 0);
125 KeInitializeSpinLock(&SystemMessageQueueLock
);
126 KeInitializeMutant(&HardwareMessageQueueLock
, 0);
128 ExInitializePagedLookasideList(&MessageLookasideList
,
132 sizeof(USER_MESSAGE
),
136 return(STATUS_SUCCESS
);
140 MsqInsertMouseMessage(MSG
* Msg
)
142 LARGE_INTEGER LargeTickCount
;
145 MSLLHOOKSTRUCT MouseHookData
;
147 KeQueryTickCount(&LargeTickCount
);
148 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
150 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
151 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
155 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
159 case WM_XBUTTONDBLCLK
:
160 case WM_NCXBUTTONDOWN
:
162 case WM_NCXBUTTONDBLCLK
:
163 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
166 MouseHookData
.mouseData
= 0;
170 MouseHookData
.flags
= 0;
171 MouseHookData
.time
= Msg
->time
;
172 MouseHookData
.dwExtraInfo
= 0;
174 /* If the hook procedure returned non zero, dont send the message */
175 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
179 * If we got WM_MOUSEMOVE and there are already messages in the
180 * system message queue, check if the last message is mouse move
181 * and if it is then just overwrite it.
183 IntLockSystemMessageQueue(OldIrql
);
186 * Bail out if the queue is full. FIXME: We should handle this case
190 if (SystemMessageQueueCount
== SYSTEM_MESSAGE_QUEUE_SIZE
)
192 IntUnLockSystemMessageQueue(OldIrql
);
196 if (Msg
->message
== WM_MOUSEMOVE
&& SystemMessageQueueCount
)
198 if (SystemMessageQueueTail
== 0)
199 Prev
= SYSTEM_MESSAGE_QUEUE_SIZE
- 1;
201 Prev
= SystemMessageQueueTail
- 1;
202 if (SystemMessageQueue
[Prev
].message
== WM_MOUSEMOVE
)
204 SystemMessageQueueTail
= Prev
;
205 SystemMessageQueueCount
--;
210 * Actually insert the message into the system message queue.
213 SystemMessageQueue
[SystemMessageQueueTail
] = *Msg
;
214 SystemMessageQueueTail
=
215 (SystemMessageQueueTail
+ 1) % SYSTEM_MESSAGE_QUEUE_SIZE
;
216 SystemMessageQueueCount
++;
218 IntUnLockSystemMessageQueue(OldIrql
);
220 KeSetEvent(&HardwareMessageEvent
, IO_NO_INCREMENT
, FALSE
);
224 MsqIsClkLck(LPMSG Msg
, BOOL Remove
)
227 PSYSTEM_CURSORINFO CurInfo
;
230 pti
= PsGetCurrentThreadWin32Thread();
231 if (pti
->rpdesk
== NULL
)
236 CurInfo
= IntGetSysCursorInfo();
238 switch (Msg
->message
)
241 Res
= ((Msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
242 if (Res
&& (!CurInfo
->ClickLockActive
))
244 CurInfo
->ClickLockActive
= TRUE
;
248 if (CurInfo
->ClickLockActive
)
251 CurInfo
->ClickLockActive
= FALSE
;
252 CurInfo
->ClickLockTime
= 0;
256 CurInfo
->ClickLockTime
= Msg
->time
;
264 MsqIsDblClk(LPMSG Msg
, BOOL Remove
)
267 PSYSTEM_CURSORINFO CurInfo
;
271 pti
= PsGetCurrentThreadWin32Thread();
272 if (pti
->rpdesk
== NULL
)
277 CurInfo
= IntGetSysCursorInfo();
278 Res
= (Msg
->hwnd
== (HWND
)CurInfo
->LastClkWnd
) &&
279 ((Msg
->time
- CurInfo
->LastBtnDown
) < gspv
.iDblClickTime
);
283 dX
= CurInfo
->LastBtnDownX
- Msg
->pt
.x
;
284 dY
= CurInfo
->LastBtnDownY
- Msg
->pt
.y
;
290 Res
= (dX
<= gspv
.iDblClickWidth
) &&
291 (dY
<= gspv
.iDblClickHeight
);
295 if(CurInfo
->ButtonsDown
)
296 Res
= (CurInfo
->ButtonsDown
== Msg
->message
);
302 CurInfo
->LastBtnDownX
= Msg
->pt
.x
;
303 CurInfo
->LastBtnDownY
= Msg
->pt
.y
;
304 CurInfo
->ButtonsDown
= Msg
->message
;
307 CurInfo
->LastBtnDown
= 0;
308 CurInfo
->LastClkWnd
= NULL
;
312 CurInfo
->LastClkWnd
= (HANDLE
)Msg
->hwnd
;
313 CurInfo
->LastBtnDown
= Msg
->time
;
321 co_MsqTranslateMouseMessage(PUSER_MESSAGE_QUEUE MessageQueue
, PWND Window
, UINT FilterLow
, UINT FilterHigh
,
322 PUSER_MESSAGE Message
, BOOL Remove
, PBOOL Freed
,
323 PWND ScopeWin
, PPOINT ScreenPoint
, BOOL FromGlobalQueue
, PLIST_ENTRY
*Next
)
325 USHORT Msg
= Message
->Msg
.message
;
326 PWND CaptureWindow
= NULL
;
329 /* FIXME: Mouse message can be sent before the Desktop is up and running in which case ScopeWin (Desktop) is 0.
330 Is this the best fix? */
331 if (ScopeWin
== 0) return FALSE
;
333 ASSERT_REFS_CO(ScopeWin
);
336 co_WinPosWindowFromPoint can return a Window, and in that case
337 that window has a ref that we need to deref. Thats why we add "dummy"
338 refs in all other cases.
341 hCaptureWin
= IntGetCaptureWindow();
342 if (hCaptureWin
== NULL
)
344 if (Msg
== WM_MOUSEWHEEL
)
346 CaptureWindow
= UserGetWindowObject(IntGetFocusWindow());
347 if (CaptureWindow
) UserReferenceObject(CaptureWindow
);
351 co_WinPosWindowFromPoint(ScopeWin
, NULL
, &Message
->Msg
.pt
, &CaptureWindow
);
352 if(CaptureWindow
== NULL
)
354 CaptureWindow
= ScopeWin
;
355 if (CaptureWindow
) UserReferenceObject(CaptureWindow
);
359 /* this is the one case where we dont add a ref, since the returned
360 window is already referenced */
366 /* FIXME - window messages should go to the right window if no buttons are
368 CaptureWindow
= UserGetWindowObject(hCaptureWin
);
369 if (CaptureWindow
) UserReferenceObject(CaptureWindow
);
374 if (CaptureWindow
== NULL
)
378 RemoveEntryList(&Message
->ListEntry
);
379 if(MessageQueue
->MouseMoveMsg
== Message
)
381 MessageQueue
->MouseMoveMsg
= NULL
;
384 // when FromGlobalQueue is true, the caller has already removed the Message
390 if (CaptureWindow
->head
.pti
->MessageQueue
!= MessageQueue
)
392 if (! FromGlobalQueue
)
394 DPRINT("Moving msg between private queues\n");
395 /* This message is already queued in a private queue, but we need
396 * to move it to a different queue, perhaps because a new window
397 * was created which now covers the screen area previously taken
398 * by another window. To move it, we need to take it out of the
399 * old queue. Note that we're already holding the lock mutexes of the
401 RemoveEntryList(&Message
->ListEntry
);
403 /* remove the pointer for the current WM_MOUSEMOVE message in case we
405 if(MessageQueue
->MouseMoveMsg
== Message
)
407 MessageQueue
->MouseMoveMsg
= NULL
;
411 /* lock the destination message queue, so we don't get in trouble with other
412 threads, messing with it at the same time */
413 IntLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
414 InsertTailList(&CaptureWindow
->head
.pti
->MessageQueue
->HardwareMessagesListHead
,
415 &Message
->ListEntry
);
416 if(Message
->Msg
.message
== WM_MOUSEMOVE
)
418 if(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
)
420 /* remove the old WM_MOUSEMOVE message, we're processing a more recent
422 RemoveEntryList(&CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
->ListEntry
);
423 ExFreePool(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
);
425 /* save the pointer to the WM_MOUSEMOVE message in the new queue */
426 CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
= Message
;
428 CaptureWindow
->head
.pti
->MessageQueue
->QueueBits
|= QS_MOUSEMOVE
;
429 CaptureWindow
->head
.pti
->MessageQueue
->ChangedBits
|= QS_MOUSEMOVE
;
430 if (CaptureWindow
->head
.pti
->MessageQueue
->WakeMask
& QS_MOUSEMOVE
)
431 KeSetEvent(CaptureWindow
->head
.pti
->MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
435 CaptureWindow
->head
.pti
->MessageQueue
->QueueBits
|= QS_MOUSEBUTTON
;
436 CaptureWindow
->head
.pti
->MessageQueue
->ChangedBits
|= QS_MOUSEBUTTON
;
437 if (CaptureWindow
->head
.pti
->MessageQueue
->WakeMask
& QS_MOUSEBUTTON
)
438 KeSetEvent(CaptureWindow
->head
.pti
->MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
440 IntUnLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
443 UserDereferenceObject(CaptureWindow
);
447 /* From here on, we're in the same message queue as the caller! */
449 *ScreenPoint
= Message
->Msg
.pt
;
451 if((Window
!= NULL
&& PtrToInt(Window
) != 1 && CaptureWindow
->head
.h
!= Window
->head
.h
) ||
452 ((FilterLow
!= 0 || FilterHigh
!= 0) && (Msg
< FilterLow
|| Msg
> FilterHigh
)))
454 /* Reject the message because it doesn't match the filter */
458 /* Lock the message queue so no other thread can mess with it.
459 Our own message queue is not locked while fetching from the global
460 queue, so we have to make sure nothing interferes! */
461 IntLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
462 /* if we're from the global queue, we need to add our message to our
463 private queue so we don't loose it! */
464 InsertTailList(&CaptureWindow
->head
.pti
->MessageQueue
->HardwareMessagesListHead
,
465 &Message
->ListEntry
);
468 if (Message
->Msg
.message
== WM_MOUSEMOVE
)
470 if(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
&&
471 (CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
!= Message
))
473 /* delete the old message */
474 RemoveEntryList(&CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
->ListEntry
);
475 ExFreePool(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
);
476 if (!FromGlobalQueue
)
478 // We might have deleted the next one in our queue, so fix next
479 *Next
= Message
->ListEntry
.Flink
;
482 /* always save a pointer to this WM_MOUSEMOVE message here because we're
483 sure that the message is in the private queue */
484 CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
= Message
;
488 IntUnLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
491 UserDereferenceObject(CaptureWindow
);
496 /* FIXME - only assign if removing? */
497 Message
->Msg
.hwnd
= CaptureWindow
->head
.h
;
498 Message
->Msg
.message
= Msg
;
499 Message
->Msg
.lParam
= MAKELONG(Message
->Msg
.pt
.x
, Message
->Msg
.pt
.y
);
501 /* remove the reference to the current WM_(NC)MOUSEMOVE message, if this message
503 if (Message
->Msg
.message
== WM_MOUSEMOVE
||
504 Message
->Msg
.message
== WM_NCMOUSEMOVE
)
508 /* Lock the message queue so no other thread can mess with it.
509 Our own message queue is not locked while fetching from the global
510 queue, so we have to make sure nothing interferes! */
511 IntLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
512 if(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
)
514 /* delete the WM_(NC)MOUSEMOVE message in the private queue, we're dealing
515 with one that's been sent later */
516 RemoveEntryList(&CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
->ListEntry
);
517 ExFreePool(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
);
518 /* our message is not in the private queue so we can remove the pointer
519 instead of setting it to the current message we're processing */
520 CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
= NULL
;
522 IntUnLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
524 else if (CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
== Message
)
526 CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
= NULL
;
530 UserDereferenceObject(CaptureWindow
);
536 co_MsqPeekHardwareMessage(PUSER_MESSAGE_QUEUE MessageQueue
, PWND Window
,
537 UINT FilterLow
, UINT FilterHigh
, BOOL Remove
,
543 PLIST_ENTRY CurrentEntry
;
544 PWND DesktopWindow
= NULL
;
545 PVOID WaitObjects
[2];
547 DECLARE_RETURN(BOOL
);
548 USER_REFERENCE_ENTRY Ref
;
549 PDESKTOPINFO Desk
= NULL
;
551 WaitObjects
[1] = MessageQueue
->NewMessages
;
552 WaitObjects
[0] = &HardwareMessageQueueLock
;
557 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
558 UserMode
, FALSE
, NULL
, NULL
);
562 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
564 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
568 UserRefObjectCo(DesktopWindow
, &Ref
);
569 Desk
= DesktopWindow
->head
.pti
->pDeskInfo
;
572 /* Process messages in the message queue itself. */
573 IntLockHardwareMessageQueue(MessageQueue
);
574 CurrentEntry
= MessageQueue
->HardwareMessagesListHead
.Flink
;
575 while (CurrentEntry
!= &MessageQueue
->HardwareMessagesListHead
)
577 PUSER_MESSAGE Current
=
578 CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
579 CurrentEntry
= CurrentEntry
->Flink
;
580 if (Current
->Msg
.message
>= WM_MOUSEFIRST
&&
581 Current
->Msg
.message
<= WM_MOUSELAST
)
585 Accept
= co_MsqTranslateMouseMessage(MessageQueue
, Window
, FilterLow
, FilterHigh
,
586 Current
, Remove
, &Freed
,
587 DesktopWindow
, &ScreenPoint
, FALSE
, &CurrentEntry
);
590 *Message
= Current
->Msg
;
593 RemoveEntryList(&Current
->ListEntry
);
594 MsqDestroyMessage(Current
);
596 IntUnLockHardwareMessageQueue(MessageQueue
);
597 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
600 Desk
->LastInputWasKbd
= FALSE
;
608 *Message
= Current
->Msg
;
611 RemoveEntryList(&Current
->ListEntry
);
612 MsqDestroyMessage(Current
);
614 IntUnLockHardwareMessageQueue(MessageQueue
);
615 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
620 IntUnLockHardwareMessageQueue(MessageQueue
);
622 /* Now try the global queue. */
624 /* Transfer all messages from the DPC accessible queue to the main queue. */
625 IntLockSystemMessageQueue(OldIrql
);
626 while (SystemMessageQueueCount
> 0)
628 PUSER_MESSAGE UserMsg
;
631 ASSERT(SystemMessageQueueHead
< SYSTEM_MESSAGE_QUEUE_SIZE
);
632 Msg
= SystemMessageQueue
[SystemMessageQueueHead
];
633 SystemMessageQueueHead
=
634 (SystemMessageQueueHead
+ 1) % SYSTEM_MESSAGE_QUEUE_SIZE
;
635 SystemMessageQueueCount
--;
636 IntUnLockSystemMessageQueue(OldIrql
);
638 UserMsg
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
639 /* What to do if out of memory? For now we just panic a bit in debug */
642 InsertTailList(&HardwareMessageQueueHead
, &UserMsg
->ListEntry
);
644 IntLockSystemMessageQueue(OldIrql
);
646 HardwareMessageQueueStamp
++;
647 IntUnLockSystemMessageQueue(OldIrql
);
649 /* Process messages in the queue until we find one to return. */
650 CurrentEntry
= HardwareMessageQueueHead
.Flink
;
651 while (CurrentEntry
!= &HardwareMessageQueueHead
)
653 PUSER_MESSAGE Current
=
654 CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
655 CurrentEntry
= CurrentEntry
->Flink
;
656 RemoveEntryList(&Current
->ListEntry
);
657 HardwareMessageQueueStamp
++;
658 if (Current
->Msg
.message
>= WM_MOUSEFIRST
&&
659 Current
->Msg
.message
<= WM_MOUSELAST
)
661 const ULONG ActiveStamp
= HardwareMessageQueueStamp
;
662 /* Translate the message. */
663 Accept
= co_MsqTranslateMouseMessage(MessageQueue
, Window
, FilterLow
, FilterHigh
,
664 Current
, Remove
, &Freed
,
665 DesktopWindow
, &ScreenPoint
, TRUE
, NULL
);
668 /* Check for no more messages in the system queue. */
669 IntLockSystemMessageQueue(OldIrql
);
670 if (SystemMessageQueueCount
== 0 &&
671 IsListEmpty(&HardwareMessageQueueHead
))
673 KeClearEvent(&HardwareMessageEvent
);
675 IntUnLockSystemMessageQueue(OldIrql
);
678 If we aren't removing the message then add it to the private
683 IntLockHardwareMessageQueue(MessageQueue
);
684 if(Current
->Msg
.message
== WM_MOUSEMOVE
)
686 if(MessageQueue
->MouseMoveMsg
)
688 RemoveEntryList(&MessageQueue
->MouseMoveMsg
->ListEntry
);
689 ExFreePool(MessageQueue
->MouseMoveMsg
);
691 MessageQueue
->MouseMoveMsg
= Current
;
693 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
694 &Current
->ListEntry
);
695 IntUnLockHardwareMessageQueue(MessageQueue
);
697 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
698 *Message
= Current
->Msg
;
702 MsqDestroyMessage(Current
);
707 /* If the contents of the queue changed then restart processing. */
708 if (HardwareMessageQueueStamp
!= ActiveStamp
)
710 CurrentEntry
= HardwareMessageQueueHead
.Flink
;
716 /* Check if the system message queue is now empty. */
717 IntLockSystemMessageQueue(OldIrql
);
718 if (SystemMessageQueueCount
== 0 && IsListEmpty(&HardwareMessageQueueHead
))
720 KeClearEvent(&HardwareMessageEvent
);
722 IntUnLockSystemMessageQueue(OldIrql
);
723 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
728 if (DesktopWindow
) UserDerefObjectCo(DesktopWindow
);
734 // Note: Only called from input.c.
737 co_MsqPostKeyboardMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
739 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
741 LARGE_INTEGER LargeTickCount
;
742 KBDLLHOOKSTRUCT KbdHookData
;
743 BOOLEAN Entered
= FALSE
;
745 DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
746 uMsg
, wParam
, lParam
);
748 // Condition may arise when calling MsqPostMessage and waiting for an event.
749 if (!UserIsEntered())
751 // Fixme: Not sure ATM if this thread is locked.
752 UserEnterExclusive();
756 FocusMessageQueue
= IntGetFocusMessageQueue();
760 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
761 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
767 KeQueryTickCount(&LargeTickCount
);
768 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
770 /* We can't get the Msg.pt point here since we don't know thread
771 (and thus the window station) the message will end up in yet. */
773 KbdHookData
.vkCode
= Msg
.wParam
;
774 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
775 KbdHookData
.flags
= (0 == (Msg
.lParam
& 0x01000000) ? 0 : LLKHF_EXTENDED
) |
776 (0 == (Msg
.lParam
& 0x20000000) ? 0 : LLKHF_ALTDOWN
) |
777 (0 == (Msg
.lParam
& 0x80000000) ? 0 : LLKHF_UP
);
778 KbdHookData
.time
= Msg
.time
;
779 KbdHookData
.dwExtraInfo
= 0;
780 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
782 DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
783 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
784 if (Entered
) UserLeave();
788 if (FocusMessageQueue
== NULL
)
790 DPRINT("No focus message queue\n");
791 if (Entered
) UserLeave();
795 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
797 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
798 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
800 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
802 Msg
.pt
= gpsi
->ptCursor
;
803 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
807 DPRINT("Invalid focus window handle\n");
810 if (Entered
) UserLeave();
815 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
818 PTHREADINFO Win32Thread
;
820 LARGE_INTEGER LargeTickCount
;
823 Status
= ObReferenceObjectByPointer (Thread
,
827 if (!NT_SUCCESS(Status
))
830 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
831 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
833 ObDereferenceObject ((PETHREAD
)Thread
);
837 Window
= IntGetWindowObject(hWnd
);
840 ObDereferenceObject ((PETHREAD
)Thread
);
845 Mesg
.message
= WM_HOTKEY
;
846 Mesg
.wParam
= wParam
;
847 Mesg
.lParam
= lParam
;
848 KeQueryTickCount(&LargeTickCount
);
849 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
850 Mesg
.pt
= gpsi
->ptCursor
;
851 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
852 UserDereferenceObject(Window
);
853 ObDereferenceObject (Thread
);
855 // InsertHeadList(&pThread->MessageQueue->PostedMessagesListHead,
856 // &Message->ListEntry);
857 // KeSetEvent(pThread->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
860 PUSER_MESSAGE FASTCALL
861 MsqCreateMessage(LPMSG Msg
)
863 PUSER_MESSAGE Message
;
865 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
871 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
877 MsqDestroyMessage(PUSER_MESSAGE Message
)
879 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
883 co_MsqDispatchSentNotifyMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
885 PLIST_ENTRY ListEntry
;
886 PUSER_SENT_MESSAGE_NOTIFY Message
;
888 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
890 ListEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
891 Message
= CONTAINING_RECORD(ListEntry
, USER_SENT_MESSAGE_NOTIFY
,
894 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
897 Message
->CompletionCallbackContext
,
905 MsqPeekSentMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
907 return(!IsListEmpty(&MessageQueue
->SentMessagesListHead
));
911 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
913 PUSER_SENT_MESSAGE Message
;
917 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
922 /* remove it from the list of pending messages */
923 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
924 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
926 /* insert it to the list of messages that are currently dispatched by this
928 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
929 &Message
->ListEntry
);
931 if (Message
->HookMessage
== MSQ_ISHOOK
)
932 { // Direct Hook Call processor
933 Result
= co_CallHook( Message
->Msg
.message
, // HookId
934 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
936 Message
->Msg
.lParam
);
938 else if (Message
->HookMessage
== MSQ_ISEVENT
)
939 { // Direct Event Call processor
940 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
943 Message
->Msg
.lParam
);
946 { /* Call the window procedure. */
947 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
948 Message
->Msg
.message
,
950 Message
->Msg
.lParam
);
953 /* remove the message from the local dispatching list, because it doesn't need
954 to be cleaned up on thread termination anymore */
955 RemoveEntryList(&Message
->ListEntry
);
957 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
958 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
960 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
962 /* only remove it from the dispatching list if not already removed by a timeout */
963 RemoveEntryList(&Message
->DispatchingListEntry
);
966 /* still keep the sender's message queue locked, so the sender can't exit the
967 MsqSendMessage() function (if timed out) */
969 /* Let the sender know the result. */
970 if (Message
->Result
!= NULL
)
972 *Message
->Result
= Result
;
975 if (Message
->HasPackedLParam
== TRUE
)
977 if (Message
->Msg
.lParam
)
978 ExFreePool((PVOID
)Message
->Msg
.lParam
);
981 /* Notify the sender. */
982 if (Message
->CompletionEvent
!= NULL
)
984 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
987 /* Call the callback if the message was sent with SendMessageCallback */
988 if (Message
->CompletionCallback
!= NULL
)
990 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
992 Message
->Msg
.message
,
993 Message
->CompletionCallbackContext
,
997 /* Only if it is not a no wait message */
998 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
1000 IntDereferenceMessageQueue(Message
->SenderQueue
);
1001 IntDereferenceMessageQueue(MessageQueue
);
1004 /* free the message */
1005 ExFreePoolWithTag(Message
, TAG_USRMSG
);
1010 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
1012 PUSER_SENT_MESSAGE SentMessage
;
1013 PUSER_MESSAGE PostedMessage
;
1014 PUSER_MESSAGE_QUEUE MessageQueue
;
1015 PLIST_ENTRY CurrentEntry
, ListHead
;
1016 PWND Window
= pWindow
;
1020 MessageQueue
= Window
->head
.pti
->MessageQueue
;
1021 ASSERT(MessageQueue
);
1023 /* remove the posted messages for this window */
1024 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1025 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1026 while (CurrentEntry
!= ListHead
)
1028 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1030 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
1032 RemoveEntryList(&PostedMessage
->ListEntry
);
1033 MsqDestroyMessage(PostedMessage
);
1034 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1038 CurrentEntry
= CurrentEntry
->Flink
;
1042 /* remove the sent messages for this window */
1043 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
1044 ListHead
= &MessageQueue
->SentMessagesListHead
;
1045 while (CurrentEntry
!= ListHead
)
1047 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1049 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
1051 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1053 RemoveEntryList(&SentMessage
->ListEntry
);
1055 /* remove the message from the dispatching list if neede */
1056 if ((!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1057 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1059 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
1062 /* wake the sender's thread */
1063 if (SentMessage
->CompletionEvent
!= NULL
)
1065 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1068 if (SentMessage
->HasPackedLParam
== TRUE
)
1070 if (SentMessage
->Msg
.lParam
)
1071 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
1074 /* Only if it is not a no wait message */
1075 if (!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1077 /* dereference our and the sender's message queue */
1078 IntDereferenceMessageQueue(MessageQueue
);
1079 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
1082 /* free the message */
1083 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
1085 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
1089 CurrentEntry
= CurrentEntry
->Flink
;
1095 MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1096 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage
)
1098 InsertTailList(&MessageQueue
->NotifyMessagesListHead
,
1099 &NotifyMessage
->ListEntry
);
1100 MessageQueue
->QueueBits
|= QS_SENDMESSAGE
;
1101 MessageQueue
->ChangedBits
|= QS_SENDMESSAGE
;
1102 if (MessageQueue
->WakeMask
& QS_SENDMESSAGE
)
1103 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1107 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1108 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
1109 UINT uTimeout
, BOOL Block
, INT HookMessage
,
1113 PUSER_SENT_MESSAGE Message
;
1114 KEVENT CompletionEvent
;
1115 NTSTATUS WaitStatus
;
1116 PUSER_MESSAGE_QUEUE ThreadQueue
;
1117 LARGE_INTEGER Timeout
;
1119 LRESULT Result
= 0; //// Result could be trashed. ////
1121 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1123 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1124 return STATUS_INSUFFICIENT_RESOURCES
;
1127 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1129 pti
= PsGetCurrentThreadWin32Thread();
1130 ThreadQueue
= pti
->MessageQueue
;
1131 ASSERT(ThreadQueue
!= MessageQueue
);
1133 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1135 /* FIXME - increase reference counter of sender's message queue here */
1137 Message
->Msg
.hwnd
= Wnd
;
1138 Message
->Msg
.message
= Msg
;
1139 Message
->Msg
.wParam
= wParam
;
1140 Message
->Msg
.lParam
= lParam
;
1141 Message
->CompletionEvent
= &CompletionEvent
;
1142 Message
->Result
= &Result
;
1143 Message
->SenderQueue
= ThreadQueue
;
1144 IntReferenceMessageQueue(ThreadQueue
);
1145 Message
->CompletionCallback
= NULL
;
1146 Message
->CompletionCallbackContext
= 0;
1147 Message
->HookMessage
= HookMessage
;
1148 Message
->HasPackedLParam
= FALSE
;
1150 IntReferenceMessageQueue(MessageQueue
);
1152 /* add it to the list of pending messages */
1153 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1155 /* queue it in the destination's message queue */
1156 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1158 MessageQueue
->QueueBits
|= QS_SENDMESSAGE
;
1159 MessageQueue
->ChangedBits
|= QS_SENDMESSAGE
;
1160 if (MessageQueue
->WakeMask
& QS_SENDMESSAGE
)
1161 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1163 /* we can't access the Message anymore since it could have already been deleted! */
1169 /* don't process messages sent to the thread */
1170 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1171 FALSE
, (uTimeout
? &Timeout
: NULL
));
1175 if(WaitStatus
== STATUS_TIMEOUT
)
1177 /* look up if the message has not yet dispatched, if so
1178 make sure it can't pass a result and it must not set the completion event anymore */
1179 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1180 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1182 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1185 /* we can access Message here, it's secure because the message queue is locked
1186 and the message is still hasn't been dispatched */
1187 Message
->CompletionEvent
= NULL
;
1188 Message
->Result
= NULL
;
1191 Entry
= Entry
->Flink
;
1194 /* remove from the local dispatching list so the other thread knows,
1195 it can't pass a result and it must not set the completion event anymore */
1196 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1197 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1199 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1202 /* we can access Message here, it's secure because the sender's message is locked
1203 and the message has definitely not yet been destroyed, otherwise it would
1204 have been removed from this list by the dispatching routine right after
1205 dispatching the message */
1206 Message
->CompletionEvent
= NULL
;
1207 Message
->Result
= NULL
;
1208 RemoveEntryList(&Message
->DispatchingListEntry
);
1209 Message
->DispatchingListEntry
.Flink
= NULL
;
1212 Entry
= Entry
->Flink
;
1215 DPRINT("MsqSendMessage (blocked) timed out\n");
1217 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1222 PVOID WaitObjects
[2];
1224 WaitObjects
[0] = &CompletionEvent
;
1225 WaitObjects
[1] = ThreadQueue
->NewMessages
;
1230 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1231 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1235 if(WaitStatus
== STATUS_TIMEOUT
)
1237 /* look up if the message has not yet been dispatched, if so
1238 make sure it can't pass a result and it must not set the completion event anymore */
1239 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1240 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1242 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1245 /* we can access Message here, it's secure because the message queue is locked
1246 and the message is still hasn't been dispatched */
1247 Message
->CompletionEvent
= NULL
;
1248 Message
->Result
= NULL
;
1251 Entry
= Entry
->Flink
;
1254 /* remove from the local dispatching list so the other thread knows,
1255 it can't pass a result and it must not set the completion event anymore */
1256 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1257 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1259 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1262 /* we can access Message here, it's secure because the sender's message is locked
1263 and the message has definitely not yet been destroyed, otherwise it would
1264 have been removed from this list by the dispatching routine right after
1265 dispatching the message */
1266 Message
->CompletionEvent
= NULL
;
1267 Message
->Result
= NULL
;
1268 RemoveEntryList(&Message
->DispatchingListEntry
);
1269 Message
->DispatchingListEntry
.Flink
= NULL
;
1272 Entry
= Entry
->Flink
;
1275 DPRINT("MsqSendMessage timed out\n");
1278 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1281 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
1284 if(WaitStatus
!= STATUS_TIMEOUT
)
1285 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1291 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
1294 PUSER_MESSAGE Message
;
1296 if(!(Message
= MsqCreateMessage(Msg
)))
1301 if(!HardwareMessage
)
1303 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1304 &Message
->ListEntry
);
1308 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1309 &Message
->ListEntry
);
1311 MessageQueue
->QueueBits
|= MessageBits
;
1312 MessageQueue
->ChangedBits
|= MessageBits
;
1313 if (MessageQueue
->WakeMask
& MessageBits
)
1314 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1318 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1320 MessageQueue
->QuitPosted
= TRUE
;
1321 MessageQueue
->QuitExitCode
= ExitCode
;
1322 MessageQueue
->QueueBits
|= QS_POSTMESSAGE
;
1323 MessageQueue
->ChangedBits
|= QS_POSTMESSAGE
;
1324 if (MessageQueue
->WakeMask
& QS_POSTMESSAGE
)
1325 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
1329 co_MsqFindMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1330 IN BOOLEAN Hardware
,
1333 IN UINT MsgFilterLow
,
1334 IN UINT MsgFilterHigh
,
1337 PLIST_ENTRY CurrentEntry
;
1338 PUSER_MESSAGE CurrentMessage
;
1339 PLIST_ENTRY ListHead
;
1343 return(co_MsqPeekHardwareMessage( MessageQueue
,
1351 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1352 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1353 while (CurrentEntry
!= ListHead
)
1355 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1358 PtrToInt(Window
) == 1 ||
1359 Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) &&
1360 ( (MsgFilterLow
== 0 && MsgFilterHigh
== 0) ||
1361 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&&
1362 MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1366 RemoveEntryList(&CurrentMessage
->ListEntry
);
1369 *Message
= CurrentMessage
->Msg
;
1373 MsqDestroyMessage(CurrentMessage
);
1378 CurrentEntry
= CurrentEntry
->Flink
;
1385 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1386 UINT MsgFilterMin
, UINT MsgFilterMax
)
1388 PVOID WaitObjects
[2] = {MessageQueue
->NewMessages
, &HardwareMessageEvent
};
1393 ret
= KeWaitForMultipleObjects(2,
1406 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1408 LARGE_INTEGER LargeTickCount
;
1410 KeQueryTickCount(&LargeTickCount
);
1411 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1415 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1417 LARGE_INTEGER LargeTickCount
;
1420 MessageQueue
->Thread
= Thread
;
1421 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1422 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1423 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1424 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1425 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1426 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1427 KeInitializeMutex(&MessageQueue
->HardwareLock
, 0);
1428 MessageQueue
->QuitPosted
= FALSE
;
1429 MessageQueue
->QuitExitCode
= 0;
1430 KeQueryTickCount(&LargeTickCount
);
1431 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1432 MessageQueue
->FocusWindow
= NULL
;
1433 MessageQueue
->PaintCount
= 0;
1434 // HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt)
1435 MessageQueue
->WakeMask
= ~0;
1436 MessageQueue
->NewMessagesHandle
= NULL
;
1438 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1439 NULL
, SynchronizationEvent
, FALSE
);
1440 if (!NT_SUCCESS(Status
))
1445 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1446 ExEventObjectType
, KernelMode
,
1447 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1448 if (!NT_SUCCESS(Status
))
1450 ZwClose(MessageQueue
->NewMessagesHandle
);
1451 MessageQueue
->NewMessagesHandle
= NULL
;
1459 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1461 PLIST_ENTRY CurrentEntry
;
1462 PUSER_MESSAGE CurrentMessage
;
1463 PUSER_SENT_MESSAGE CurrentSentMessage
;
1465 /* cleanup posted messages */
1466 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1468 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1469 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1471 MsqDestroyMessage(CurrentMessage
);
1474 /* remove the messages that have not yet been dispatched */
1475 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1477 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1478 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1481 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1483 /* remove the message from the dispatching list if needed */
1484 if ((!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1485 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1487 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1490 /* wake the sender's thread */
1491 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1493 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1496 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1498 if (CurrentSentMessage
->Msg
.lParam
)
1499 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1502 /* Only if it is not a no wait message */
1503 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1505 /* dereference our and the sender's message queue */
1506 IntDereferenceMessageQueue(MessageQueue
);
1507 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1510 /* free the message */
1511 ExFreePool(CurrentSentMessage
);
1514 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1515 ExitThread() was called in a SendMessage() umode callback */
1516 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1518 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1519 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1522 /* remove the message from the dispatching list */
1523 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1525 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1528 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1530 /* wake the sender's thread */
1531 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1533 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1536 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1538 if (CurrentSentMessage
->Msg
.lParam
)
1539 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1542 /* Only if it is not a no wait message */
1543 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1545 /* dereference our and the sender's message queue */
1546 IntDereferenceMessageQueue(MessageQueue
);
1547 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1550 /* free the message */
1551 ExFreePool(CurrentSentMessage
);
1554 /* tell other threads not to bother returning any info to us */
1555 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
1557 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
1558 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1559 DispatchingListEntry
);
1560 CurrentSentMessage
->CompletionEvent
= NULL
;
1561 CurrentSentMessage
->Result
= NULL
;
1563 /* do NOT dereference our message queue as it might get attempted to be
1569 PUSER_MESSAGE_QUEUE FASTCALL
1570 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
1572 PUSER_MESSAGE_QUEUE MessageQueue
;
1574 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
1575 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
1583 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
1584 /* hold at least one reference until it'll be destroyed */
1585 IntReferenceMessageQueue(MessageQueue
);
1586 /* initialize the queue */
1587 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
1589 IntDereferenceMessageQueue(MessageQueue
);
1593 return MessageQueue
;
1597 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1601 /* remove the message queue from any desktops */
1602 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
1604 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
1605 IntDereferenceMessageQueue(MessageQueue
);
1609 MsqCleanupMessageQueue(MessageQueue
);
1611 /* decrease the reference counter, if it hits zero, the queue will be freed */
1612 IntDereferenceMessageQueue(MessageQueue
);
1616 MsqSetMessageExtraInfo(LPARAM lParam
)
1620 PUSER_MESSAGE_QUEUE MessageQueue
;
1622 pti
= PsGetCurrentThreadWin32Thread();
1623 MessageQueue
= pti
->MessageQueue
;
1629 Ret
= MessageQueue
->ExtraInfo
;
1630 MessageQueue
->ExtraInfo
= lParam
;
1636 MsqGetMessageExtraInfo(VOID
)
1639 PUSER_MESSAGE_QUEUE MessageQueue
;
1641 pti
= PsGetCurrentThreadWin32Thread();
1642 MessageQueue
= pti
->MessageQueue
;
1648 return MessageQueue
->ExtraInfo
;
1652 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
1658 case MSQ_STATE_CAPTURE
:
1659 Prev
= MessageQueue
->CaptureWindow
;
1660 MessageQueue
->CaptureWindow
= hWnd
;
1662 case MSQ_STATE_ACTIVE
:
1663 Prev
= MessageQueue
->ActiveWindow
;
1664 MessageQueue
->ActiveWindow
= hWnd
;
1666 case MSQ_STATE_FOCUS
:
1667 Prev
= MessageQueue
->FocusWindow
;
1668 MessageQueue
->FocusWindow
= hWnd
;
1670 case MSQ_STATE_MENUOWNER
:
1671 Prev
= MessageQueue
->MenuOwner
;
1672 MessageQueue
->MenuOwner
= hWnd
;
1674 case MSQ_STATE_MOVESIZE
:
1675 Prev
= MessageQueue
->MoveSize
;
1676 MessageQueue
->MoveSize
= hWnd
;
1678 case MSQ_STATE_CARET
:
1679 ASSERT(MessageQueue
->CaretInfo
);
1680 Prev
= MessageQueue
->CaretInfo
->hWnd
;
1681 MessageQueue
->CaretInfo
->hWnd
= hWnd
;