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 if (Win32Thread
->pcti
)
81 Win32Thread
->pcti
->fsWakeMask
= WakeMask
;
85 return MessageEventHandle
;
89 IntMsqClearWakeMask(VOID
)
91 PTHREADINFO Win32Thread
;
92 PUSER_MESSAGE_QUEUE MessageQueue
;
94 Win32Thread
= PsGetCurrentThreadWin32Thread();
95 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
98 MessageQueue
= Win32Thread
->MessageQueue
;
99 // HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt)
100 MessageQueue
->WakeMask
= ~0;
102 if (Win32Thread
->pcti
)
103 Win32Thread
->pcti
->fsWakeMask
= 0;
111 MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue
, DWORD MessageBits
)
113 Queue
->QueueBits
|= MessageBits
;
114 Queue
->ChangedBits
|= MessageBits
;
115 if (Queue
->WakeMask
& MessageBits
)
116 KeSetEvent(Queue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
120 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
123 MsqWakeQueue(Queue
, QS_PAINT
);
127 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
136 MsqInitializeImpl(VOID
)
138 /*CurrentFocusMessageQueue = NULL;*/
139 InitializeListHead(&HardwareMessageQueueHead
);
140 KeInitializeEvent(&HardwareMessageEvent
, NotificationEvent
, 0);
141 KeInitializeSpinLock(&SystemMessageQueueLock
);
142 KeInitializeMutant(&HardwareMessageQueueLock
, 0);
144 ExInitializePagedLookasideList(&MessageLookasideList
,
148 sizeof(USER_MESSAGE
),
152 return(STATUS_SUCCESS
);
156 co_MsqInsertMouseMessage(MSG
* Msg
)
158 LARGE_INTEGER LargeTickCount
;
161 MSLLHOOKSTRUCT MouseHookData
;
163 KeQueryTickCount(&LargeTickCount
);
164 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
166 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
167 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
171 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
175 case WM_XBUTTONDBLCLK
:
176 case WM_NCXBUTTONDOWN
:
178 case WM_NCXBUTTONDBLCLK
:
179 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
182 MouseHookData
.mouseData
= 0;
186 MouseHookData
.flags
= 0;
187 MouseHookData
.time
= Msg
->time
;
188 MouseHookData
.dwExtraInfo
= 0;
190 /* If the hook procedure returned non zero, dont send the message */
191 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
195 * If we got WM_MOUSEMOVE and there are already messages in the
196 * system message queue, check if the last message is mouse move
197 * and if it is then just overwrite it.
199 IntLockSystemMessageQueue(OldIrql
);
202 * Bail out if the queue is full. FIXME: We should handle this case
206 if (SystemMessageQueueCount
== SYSTEM_MESSAGE_QUEUE_SIZE
)
208 IntUnLockSystemMessageQueue(OldIrql
);
212 if (Msg
->message
== WM_MOUSEMOVE
&& SystemMessageQueueCount
)
214 if (SystemMessageQueueTail
== 0)
215 Prev
= SYSTEM_MESSAGE_QUEUE_SIZE
- 1;
217 Prev
= SystemMessageQueueTail
- 1;
218 if (SystemMessageQueue
[Prev
].message
== WM_MOUSEMOVE
)
220 SystemMessageQueueTail
= Prev
;
221 SystemMessageQueueCount
--;
226 * Actually insert the message into the system message queue.
229 SystemMessageQueue
[SystemMessageQueueTail
] = *Msg
;
230 SystemMessageQueueTail
=
231 (SystemMessageQueueTail
+ 1) % SYSTEM_MESSAGE_QUEUE_SIZE
;
232 SystemMessageQueueCount
++;
234 IntUnLockSystemMessageQueue(OldIrql
);
236 KeSetEvent(&HardwareMessageEvent
, IO_NO_INCREMENT
, FALSE
);
240 MsqIsClkLck(LPMSG Msg
, BOOL Remove
)
243 PSYSTEM_CURSORINFO CurInfo
;
246 pti
= PsGetCurrentThreadWin32Thread();
247 if (pti
->rpdesk
== NULL
)
252 CurInfo
= IntGetSysCursorInfo();
254 switch (Msg
->message
)
257 Res
= ((Msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
258 if (Res
&& (!CurInfo
->ClickLockActive
))
260 CurInfo
->ClickLockActive
= TRUE
;
264 if (CurInfo
->ClickLockActive
)
267 CurInfo
->ClickLockActive
= FALSE
;
268 CurInfo
->ClickLockTime
= 0;
272 CurInfo
->ClickLockTime
= Msg
->time
;
280 MsqIsDblClk(LPMSG Msg
, BOOL Remove
)
283 PSYSTEM_CURSORINFO CurInfo
;
287 pti
= PsGetCurrentThreadWin32Thread();
288 if (pti
->rpdesk
== NULL
)
293 CurInfo
= IntGetSysCursorInfo();
294 Res
= (Msg
->hwnd
== (HWND
)CurInfo
->LastClkWnd
) &&
295 ((Msg
->time
- CurInfo
->LastBtnDown
) < gspv
.iDblClickTime
);
299 dX
= CurInfo
->LastBtnDownX
- Msg
->pt
.x
;
300 dY
= CurInfo
->LastBtnDownY
- Msg
->pt
.y
;
306 Res
= (dX
<= gspv
.iDblClickWidth
) &&
307 (dY
<= gspv
.iDblClickHeight
);
311 if(CurInfo
->ButtonsDown
)
312 Res
= (CurInfo
->ButtonsDown
== Msg
->message
);
318 CurInfo
->LastBtnDownX
= Msg
->pt
.x
;
319 CurInfo
->LastBtnDownY
= Msg
->pt
.y
;
320 CurInfo
->ButtonsDown
= Msg
->message
;
323 CurInfo
->LastBtnDown
= 0;
324 CurInfo
->LastClkWnd
= NULL
;
328 CurInfo
->LastClkWnd
= (HANDLE
)Msg
->hwnd
;
329 CurInfo
->LastBtnDown
= Msg
->time
;
337 co_MsqTranslateMouseMessage(PUSER_MESSAGE_QUEUE MessageQueue
, PWND Window
, UINT FilterLow
, UINT FilterHigh
,
338 PUSER_MESSAGE Message
, BOOL Remove
, PBOOL Freed
,
339 PWND ScopeWin
, PPOINT ScreenPoint
, BOOL FromGlobalQueue
, PLIST_ENTRY
*Next
)
341 USHORT Msg
= Message
->Msg
.message
;
342 PWND CaptureWindow
= NULL
;
345 /* FIXME: Mouse message can be sent before the Desktop is up and running in which case ScopeWin (Desktop) is 0.
346 Is this the best fix? */
347 if (ScopeWin
== 0) return FALSE
;
349 ASSERT_REFS_CO(ScopeWin
);
352 co_WinPosWindowFromPoint can return a Window, and in that case
353 that window has a ref that we need to deref. Thats why we add "dummy"
354 refs in all other cases.
357 hCaptureWin
= IntGetCaptureWindow();
358 if (hCaptureWin
== NULL
)
360 if (Msg
== WM_MOUSEWHEEL
)
362 CaptureWindow
= UserGetWindowObject(IntGetFocusWindow());
363 if (CaptureWindow
) UserReferenceObject(CaptureWindow
);
367 co_WinPosWindowFromPoint(ScopeWin
, NULL
, &Message
->Msg
.pt
, &CaptureWindow
);
368 if(CaptureWindow
== NULL
)
370 CaptureWindow
= ScopeWin
;
371 if (CaptureWindow
) UserReferenceObject(CaptureWindow
);
375 /* this is the one case where we dont add a ref, since the returned
376 window is already referenced */
382 /* FIXME - window messages should go to the right window if no buttons are
384 CaptureWindow
= UserGetWindowObject(hCaptureWin
);
385 if (CaptureWindow
) UserReferenceObject(CaptureWindow
);
390 if (CaptureWindow
== NULL
)
394 RemoveEntryList(&Message
->ListEntry
);
395 if(MessageQueue
->MouseMoveMsg
== Message
)
397 MessageQueue
->MouseMoveMsg
= NULL
;
400 // when FromGlobalQueue is true, the caller has already removed the Message
406 if (CaptureWindow
->head
.pti
->MessageQueue
!= MessageQueue
)
408 if (! FromGlobalQueue
)
410 DPRINT("Moving msg between private queues\n");
411 /* This message is already queued in a private queue, but we need
412 * to move it to a different queue, perhaps because a new window
413 * was created which now covers the screen area previously taken
414 * by another window. To move it, we need to take it out of the
415 * old queue. Note that we're already holding the lock mutexes of the
417 RemoveEntryList(&Message
->ListEntry
);
419 /* remove the pointer for the current WM_MOUSEMOVE message in case we
421 if(MessageQueue
->MouseMoveMsg
== Message
)
423 MessageQueue
->MouseMoveMsg
= NULL
;
427 /* lock the destination message queue, so we don't get in trouble with other
428 threads, messing with it at the same time */
429 IntLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
430 InsertTailList(&CaptureWindow
->head
.pti
->MessageQueue
->HardwareMessagesListHead
,
431 &Message
->ListEntry
);
432 if(Message
->Msg
.message
== WM_MOUSEMOVE
)
434 if(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
)
436 /* remove the old WM_MOUSEMOVE message, we're processing a more recent
438 RemoveEntryList(&CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
->ListEntry
);
439 ExFreePool(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
);
441 /* save the pointer to the WM_MOUSEMOVE message in the new queue */
442 CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
= Message
;
444 MsqWakeQueue(CaptureWindow
->head
.pti
->MessageQueue
, QS_MOUSEMOVE
);
448 MsqWakeQueue(CaptureWindow
->head
.pti
->MessageQueue
, QS_MOUSEBUTTON
);
450 IntUnLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
453 UserDereferenceObject(CaptureWindow
);
457 /* From here on, we're in the same message queue as the caller! */
459 *ScreenPoint
= Message
->Msg
.pt
;
461 if((Window
!= NULL
&& PtrToInt(Window
) != 1 && CaptureWindow
->head
.h
!= Window
->head
.h
) ||
462 ((FilterLow
!= 0 || FilterHigh
!= 0) && (Msg
< FilterLow
|| Msg
> FilterHigh
)))
464 /* Reject the message because it doesn't match the filter */
468 /* Lock the message queue so no other thread can mess with it.
469 Our own message queue is not locked while fetching from the global
470 queue, so we have to make sure nothing interferes! */
471 IntLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
472 /* if we're from the global queue, we need to add our message to our
473 private queue so we don't loose it! */
474 InsertTailList(&CaptureWindow
->head
.pti
->MessageQueue
->HardwareMessagesListHead
,
475 &Message
->ListEntry
);
478 if (Message
->Msg
.message
== WM_MOUSEMOVE
)
480 if(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
&&
481 (CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
!= Message
))
483 /* delete the old message */
484 RemoveEntryList(&CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
->ListEntry
);
485 ExFreePool(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
);
486 if (!FromGlobalQueue
)
488 // We might have deleted the next one in our queue, so fix next
489 *Next
= Message
->ListEntry
.Flink
;
492 /* always save a pointer to this WM_MOUSEMOVE message here because we're
493 sure that the message is in the private queue */
494 CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
= Message
;
498 IntUnLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
501 UserDereferenceObject(CaptureWindow
);
506 /* FIXME - only assign if removing? */
507 Message
->Msg
.hwnd
= CaptureWindow
->head
.h
;
508 Message
->Msg
.message
= Msg
;
509 Message
->Msg
.lParam
= MAKELONG(Message
->Msg
.pt
.x
, Message
->Msg
.pt
.y
);
511 /* remove the reference to the current WM_(NC)MOUSEMOVE message, if this message
513 if (Message
->Msg
.message
== WM_MOUSEMOVE
||
514 Message
->Msg
.message
== WM_NCMOUSEMOVE
)
518 /* Lock the message queue so no other thread can mess with it.
519 Our own message queue is not locked while fetching from the global
520 queue, so we have to make sure nothing interferes! */
521 IntLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
522 if(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
)
524 /* delete the WM_(NC)MOUSEMOVE message in the private queue, we're dealing
525 with one that's been sent later */
526 RemoveEntryList(&CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
->ListEntry
);
527 ExFreePool(CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
);
528 /* our message is not in the private queue so we can remove the pointer
529 instead of setting it to the current message we're processing */
530 CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
= NULL
;
532 IntUnLockHardwareMessageQueue(CaptureWindow
->head
.pti
->MessageQueue
);
534 else if (CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
== Message
)
536 CaptureWindow
->head
.pti
->MessageQueue
->MouseMoveMsg
= NULL
;
540 UserDereferenceObject(CaptureWindow
);
546 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
556 PLIST_ENTRY CurrentEntry
;
557 PWND DesktopWindow
= NULL
;
558 PVOID WaitObjects
[2];
560 DECLARE_RETURN(BOOL
);
561 USER_REFERENCE_ENTRY Ref
;
562 PDESKTOPINFO Desk
= NULL
;
564 WaitObjects
[1] = MessageQueue
->NewMessages
;
565 WaitObjects
[0] = &HardwareMessageQueueLock
;
570 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
571 UserMode
, FALSE
, NULL
, NULL
);
575 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
577 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
581 UserRefObjectCo(DesktopWindow
, &Ref
);
582 Desk
= DesktopWindow
->head
.pti
->pDeskInfo
;
585 /* Process messages in the message queue itself. */
586 IntLockHardwareMessageQueue(MessageQueue
);
587 CurrentEntry
= MessageQueue
->HardwareMessagesListHead
.Flink
;
588 while (CurrentEntry
!= &MessageQueue
->HardwareMessagesListHead
)
590 PUSER_MESSAGE Current
=
591 CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
592 CurrentEntry
= CurrentEntry
->Flink
;
593 if (Current
->Msg
.message
>= WM_MOUSEFIRST
&&
594 Current
->Msg
.message
<= WM_MOUSELAST
)
598 Accept
= co_MsqTranslateMouseMessage(MessageQueue
, Window
, FilterLow
, FilterHigh
,
599 Current
, Remove
, &Freed
,
600 DesktopWindow
, &ScreenPoint
, FALSE
, &CurrentEntry
);
603 *Message
= Current
->Msg
;
606 RemoveEntryList(&Current
->ListEntry
);
607 MsqDestroyMessage(Current
);
609 IntUnLockHardwareMessageQueue(MessageQueue
);
610 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
613 Desk
->LastInputWasKbd
= FALSE
;
621 *Message
= Current
->Msg
;
624 RemoveEntryList(&Current
->ListEntry
);
625 MsqDestroyMessage(Current
);
627 IntUnLockHardwareMessageQueue(MessageQueue
);
628 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
633 IntUnLockHardwareMessageQueue(MessageQueue
);
635 /* Now try the global queue. */
637 /* Transfer all messages from the DPC accessible queue to the main queue. */
638 IntLockSystemMessageQueue(OldIrql
);
639 while (SystemMessageQueueCount
> 0)
641 PUSER_MESSAGE UserMsg
;
644 ASSERT(SystemMessageQueueHead
< SYSTEM_MESSAGE_QUEUE_SIZE
);
645 Msg
= SystemMessageQueue
[SystemMessageQueueHead
];
646 SystemMessageQueueHead
=
647 (SystemMessageQueueHead
+ 1) % SYSTEM_MESSAGE_QUEUE_SIZE
;
648 SystemMessageQueueCount
--;
649 IntUnLockSystemMessageQueue(OldIrql
);
651 UserMsg
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
652 /* What to do if out of memory? For now we just panic a bit in debug */
655 InsertTailList(&HardwareMessageQueueHead
, &UserMsg
->ListEntry
);
657 IntLockSystemMessageQueue(OldIrql
);
659 HardwareMessageQueueStamp
++;
660 IntUnLockSystemMessageQueue(OldIrql
);
662 /* Process messages in the queue until we find one to return. */
663 CurrentEntry
= HardwareMessageQueueHead
.Flink
;
664 while (CurrentEntry
!= &HardwareMessageQueueHead
)
666 PUSER_MESSAGE Current
=
667 CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
668 CurrentEntry
= CurrentEntry
->Flink
;
669 RemoveEntryList(&Current
->ListEntry
);
670 HardwareMessageQueueStamp
++;
671 if (Current
->Msg
.message
>= WM_MOUSEFIRST
&&
672 Current
->Msg
.message
<= WM_MOUSELAST
)
674 const ULONG ActiveStamp
= HardwareMessageQueueStamp
;
675 /* Translate the message. */
676 Accept
= co_MsqTranslateMouseMessage(MessageQueue
, Window
, FilterLow
, FilterHigh
,
677 Current
, Remove
, &Freed
,
678 DesktopWindow
, &ScreenPoint
, TRUE
, NULL
);
681 /* Check for no more messages in the system queue. */
682 IntLockSystemMessageQueue(OldIrql
);
683 if (SystemMessageQueueCount
== 0 &&
684 IsListEmpty(&HardwareMessageQueueHead
))
686 KeClearEvent(&HardwareMessageEvent
);
688 IntUnLockSystemMessageQueue(OldIrql
);
691 If we aren't removing the message then add it to the private
696 IntLockHardwareMessageQueue(MessageQueue
);
697 if(Current
->Msg
.message
== WM_MOUSEMOVE
)
699 if(MessageQueue
->MouseMoveMsg
)
701 RemoveEntryList(&MessageQueue
->MouseMoveMsg
->ListEntry
);
702 ExFreePool(MessageQueue
->MouseMoveMsg
);
704 MessageQueue
->MouseMoveMsg
= Current
;
706 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
707 &Current
->ListEntry
);
708 IntUnLockHardwareMessageQueue(MessageQueue
);
710 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
711 *Message
= Current
->Msg
;
715 MsqDestroyMessage(Current
);
720 /* If the contents of the queue changed then restart processing. */
721 if (HardwareMessageQueueStamp
!= ActiveStamp
)
723 CurrentEntry
= HardwareMessageQueueHead
.Flink
;
729 /* Check if the system message queue is now empty. */
730 IntLockSystemMessageQueue(OldIrql
);
731 if (SystemMessageQueueCount
== 0 && IsListEmpty(&HardwareMessageQueueHead
))
733 KeClearEvent(&HardwareMessageEvent
);
735 IntUnLockSystemMessageQueue(OldIrql
);
736 IntUnLockSystemHardwareMessageQueueLock(FALSE
);
741 if (DesktopWindow
) UserDerefObjectCo(DesktopWindow
);
747 // Note: Only called from input.c.
750 co_MsqPostKeyboardMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
752 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
754 LARGE_INTEGER LargeTickCount
;
755 KBDLLHOOKSTRUCT KbdHookData
;
756 BOOLEAN Entered
= FALSE
;
758 DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
759 uMsg
, wParam
, lParam
);
761 // Condition may arise when calling MsqPostMessage and waiting for an event.
762 if (!UserIsEntered())
764 // Fixme: Not sure ATM if this thread is locked.
765 UserEnterExclusive();
769 FocusMessageQueue
= IntGetFocusMessageQueue();
773 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
774 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
780 KeQueryTickCount(&LargeTickCount
);
781 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
783 /* We can't get the Msg.pt point here since we don't know thread
784 (and thus the window station) the message will end up in yet. */
786 KbdHookData
.vkCode
= Msg
.wParam
;
787 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
788 KbdHookData
.flags
= (0 == (Msg
.lParam
& 0x01000000) ? 0 : LLKHF_EXTENDED
) |
789 (0 == (Msg
.lParam
& 0x20000000) ? 0 : LLKHF_ALTDOWN
) |
790 (0 == (Msg
.lParam
& 0x80000000) ? 0 : LLKHF_UP
);
791 KbdHookData
.time
= Msg
.time
;
792 KbdHookData
.dwExtraInfo
= 0;
793 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
795 DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
796 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
797 if (Entered
) UserLeave();
801 if (FocusMessageQueue
== NULL
)
803 DPRINT("No focus message queue\n");
804 if (Entered
) UserLeave();
808 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
810 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
811 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
813 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
815 Msg
.pt
= gpsi
->ptCursor
;
816 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
820 DPRINT("Invalid focus window handle\n");
823 if (Entered
) UserLeave();
828 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
831 PTHREADINFO Win32Thread
;
833 LARGE_INTEGER LargeTickCount
;
836 Status
= ObReferenceObjectByPointer (Thread
,
840 if (!NT_SUCCESS(Status
))
843 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
844 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
846 ObDereferenceObject ((PETHREAD
)Thread
);
850 Window
= IntGetWindowObject(hWnd
);
853 ObDereferenceObject ((PETHREAD
)Thread
);
858 Mesg
.message
= WM_HOTKEY
;
859 Mesg
.wParam
= wParam
;
860 Mesg
.lParam
= lParam
;
861 KeQueryTickCount(&LargeTickCount
);
862 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
863 Mesg
.pt
= gpsi
->ptCursor
;
864 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
865 UserDereferenceObject(Window
);
866 ObDereferenceObject (Thread
);
870 PUSER_MESSAGE FASTCALL
871 MsqCreateMessage(LPMSG Msg
)
873 PUSER_MESSAGE Message
;
875 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
881 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
887 MsqDestroyMessage(PUSER_MESSAGE Message
)
889 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
893 co_MsqDispatchSentNotifyMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
895 PLIST_ENTRY ListEntry
;
896 PUSER_SENT_MESSAGE_NOTIFY Message
;
898 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
900 ListEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
901 Message
= CONTAINING_RECORD(ListEntry
, USER_SENT_MESSAGE_NOTIFY
,
904 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
907 Message
->CompletionCallbackContext
,
915 MsqPeekSentMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
917 return(!IsListEmpty(&MessageQueue
->SentMessagesListHead
));
921 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
923 PUSER_SENT_MESSAGE Message
;
927 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
932 /* remove it from the list of pending messages */
933 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
934 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
936 /* insert it to the list of messages that are currently dispatched by this
938 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
939 &Message
->ListEntry
);
941 if (Message
->HookMessage
== MSQ_ISHOOK
)
942 { // Direct Hook Call processor
943 Result
= co_CallHook( Message
->Msg
.message
, // HookId
944 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
946 Message
->Msg
.lParam
);
948 else if (Message
->HookMessage
== MSQ_ISEVENT
)
949 { // Direct Event Call processor
950 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
953 Message
->Msg
.lParam
);
956 { /* Call the window procedure. */
957 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
958 Message
->Msg
.message
,
960 Message
->Msg
.lParam
);
963 /* remove the message from the local dispatching list, because it doesn't need
964 to be cleaned up on thread termination anymore */
965 RemoveEntryList(&Message
->ListEntry
);
967 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
968 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
970 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
972 /* only remove it from the dispatching list if not already removed by a timeout */
973 RemoveEntryList(&Message
->DispatchingListEntry
);
976 /* still keep the sender's message queue locked, so the sender can't exit the
977 MsqSendMessage() function (if timed out) */
979 /* Let the sender know the result. */
980 if (Message
->Result
!= NULL
)
982 *Message
->Result
= Result
;
985 if (Message
->HasPackedLParam
== TRUE
)
987 if (Message
->Msg
.lParam
)
988 ExFreePool((PVOID
)Message
->Msg
.lParam
);
991 /* Notify the sender. */
992 if (Message
->CompletionEvent
!= NULL
)
994 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
997 /* Call the callback if the message was sent with SendMessageCallback */
998 if (Message
->CompletionCallback
!= NULL
)
1000 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
1002 Message
->Msg
.message
,
1003 Message
->CompletionCallbackContext
,
1007 /* Only if it is not a no wait message */
1008 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
1010 IntDereferenceMessageQueue(Message
->SenderQueue
);
1011 IntDereferenceMessageQueue(MessageQueue
);
1014 /* free the message */
1015 ExFreePoolWithTag(Message
, TAG_USRMSG
);
1020 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
1022 PUSER_SENT_MESSAGE SentMessage
;
1023 PUSER_MESSAGE PostedMessage
;
1024 PUSER_MESSAGE_QUEUE MessageQueue
;
1025 PLIST_ENTRY CurrentEntry
, ListHead
;
1026 PWND Window
= pWindow
;
1030 MessageQueue
= Window
->head
.pti
->MessageQueue
;
1031 ASSERT(MessageQueue
);
1033 /* remove the posted messages for this window */
1034 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1035 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1036 while (CurrentEntry
!= ListHead
)
1038 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1040 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
1042 RemoveEntryList(&PostedMessage
->ListEntry
);
1043 MsqDestroyMessage(PostedMessage
);
1044 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1048 CurrentEntry
= CurrentEntry
->Flink
;
1052 /* remove the sent messages for this window */
1053 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
1054 ListHead
= &MessageQueue
->SentMessagesListHead
;
1055 while (CurrentEntry
!= ListHead
)
1057 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1059 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
1061 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1063 RemoveEntryList(&SentMessage
->ListEntry
);
1065 /* remove the message from the dispatching list if neede */
1066 if ((!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1067 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1069 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
1072 /* wake the sender's thread */
1073 if (SentMessage
->CompletionEvent
!= NULL
)
1075 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1078 if (SentMessage
->HasPackedLParam
== TRUE
)
1080 if (SentMessage
->Msg
.lParam
)
1081 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
1084 /* Only if it is not a no wait message */
1085 if (!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1087 /* dereference our and the sender's message queue */
1088 IntDereferenceMessageQueue(MessageQueue
);
1089 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
1092 /* free the message */
1093 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
1095 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
1099 CurrentEntry
= CurrentEntry
->Flink
;
1105 MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1106 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage
)
1108 InsertTailList(&MessageQueue
->NotifyMessagesListHead
,
1109 &NotifyMessage
->ListEntry
);
1110 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
);
1114 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
1115 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
1116 UINT uTimeout
, BOOL Block
, INT HookMessage
,
1120 PUSER_SENT_MESSAGE Message
;
1121 KEVENT CompletionEvent
;
1122 NTSTATUS WaitStatus
;
1123 PUSER_MESSAGE_QUEUE ThreadQueue
;
1124 LARGE_INTEGER Timeout
;
1126 LRESULT Result
= 0; //// Result could be trashed. ////
1128 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1130 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1131 return STATUS_INSUFFICIENT_RESOURCES
;
1134 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1136 pti
= PsGetCurrentThreadWin32Thread();
1137 ThreadQueue
= pti
->MessageQueue
;
1138 ASSERT(ThreadQueue
!= MessageQueue
);
1140 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
1142 /* 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
->CompletionCallbackContext
= 0;
1154 Message
->HookMessage
= HookMessage
;
1155 Message
->HasPackedLParam
= FALSE
;
1157 IntReferenceMessageQueue(MessageQueue
);
1159 /* add it to the list of pending messages */
1160 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1162 /* queue it in the destination's message queue */
1163 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1165 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
);
1167 /* we can't access the Message anymore since it could have already been deleted! */
1173 /* don't process messages sent to the thread */
1174 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
1175 FALSE
, (uTimeout
? &Timeout
: NULL
));
1179 if(WaitStatus
== STATUS_TIMEOUT
)
1181 /* look up if the message has not yet dispatched, if so
1182 make sure it can't pass a result and it must not set the completion event anymore */
1183 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1184 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1186 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1189 /* we can access Message here, it's secure because the message queue is locked
1190 and the message is still hasn't been dispatched */
1191 Message
->CompletionEvent
= NULL
;
1192 Message
->Result
= NULL
;
1195 Entry
= Entry
->Flink
;
1198 /* remove from the local dispatching list so the other thread knows,
1199 it can't pass a result and it must not set the completion event anymore */
1200 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1201 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1203 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1206 /* we can access Message here, it's secure because the sender's message is locked
1207 and the message has definitely not yet been destroyed, otherwise it would
1208 have been removed from this list by the dispatching routine right after
1209 dispatching the message */
1210 Message
->CompletionEvent
= NULL
;
1211 Message
->Result
= NULL
;
1212 RemoveEntryList(&Message
->DispatchingListEntry
);
1213 Message
->DispatchingListEntry
.Flink
= NULL
;
1216 Entry
= Entry
->Flink
;
1219 DPRINT("MsqSendMessage (blocked) timed out\n");
1221 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1226 PVOID WaitObjects
[2];
1228 WaitObjects
[0] = &CompletionEvent
;
1229 WaitObjects
[1] = ThreadQueue
->NewMessages
;
1234 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1235 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1239 if(WaitStatus
== STATUS_TIMEOUT
)
1241 /* look up if the message has not yet been dispatched, if so
1242 make sure it can't pass a result and it must not set the completion event anymore */
1243 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
1244 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
1246 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1249 /* we can access Message here, it's secure because the message queue is locked
1250 and the message is still hasn't been dispatched */
1251 Message
->CompletionEvent
= NULL
;
1252 Message
->Result
= NULL
;
1255 Entry
= Entry
->Flink
;
1258 /* remove from the local dispatching list so the other thread knows,
1259 it can't pass a result and it must not set the completion event anymore */
1260 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
1261 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
1263 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1266 /* we can access Message here, it's secure because the sender's message is locked
1267 and the message has definitely not yet been destroyed, otherwise it would
1268 have been removed from this list by the dispatching routine right after
1269 dispatching the message */
1270 Message
->CompletionEvent
= NULL
;
1271 Message
->Result
= NULL
;
1272 RemoveEntryList(&Message
->DispatchingListEntry
);
1273 Message
->DispatchingListEntry
.Flink
= NULL
;
1276 Entry
= Entry
->Flink
;
1279 DPRINT("MsqSendMessage timed out\n");
1282 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
1285 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
1288 if(WaitStatus
!= STATUS_TIMEOUT
)
1289 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1295 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
1298 PUSER_MESSAGE Message
;
1300 if(!(Message
= MsqCreateMessage(Msg
)))
1305 if(!HardwareMessage
)
1307 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
1308 &Message
->ListEntry
);
1312 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
1313 &Message
->ListEntry
);
1315 MsqWakeQueue(MessageQueue
, MessageBits
);
1319 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
1321 MessageQueue
->QuitPosted
= TRUE
;
1322 MessageQueue
->QuitExitCode
= ExitCode
;
1323 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
);
1327 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1330 IN UINT MsgFilterLow
,
1331 IN UINT MsgFilterHigh
,
1334 PLIST_ENTRY CurrentEntry
;
1335 PUSER_MESSAGE CurrentMessage
;
1336 PLIST_ENTRY ListHead
;
1338 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1339 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1340 while (CurrentEntry
!= ListHead
)
1342 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1345 PtrToInt(Window
) == 1 ||
1346 Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) &&
1347 ( (MsgFilterLow
== 0 && MsgFilterHigh
== 0) ||
1348 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&&
1349 MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1351 *Message
= CurrentMessage
->Msg
;
1355 RemoveEntryList(&CurrentMessage
->ListEntry
);
1356 MsqDestroyMessage(CurrentMessage
);
1361 CurrentEntry
= CurrentEntry
->Flink
;
1368 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1369 UINT MsgFilterMin
, UINT MsgFilterMax
)
1371 PVOID WaitObjects
[2] = {MessageQueue
->NewMessages
, &HardwareMessageEvent
};
1376 ret
= KeWaitForMultipleObjects(2,
1389 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1391 LARGE_INTEGER LargeTickCount
;
1393 KeQueryTickCount(&LargeTickCount
);
1394 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1398 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1400 LARGE_INTEGER LargeTickCount
;
1403 MessageQueue
->Thread
= Thread
;
1404 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1405 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1406 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1407 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1408 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1409 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1410 KeInitializeMutex(&MessageQueue
->HardwareLock
, 0);
1411 MessageQueue
->QuitPosted
= FALSE
;
1412 MessageQueue
->QuitExitCode
= 0;
1413 KeQueryTickCount(&LargeTickCount
);
1414 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1415 MessageQueue
->FocusWindow
= NULL
;
1416 MessageQueue
->PaintCount
= 0;
1417 // HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt)
1418 MessageQueue
->WakeMask
= ~0;
1419 MessageQueue
->NewMessagesHandle
= NULL
;
1421 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1422 NULL
, SynchronizationEvent
, FALSE
);
1423 if (!NT_SUCCESS(Status
))
1428 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1429 ExEventObjectType
, KernelMode
,
1430 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1431 if (!NT_SUCCESS(Status
))
1433 ZwClose(MessageQueue
->NewMessagesHandle
);
1434 MessageQueue
->NewMessagesHandle
= NULL
;
1442 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1444 PLIST_ENTRY CurrentEntry
;
1445 PUSER_MESSAGE CurrentMessage
;
1446 PUSER_SENT_MESSAGE CurrentSentMessage
;
1448 /* cleanup posted messages */
1449 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1451 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1452 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1454 MsqDestroyMessage(CurrentMessage
);
1457 /* remove the messages that have not yet been dispatched */
1458 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1460 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1461 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1464 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1466 /* remove the message from the dispatching list if needed */
1467 if ((!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1468 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1470 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1473 /* wake the sender's thread */
1474 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1476 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1479 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1481 if (CurrentSentMessage
->Msg
.lParam
)
1482 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1485 /* Only if it is not a no wait message */
1486 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1488 /* dereference our and the sender's message queue */
1489 IntDereferenceMessageQueue(MessageQueue
);
1490 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1493 /* free the message */
1494 ExFreePool(CurrentSentMessage
);
1497 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1498 ExitThread() was called in a SendMessage() umode callback */
1499 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1501 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1502 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1505 /* remove the message from the dispatching list */
1506 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1508 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1511 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1513 /* wake the sender's thread */
1514 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1516 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1519 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1521 if (CurrentSentMessage
->Msg
.lParam
)
1522 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1525 /* Only if it is not a no wait message */
1526 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1528 /* dereference our and the sender's message queue */
1529 IntDereferenceMessageQueue(MessageQueue
);
1530 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1533 /* free the message */
1534 ExFreePool(CurrentSentMessage
);
1537 /* tell other threads not to bother returning any info to us */
1538 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
1540 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
1541 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1542 DispatchingListEntry
);
1543 CurrentSentMessage
->CompletionEvent
= NULL
;
1544 CurrentSentMessage
->Result
= NULL
;
1546 /* do NOT dereference our message queue as it might get attempted to be
1552 PUSER_MESSAGE_QUEUE FASTCALL
1553 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
1555 PUSER_MESSAGE_QUEUE MessageQueue
;
1557 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
1558 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
1566 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
1567 /* hold at least one reference until it'll be destroyed */
1568 IntReferenceMessageQueue(MessageQueue
);
1569 /* initialize the queue */
1570 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
1572 IntDereferenceMessageQueue(MessageQueue
);
1576 return MessageQueue
;
1580 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1584 /* remove the message queue from any desktops */
1585 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
1587 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
1588 IntDereferenceMessageQueue(MessageQueue
);
1592 MsqCleanupMessageQueue(MessageQueue
);
1594 /* decrease the reference counter, if it hits zero, the queue will be freed */
1595 IntDereferenceMessageQueue(MessageQueue
);
1599 MsqSetMessageExtraInfo(LPARAM lParam
)
1603 PUSER_MESSAGE_QUEUE MessageQueue
;
1605 pti
= PsGetCurrentThreadWin32Thread();
1606 MessageQueue
= pti
->MessageQueue
;
1612 Ret
= MessageQueue
->ExtraInfo
;
1613 MessageQueue
->ExtraInfo
= lParam
;
1619 MsqGetMessageExtraInfo(VOID
)
1622 PUSER_MESSAGE_QUEUE MessageQueue
;
1624 pti
= PsGetCurrentThreadWin32Thread();
1625 MessageQueue
= pti
->MessageQueue
;
1631 return MessageQueue
->ExtraInfo
;
1635 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
1641 case MSQ_STATE_CAPTURE
:
1642 Prev
= MessageQueue
->CaptureWindow
;
1643 MessageQueue
->CaptureWindow
= hWnd
;
1645 case MSQ_STATE_ACTIVE
:
1646 Prev
= MessageQueue
->ActiveWindow
;
1647 MessageQueue
->ActiveWindow
= hWnd
;
1649 case MSQ_STATE_FOCUS
:
1650 Prev
= MessageQueue
->FocusWindow
;
1651 MessageQueue
->FocusWindow
= hWnd
;
1653 case MSQ_STATE_MENUOWNER
:
1654 Prev
= MessageQueue
->MenuOwner
;
1655 MessageQueue
->MenuOwner
= hWnd
;
1657 case MSQ_STATE_MOVESIZE
:
1658 Prev
= MessageQueue
->MoveSize
;
1659 MessageQueue
->MoveSize
= hWnd
;
1661 case MSQ_STATE_CARET
:
1662 ASSERT(MessageQueue
->CaretInfo
);
1663 Prev
= MessageQueue
->CaretInfo
->hWnd
;
1664 MessageQueue
->CaretInfo
->hWnd
= hWnd
;