2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Message queues
5 * FILE: subsystems/win32/win32k/ntuser/msgqueue.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
10 * 06-06-2001 CSH Created
13 /* INCLUDES ******************************************************************/
20 /* GLOBALS *******************************************************************/
22 static PAGED_LOOKASIDE_LIST MessageLookasideList
;
24 /* FUNCTIONS *****************************************************************/
29 MsqInitializeImpl(VOID
)
31 ExInitializePagedLookasideList(&MessageLookasideList
,
39 return(STATUS_SUCCESS
);
43 IntMsqSetWakeMask(DWORD WakeMask
)
45 PTHREADINFO Win32Thread
;
46 PUSER_MESSAGE_QUEUE MessageQueue
;
47 HANDLE MessageEventHandle
;
48 DWORD dwFlags
= HIWORD(WakeMask
);
50 Win32Thread
= PsGetCurrentThreadWin32Thread();
51 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
54 MessageQueue
= Win32Thread
->MessageQueue
;
55 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
56 MessageEventHandle
= MessageQueue
->NewMessagesHandle
;
58 if (Win32Thread
->pcti
)
60 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
61 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
63 DPRINT1("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
64 KeSetEvent(MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
65 return MessageEventHandle
;
71 return MessageEventHandle
;
75 IntMsqClearWakeMask(VOID
)
77 PTHREADINFO Win32Thread
;
79 Win32Thread
= PsGetCurrentThreadWin32Thread();
80 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
82 // Very hacky, but that is what they do.
83 Win32Thread
->pcti
->fsWakeBits
= 0;
91 Due to the uncertainty of knowing what was set in our multilevel message queue,
92 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
93 I think this is the best solution... (jt) */
95 MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue
, DWORD MessageBits
, BOOL KeyEvent
)
99 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
100 pti
->pcti
->fsWakeBits
|= MessageBits
;
101 pti
->pcti
->fsChangeBits
|= MessageBits
;
103 // Start bit accounting to help clear the main set of bits.
104 if (MessageBits
& QS_KEY
) Queue
->nCntsQBits
[QSRosKey
]++;
105 if (MessageBits
& QS_MOUSEMOVE
) Queue
->nCntsQBits
[QSRosMouseMove
]++;
106 if (MessageBits
& QS_MOUSEBUTTON
) Queue
->nCntsQBits
[QSRosMouseButton
]++;
107 if (MessageBits
& QS_POSTMESSAGE
) Queue
->nCntsQBits
[QSRosPostMessage
]++;
108 if (MessageBits
& QS_SENDMESSAGE
) Queue
->nCntsQBits
[QSRosSendMessage
]++;
109 if (MessageBits
& QS_HOTKEY
) Queue
->nCntsQBits
[QSRosHotKey
]++;
112 KeSetEvent(Queue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
116 ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue
, UINT MessageBits
)
121 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
123 if (MessageBits
& QS_KEY
)
125 if (--Queue
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
127 if (MessageBits
& QS_MOUSEMOVE
) // ReactOS hard coded.
128 { // Account for tracking mouse moves..
129 if (--Queue
->nCntsQBits
[QSRosMouseMove
] == 0) ClrMask
|= QS_MOUSEMOVE
;
130 // Handle mouse move bits here.
131 if (Queue
->MouseMoved
) ClrMask
|= QS_MOUSEMOVE
;
133 if (MessageBits
& QS_MOUSEBUTTON
)
135 if (--Queue
->nCntsQBits
[QSRosMouseButton
] == 0) ClrMask
|= QS_MOUSEBUTTON
;
137 if (MessageBits
& QS_POSTMESSAGE
)
139 if (--Queue
->nCntsQBits
[QSRosPostMessage
] == 0) ClrMask
|= QS_POSTMESSAGE
;
141 if (MessageBits
& QS_TIMER
) // ReactOS hard coded.
142 { // Handle timer bits here.
143 if ( pti
->cTimersReady
)
145 if (--pti
->cTimersReady
== 0) ClrMask
|= QS_TIMER
;
148 if (MessageBits
& QS_PAINT
) // ReactOS hard coded.
149 { // Handle paint bits here.
150 if ( pti
->cPaintsReady
)
152 if (--pti
->cPaintsReady
== 0) ClrMask
|= QS_PAINT
;
155 if (MessageBits
& QS_SENDMESSAGE
)
157 if (--Queue
->nCntsQBits
[QSRosSendMessage
] == 0) ClrMask
|= QS_SENDMESSAGE
;
159 if (MessageBits
& QS_HOTKEY
)
161 if (--Queue
->nCntsQBits
[QSRosHotKey
] == 0) ClrMask
|= QS_HOTKEY
;
164 pti
->pcti
->fsWakeBits
&= ~ClrMask
;
165 pti
->pcti
->fsChangeBits
&= ~ClrMask
;
169 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
172 pti
= Queue
->Thread
->Tcb
.Win32Thread
;
174 MsqWakeQueue(Queue
, QS_PAINT
, TRUE
);
178 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue
)
180 ClearMsgBitsMask(Queue
, QS_PAINT
);
184 MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
)
186 MessageQueue
->MouseMoveMsg
= *Msg
;
187 MessageQueue
->MouseMoved
= TRUE
;
188 MsqWakeQueue(MessageQueue
, QS_MOUSEMOVE
, TRUE
);
192 co_MsqInsertMouseMessage(MSG
* Msg
)
194 LARGE_INTEGER LargeTickCount
;
195 MSLLHOOKSTRUCT MouseHookData
;
196 PWND pwnd
, pwndDesktop
;
198 KeQueryTickCount(&LargeTickCount
);
199 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
201 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
202 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
206 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
210 case WM_XBUTTONDBLCLK
:
211 case WM_NCXBUTTONDOWN
:
213 case WM_NCXBUTTONDBLCLK
:
214 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
217 MouseHookData
.mouseData
= 0;
221 MouseHookData
.flags
= 0;
222 MouseHookData
.time
= Msg
->time
;
223 MouseHookData
.dwExtraInfo
= 0;
225 /* If the hook procedure returned non zero, dont send the message */
226 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
229 /* Get the desktop window */
230 pwndDesktop
= UserGetDesktopWindow();
234 /* Check if the mouse is captured */
235 Msg
->hwnd
= IntGetCaptureWindow();
236 if(Msg
->hwnd
!= NULL
)
238 pwnd
= UserGetWindowObject(Msg
->hwnd
);
242 /* Loop all top level windows to find which one should receive input */
243 for( pwnd
= pwndDesktop
->spwndChild
;
245 pwnd
= pwnd
->spwndNext
)
247 if((pwnd
->style
& WS_VISIBLE
) &&
248 IntPtInWindow(pwnd
, Msg
->pt
.x
, Msg
->pt
.y
))
250 Msg
->hwnd
= pwnd
->head
.h
;
256 /* Check if we found a window */
257 if(Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
259 if(Msg
->message
== WM_MOUSEMOVE
)
261 /* Mouse move is a special case*/
262 MsqPostMouseMove(pwnd
->head
.pti
->MessageQueue
, Msg
);
266 DPRINT("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd
));
267 MsqPostMessage(pwnd
->head
.pti
->MessageQueue
, Msg
, TRUE
, QS_MOUSEBUTTON
);
273 // Note: Only called from input.c.
276 co_MsqPostKeyboardMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
278 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
280 LARGE_INTEGER LargeTickCount
;
281 KBDLLHOOKSTRUCT KbdHookData
;
282 BOOLEAN Entered
= FALSE
;
284 DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
285 uMsg
, wParam
, lParam
);
287 // Condition may arise when calling MsqPostMessage and waiting for an event.
288 if (!UserIsEntered())
290 // Fixme: Not sure ATM if this thread is locked.
291 UserEnterExclusive();
295 FocusMessageQueue
= IntGetFocusMessageQueue();
299 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
300 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
306 KeQueryTickCount(&LargeTickCount
);
307 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
309 /* We can't get the Msg.pt point here since we don't know thread
310 (and thus the window station) the message will end up in yet. */
312 KbdHookData
.vkCode
= Msg
.wParam
;
313 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
314 KbdHookData
.flags
= (0 == (Msg
.lParam
& 0x01000000) ? 0 : LLKHF_EXTENDED
) |
315 (0 == (Msg
.lParam
& 0x20000000) ? 0 : LLKHF_ALTDOWN
) |
316 (0 == (Msg
.lParam
& 0x80000000) ? 0 : LLKHF_UP
);
317 KbdHookData
.time
= Msg
.time
;
318 KbdHookData
.dwExtraInfo
= 0;
319 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
321 DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
322 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
323 if (Entered
) UserLeave();
327 if (FocusMessageQueue
== NULL
)
329 DPRINT("No focus message queue\n");
330 if (Entered
) UserLeave();
334 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
336 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
337 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
339 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
341 Msg
.pt
= gpsi
->ptCursor
;
342 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
346 DPRINT("Invalid focus window handle\n");
349 if (Entered
) UserLeave();
354 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
357 PTHREADINFO Win32Thread
;
359 LARGE_INTEGER LargeTickCount
;
362 Status
= ObReferenceObjectByPointer (Thread
,
366 if (!NT_SUCCESS(Status
))
369 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
370 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
372 ObDereferenceObject ((PETHREAD
)Thread
);
376 Window
= IntGetWindowObject(hWnd
);
379 ObDereferenceObject ((PETHREAD
)Thread
);
384 Mesg
.message
= WM_HOTKEY
;
385 Mesg
.wParam
= wParam
;
386 Mesg
.lParam
= lParam
;
387 KeQueryTickCount(&LargeTickCount
);
388 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
389 Mesg
.pt
= gpsi
->ptCursor
;
390 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
391 UserDereferenceObject(Window
);
392 ObDereferenceObject (Thread
);
396 PUSER_MESSAGE FASTCALL
397 MsqCreateMessage(LPMSG Msg
)
399 PUSER_MESSAGE Message
;
401 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
407 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
413 MsqDestroyMessage(PUSER_MESSAGE Message
)
415 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
419 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
421 PUSER_SENT_MESSAGE SaveMsg
, Message
;
426 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
431 /* remove it from the list of pending messages */
432 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
433 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
435 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
437 SaveMsg
= pti
->pusmCurrent
;
438 pti
->pusmCurrent
= Message
;
440 // Processing a message sent to it from another thread.
441 if ( ( Message
->SenderQueue
&& MessageQueue
!= Message
->SenderQueue
) ||
442 ( Message
->CallBackSenderQueue
&& MessageQueue
!= Message
->CallBackSenderQueue
))
443 { // most likely, but, to be sure.
444 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
447 /* insert it to the list of messages that are currently dispatched by this
449 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
450 &Message
->ListEntry
);
452 ClearMsgBitsMask(MessageQueue
, Message
->QS_Flags
);
454 if (Message
->HookMessage
== MSQ_ISHOOK
)
455 { // Direct Hook Call processor
456 Result
= co_CallHook( Message
->Msg
.message
, // HookId
457 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
459 Message
->Msg
.lParam
);
461 else if (Message
->HookMessage
== MSQ_ISEVENT
)
462 { // Direct Event Call processor
463 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
466 Message
->Msg
.lParam
);
469 { /* Call the window procedure. */
470 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
471 Message
->Msg
.message
,
473 Message
->Msg
.lParam
);
476 /* remove the message from the local dispatching list, because it doesn't need
477 to be cleaned up on thread termination anymore */
478 RemoveEntryList(&Message
->ListEntry
);
480 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
481 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
483 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
485 /* only remove it from the dispatching list if not already removed by a timeout */
486 RemoveEntryList(&Message
->DispatchingListEntry
);
489 /* still keep the sender's message queue locked, so the sender can't exit the
490 MsqSendMessage() function (if timed out) */
492 if (Message
->QS_Flags
& QS_SMRESULT
)
494 Result
= Message
->lResult
;
497 /* Let the sender know the result. */
498 if (Message
->Result
!= NULL
)
500 *Message
->Result
= Result
;
503 if (Message
->HasPackedLParam
== TRUE
)
505 if (Message
->Msg
.lParam
)
506 ExFreePool((PVOID
)Message
->Msg
.lParam
);
509 /* Notify the sender. */
510 if (Message
->CompletionEvent
!= NULL
)
512 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
515 /* Call the callback if the message was sent with SendMessageCallback */
516 if (Message
->CompletionCallback
!= NULL
)
518 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
520 Message
->Msg
.message
,
521 Message
->CompletionCallbackContext
,
525 /* Only if it is not a no wait message */
526 if (!(Message
->HookMessage
& MSQ_SENTNOWAIT
))
528 IntDereferenceMessageQueue(Message
->SenderQueue
);
529 IntDereferenceMessageQueue(MessageQueue
);
532 /* free the message */
533 ExFreePoolWithTag(Message
, TAG_USRMSG
);
535 /* do not hangup on the user if this is reentering */
536 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
537 pti
->pusmCurrent
= SaveMsg
;
543 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
545 PUSER_SENT_MESSAGE SentMessage
;
546 PUSER_MESSAGE PostedMessage
;
547 PUSER_MESSAGE_QUEUE MessageQueue
;
548 PLIST_ENTRY CurrentEntry
, ListHead
;
549 PWND Window
= pWindow
;
553 MessageQueue
= Window
->head
.pti
->MessageQueue
;
554 ASSERT(MessageQueue
);
556 /* remove the posted messages for this window */
557 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
558 ListHead
= &MessageQueue
->PostedMessagesListHead
;
559 while (CurrentEntry
!= ListHead
)
561 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
563 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
565 RemoveEntryList(&PostedMessage
->ListEntry
);
566 ClearMsgBitsMask(MessageQueue
, PostedMessage
->QS_Flags
);
567 MsqDestroyMessage(PostedMessage
);
568 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
572 CurrentEntry
= CurrentEntry
->Flink
;
576 /* remove the sent messages for this window */
577 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
578 ListHead
= &MessageQueue
->SentMessagesListHead
;
579 while (CurrentEntry
!= ListHead
)
581 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
583 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
585 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
587 RemoveEntryList(&SentMessage
->ListEntry
);
588 ClearMsgBitsMask(MessageQueue
, SentMessage
->QS_Flags
);
590 /* remove the message from the dispatching list if neede */
591 if ((!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
592 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
594 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
597 /* wake the sender's thread */
598 if (SentMessage
->CompletionEvent
!= NULL
)
600 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
603 if (SentMessage
->HasPackedLParam
== TRUE
)
605 if (SentMessage
->Msg
.lParam
)
606 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
609 /* Only if it is not a no wait message */
610 if (!(SentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
612 /* dereference our and the sender's message queue */
613 IntDereferenceMessageQueue(MessageQueue
);
614 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
617 /* free the message */
618 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
620 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
624 CurrentEntry
= CurrentEntry
->Flink
;
630 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
631 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
632 UINT uTimeout
, BOOL Block
, INT HookMessage
,
636 PUSER_SENT_MESSAGE Message
;
637 KEVENT CompletionEvent
;
639 PUSER_MESSAGE_QUEUE ThreadQueue
;
640 LARGE_INTEGER Timeout
;
642 LRESULT Result
= 0; //// Result could be trashed. ////
644 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
646 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
647 return STATUS_INSUFFICIENT_RESOURCES
;
650 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
652 pti
= PsGetCurrentThreadWin32Thread();
653 ThreadQueue
= pti
->MessageQueue
;
654 ASSERT(ThreadQueue
!= MessageQueue
);
656 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
658 /* FIXME - increase reference counter of sender's message queue here */
660 Message
->Msg
.hwnd
= Wnd
;
661 Message
->Msg
.message
= Msg
;
662 Message
->Msg
.wParam
= wParam
;
663 Message
->Msg
.lParam
= lParam
;
664 Message
->CompletionEvent
= &CompletionEvent
;
665 Message
->Result
= &Result
;
666 Message
->lResult
= 0;
667 Message
->QS_Flags
= 0;
668 Message
->SenderQueue
= ThreadQueue
;
669 Message
->CallBackSenderQueue
= NULL
;
670 IntReferenceMessageQueue(ThreadQueue
);
671 Message
->CompletionCallback
= NULL
;
672 Message
->CompletionCallbackContext
= 0;
673 Message
->HookMessage
= HookMessage
;
674 Message
->HasPackedLParam
= FALSE
;
676 IntReferenceMessageQueue(MessageQueue
);
678 /* add it to the list of pending messages */
679 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
681 /* queue it in the destination's message queue */
682 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
684 Message
->QS_Flags
= QS_SENDMESSAGE
;
685 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
, TRUE
);
687 /* we can't access the Message anymore since it could have already been deleted! */
693 /* don't process messages sent to the thread */
694 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
695 FALSE
, (uTimeout
? &Timeout
: NULL
));
699 if(WaitStatus
== STATUS_TIMEOUT
)
701 /* look up if the message has not yet dispatched, if so
702 make sure it can't pass a result and it must not set the completion event anymore */
703 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
704 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
706 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
709 /* we can access Message here, it's secure because the message queue is locked
710 and the message is still hasn't been dispatched */
711 Message
->CompletionEvent
= NULL
;
712 Message
->Result
= NULL
;
715 Entry
= Entry
->Flink
;
718 /* remove from the local dispatching list so the other thread knows,
719 it can't pass a result and it must not set the completion event anymore */
720 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
721 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
723 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
726 /* we can access Message here, it's secure because the sender's message is locked
727 and the message has definitely not yet been destroyed, otherwise it would
728 have been removed from this list by the dispatching routine right after
729 dispatching the message */
730 Message
->CompletionEvent
= NULL
;
731 Message
->Result
= NULL
;
732 RemoveEntryList(&Message
->DispatchingListEntry
);
733 Message
->DispatchingListEntry
.Flink
= NULL
;
736 Entry
= Entry
->Flink
;
739 DPRINT("MsqSendMessage (blocked) timed out\n");
741 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
746 PVOID WaitObjects
[2];
748 WaitObjects
[0] = &CompletionEvent
;
749 WaitObjects
[1] = ThreadQueue
->NewMessages
;
754 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
755 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
759 if(WaitStatus
== STATUS_TIMEOUT
)
761 /* look up if the message has not yet been dispatched, if so
762 make sure it can't pass a result and it must not set the completion event anymore */
763 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
764 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
766 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
769 /* we can access Message here, it's secure because the message queue is locked
770 and the message is still hasn't been dispatched */
771 Message
->CompletionEvent
= NULL
;
772 Message
->Result
= NULL
;
775 Entry
= Entry
->Flink
;
778 /* remove from the local dispatching list so the other thread knows,
779 it can't pass a result and it must not set the completion event anymore */
780 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
781 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
783 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
786 /* we can access Message here, it's secure because the sender's message is locked
787 and the message has definitely not yet been destroyed, otherwise it would
788 have been removed from this list by the dispatching routine right after
789 dispatching the message */
790 Message
->CompletionEvent
= NULL
;
791 Message
->Result
= NULL
;
792 RemoveEntryList(&Message
->DispatchingListEntry
);
793 Message
->DispatchingListEntry
.Flink
= NULL
;
796 Entry
= Entry
->Flink
;
799 DPRINT("MsqSendMessage timed out\n");
802 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
805 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
808 if(WaitStatus
!= STATUS_TIMEOUT
)
809 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
815 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
818 PUSER_MESSAGE Message
;
820 if(!(Message
= MsqCreateMessage(Msg
)))
827 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
828 &Message
->ListEntry
);
832 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
833 &Message
->ListEntry
);
836 Message
->QS_Flags
= MessageBits
;
837 MsqWakeQueue(MessageQueue
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
841 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
843 MessageQueue
->QuitPosted
= TRUE
;
844 MessageQueue
->QuitExitCode
= ExitCode
;
845 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
848 /***********************************************************************
849 * MsqSendParentNotify
851 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
852 * the window has the WS_EX_NOPARENTNOTIFY style.
854 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
856 PWND pwndDesktop
= UserGetWindowObject(IntGetDesktopWindow());
858 /* pt has to be in the client coordinates of the parent window */
859 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
860 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
866 if (!(pwnd
->style
& WS_CHILD
)) break;
867 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
868 if (!(pwndParent
= IntGetParent(pwnd
))) break;
869 if (pwndParent
== pwndDesktop
) break;
870 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
871 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
874 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
875 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
879 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
886 MOUSEHOOKSTRUCT hook
;
889 PWND pwndMsg
, pwndDesktop
;
890 PUSER_MESSAGE_QUEUE MessageQueue
;
892 PSYSTEM_CURSORINFO CurInfo
;
893 DECLARE_RETURN(BOOL
);
895 pti
= PsGetCurrentThreadWin32Thread();
896 pwndDesktop
= UserGetDesktopWindow();
897 MessageQueue
= pti
->MessageQueue
;
898 CurInfo
= IntGetSysCursorInfo();
899 pwndMsg
= UserGetWindowObject(msg
->hwnd
);
900 clk_msg
= MessageQueue
->msgDblClk
;
902 /* find the window to dispatch this mouse message to */
903 if (MessageQueue
->CaptureWindow
)
906 pwndMsg
= IntGetWindowObject(MessageQueue
->CaptureWindow
);
910 pwndMsg
= co_WinPosWindowFromPoint(pwndMsg
, &msg
->pt
, &hittest
);
913 DPRINT("Got mouse message for 0x%x, hittest: 0x%x\n", msg
->hwnd
, hittest
);
915 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
917 /* Remove and ignore the message */
918 *RemoveMessages
= TRUE
;
922 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
925 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
929 message
= msg
->message
;
930 /* Note: windows has no concept of a non-client wheel message */
931 if (message
!= WM_MOUSEWHEEL
)
933 if (hittest
!= HTCLIENT
)
935 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
936 msg
->wParam
= hittest
;
940 /* coordinates don't get translated while tracking a menu */
941 /* FIXME: should differentiate popups and top-level menus */
942 if (!(MessageQueue
->MenuOwner
))
944 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
945 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
949 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
951 /* translate double clicks */
953 if ((msg
->message
== WM_LBUTTONDOWN
) ||
954 (msg
->message
== WM_RBUTTONDOWN
) ||
955 (msg
->message
== WM_MBUTTONDOWN
) ||
956 (msg
->message
== WM_XBUTTONDOWN
))
958 BOOL update
= *RemoveMessages
;
960 /* translate double clicks -
961 * note that ...MOUSEMOVEs can slip in between
962 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
964 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
965 hittest
!= HTCLIENT
||
966 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
968 if ((msg
->message
== clk_msg
.message
) &&
969 (msg
->hwnd
== clk_msg
.hwnd
) &&
970 (msg
->wParam
== clk_msg
.wParam
) &&
971 (msg
->time
- clk_msg
.time
< gspv
.iDblClickTime
) &&
972 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
973 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
975 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
978 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
984 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
986 DPRINT("Message out of range!!!\n");
990 /* update static double click conditions */
991 if (update
) MessageQueue
->msgDblClk
= *msg
;
995 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
997 DPRINT("Message out of range!!!\n");
1002 if(gspv
.bMouseClickLock
)
1004 BOOL IsClkLck
= FALSE
;
1006 if(msg
->message
== WM_LBUTTONUP
)
1008 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1009 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1011 CurInfo
->ClickLockActive
= TRUE
;
1014 else if (msg
->message
== WM_LBUTTONDOWN
)
1016 if (CurInfo
->ClickLockActive
)
1019 CurInfo
->ClickLockActive
= FALSE
;
1022 CurInfo
->ClickLockTime
= msg
->time
;
1027 /* Remove and ignore the message */
1028 *RemoveMessages
= TRUE
;
1033 /* message is accepted now (but may still get dropped) */
1035 pti
->rpdesk
->htEx
= hittest
; /* Now set the capture hit. */
1037 event
.message
= msg
->message
;
1038 event
.time
= msg
->time
;
1039 event
.hwnd
= msg
->hwnd
;
1040 event
.paramL
= msg
->pt
.x
;
1041 event
.paramH
= msg
->pt
.y
;
1042 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1045 hook
.hwnd
= msg
->hwnd
;
1046 hook
.wHitTestCode
= hittest
;
1047 hook
.dwExtraInfo
= 0/*extra_info*/;
1048 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1049 message
, (LPARAM
)&hook
))
1052 hook
.hwnd
= msg
->hwnd
;
1053 hook
.wHitTestCode
= hittest
;
1054 hook
.dwExtraInfo
= 0/*extra_info*/;
1055 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1057 DPRINT1("WH_MOUSE dorpped mouse message!\n");
1059 /* Remove and skip message */
1060 *RemoveMessages
= TRUE
;
1064 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1066 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1067 MAKELONG( hittest
, msg
->message
));
1069 /* Remove and skip message */
1070 *RemoveMessages
= TRUE
;
1074 if ((*RemoveMessages
== FALSE
) || MessageQueue
->CaptureWindow
)
1076 /* Accept the message */
1077 msg
->message
= message
;
1083 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1084 (msg
->message
== WM_RBUTTONDOWN
) ||
1085 (msg
->message
== WM_MBUTTONDOWN
) ||
1086 (msg
->message
== WM_XBUTTONDOWN
))
1088 /* Send the WM_PARENTNOTIFY,
1089 * note that even for double/nonclient clicks
1090 * notification message is still WM_L/M/RBUTTONDOWN.
1092 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1094 /* Activate the window if needed */
1096 if (msg
->hwnd
!= UserGetForegroundWindow())
1098 PWND pwndTop
= pwndMsg
;
1101 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
1102 pwndTop
= IntGetParent( pwndTop
);
1105 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1107 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1109 (WPARAM
)UserHMGetHandle(pwndTop
),
1110 MAKELONG( hittest
, msg
->message
));
1113 case MA_NOACTIVATEANDEAT
:
1118 case MA_ACTIVATEANDEAT
:
1123 if(!co_IntMouseActivateWindow(pwndMsg
)) eatMsg
= TRUE
;
1126 DPRINT1( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1133 /* send the WM_SETCURSOR message */
1135 /* Windows sends the normal mouse message as the message parameter
1136 in the WM_SETCURSOR message even if it's non-client mouse message */
1137 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1139 msg
->message
= message
;
1144 UserDereferenceObject(pwndMsg
);
1149 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1153 Event
.message
= Msg
->message
;
1154 Event
.hwnd
= Msg
->hwnd
;
1155 Event
.time
= Msg
->time
;
1156 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1157 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1158 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1159 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1161 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1162 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1163 LOWORD(Msg
->wParam
),
1166 /* skip this message */
1167 co_HOOK_CallHooks( WH_CBT
,
1169 LOWORD(Msg
->wParam
),
1171 DPRINT1("KeyboardMessage WH_CBT Call Hook return!\n");
1177 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1179 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1181 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1183 else if ( IS_KBD_MESSAGE(Msg
->message
))
1185 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1192 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1195 IN UINT MsgFilterLow
,
1196 IN UINT MsgFilterHigh
,
1202 if(!(MessageQueue
->MouseMoved
))
1205 msg
= MessageQueue
->MouseMoveMsg
;
1207 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1214 ClearMsgBitsMask(MessageQueue
, QS_MOUSEMOVE
);
1215 MessageQueue
->MouseMoved
= FALSE
;
1218 return AcceptMessage
;
1221 /* check whether a message filter contains at least one potential hardware message */
1223 filter_contains_hw_range( UINT first
, UINT last
)
1225 /* hardware message ranges are (in numerical order):
1226 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1227 * WM_KEYFIRST .. WM_KEYLAST
1228 * WM_MOUSEFIRST .. WM_MOUSELAST
1231 if (last
< WM_NCMOUSEFIRST
) return 0;
1232 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1233 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1234 if (first
> WM_MOUSELAST
) return 0;
1239 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1242 IN UINT MsgFilterLow
,
1243 IN UINT MsgFilterHigh
,
1249 PUSER_MESSAGE CurrentMessage
;
1250 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1253 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1255 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1256 CurrentEntry
= ListHead
->Flink
;
1258 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1260 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1264 if (IsListEmpty(CurrentEntry
)) break;
1265 if (!CurrentMessage
) break;
1266 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1268 if ( (( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && (CurrentMessage
->QS_Flags
& QSflags
)) ||
1269 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) )
1271 msg
= CurrentMessage
->Msg
;
1273 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1277 RemoveEntryList(&CurrentMessage
->ListEntry
);
1278 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1279 MsqDestroyMessage(CurrentMessage
);
1288 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1291 while(CurrentEntry
!= ListHead
);
1297 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1300 IN UINT MsgFilterLow
,
1301 IN UINT MsgFilterHigh
,
1305 PLIST_ENTRY CurrentEntry
;
1306 PUSER_MESSAGE CurrentMessage
;
1307 PLIST_ENTRY ListHead
;
1309 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1310 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1312 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1314 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1318 if (IsListEmpty(CurrentEntry
)) break;
1319 if (!CurrentMessage
) break;
1320 CurrentEntry
= CurrentEntry
->Flink
;
1322 if ( ( !Window
|| Window
== HWND_BOTTOM
|| Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) &&
1323 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1324 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1326 *Message
= CurrentMessage
->Msg
;
1330 RemoveEntryList(&CurrentMessage
->ListEntry
);
1331 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1332 MsqDestroyMessage(CurrentMessage
);
1336 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1339 while (CurrentEntry
!= ListHead
);
1345 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1346 UINT MsgFilterMin
, UINT MsgFilterMax
)
1351 ret
= KeWaitForSingleObject(MessageQueue
->NewMessages
,
1361 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1363 LARGE_INTEGER LargeTickCount
;
1365 KeQueryTickCount(&LargeTickCount
);
1366 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1370 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1372 LARGE_INTEGER LargeTickCount
;
1375 MessageQueue
->Thread
= Thread
;
1376 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1377 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1378 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1379 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1380 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1381 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1382 KeInitializeMutex(&MessageQueue
->HardwareLock
, 0);
1383 MessageQueue
->QuitPosted
= FALSE
;
1384 MessageQueue
->QuitExitCode
= 0;
1385 KeQueryTickCount(&LargeTickCount
);
1386 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1387 MessageQueue
->FocusWindow
= NULL
;
1388 MessageQueue
->NewMessagesHandle
= NULL
;
1390 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1391 NULL
, SynchronizationEvent
, FALSE
);
1392 if (!NT_SUCCESS(Status
))
1397 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1398 ExEventObjectType
, KernelMode
,
1399 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1400 if (!NT_SUCCESS(Status
))
1402 ZwClose(MessageQueue
->NewMessagesHandle
);
1403 MessageQueue
->NewMessagesHandle
= NULL
;
1411 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1413 PLIST_ENTRY CurrentEntry
;
1414 PUSER_MESSAGE CurrentMessage
;
1415 PUSER_SENT_MESSAGE CurrentSentMessage
;
1418 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1421 /* cleanup posted messages */
1422 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1424 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1425 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1427 MsqDestroyMessage(CurrentMessage
);
1430 /* remove the messages that have not yet been dispatched */
1431 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1433 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1434 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1437 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1439 /* remove the message from the dispatching list if needed */
1440 if ((!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1441 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1443 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1446 /* wake the sender's thread */
1447 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1449 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1452 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1454 if (CurrentSentMessage
->Msg
.lParam
)
1455 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1458 /* Only if it is not a no wait message */
1459 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1461 /* dereference our and the sender's message queue */
1462 IntDereferenceMessageQueue(MessageQueue
);
1463 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1466 /* free the message */
1467 ExFreePool(CurrentSentMessage
);
1470 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1471 ExitThread() was called in a SendMessage() umode callback */
1472 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1474 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1475 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1478 /* remove the message from the dispatching list */
1479 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1481 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1484 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1486 /* wake the sender's thread */
1487 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1489 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1492 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1494 if (CurrentSentMessage
->Msg
.lParam
)
1495 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1498 /* Only if it is not a no wait message */
1499 if (!(CurrentSentMessage
->HookMessage
& MSQ_SENTNOWAIT
))
1501 /* dereference our and the sender's message queue */
1502 IntDereferenceMessageQueue(MessageQueue
);
1503 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1506 /* free the message */
1507 ExFreePool(CurrentSentMessage
);
1510 /* tell other threads not to bother returning any info to us */
1511 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
1513 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
1514 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1515 DispatchingListEntry
);
1516 CurrentSentMessage
->CompletionEvent
= NULL
;
1517 CurrentSentMessage
->Result
= NULL
;
1519 /* do NOT dereference our message queue as it might get attempted to be
1523 // Clear it all out.
1524 pti
->pcti
->fsWakeBits
= 0;
1525 pti
->pcti
->fsChangeBits
= 0;
1527 MessageQueue
->nCntsQBits
[QSRosKey
] = 0;
1528 MessageQueue
->nCntsQBits
[QSRosMouseMove
] = 0;
1529 MessageQueue
->nCntsQBits
[QSRosMouseButton
] = 0;
1530 MessageQueue
->nCntsQBits
[QSRosPostMessage
] = 0;
1531 MessageQueue
->nCntsQBits
[QSRosSendMessage
] = 0;
1532 MessageQueue
->nCntsQBits
[QSRosHotKey
] = 0;
1535 PUSER_MESSAGE_QUEUE FASTCALL
1536 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
1538 PUSER_MESSAGE_QUEUE MessageQueue
;
1540 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
1541 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
1549 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
1550 /* hold at least one reference until it'll be destroyed */
1551 IntReferenceMessageQueue(MessageQueue
);
1552 /* initialize the queue */
1553 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
1555 IntDereferenceMessageQueue(MessageQueue
);
1559 return MessageQueue
;
1563 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1567 /* remove the message queue from any desktops */
1568 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
1570 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
1571 IntDereferenceMessageQueue(MessageQueue
);
1575 MsqCleanupMessageQueue(MessageQueue
);
1577 /* decrease the reference counter, if it hits zero, the queue will be freed */
1578 IntDereferenceMessageQueue(MessageQueue
);
1582 MsqSetMessageExtraInfo(LPARAM lParam
)
1586 PUSER_MESSAGE_QUEUE MessageQueue
;
1588 pti
= PsGetCurrentThreadWin32Thread();
1589 MessageQueue
= pti
->MessageQueue
;
1595 Ret
= MessageQueue
->ExtraInfo
;
1596 MessageQueue
->ExtraInfo
= lParam
;
1602 MsqGetMessageExtraInfo(VOID
)
1605 PUSER_MESSAGE_QUEUE MessageQueue
;
1607 pti
= PsGetCurrentThreadWin32Thread();
1608 MessageQueue
= pti
->MessageQueue
;
1614 return MessageQueue
->ExtraInfo
;
1617 // ReplyMessage is called by the thread receiving the window message.
1619 co_MsqReplyMessage( LRESULT lResult
)
1621 PUSER_SENT_MESSAGE Message
;
1624 pti
= PsGetCurrentThreadWin32Thread();
1625 Message
= pti
->pusmCurrent
;
1627 if (!Message
) return FALSE
;
1629 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
1631 // SendMessageXxx || Callback msg and not a notify msg
1632 if (Message
->SenderQueue
|| Message
->CompletionCallback
)
1634 Message
->lResult
= lResult
;
1635 Message
->QS_Flags
|= QS_SMRESULT
;
1636 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
1642 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
1648 case MSQ_STATE_CAPTURE
:
1649 Prev
= MessageQueue
->CaptureWindow
;
1650 MessageQueue
->CaptureWindow
= hWnd
;
1652 case MSQ_STATE_ACTIVE
:
1653 Prev
= MessageQueue
->ActiveWindow
;
1654 MessageQueue
->ActiveWindow
= hWnd
;
1656 case MSQ_STATE_FOCUS
:
1657 Prev
= MessageQueue
->FocusWindow
;
1658 MessageQueue
->FocusWindow
= hWnd
;
1660 case MSQ_STATE_MENUOWNER
:
1661 Prev
= MessageQueue
->MenuOwner
;
1662 MessageQueue
->MenuOwner
= hWnd
;
1664 case MSQ_STATE_MOVESIZE
:
1665 Prev
= MessageQueue
->MoveSize
;
1666 MessageQueue
->MoveSize
= hWnd
;
1668 case MSQ_STATE_CARET
:
1669 ASSERT(MessageQueue
->CaretInfo
);
1670 Prev
= MessageQueue
->CaretInfo
->hWnd
;
1671 MessageQueue
->CaretInfo
->hWnd
= hWnd
;