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
;
197 PWND pwnd
, pwndDesktop
;
199 KeQueryTickCount(&LargeTickCount
);
200 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
202 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
203 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
207 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
211 case WM_XBUTTONDBLCLK
:
212 case WM_NCXBUTTONDOWN
:
214 case WM_NCXBUTTONDBLCLK
:
215 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
218 MouseHookData
.mouseData
= 0;
222 MouseHookData
.flags
= 0;
223 MouseHookData
.time
= Msg
->time
;
224 MouseHookData
.dwExtraInfo
= 0;
226 /* If the hook procedure returned non zero, dont send the message */
227 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
230 /* Get the desktop window */
231 pwndDesktop
= UserGetDesktopWindow();
235 /* Check if the mouse is captured */
236 Msg
->hwnd
= IntGetCaptureWindow();
237 if(Msg
->hwnd
!= NULL
)
239 pwnd
= UserGetWindowObject(Msg
->hwnd
);
243 /* Loop all top level windows to find which one should receive input */
244 for( pwnd
= pwndDesktop
->spwndChild
;
246 pwnd
= pwnd
->spwndNext
)
248 if ( pwnd
->state2
& WNDS2_INDESTROY
|| pwnd
->state
& WNDS_DESTROYED
)
250 DPRINT("The Window is in DESTROY!\n");
254 if((pwnd
->style
& WS_VISIBLE
) &&
255 IntPtInWindow(pwnd
, Msg
->pt
.x
, Msg
->pt
.y
))
257 Msg
->hwnd
= pwnd
->head
.h
;
258 pDesk
= pwnd
->head
.rpdesk
;
259 pDesk
->htEx
= HTCLIENT
;
260 pDesk
->spwndTrack
= pwnd
;
266 /* Check if we found a window */
267 if(Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
269 if(Msg
->message
== WM_MOUSEMOVE
)
271 /* Mouse move is a special case*/
272 MsqPostMouseMove(pwnd
->head
.pti
->MessageQueue
, Msg
);
276 DPRINT("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd
));
277 MsqPostMessage(pwnd
->head
.pti
->MessageQueue
, Msg
, TRUE
, QS_MOUSEBUTTON
);
283 // Note: Only called from input.c.
286 co_MsqPostKeyboardMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
288 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
290 LARGE_INTEGER LargeTickCount
;
291 KBDLLHOOKSTRUCT KbdHookData
;
293 DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
294 uMsg
, wParam
, lParam
);
296 // Condition may arise when calling MsqPostMessage and waiting for an event.
297 ASSERT(UserIsEntered());
299 FocusMessageQueue
= IntGetFocusMessageQueue();
303 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
304 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
310 KeQueryTickCount(&LargeTickCount
);
311 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
313 /* We can't get the Msg.pt point here since we don't know thread
314 (and thus the window station) the message will end up in yet. */
316 KbdHookData
.vkCode
= Msg
.wParam
;
317 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
318 KbdHookData
.flags
= (0 == (Msg
.lParam
& 0x01000000) ? 0 : LLKHF_EXTENDED
) |
319 (0 == (Msg
.lParam
& 0x20000000) ? 0 : LLKHF_ALTDOWN
) |
320 (0 == (Msg
.lParam
& 0x80000000) ? 0 : LLKHF_UP
);
321 KbdHookData
.time
= Msg
.time
;
322 KbdHookData
.dwExtraInfo
= 0;
323 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
325 DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
326 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
330 if (FocusMessageQueue
== NULL
)
332 DPRINT("No focus message queue\n");
336 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
338 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
339 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
341 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
343 Msg
.pt
= gpsi
->ptCursor
;
344 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
348 DPRINT("Invalid focus window handle\n");
355 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
358 PTHREADINFO Win32Thread
;
360 LARGE_INTEGER LargeTickCount
;
363 Status
= ObReferenceObjectByPointer (Thread
,
367 if (!NT_SUCCESS(Status
))
370 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
371 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
373 ObDereferenceObject ((PETHREAD
)Thread
);
377 Window
= IntGetWindowObject(hWnd
);
380 ObDereferenceObject ((PETHREAD
)Thread
);
385 Mesg
.message
= WM_HOTKEY
;
386 Mesg
.wParam
= wParam
;
387 Mesg
.lParam
= lParam
;
388 KeQueryTickCount(&LargeTickCount
);
389 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
390 Mesg
.pt
= gpsi
->ptCursor
;
391 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
392 UserDereferenceObject(Window
);
393 ObDereferenceObject (Thread
);
397 PUSER_MESSAGE FASTCALL
398 MsqCreateMessage(LPMSG Msg
)
400 PUSER_MESSAGE Message
;
402 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
408 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
414 MsqDestroyMessage(PUSER_MESSAGE Message
)
416 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
420 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
422 PUSER_SENT_MESSAGE SaveMsg
, Message
;
427 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
432 /* remove it from the list of pending messages */
433 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
434 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
436 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
438 SaveMsg
= pti
->pusmCurrent
;
439 pti
->pusmCurrent
= Message
;
441 // Processing a message sent to it from another thread.
442 if ( ( Message
->SenderQueue
&& MessageQueue
!= Message
->SenderQueue
) ||
443 ( Message
->CallBackSenderQueue
&& MessageQueue
!= Message
->CallBackSenderQueue
))
444 { // most likely, but, to be sure.
445 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
448 /* insert it to the list of messages that are currently dispatched by this
450 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
451 &Message
->ListEntry
);
453 ClearMsgBitsMask(MessageQueue
, Message
->QS_Flags
);
455 if (Message
->HookMessage
== MSQ_ISHOOK
)
456 { // Direct Hook Call processor
457 Result
= co_CallHook( Message
->Msg
.message
, // HookId
458 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
460 Message
->Msg
.lParam
);
462 else if (Message
->HookMessage
== MSQ_ISEVENT
)
463 { // Direct Event Call processor
464 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
467 Message
->Msg
.lParam
);
470 { /* Call the window procedure. */
471 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
472 Message
->Msg
.message
,
474 Message
->Msg
.lParam
);
477 /* remove the message from the local dispatching list, because it doesn't need
478 to be cleaned up on thread termination anymore */
479 RemoveEntryList(&Message
->ListEntry
);
481 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
482 if (Message
->SenderQueue
)
484 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
486 /* only remove it from the dispatching list if not already removed by a timeout */
487 RemoveEntryList(&Message
->DispatchingListEntry
);
490 /* still keep the sender's message queue locked, so the sender can't exit the
491 MsqSendMessage() function (if timed out) */
493 if (Message
->QS_Flags
& QS_SMRESULT
)
495 Result
= Message
->lResult
;
498 /* Let the sender know the result. */
499 if (Message
->Result
!= NULL
)
501 *Message
->Result
= Result
;
504 if (Message
->HasPackedLParam
== TRUE
)
506 if (Message
->Msg
.lParam
)
507 ExFreePool((PVOID
)Message
->Msg
.lParam
);
510 /* Notify the sender. */
511 if (Message
->CompletionEvent
!= NULL
)
513 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
516 /* Call the callback if the message was sent with SendMessageCallback */
517 if (Message
->CompletionCallback
!= NULL
)
519 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
521 Message
->Msg
.message
,
522 Message
->CompletionCallbackContext
,
526 /* Only if the message has a sender was the queue referenced */
527 if (Message
->SenderQueue
)
529 IntDereferenceMessageQueue(Message
->SenderQueue
);
530 IntDereferenceMessageQueue(MessageQueue
);
533 /* free the message */
534 ExFreePoolWithTag(Message
, TAG_USRMSG
);
536 /* do not hangup on the user if this is reentering */
537 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
538 pti
->pusmCurrent
= SaveMsg
;
544 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
546 PUSER_SENT_MESSAGE SentMessage
;
547 PUSER_MESSAGE PostedMessage
;
548 PUSER_MESSAGE_QUEUE MessageQueue
;
549 PLIST_ENTRY CurrentEntry
, ListHead
;
550 PWND Window
= pWindow
;
554 MessageQueue
= Window
->head
.pti
->MessageQueue
;
555 ASSERT(MessageQueue
);
557 /* remove the posted messages for this window */
558 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
559 ListHead
= &MessageQueue
->PostedMessagesListHead
;
560 while (CurrentEntry
!= ListHead
)
562 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
564 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
566 RemoveEntryList(&PostedMessage
->ListEntry
);
567 ClearMsgBitsMask(MessageQueue
, PostedMessage
->QS_Flags
);
568 MsqDestroyMessage(PostedMessage
);
569 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
573 CurrentEntry
= CurrentEntry
->Flink
;
577 /* remove the sent messages for this window */
578 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
579 ListHead
= &MessageQueue
->SentMessagesListHead
;
580 while (CurrentEntry
!= ListHead
)
582 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
584 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
586 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
588 RemoveEntryList(&SentMessage
->ListEntry
);
589 ClearMsgBitsMask(MessageQueue
, SentMessage
->QS_Flags
);
591 /* Only if the message has a sender was the queue referenced */
592 if ((SentMessage
->SenderQueue
)
593 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
595 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
598 /* wake the sender's thread */
599 if (SentMessage
->CompletionEvent
!= NULL
)
601 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
604 if (SentMessage
->HasPackedLParam
== TRUE
)
606 if (SentMessage
->Msg
.lParam
)
607 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
610 /* Only if the message has a sender was the queue referenced */
611 if (SentMessage
->SenderQueue
)
613 /* dereference our and the sender's message queue */
614 IntDereferenceMessageQueue(MessageQueue
);
615 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
618 /* free the message */
619 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
621 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
625 CurrentEntry
= CurrentEntry
->Flink
;
631 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
632 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
633 UINT uTimeout
, BOOL Block
, INT HookMessage
,
636 PTHREADINFO pti
, ptirec
;
637 PUSER_SENT_MESSAGE Message
;
638 KEVENT CompletionEvent
;
640 PUSER_MESSAGE_QUEUE ThreadQueue
;
641 LARGE_INTEGER Timeout
;
643 LRESULT Result
= 0; //// Result could be trashed. ////
645 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
647 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
648 return STATUS_INSUFFICIENT_RESOURCES
;
651 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
653 pti
= PsGetCurrentThreadWin32Thread();
654 ThreadQueue
= pti
->MessageQueue
;
655 ptirec
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
656 ASSERT(ThreadQueue
!= MessageQueue
);
657 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
659 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
661 /* FIXME - increase reference counter of sender's message queue here */
663 Message
->Msg
.hwnd
= Wnd
;
664 Message
->Msg
.message
= Msg
;
665 Message
->Msg
.wParam
= wParam
;
666 Message
->Msg
.lParam
= lParam
;
667 Message
->CompletionEvent
= &CompletionEvent
;
668 Message
->Result
= &Result
;
669 Message
->lResult
= 0;
670 Message
->QS_Flags
= 0;
671 Message
->SenderQueue
= ThreadQueue
;
672 Message
->CallBackSenderQueue
= NULL
;
673 IntReferenceMessageQueue(ThreadQueue
);
674 Message
->CompletionCallback
= NULL
;
675 Message
->CompletionCallbackContext
= 0;
676 Message
->HookMessage
= HookMessage
;
677 Message
->HasPackedLParam
= FALSE
;
679 IntReferenceMessageQueue(MessageQueue
);
681 /* add it to the list of pending messages */
682 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
684 /* queue it in the destination's message queue */
685 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
687 Message
->QS_Flags
= QS_SENDMESSAGE
;
688 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
, TRUE
);
690 /* we can't access the Message anymore since it could have already been deleted! */
696 /* don't process messages sent to the thread */
697 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
698 FALSE
, (uTimeout
? &Timeout
: NULL
));
702 if(WaitStatus
== STATUS_TIMEOUT
)
704 /* look up if the message has not yet dispatched, if so
705 make sure it can't pass a result and it must not set the completion event anymore */
706 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
707 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
709 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
712 /* we can access Message here, it's secure because the message queue is locked
713 and the message is still hasn't been dispatched */
714 Message
->CompletionEvent
= NULL
;
715 Message
->Result
= NULL
;
718 Entry
= Entry
->Flink
;
721 /* remove from the local dispatching list so the other thread knows,
722 it can't pass a result and it must not set the completion event anymore */
723 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
724 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
726 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
729 /* we can access Message here, it's secure because the sender's message is locked
730 and the message has definitely not yet been destroyed, otherwise it would
731 have been removed from this list by the dispatching routine right after
732 dispatching the message */
733 Message
->CompletionEvent
= NULL
;
734 Message
->Result
= NULL
;
735 RemoveEntryList(&Message
->DispatchingListEntry
);
736 Message
->DispatchingListEntry
.Flink
= NULL
;
739 Entry
= Entry
->Flink
;
742 DPRINT("MsqSendMessage (blocked) timed out 1\n");
744 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
749 PVOID WaitObjects
[2];
751 WaitObjects
[0] = &CompletionEvent
;
752 WaitObjects
[1] = ThreadQueue
->NewMessages
;
757 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
758 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
762 if(WaitStatus
== STATUS_TIMEOUT
)
764 /* look up if the message has not yet been dispatched, if so
765 make sure it can't pass a result and it must not set the completion event anymore */
766 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
767 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
769 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
772 /* we can access Message here, it's secure because the message queue is locked
773 and the message is still hasn't been dispatched */
774 Message
->CompletionEvent
= NULL
;
775 Message
->Result
= NULL
;
778 Entry
= Entry
->Flink
;
781 /* remove from the local dispatching list so the other thread knows,
782 it can't pass a result and it must not set the completion event anymore */
783 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
784 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
786 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
789 /* we can access Message here, it's secure because the sender's message is locked
790 and the message has definitely not yet been destroyed, otherwise it would
791 have been removed from this list by the dispatching routine right after
792 dispatching the message */
793 Message
->CompletionEvent
= NULL
;
794 Message
->Result
= NULL
;
795 RemoveEntryList(&Message
->DispatchingListEntry
);
796 Message
->DispatchingListEntry
.Flink
= NULL
;
799 Entry
= Entry
->Flink
;
802 DPRINT("MsqSendMessage timed out 2\n");
805 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
808 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
811 if(WaitStatus
!= STATUS_TIMEOUT
)
812 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
818 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
821 PUSER_MESSAGE Message
;
823 if(!(Message
= MsqCreateMessage(Msg
)))
830 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
831 &Message
->ListEntry
);
835 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
836 &Message
->ListEntry
);
839 Message
->QS_Flags
= MessageBits
;
840 MsqWakeQueue(MessageQueue
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
844 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
846 MessageQueue
->QuitPosted
= TRUE
;
847 MessageQueue
->QuitExitCode
= ExitCode
;
848 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
851 /***********************************************************************
852 * MsqSendParentNotify
854 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
855 * the window has the WS_EX_NOPARENTNOTIFY style.
857 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
859 PWND pwndDesktop
= UserGetWindowObject(IntGetDesktopWindow());
861 /* pt has to be in the client coordinates of the parent window */
862 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
863 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
869 if (!(pwnd
->style
& WS_CHILD
)) break;
870 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
871 if (!(pwndParent
= IntGetParent(pwnd
))) break;
872 if (pwndParent
== pwndDesktop
) break;
873 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
874 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
877 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
878 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
882 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
889 MOUSEHOOKSTRUCT hook
;
892 PWND pwndMsg
, pwndDesktop
;
893 PUSER_MESSAGE_QUEUE MessageQueue
;
895 PSYSTEM_CURSORINFO CurInfo
;
896 DECLARE_RETURN(BOOL
);
898 pti
= PsGetCurrentThreadWin32Thread();
899 pwndDesktop
= UserGetDesktopWindow();
900 MessageQueue
= pti
->MessageQueue
;
901 CurInfo
= IntGetSysCursorInfo();
902 pwndMsg
= UserGetWindowObject(msg
->hwnd
);
903 clk_msg
= MessageQueue
->msgDblClk
;
905 /* find the window to dispatch this mouse message to */
906 if (MessageQueue
->CaptureWindow
)
909 pwndMsg
= IntGetWindowObject(MessageQueue
->CaptureWindow
);
913 pwndMsg
= co_WinPosWindowFromPoint(pwndMsg
, &msg
->pt
, &hittest
);
916 DPRINT("Got mouse message for 0x%x, hittest: 0x%x\n", msg
->hwnd
, hittest
);
918 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
920 /* Remove and ignore the message */
921 *RemoveMessages
= TRUE
;
925 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
928 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
932 message
= msg
->message
;
933 /* Note: windows has no concept of a non-client wheel message */
934 if (message
!= WM_MOUSEWHEEL
)
936 if (hittest
!= HTCLIENT
)
938 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
939 msg
->wParam
= hittest
;
943 /* coordinates don't get translated while tracking a menu */
944 /* FIXME: should differentiate popups and top-level menus */
945 if (!(MessageQueue
->MenuOwner
))
947 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
948 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
952 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
954 /* translate double clicks */
956 if ((msg
->message
== WM_LBUTTONDOWN
) ||
957 (msg
->message
== WM_RBUTTONDOWN
) ||
958 (msg
->message
== WM_MBUTTONDOWN
) ||
959 (msg
->message
== WM_XBUTTONDOWN
))
961 BOOL update
= *RemoveMessages
;
963 /* translate double clicks -
964 * note that ...MOUSEMOVEs can slip in between
965 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
967 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
968 hittest
!= HTCLIENT
||
969 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
971 if ((msg
->message
== clk_msg
.message
) &&
972 (msg
->hwnd
== clk_msg
.hwnd
) &&
973 (msg
->wParam
== clk_msg
.wParam
) &&
974 (msg
->time
- clk_msg
.time
< gspv
.iDblClickTime
) &&
975 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
976 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
978 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
981 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
987 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
989 DPRINT("Message out of range!!!\n");
993 /* update static double click conditions */
994 if (update
) MessageQueue
->msgDblClk
= *msg
;
998 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1000 DPRINT("Message out of range!!!\n");
1005 if(gspv
.bMouseClickLock
)
1007 BOOL IsClkLck
= FALSE
;
1009 if(msg
->message
== WM_LBUTTONUP
)
1011 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1012 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1014 CurInfo
->ClickLockActive
= TRUE
;
1017 else if (msg
->message
== WM_LBUTTONDOWN
)
1019 if (CurInfo
->ClickLockActive
)
1022 CurInfo
->ClickLockActive
= FALSE
;
1025 CurInfo
->ClickLockTime
= msg
->time
;
1030 /* Remove and ignore the message */
1031 *RemoveMessages
= TRUE
;
1036 /* message is accepted now (but may still get dropped) */
1038 event
.message
= msg
->message
;
1039 event
.time
= msg
->time
;
1040 event
.hwnd
= msg
->hwnd
;
1041 event
.paramL
= msg
->pt
.x
;
1042 event
.paramH
= msg
->pt
.y
;
1043 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1046 hook
.hwnd
= msg
->hwnd
;
1047 hook
.wHitTestCode
= hittest
;
1048 hook
.dwExtraInfo
= 0/*extra_info*/;
1049 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1050 message
, (LPARAM
)&hook
))
1053 hook
.hwnd
= msg
->hwnd
;
1054 hook
.wHitTestCode
= hittest
;
1055 hook
.dwExtraInfo
= 0/*extra_info*/;
1056 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1058 DPRINT1("WH_MOUSE dorpped mouse message!\n");
1060 /* Remove and skip message */
1061 *RemoveMessages
= TRUE
;
1065 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1067 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1068 MAKELONG( hittest
, msg
->message
));
1070 /* Remove and skip message */
1071 *RemoveMessages
= TRUE
;
1075 if ((*RemoveMessages
== FALSE
) || MessageQueue
->CaptureWindow
)
1077 /* Accept the message */
1078 msg
->message
= message
;
1084 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1085 (msg
->message
== WM_RBUTTONDOWN
) ||
1086 (msg
->message
== WM_MBUTTONDOWN
) ||
1087 (msg
->message
== WM_XBUTTONDOWN
))
1089 /* Send the WM_PARENTNOTIFY,
1090 * note that even for double/nonclient clicks
1091 * notification message is still WM_L/M/RBUTTONDOWN.
1093 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1095 /* Activate the window if needed */
1097 if (msg
->hwnd
!= UserGetForegroundWindow())
1099 PWND pwndTop
= pwndMsg
;
1102 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
1103 pwndTop
= IntGetParent( pwndTop
);
1106 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1108 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1110 (WPARAM
)UserHMGetHandle(pwndTop
),
1111 MAKELONG( hittest
, msg
->message
));
1114 case MA_NOACTIVATEANDEAT
:
1119 case MA_ACTIVATEANDEAT
:
1124 if(!co_IntMouseActivateWindow(pwndMsg
)) eatMsg
= TRUE
;
1127 DPRINT1( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1134 /* send the WM_SETCURSOR message */
1136 /* Windows sends the normal mouse message as the message parameter
1137 in the WM_SETCURSOR message even if it's non-client mouse message */
1138 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1140 msg
->message
= message
;
1145 UserDereferenceObject(pwndMsg
);
1150 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1154 Event
.message
= Msg
->message
;
1155 Event
.hwnd
= Msg
->hwnd
;
1156 Event
.time
= Msg
->time
;
1157 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1158 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1159 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1160 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1162 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1163 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1164 LOWORD(Msg
->wParam
),
1167 /* skip this message */
1168 co_HOOK_CallHooks( WH_CBT
,
1170 LOWORD(Msg
->wParam
),
1172 DPRINT1("KeyboardMessage WH_CBT Call Hook return!\n");
1178 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1180 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1182 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1184 else if ( IS_KBD_MESSAGE(Msg
->message
))
1186 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1193 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1196 IN UINT MsgFilterLow
,
1197 IN UINT MsgFilterHigh
,
1203 if(!(MessageQueue
->MouseMoved
))
1206 msg
= MessageQueue
->MouseMoveMsg
;
1208 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1215 ClearMsgBitsMask(MessageQueue
, QS_MOUSEMOVE
);
1216 MessageQueue
->MouseMoved
= FALSE
;
1219 return AcceptMessage
;
1222 /* check whether a message filter contains at least one potential hardware message */
1224 filter_contains_hw_range( UINT first
, UINT last
)
1226 /* hardware message ranges are (in numerical order):
1227 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1228 * WM_KEYFIRST .. WM_KEYLAST
1229 * WM_MOUSEFIRST .. WM_MOUSELAST
1232 if (last
< WM_NCMOUSEFIRST
) return 0;
1233 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1234 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1235 if (first
> WM_MOUSELAST
) return 0;
1240 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1243 IN UINT MsgFilterLow
,
1244 IN UINT MsgFilterHigh
,
1250 PUSER_MESSAGE CurrentMessage
;
1251 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1254 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1256 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1257 CurrentEntry
= ListHead
->Flink
;
1259 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1261 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1265 if (IsListEmpty(CurrentEntry
)) break;
1266 if (!CurrentMessage
) break;
1267 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1269 if ( (( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && (CurrentMessage
->QS_Flags
& QSflags
)) ||
1270 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) )
1272 msg
= CurrentMessage
->Msg
;
1274 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1278 RemoveEntryList(&CurrentMessage
->ListEntry
);
1279 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1280 MsqDestroyMessage(CurrentMessage
);
1289 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1292 while(CurrentEntry
!= ListHead
);
1298 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1301 IN UINT MsgFilterLow
,
1302 IN UINT MsgFilterHigh
,
1306 PLIST_ENTRY CurrentEntry
;
1307 PUSER_MESSAGE CurrentMessage
;
1308 PLIST_ENTRY ListHead
;
1310 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1311 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1313 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1315 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1319 if (IsListEmpty(CurrentEntry
)) break;
1320 if (!CurrentMessage
) break;
1321 CurrentEntry
= CurrentEntry
->Flink
;
1324 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1325 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1326 3: handle to the window whose messages are to be retrieved.
1328 if ( ( !Window
|| // 1
1329 ( Window
== HWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1330 ( Window
!= HWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
1331 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1332 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1334 *Message
= CurrentMessage
->Msg
;
1338 RemoveEntryList(&CurrentMessage
->ListEntry
);
1339 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1340 MsqDestroyMessage(CurrentMessage
);
1344 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1347 while (CurrentEntry
!= ListHead
);
1353 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1354 UINT MsgFilterMin
, UINT MsgFilterMax
)
1358 ret
= KeWaitForSingleObject( MessageQueue
->NewMessages
,
1368 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1370 LARGE_INTEGER LargeTickCount
;
1372 KeQueryTickCount(&LargeTickCount
);
1373 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1378 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
1380 //DoTheScreenSaver();
1381 DPRINT("HungAppSysTimerProc\n");
1382 // Process list of windows that are hung and waiting.
1386 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1388 LARGE_INTEGER LargeTickCount
;
1391 MessageQueue
->Thread
= Thread
;
1392 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1393 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1394 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1395 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1396 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1397 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1398 KeInitializeMutex(&MessageQueue
->HardwareLock
, 0);
1399 MessageQueue
->QuitPosted
= FALSE
;
1400 MessageQueue
->QuitExitCode
= 0;
1401 KeQueryTickCount(&LargeTickCount
);
1402 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1403 MessageQueue
->FocusWindow
= NULL
;
1404 MessageQueue
->NewMessagesHandle
= NULL
;
1406 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1407 NULL
, SynchronizationEvent
, FALSE
);
1408 if (!NT_SUCCESS(Status
))
1413 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1414 ExEventObjectType
, KernelMode
,
1415 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1416 if (!NT_SUCCESS(Status
))
1418 ZwClose(MessageQueue
->NewMessagesHandle
);
1419 MessageQueue
->NewMessagesHandle
= NULL
;
1427 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1429 PLIST_ENTRY CurrentEntry
;
1430 PUSER_MESSAGE CurrentMessage
;
1431 PUSER_SENT_MESSAGE CurrentSentMessage
;
1434 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1437 /* cleanup posted messages */
1438 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1440 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1441 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1443 MsqDestroyMessage(CurrentMessage
);
1446 /* remove the messages that have not yet been dispatched */
1447 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1449 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1450 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1453 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1454 /* Only if the message has a sender was the queue referenced */
1455 if ((CurrentSentMessage
->SenderQueue
)
1456 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
1458 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1461 /* wake the sender's thread */
1462 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1464 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1467 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1469 if (CurrentSentMessage
->Msg
.lParam
)
1470 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1473 /* Only if the message has a sender was the queue referenced */
1474 if (CurrentSentMessage
->SenderQueue
)
1476 /* dereference our and the sender's message queue */
1477 IntDereferenceMessageQueue(MessageQueue
);
1478 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1481 /* free the message */
1482 ExFreePool(CurrentSentMessage
);
1485 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1486 ExitThread() was called in a SendMessage() umode callback */
1487 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1489 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1490 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1493 /* remove the message from the dispatching list */
1494 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
1496 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
1499 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1501 /* wake the sender's thread */
1502 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
1504 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1507 if (CurrentSentMessage
->HasPackedLParam
== TRUE
)
1509 if (CurrentSentMessage
->Msg
.lParam
)
1510 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
1513 /* Only if the message has a sender was the queue referenced */
1514 if (CurrentSentMessage
->SenderQueue
)
1516 /* dereference our and the sender's message queue */
1517 IntDereferenceMessageQueue(MessageQueue
);
1518 IntDereferenceMessageQueue(CurrentSentMessage
->SenderQueue
);
1521 /* free the message */
1522 ExFreePool(CurrentSentMessage
);
1525 /* tell other threads not to bother returning any info to us */
1526 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
1528 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
1529 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1530 DispatchingListEntry
);
1531 CurrentSentMessage
->CompletionEvent
= NULL
;
1532 CurrentSentMessage
->Result
= NULL
;
1534 /* do NOT dereference our message queue as it might get attempted to be
1538 // Clear it all out.
1539 pti
->pcti
->fsWakeBits
= 0;
1540 pti
->pcti
->fsChangeBits
= 0;
1542 MessageQueue
->nCntsQBits
[QSRosKey
] = 0;
1543 MessageQueue
->nCntsQBits
[QSRosMouseMove
] = 0;
1544 MessageQueue
->nCntsQBits
[QSRosMouseButton
] = 0;
1545 MessageQueue
->nCntsQBits
[QSRosPostMessage
] = 0;
1546 MessageQueue
->nCntsQBits
[QSRosSendMessage
] = 0;
1547 MessageQueue
->nCntsQBits
[QSRosHotKey
] = 0;
1550 PUSER_MESSAGE_QUEUE FASTCALL
1551 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
1553 PUSER_MESSAGE_QUEUE MessageQueue
;
1555 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
1556 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
1564 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
1565 /* hold at least one reference until it'll be destroyed */
1566 IntReferenceMessageQueue(MessageQueue
);
1567 /* initialize the queue */
1568 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
1570 IntDereferenceMessageQueue(MessageQueue
);
1574 return MessageQueue
;
1578 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1582 MessageQueue
->QF_flags
|= QF_INDESTROY
;
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 if (MessageQueue
->NewMessagesHandle
!= NULL
)
1595 ZwClose(MessageQueue
->NewMessagesHandle
);
1596 MessageQueue
->NewMessagesHandle
= NULL
;
1597 /* decrease the reference counter, if it hits zero, the queue will be freed */
1598 IntDereferenceMessageQueue(MessageQueue
);
1602 MsqSetMessageExtraInfo(LPARAM lParam
)
1606 PUSER_MESSAGE_QUEUE MessageQueue
;
1608 pti
= PsGetCurrentThreadWin32Thread();
1609 MessageQueue
= pti
->MessageQueue
;
1615 Ret
= MessageQueue
->ExtraInfo
;
1616 MessageQueue
->ExtraInfo
= lParam
;
1622 MsqGetMessageExtraInfo(VOID
)
1625 PUSER_MESSAGE_QUEUE MessageQueue
;
1627 pti
= PsGetCurrentThreadWin32Thread();
1628 MessageQueue
= pti
->MessageQueue
;
1634 return MessageQueue
->ExtraInfo
;
1637 // ReplyMessage is called by the thread receiving the window message.
1639 co_MsqReplyMessage( LRESULT lResult
)
1641 PUSER_SENT_MESSAGE Message
;
1644 pti
= PsGetCurrentThreadWin32Thread();
1645 Message
= pti
->pusmCurrent
;
1647 if (!Message
) return FALSE
;
1649 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
1651 // SendMessageXxx || Callback msg and not a notify msg
1652 if (Message
->SenderQueue
|| Message
->CompletionCallback
)
1654 Message
->lResult
= lResult
;
1655 Message
->QS_Flags
|= QS_SMRESULT
;
1656 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
1662 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
1668 case MSQ_STATE_CAPTURE
:
1669 Prev
= MessageQueue
->CaptureWindow
;
1670 MessageQueue
->CaptureWindow
= hWnd
;
1672 case MSQ_STATE_ACTIVE
:
1673 Prev
= MessageQueue
->ActiveWindow
;
1674 MessageQueue
->ActiveWindow
= hWnd
;
1676 case MSQ_STATE_FOCUS
:
1677 Prev
= MessageQueue
->FocusWindow
;
1678 MessageQueue
->FocusWindow
= hWnd
;
1680 case MSQ_STATE_MENUOWNER
:
1681 Prev
= MessageQueue
->MenuOwner
;
1682 MessageQueue
->MenuOwner
= hWnd
;
1684 case MSQ_STATE_MOVESIZE
:
1685 Prev
= MessageQueue
->MoveSize
;
1686 MessageQueue
->MoveSize
= hWnd
;
1688 case MSQ_STATE_CARET
:
1689 ASSERT(MessageQueue
->CaretInfo
);
1690 Prev
= MessageQueue
->CaretInfo
->hWnd
;
1691 MessageQueue
->CaretInfo
->hWnd
= hWnd
;