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)
28 * 06-06-2001 CSH Created
31 /* INCLUDES ******************************************************************/
38 /* GLOBALS *******************************************************************/
40 static PAGED_LOOKASIDE_LIST MessageLookasideList
;
42 /* FUNCTIONS *****************************************************************/
45 IntMsqSetWakeMask(DWORD WakeMask
)
47 PTHREADINFO Win32Thread
;
48 PUSER_MESSAGE_QUEUE MessageQueue
;
49 HANDLE MessageEventHandle
;
51 Win32Thread
= PsGetCurrentThreadWin32Thread();
52 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
55 MessageQueue
= Win32Thread
->MessageQueue
;
56 MessageQueue
->WakeMask
= WakeMask
;
57 MessageEventHandle
= MessageQueue
->NewMessagesHandle
;
59 if (Win32Thread
->pcti
)
60 Win32Thread
->pcti
->fsWakeMask
= WakeMask
;
64 return MessageEventHandle
;
68 IntMsqClearWakeMask(VOID
)
70 PTHREADINFO Win32Thread
;
71 PUSER_MESSAGE_QUEUE MessageQueue
;
73 Win32Thread
= PsGetCurrentThreadWin32Thread();
74 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
77 MessageQueue
= Win32Thread
->MessageQueue
;
78 // HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt)
79 MessageQueue
->WakeMask
= ~0;
81 if (Win32Thread
->pcti
)
82 Win32Thread
->pcti
->fsWakeMask
= 0;
90 MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue
, DWORD MessageBits
)
92 Queue
->QueueBits
|= MessageBits
;
93 Queue
->ChangedBits
|= MessageBits
;
94 if (Queue
->WakeMask
& MessageBits
)
95 KeSetEvent(Queue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
99 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
102 MsqWakeQueue(Queue
, QS_PAINT
);
106 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
115 MsqInitializeImpl(VOID
)
117 ExInitializePagedLookasideList(&MessageLookasideList
,
121 sizeof(USER_MESSAGE
),
125 return(STATUS_SUCCESS
);
129 MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
)
131 MessageQueue
->MouseMoveMsg
= *Msg
;
132 MessageQueue
->MouseMoved
= TRUE
;
133 MsqWakeQueue(MessageQueue
, QS_MOUSEMOVE
);
137 co_MsqInsertMouseMessage(MSG
* Msg
)
139 LARGE_INTEGER LargeTickCount
;
140 MSLLHOOKSTRUCT MouseHookData
;
141 PWND pwnd
, pwndDesktop
;
143 KeQueryTickCount(&LargeTickCount
);
144 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
146 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
147 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
151 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
155 case WM_XBUTTONDBLCLK
:
156 case WM_NCXBUTTONDOWN
:
158 case WM_NCXBUTTONDBLCLK
:
159 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
162 MouseHookData
.mouseData
= 0;
166 MouseHookData
.flags
= 0;
167 MouseHookData
.time
= Msg
->time
;
168 MouseHookData
.dwExtraInfo
= 0;
170 /* If the hook procedure returned non zero, dont send the message */
171 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
174 /* Get the desktop window */
175 pwndDesktop
= UserGetDesktopWindow();
179 /* Check if the mouse is captured */
180 Msg
->hwnd
= IntGetCaptureWindow();
181 if(Msg
->hwnd
!= NULL
)
183 pwnd
= UserGetWindowObject(Msg
->hwnd
);
187 /* Loop all top level windows to find which one should receive input */
188 for( pwnd
= pwndDesktop
->spwndChild
;
190 pwnd
= pwnd
->spwndNext
)
192 if((pwnd
->style
& WS_VISIBLE
) &&
193 IntPtInWindow(pwnd
, Msg
->pt
.x
, Msg
->pt
.y
))
195 Msg
->hwnd
= pwnd
->head
.h
;
201 /* Check if we found a window */
202 if(Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
204 if(Msg
->message
== WM_MOUSEMOVE
)
206 /* Mouse move is a special case*/
207 MsqPostMouseMove(pwnd
->head
.pti
->MessageQueue
, Msg
);
211 DPRINT("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd
));
212 MsqPostMessage(pwnd
->head
.pti
->MessageQueue
, Msg
, TRUE
, QS_MOUSEBUTTON
);
218 // Note: Only called from input.c.
221 co_MsqPostKeyboardMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
223 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
225 LARGE_INTEGER LargeTickCount
;
226 KBDLLHOOKSTRUCT KbdHookData
;
227 BOOLEAN Entered
= FALSE
;
229 DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
230 uMsg
, wParam
, lParam
);
232 // Condition may arise when calling MsqPostMessage and waiting for an event.
233 if (!UserIsEntered())
235 // Fixme: Not sure ATM if this thread is locked.
236 UserEnterExclusive();
240 FocusMessageQueue
= IntGetFocusMessageQueue();
244 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
245 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
251 KeQueryTickCount(&LargeTickCount
);
252 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
254 /* We can't get the Msg.pt point here since we don't know thread
255 (and thus the window station) the message will end up in yet. */
257 KbdHookData
.vkCode
= Msg
.wParam
;
258 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
259 KbdHookData
.flags
= (0 == (Msg
.lParam
& 0x01000000) ? 0 : LLKHF_EXTENDED
) |
260 (0 == (Msg
.lParam
& 0x20000000) ? 0 : LLKHF_ALTDOWN
) |
261 (0 == (Msg
.lParam
& 0x80000000) ? 0 : LLKHF_UP
);
262 KbdHookData
.time
= Msg
.time
;
263 KbdHookData
.dwExtraInfo
= 0;
264 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
266 DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
267 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
268 if (Entered
) UserLeave();
272 if (FocusMessageQueue
== NULL
)
274 DPRINT("No focus message queue\n");
275 if (Entered
) UserLeave();
279 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
281 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
282 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
284 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
286 Msg
.pt
= gpsi
->ptCursor
;
287 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
291 DPRINT("Invalid focus window handle\n");
294 if (Entered
) UserLeave();
299 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
302 PTHREADINFO Win32Thread
;
304 LARGE_INTEGER LargeTickCount
;
307 Status
= ObReferenceObjectByPointer (Thread
,
311 if (!NT_SUCCESS(Status
))
314 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
315 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
317 ObDereferenceObject ((PETHREAD
)Thread
);
321 Window
= IntGetWindowObject(hWnd
);
324 ObDereferenceObject ((PETHREAD
)Thread
);
329 Mesg
.message
= WM_HOTKEY
;
330 Mesg
.wParam
= wParam
;
331 Mesg
.lParam
= lParam
;
332 KeQueryTickCount(&LargeTickCount
);
333 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
334 Mesg
.pt
= gpsi
->ptCursor
;
335 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
336 UserDereferenceObject(Window
);
337 ObDereferenceObject (Thread
);
341 PUSER_MESSAGE FASTCALL
342 MsqCreateMessage(LPMSG Msg
)
344 PUSER_MESSAGE Message
;
346 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
352 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
358 MsqDestroyMessage(PUSER_MESSAGE Message
)
360 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
364 co_MsqDispatchSentNotifyMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
366 PLIST_ENTRY ListEntry
;
367 PUSER_SENT_MESSAGE_NOTIFY Message
;
369 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
371 ListEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
372 Message
= CONTAINING_RECORD(ListEntry
, USER_SENT_MESSAGE_NOTIFY
,
375 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
378 Message
->CompletionCallbackContext
,
386 MsqPeekSentMessages(PUSER_MESSAGE_QUEUE MessageQueue
)
388 return(!IsListEmpty(&MessageQueue
->SentMessagesListHead
));
392 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
394 PUSER_SENT_MESSAGE Message
;
398 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
403 /* remove it from the list of pending messages */
404 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
405 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
407 /* insert it to the list of messages that are currently dispatched by this
409 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
410 &Message
->ListEntry
);
412 if (Message
->HookMessage
== MSQ_ISHOOK
)
413 { // Direct Hook Call processor
414 Result
= co_CallHook( Message
->Msg
.message
, // HookId
415 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
417 Message
->Msg
.lParam
);
419 else if (Message
->HookMessage
== MSQ_ISEVENT
)
420 { // Direct Event Call processor
421 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
424 Message
->Msg
.lParam
);
427 { /* Call the window procedure. */
428 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
429 Message
->Msg
.message
,
431 Message
->Msg
.lParam
);
434 /* remove the message from the local dispatching list, because it doesn't need
435 to be cleaned up on thread termination anymore */
436 RemoveEntryList(&Message
->ListEntry
);
438 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
439 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
441 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
443 /* only remove it from the dispatching list if not already removed by a timeout */
444 RemoveEntryList(&Message
->DispatchingListEntry
);
447 /* still keep the sender's message queue locked, so the sender can't exit the
448 MsqSendMessage() function (if timed out) */
450 /* Let the sender know the result. */
451 if (Message
->Result
!= NULL
)
453 *Message
->Result
= Result
;
456 if (Message
->HasPackedLParam
== TRUE
)
458 if (Message
->Msg
.lParam
)
459 ExFreePool((PVOID
)Message
->Msg
.lParam
);
462 /* Notify the sender. */
463 if (Message
->CompletionEvent
!= NULL
)
465 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
468 /* Call the callback if the message was sent with SendMessageCallback */
469 if (Message
->CompletionCallback
!= NULL
)
471 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
473 Message
->Msg
.message
,
474 Message
->CompletionCallbackContext
,
478 /* Only if it is not a no wait message */
479 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
481 IntDereferenceMessageQueue(Message
->SenderQueue
);
482 IntDereferenceMessageQueue(MessageQueue
);
485 /* free the message */
486 ExFreePoolWithTag(Message
, TAG_USRMSG
);
491 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
493 PUSER_SENT_MESSAGE SentMessage
;
494 PUSER_MESSAGE PostedMessage
;
495 PUSER_MESSAGE_QUEUE MessageQueue
;
496 PLIST_ENTRY CurrentEntry
, ListHead
;
497 PWND Window
= pWindow
;
501 MessageQueue
= Window
->head
.pti
->MessageQueue
;
502 ASSERT(MessageQueue
);
504 /* remove the posted messages for this window */
505 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
506 ListHead
= &MessageQueue
->PostedMessagesListHead
;
507 while (CurrentEntry
!= ListHead
)
509 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
511 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
513 RemoveEntryList(&PostedMessage
->ListEntry
);
514 MsqDestroyMessage(PostedMessage
);
515 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
519 CurrentEntry
= CurrentEntry
->Flink
;
523 /* remove the sent messages for this window */
524 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
525 ListHead
= &MessageQueue
->SentMessagesListHead
;
526 while (CurrentEntry
!= ListHead
)
528 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
530 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
532 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
534 RemoveEntryList(&SentMessage
->ListEntry
);
536 /* remove the message from the dispatching list if neede */
537 if ((!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
538 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
540 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
543 /* wake the sender's thread */
544 if (SentMessage
->CompletionEvent
!= NULL
)
546 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
549 if (SentMessage
->HasPackedLParam
== TRUE
)
551 if (SentMessage
->Msg
.lParam
)
552 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
555 /* Only if it is not a no wait message */
556 if (!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
558 /* dereference our and the sender's message queue */
559 IntDereferenceMessageQueue(MessageQueue
);
560 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
563 /* free the message */
564 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
566 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
570 CurrentEntry
= CurrentEntry
->Flink
;
576 MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
577 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage
)
579 InsertTailList(&MessageQueue
->NotifyMessagesListHead
,
580 &NotifyMessage
->ListEntry
);
581 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
);
585 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
586 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
587 UINT uTimeout
, BOOL Block
, INT HookMessage
,
591 PUSER_SENT_MESSAGE Message
;
592 KEVENT CompletionEvent
;
594 PUSER_MESSAGE_QUEUE ThreadQueue
;
595 LARGE_INTEGER Timeout
;
597 LRESULT Result
= 0; //// Result could be trashed. ////
599 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
601 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
602 return STATUS_INSUFFICIENT_RESOURCES
;
605 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
607 pti
= PsGetCurrentThreadWin32Thread();
608 ThreadQueue
= pti
->MessageQueue
;
609 ASSERT(ThreadQueue
!= MessageQueue
);
611 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
613 /* FIXME - increase reference counter of sender's message queue here */
615 Message
->Msg
.hwnd
= Wnd
;
616 Message
->Msg
.message
= Msg
;
617 Message
->Msg
.wParam
= wParam
;
618 Message
->Msg
.lParam
= lParam
;
619 Message
->CompletionEvent
= &CompletionEvent
;
620 Message
->Result
= &Result
;
621 Message
->SenderQueue
= ThreadQueue
;
622 IntReferenceMessageQueue(ThreadQueue
);
623 Message
->CompletionCallback
= NULL
;
624 Message
->CompletionCallbackContext
= 0;
625 Message
->HookMessage
= HookMessage
;
626 Message
->HasPackedLParam
= FALSE
;
628 IntReferenceMessageQueue(MessageQueue
);
630 /* add it to the list of pending messages */
631 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
633 /* queue it in the destination's message queue */
634 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
636 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
);
638 /* we can't access the Message anymore since it could have already been deleted! */
644 /* don't process messages sent to the thread */
645 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
646 FALSE
, (uTimeout
? &Timeout
: NULL
));
650 if(WaitStatus
== STATUS_TIMEOUT
)
652 /* look up if the message has not yet dispatched, if so
653 make sure it can't pass a result and it must not set the completion event anymore */
654 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
655 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
657 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
660 /* we can access Message here, it's secure because the message queue is locked
661 and the message is still hasn't been dispatched */
662 Message
->CompletionEvent
= NULL
;
663 Message
->Result
= NULL
;
666 Entry
= Entry
->Flink
;
669 /* remove from the local dispatching list so the other thread knows,
670 it can't pass a result and it must not set the completion event anymore */
671 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
672 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
674 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
677 /* we can access Message here, it's secure because the sender's message is locked
678 and the message has definitely not yet been destroyed, otherwise it would
679 have been removed from this list by the dispatching routine right after
680 dispatching the message */
681 Message
->CompletionEvent
= NULL
;
682 Message
->Result
= NULL
;
683 RemoveEntryList(&Message
->DispatchingListEntry
);
684 Message
->DispatchingListEntry
.Flink
= NULL
;
687 Entry
= Entry
->Flink
;
690 DPRINT("MsqSendMessage (blocked) timed out\n");
692 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
697 PVOID WaitObjects
[2];
699 WaitObjects
[0] = &CompletionEvent
;
700 WaitObjects
[1] = ThreadQueue
->NewMessages
;
705 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
706 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
710 if(WaitStatus
== STATUS_TIMEOUT
)
712 /* look up if the message has not yet been dispatched, if so
713 make sure it can't pass a result and it must not set the completion event anymore */
714 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
715 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
717 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
720 /* we can access Message here, it's secure because the message queue is locked
721 and the message is still hasn't been dispatched */
722 Message
->CompletionEvent
= NULL
;
723 Message
->Result
= NULL
;
726 Entry
= Entry
->Flink
;
729 /* remove from the local dispatching list so the other thread knows,
730 it can't pass a result and it must not set the completion event anymore */
731 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
732 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
734 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
737 /* we can access Message here, it's secure because the sender's message is locked
738 and the message has definitely not yet been destroyed, otherwise it would
739 have been removed from this list by the dispatching routine right after
740 dispatching the message */
741 Message
->CompletionEvent
= NULL
;
742 Message
->Result
= NULL
;
743 RemoveEntryList(&Message
->DispatchingListEntry
);
744 Message
->DispatchingListEntry
.Flink
= NULL
;
747 Entry
= Entry
->Flink
;
750 DPRINT("MsqSendMessage timed out\n");
753 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
756 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
759 if(WaitStatus
!= STATUS_TIMEOUT
)
760 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
766 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
769 PUSER_MESSAGE Message
;
771 if(!(Message
= MsqCreateMessage(Msg
)))
778 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
779 &Message
->ListEntry
);
783 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
784 &Message
->ListEntry
);
786 MsqWakeQueue(MessageQueue
, MessageBits
);
790 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
792 MessageQueue
->QuitPosted
= TRUE
;
793 MessageQueue
->QuitExitCode
= ExitCode
;
794 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
);
797 /***********************************************************************
798 * MsqSendParentNotify
800 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
801 * the window has the WS_EX_NOPARENTNOTIFY style.
803 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
805 PWND pwndDesktop
= UserGetWindowObject(IntGetDesktopWindow());
807 /* pt has to be in the client coordinates of the parent window */
808 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
809 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
815 if (!(pwnd
->style
& WS_CHILD
)) break;
816 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
817 if (!(pwndParent
= IntGetParent(pwnd
))) break;
818 if (pwndParent
== pwndDesktop
) break;
819 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
820 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
823 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
824 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
828 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
835 MOUSEHOOKSTRUCT hook
;
838 PWND pwndMsg
, pwndDesktop
;
839 PUSER_MESSAGE_QUEUE MessageQueue
;
841 PSYSTEM_CURSORINFO CurInfo
;
842 DECLARE_RETURN(BOOL
);
844 pti
= PsGetCurrentThreadWin32Thread();
845 pwndDesktop
= UserGetDesktopWindow();
846 MessageQueue
= pti
->MessageQueue
;
847 CurInfo
= IntGetSysCursorInfo();
848 pwndMsg
= UserGetWindowObject(msg
->hwnd
);
849 clk_msg
= MessageQueue
->msgDblClk
;
851 /* find the window to dispatch this mouse message to */
852 if (MessageQueue
->CaptureWindow
)
855 pwndMsg
= IntGetWindowObject(MessageQueue
->CaptureWindow
);
859 pwndMsg
= co_WinPosWindowFromPoint(pwndMsg
, &msg
->pt
, &hittest
);
862 DPRINT("Got mouse message for 0x%x, hittest: 0x%x\n", msg
->hwnd
, hittest
);
864 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
866 /* Remove and ignore the message */
867 *RemoveMessages
= TRUE
;
871 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
873 /* FIXME: is this really the right place for this hook? */
874 event
.message
= msg
->message
;
875 event
.time
= msg
->time
;
876 event
.hwnd
= msg
->hwnd
;
877 event
.paramL
= msg
->pt
.x
;
878 event
.paramH
= msg
->pt
.y
;
879 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
882 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
886 message
= msg
->message
;
887 /* Note: windows has no concept of a non-client wheel message */
888 if (message
!= WM_MOUSEWHEEL
)
890 if (hittest
!= HTCLIENT
)
892 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
893 msg
->wParam
= hittest
;
897 /* coordinates don't get translated while tracking a menu */
898 /* FIXME: should differentiate popups and top-level menus */
899 if (!(MessageQueue
->MenuOwner
))
901 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
902 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
906 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
908 /* translate double clicks */
910 if ((msg
->message
== WM_LBUTTONDOWN
) ||
911 (msg
->message
== WM_RBUTTONDOWN
) ||
912 (msg
->message
== WM_MBUTTONDOWN
) ||
913 (msg
->message
== WM_XBUTTONDOWN
))
915 BOOL update
= *RemoveMessages
;
917 /* translate double clicks -
918 * note that ...MOUSEMOVEs can slip in between
919 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
921 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
922 hittest
!= HTCLIENT
||
923 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
925 if ((msg
->message
== clk_msg
.message
) &&
926 (msg
->hwnd
== clk_msg
.hwnd
) &&
927 (msg
->wParam
== clk_msg
.wParam
) &&
928 (msg
->time
- clk_msg
.time
< gspv
.iDblClickTime
) &&
929 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
930 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
932 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
935 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
941 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
943 DPRINT("Message out of range!!!\n");
947 /* update static double click conditions */
948 if (update
) MessageQueue
->msgDblClk
= *msg
;
952 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
954 DPRINT("Message out of range!!!\n");
959 if(gspv
.bMouseClickLock
)
961 BOOL IsClkLck
= FALSE
;
963 if(msg
->message
== WM_LBUTTONUP
)
965 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
966 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
968 CurInfo
->ClickLockActive
= TRUE
;
971 else if (msg
->message
== WM_LBUTTONDOWN
)
973 if (CurInfo
->ClickLockActive
)
976 CurInfo
->ClickLockActive
= FALSE
;
979 CurInfo
->ClickLockTime
= msg
->time
;
984 /* Remove and ignore the message */
985 *RemoveMessages
= TRUE
;
990 /* message is accepted now (but may still get dropped) */
993 hook
.hwnd
= msg
->hwnd
;
994 hook
.wHitTestCode
= hittest
;
995 hook
.dwExtraInfo
= 0/*extra_info*/;
996 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
997 message
, (LPARAM
)&hook
))
1000 hook
.hwnd
= msg
->hwnd
;
1001 hook
.wHitTestCode
= hittest
;
1002 hook
.dwExtraInfo
= 0/*extra_info*/;
1003 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1005 DPRINT1("WH_MOUSE dorpped mouse message!\n");
1007 /* Remove and skip message */
1008 *RemoveMessages
= TRUE
;
1012 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1014 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1015 MAKELONG( hittest
, msg
->message
));
1017 /* Remove and skip message */
1018 *RemoveMessages
= TRUE
;
1022 if ((*RemoveMessages
== FALSE
) || MessageQueue
->CaptureWindow
)
1024 /* Accept the message */
1025 msg
->message
= message
;
1031 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1032 (msg
->message
== WM_RBUTTONDOWN
) ||
1033 (msg
->message
== WM_MBUTTONDOWN
) ||
1034 (msg
->message
== WM_XBUTTONDOWN
))
1036 /* Send the WM_PARENTNOTIFY,
1037 * note that even for double/nonclient clicks
1038 * notification message is still WM_L/M/RBUTTONDOWN.
1040 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1042 /* Activate the window if needed */
1044 if (msg
->hwnd
!= MessageQueue
->ActiveWindow
)
1046 PWND pwndTop
= pwndMsg
;
1049 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
1050 pwndTop
= IntGetParent( pwndTop
);
1053 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1055 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1057 (WPARAM
)UserHMGetHandle(pwndTop
),
1058 MAKELONG( hittest
, msg
->message
));
1061 case MA_NOACTIVATEANDEAT
:
1066 case MA_ACTIVATEANDEAT
:
1071 if(!co_IntMouseActivateWindow(pwndMsg
)) eatMsg
= TRUE
;
1074 DPRINT1( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1081 /* send the WM_SETCURSOR message */
1083 /* Windows sends the normal mouse message as the message parameter
1084 in the WM_SETCURSOR message even if it's non-client mouse message */
1085 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1087 msg
->message
= message
;
1092 UserDereferenceObject(pwndMsg
);
1097 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1101 Event
.message
= Msg
->message
;
1102 Event
.hwnd
= Msg
->hwnd
;
1103 Event
.time
= Msg
->time
;
1104 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1105 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1106 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1107 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1109 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1110 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1111 LOWORD(Msg
->wParam
),
1114 /* skip this message */
1115 co_HOOK_CallHooks( WH_CBT
,
1117 LOWORD(Msg
->wParam
),
1119 DPRINT1("KeyboardMessage WH_CBT Call Hook return!\n");
1125 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1127 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1129 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1131 else if ( IS_KBD_MESSAGE(Msg
->message
))
1133 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1140 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1143 IN UINT MsgFilterLow
,
1144 IN UINT MsgFilterHigh
,
1150 if(!(MessageQueue
->MouseMoved
))
1153 msg
= MessageQueue
->MouseMoveMsg
;
1155 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1161 MessageQueue
->MouseMoved
= FALSE
;
1163 return AcceptMessage
;
1167 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1170 IN UINT MsgFilterLow
,
1171 IN UINT MsgFilterHigh
,
1176 PUSER_MESSAGE CurrentMessage
;
1177 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1180 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1181 CurrentEntry
= ListHead
->Flink
;
1183 while(CurrentEntry
!= ListHead
)
1185 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1188 msg
= CurrentMessage
->Msg
;
1190 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1192 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1196 RemoveEntryList(&CurrentMessage
->ListEntry
);
1197 MsqDestroyMessage(CurrentMessage
);
1212 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1215 IN UINT MsgFilterLow
,
1216 IN UINT MsgFilterHigh
,
1219 PLIST_ENTRY CurrentEntry
;
1220 PUSER_MESSAGE CurrentMessage
;
1221 PLIST_ENTRY ListHead
;
1223 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1224 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1225 while (CurrentEntry
!= ListHead
)
1227 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1230 PtrToInt(Window
) == 1 ||
1231 Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) &&
1232 ( (MsgFilterLow
== 0 && MsgFilterHigh
== 0) ||
1233 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&&
1234 MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1236 *Message
= CurrentMessage
->Msg
;
1240 RemoveEntryList(&CurrentMessage
->ListEntry
);
1241 MsqDestroyMessage(CurrentMessage
);
1246 CurrentEntry
= CurrentEntry
->Flink
;
1253 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1254 UINT MsgFilterMin
, UINT MsgFilterMax
)
1259 ret
= KeWaitForSingleObject(MessageQueue
->NewMessages
,
1269 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1271 LARGE_INTEGER LargeTickCount
;
1273 KeQueryTickCount(&LargeTickCount
);
1274 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1278 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1280 LARGE_INTEGER LargeTickCount
;
1283 MessageQueue
->Thread
= Thread
;
1284 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1285 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1286 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1287 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1288 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1289 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1290 KeInitializeMutex(&MessageQueue
->HardwareLock
, 0);
1291 MessageQueue
->QuitPosted
= FALSE
;
1292 MessageQueue
->QuitExitCode
= 0;
1293 KeQueryTickCount(&LargeTickCount
);
1294 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1295 MessageQueue
->FocusWindow
= NULL
;
1296 MessageQueue
->PaintCount
= 0;
1297 // HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt)
1298 MessageQueue
->WakeMask
= ~0;
1299 MessageQueue
->NewMessagesHandle
= NULL
;
1301 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1302 NULL
, SynchronizationEvent
, FALSE
);
1303 if (!NT_SUCCESS(Status
))
1308 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1309 ExEventObjectType
, KernelMode
,
1310 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1311 if (!NT_SUCCESS(Status
))
1313 ZwClose(MessageQueue
->NewMessagesHandle
);
1314 MessageQueue
->NewMessagesHandle
= NULL
;
1322 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1324 PLIST_ENTRY CurrentEntry
;
1325 PUSER_MESSAGE CurrentMessage
;
1326 PUSER_SENT_MESSAGE CurrentSentMessage
;
1328 /* cleanup posted messages */
1329 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1331 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1332 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1334 MsqDestroyMessage(CurrentMessage
);
1337 /* remove the messages that have not yet been dispatched */
1338 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1340 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1341 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1344 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1346 /* remove the message from the dispatching list if needed */
1347 if ((!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1348 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1350 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1353 /* wake the sender's thread */
1354 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1356 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1359 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1361 if (CurrentSentMessage
->Msg
.lParam
)
1362 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1365 /* Only if it is not a no wait message */
1366 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1368 /* dereference our and the sender's message queue */
1369 IntDereferenceMessageQueue(MessageQueue
);
1370 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1373 /* free the message */
1374 ExFreePool(CurrentSentMessage
);
1377 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1378 ExitThread() was called in a SendMessage() umode callback */
1379 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1381 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1382 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1385 /* remove the message from the dispatching list */
1386 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1388 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1391 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1393 /* wake the sender's thread */
1394 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1396 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1399 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1401 if (CurrentSentMessage
->Msg
.lParam
)
1402 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1405 /* Only if it is not a no wait message */
1406 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1408 /* dereference our and the sender's message queue */
1409 IntDereferenceMessageQueue(MessageQueue
);
1410 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1413 /* free the message */
1414 ExFreePool(CurrentSentMessage
);
1417 /* tell other threads not to bother returning any info to us */
1418 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
1420 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
1421 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1422 DispatchingListEntry
);
1423 CurrentSentMessage
->CompletionEvent
= NULL
;
1424 CurrentSentMessage
->Result
= NULL
;
1426 /* do NOT dereference our message queue as it might get attempted to be
1432 PUSER_MESSAGE_QUEUE FASTCALL
1433 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
1435 PUSER_MESSAGE_QUEUE MessageQueue
;
1437 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
1438 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
1446 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
1447 /* hold at least one reference until it'll be destroyed */
1448 IntReferenceMessageQueue(MessageQueue
);
1449 /* initialize the queue */
1450 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
1452 IntDereferenceMessageQueue(MessageQueue
);
1456 return MessageQueue
;
1460 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1464 /* remove the message queue from any desktops */
1465 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
1467 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
1468 IntDereferenceMessageQueue(MessageQueue
);
1472 MsqCleanupMessageQueue(MessageQueue
);
1474 /* decrease the reference counter, if it hits zero, the queue will be freed */
1475 IntDereferenceMessageQueue(MessageQueue
);
1479 MsqSetMessageExtraInfo(LPARAM lParam
)
1483 PUSER_MESSAGE_QUEUE MessageQueue
;
1485 pti
= PsGetCurrentThreadWin32Thread();
1486 MessageQueue
= pti
->MessageQueue
;
1492 Ret
= MessageQueue
->ExtraInfo
;
1493 MessageQueue
->ExtraInfo
= lParam
;
1499 MsqGetMessageExtraInfo(VOID
)
1502 PUSER_MESSAGE_QUEUE MessageQueue
;
1504 pti
= PsGetCurrentThreadWin32Thread();
1505 MessageQueue
= pti
->MessageQueue
;
1511 return MessageQueue
->ExtraInfo
;
1515 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
1521 case MSQ_STATE_CAPTURE
:
1522 Prev
= MessageQueue
->CaptureWindow
;
1523 MessageQueue
->CaptureWindow
= hWnd
;
1525 case MSQ_STATE_ACTIVE
:
1526 Prev
= MessageQueue
->ActiveWindow
;
1527 MessageQueue
->ActiveWindow
= hWnd
;
1529 case MSQ_STATE_FOCUS
:
1530 Prev
= MessageQueue
->FocusWindow
;
1531 MessageQueue
->FocusWindow
= hWnd
;
1533 case MSQ_STATE_MENUOWNER
:
1534 Prev
= MessageQueue
->MenuOwner
;
1535 MessageQueue
->MenuOwner
= hWnd
;
1537 case MSQ_STATE_MOVESIZE
:
1538 Prev
= MessageQueue
->MoveSize
;
1539 MessageQueue
->MoveSize
= hWnd
;
1541 case MSQ_STATE_CARET
:
1542 ASSERT(MessageQueue
->CaretInfo
);
1543 Prev
= MessageQueue
->CaretInfo
->hWnd
;
1544 MessageQueue
->CaretInfo
->hWnd
= hWnd
;