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
;
283 DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
284 uMsg
, wParam
, lParam
);
286 // Condition may arise when calling MsqPostMessage and waiting for an event.
287 ASSERT(UserIsEntered());
289 FocusMessageQueue
= IntGetFocusMessageQueue();
293 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
294 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
300 KeQueryTickCount(&LargeTickCount
);
301 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
303 /* We can't get the Msg.pt point here since we don't know thread
304 (and thus the window station) the message will end up in yet. */
306 KbdHookData
.vkCode
= Msg
.wParam
;
307 KbdHookData
.scanCode
= (Msg
.lParam
>> 16) & 0xff;
308 KbdHookData
.flags
= (0 == (Msg
.lParam
& 0x01000000) ? 0 : LLKHF_EXTENDED
) |
309 (0 == (Msg
.lParam
& 0x20000000) ? 0 : LLKHF_ALTDOWN
) |
310 (0 == (Msg
.lParam
& 0x80000000) ? 0 : LLKHF_UP
);
311 KbdHookData
.time
= Msg
.time
;
312 KbdHookData
.dwExtraInfo
= 0;
313 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
315 DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
316 Msg
.message
, Msg
.wParam
, Msg
.lParam
);
320 if (FocusMessageQueue
== NULL
)
322 DPRINT("No focus message queue\n");
326 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
328 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
329 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
331 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
333 Msg
.pt
= gpsi
->ptCursor
;
334 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
338 DPRINT("Invalid focus window handle\n");
345 MsqPostHotKeyMessage(PVOID Thread
, HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
348 PTHREADINFO Win32Thread
;
350 LARGE_INTEGER LargeTickCount
;
353 Status
= ObReferenceObjectByPointer (Thread
,
357 if (!NT_SUCCESS(Status
))
360 Win32Thread
= ((PETHREAD
)Thread
)->Tcb
.Win32Thread
;
361 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
363 ObDereferenceObject ((PETHREAD
)Thread
);
367 Window
= IntGetWindowObject(hWnd
);
370 ObDereferenceObject ((PETHREAD
)Thread
);
375 Mesg
.message
= WM_HOTKEY
;
376 Mesg
.wParam
= wParam
;
377 Mesg
.lParam
= lParam
;
378 KeQueryTickCount(&LargeTickCount
);
379 Mesg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
380 Mesg
.pt
= gpsi
->ptCursor
;
381 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
382 UserDereferenceObject(Window
);
383 ObDereferenceObject (Thread
);
387 PUSER_MESSAGE FASTCALL
388 MsqCreateMessage(LPMSG Msg
)
390 PUSER_MESSAGE Message
;
392 Message
= ExAllocateFromPagedLookasideList(&MessageLookasideList
);
398 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
404 MsqDestroyMessage(PUSER_MESSAGE Message
)
406 ExFreeToPagedLookasideList(&MessageLookasideList
, Message
);
410 MsqDestroySentMessage(PUSER_MESSAGE_QUEUE MessageQueue
, PUSER_SENT_MESSAGE SentMessage
)
412 /* remove the message from the dispatching list if needed */
413 if (SentMessage
->DispatchingListEntry
.Flink
!= NULL
)
415 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
418 /* wake the sender's thread */
419 if (SentMessage
->CompletionEvent
!= NULL
)
421 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
424 /* dereference message queues */
425 IntDereferenceMessageQueue(MessageQueue
);
426 if (SentMessage
->SenderQueue
)
428 IntDereferenceMessageQueue(SentMessage
->SenderQueue
);
430 if (SentMessage
->CallBackSenderQueue
)
432 IntDereferenceMessageQueue(SentMessage
->CallBackSenderQueue
);
435 /* free lParam if needed */
436 if (SentMessage
->HasPackedLParam
== TRUE
&& SentMessage
->Msg
.lParam
)
438 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
441 /* free the message */
442 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
446 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue
)
448 PUSER_SENT_MESSAGE SaveMsg
, Message
;
453 if (IsListEmpty(&MessageQueue
->SentMessagesListHead
))
458 /* remove it from the list of pending messages */
459 Entry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
460 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
462 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
464 SaveMsg
= pti
->pusmCurrent
;
465 pti
->pusmCurrent
= Message
;
467 // Processing a message sent to it from another thread.
468 if ( ( Message
->SenderQueue
&& MessageQueue
!= Message
->SenderQueue
) ||
469 ( Message
->CallBackSenderQueue
&& MessageQueue
!= Message
->CallBackSenderQueue
))
470 { // most likely, but, to be sure.
471 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
474 /* insert it to the list of messages that are currently dispatched by this
476 InsertTailList(&MessageQueue
->LocalDispatchingMessagesHead
,
477 &Message
->ListEntry
);
479 ClearMsgBitsMask(MessageQueue
, Message
->QS_Flags
);
481 if (Message
->HookMessage
== MSQ_ISHOOK
)
482 { // Direct Hook Call processor
483 Result
= co_CallHook( Message
->Msg
.message
, // HookId
484 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
486 Message
->Msg
.lParam
);
488 else if (Message
->HookMessage
== MSQ_ISEVENT
)
489 { // Direct Event Call processor
490 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
493 Message
->Msg
.lParam
);
496 { /* Call the window procedure. */
497 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
498 Message
->Msg
.message
,
500 Message
->Msg
.lParam
);
503 /* remove the message from the local dispatching list, because it doesn't need
504 to be cleaned up on thread termination anymore */
505 RemoveEntryList(&Message
->ListEntry
);
507 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
508 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
510 RemoveEntryList(&Message
->DispatchingListEntry
);
511 Message
->DispatchingListEntry
.Flink
= NULL
;
513 /* still keep the sender's message queue locked, so the sender can't exit the
514 MsqSendMessage() function (if timed out) */
516 if (Message
->QS_Flags
& QS_SMRESULT
)
518 Result
= Message
->lResult
;
521 /* Let the sender know the result. */
522 if (Message
->Result
!= NULL
)
524 *Message
->Result
= Result
;
527 /* Notify the sender. */
528 if (Message
->CompletionEvent
!= NULL
)
530 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
531 Message
->CompletionEvent
= NULL
; /* prevent MsqDestroySentMessage from setting this event again */
534 /* Call the callback if the message was sent with SendMessageCallback */
535 if (Message
->CompletionCallback
!= NULL
)
537 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
539 Message
->Msg
.message
,
540 Message
->CompletionCallbackContext
,
544 MsqDestroySentMessage(MessageQueue
, Message
);
546 /* do not hangup on the user if this is reentering */
547 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
548 pti
->pusmCurrent
= SaveMsg
;
554 MsqRemoveWindowMessagesFromQueue(PVOID pWindow
)
556 PUSER_SENT_MESSAGE SentMessage
;
557 PUSER_MESSAGE PostedMessage
;
558 PUSER_MESSAGE_QUEUE MessageQueue
;
559 PLIST_ENTRY CurrentEntry
, ListHead
;
560 PWND Window
= pWindow
;
564 MessageQueue
= Window
->head
.pti
->MessageQueue
;
565 ASSERT(MessageQueue
);
567 /* remove the posted messages for this window */
568 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
569 ListHead
= &MessageQueue
->PostedMessagesListHead
;
570 while (CurrentEntry
!= ListHead
)
572 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
574 /* set CurrentEntry to next before destroying message */
575 CurrentEntry
= CurrentEntry
->Flink
;
577 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
579 RemoveEntryList(&PostedMessage
->ListEntry
);
580 ClearMsgBitsMask(MessageQueue
, PostedMessage
->QS_Flags
);
581 MsqDestroyMessage(PostedMessage
);
585 /* remove the sent messages for this window */
586 CurrentEntry
= MessageQueue
->SentMessagesListHead
.Flink
;
587 ListHead
= &MessageQueue
->SentMessagesListHead
;
588 while (CurrentEntry
!= ListHead
)
590 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
592 /* set CurrentEntry to next before destroying message */
593 CurrentEntry
= CurrentEntry
->Flink
;
595 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
597 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
599 RemoveEntryList(&SentMessage
->ListEntry
);
600 ClearMsgBitsMask(MessageQueue
, SentMessage
->QS_Flags
);
602 MsqDestroySentMessage(MessageQueue
, SentMessage
);
608 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue
,
609 HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
,
610 UINT uTimeout
, BOOL Block
, INT HookMessage
,
614 PUSER_SENT_MESSAGE Message
;
615 KEVENT CompletionEvent
;
617 PUSER_MESSAGE_QUEUE ThreadQueue
;
618 LARGE_INTEGER Timeout
;
620 LRESULT Result
= 0; //// Result could be trashed. ////
622 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
624 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
625 return STATUS_INSUFFICIENT_RESOURCES
;
628 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
630 pti
= PsGetCurrentThreadWin32Thread();
631 ThreadQueue
= pti
->MessageQueue
;
632 ASSERT(ThreadQueue
!= MessageQueue
);
634 Timeout
.QuadPart
= (LONGLONG
) uTimeout
* (LONGLONG
) -10000;
636 /* FIXME - increase reference counter of sender's message queue here - isn't it done? */
638 Message
->Msg
.hwnd
= Wnd
;
639 Message
->Msg
.message
= Msg
;
640 Message
->Msg
.wParam
= wParam
;
641 Message
->Msg
.lParam
= lParam
;
642 Message
->CompletionEvent
= &CompletionEvent
;
643 Message
->Result
= &Result
;
644 Message
->lResult
= 0;
645 Message
->QS_Flags
= 0;
646 IntReferenceMessageQueue(ThreadQueue
);
647 Message
->SenderQueue
= ThreadQueue
;
648 Message
->CallBackSenderQueue
= NULL
;
649 Message
->CompletionCallback
= NULL
;
650 Message
->CompletionCallbackContext
= 0;
651 Message
->HookMessage
= HookMessage
;
652 Message
->HasPackedLParam
= FALSE
;
654 IntReferenceMessageQueue(MessageQueue
);
656 /* add it to the list of pending messages */
657 InsertTailList(&ThreadQueue
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
659 /* queue it in the destination's message queue */
660 InsertTailList(&MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
662 Message
->QS_Flags
= QS_SENDMESSAGE
;
663 MsqWakeQueue(MessageQueue
, QS_SENDMESSAGE
, TRUE
);
665 /* we can't access the Message anymore since it could have already been deleted! */
671 /* don't process messages sent to the thread */
672 WaitStatus
= KeWaitForSingleObject(&CompletionEvent
, UserRequest
, UserMode
,
673 FALSE
, (uTimeout
? &Timeout
: NULL
));
677 if(WaitStatus
== STATUS_TIMEOUT
)
679 /* look up if the message has not yet dispatched, if so
680 make sure it can't pass a result and it must not set the completion event anymore */
681 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
682 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
684 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
687 /* we can access Message here, it's secure because the message queue is locked
688 and the message is still hasn't been dispatched */
689 Message
->CompletionEvent
= NULL
;
690 Message
->Result
= NULL
;
693 Entry
= Entry
->Flink
;
696 /* remove from the local dispatching list so the other thread knows,
697 it can't pass a result and it must not set the completion event anymore */
698 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
699 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
701 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
704 /* we can access Message here, it's secure because the sender's message is locked
705 and the message has definitely not yet been destroyed, otherwise it would
706 have been removed from this list by the dispatching routine right after
707 dispatching the message */
708 Message
->CompletionEvent
= NULL
;
709 Message
->Result
= NULL
;
710 RemoveEntryList(&Message
->DispatchingListEntry
);
711 Message
->DispatchingListEntry
.Flink
= NULL
;
714 Entry
= Entry
->Flink
;
717 DPRINT("MsqSendMessage (blocked) timed out\n");
719 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
724 PVOID WaitObjects
[2];
726 WaitObjects
[0] = &CompletionEvent
;
727 WaitObjects
[1] = ThreadQueue
->NewMessages
;
732 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
733 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
737 if(WaitStatus
== STATUS_TIMEOUT
)
739 /* look up if the message has not yet been dispatched, if so
740 make sure it can't pass a result and it must not set the completion event anymore */
741 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
742 while (Entry
!= &MessageQueue
->SentMessagesListHead
)
744 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
747 /* we can access Message here, it's secure because the message queue is locked
748 and the message is still hasn't been dispatched */
749 Message
->CompletionEvent
= NULL
;
750 Message
->Result
= NULL
;
753 Entry
= Entry
->Flink
;
756 /* remove from the local dispatching list so the other thread knows,
757 it can't pass a result and it must not set the completion event anymore */
758 Entry
= ThreadQueue
->DispatchingMessagesHead
.Flink
;
759 while (Entry
!= &ThreadQueue
->DispatchingMessagesHead
)
761 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
764 /* we can access Message here, it's secure because the sender's message is locked
765 and the message has definitely not yet been destroyed, otherwise it would
766 have been removed from this list by the dispatching routine right after
767 dispatching the message */
768 Message
->CompletionEvent
= NULL
;
769 Message
->Result
= NULL
;
770 RemoveEntryList(&Message
->DispatchingListEntry
);
771 Message
->DispatchingListEntry
.Flink
= NULL
;
774 Entry
= Entry
->Flink
;
777 DPRINT("MsqSendMessage timed out\n");
780 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
783 while (NT_SUCCESS(WaitStatus
) && STATUS_WAIT_0
!= WaitStatus
);
786 if(WaitStatus
!= STATUS_TIMEOUT
)
787 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
793 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* Msg
, BOOLEAN HardwareMessage
,
796 PUSER_MESSAGE Message
;
798 if(!(Message
= MsqCreateMessage(Msg
)))
805 InsertTailList(&MessageQueue
->PostedMessagesListHead
,
806 &Message
->ListEntry
);
810 InsertTailList(&MessageQueue
->HardwareMessagesListHead
,
811 &Message
->ListEntry
);
814 Message
->QS_Flags
= MessageBits
;
815 MsqWakeQueue(MessageQueue
, MessageBits
, (MessageBits
& QS_TIMER
? FALSE
: TRUE
));
819 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG ExitCode
)
821 MessageQueue
->QuitPosted
= TRUE
;
822 MessageQueue
->QuitExitCode
= ExitCode
;
823 MsqWakeQueue(MessageQueue
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
826 /***********************************************************************
827 * MsqSendParentNotify
829 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
830 * the window has the WS_EX_NOPARENTNOTIFY style.
832 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
834 PWND pwndDesktop
= UserGetWindowObject(IntGetDesktopWindow());
836 /* pt has to be in the client coordinates of the parent window */
837 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
838 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
844 if (!(pwnd
->style
& WS_CHILD
)) break;
845 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
846 if (!(pwndParent
= IntGetParent(pwnd
))) break;
847 if (pwndParent
== pwndDesktop
) break;
848 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
849 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
852 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
853 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
857 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
864 MOUSEHOOKSTRUCT hook
;
867 PWND pwndMsg
, pwndDesktop
;
868 PUSER_MESSAGE_QUEUE MessageQueue
;
870 PSYSTEM_CURSORINFO CurInfo
;
871 DECLARE_RETURN(BOOL
);
873 pti
= PsGetCurrentThreadWin32Thread();
874 pwndDesktop
= UserGetDesktopWindow();
875 MessageQueue
= pti
->MessageQueue
;
876 CurInfo
= IntGetSysCursorInfo();
877 pwndMsg
= UserGetWindowObject(msg
->hwnd
);
878 clk_msg
= MessageQueue
->msgDblClk
;
880 /* find the window to dispatch this mouse message to */
881 if (MessageQueue
->CaptureWindow
)
884 pwndMsg
= IntGetWindowObject(MessageQueue
->CaptureWindow
);
888 pwndMsg
= co_WinPosWindowFromPoint(pwndMsg
, &msg
->pt
, &hittest
);
891 DPRINT("Got mouse message for 0x%x, hittest: 0x%x\n", msg
->hwnd
, hittest
);
893 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
!= pti
)
895 /* Remove and ignore the message */
896 *RemoveMessages
= TRUE
;
900 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
903 if (!check_hwnd_filter( msg
, hwnd_filter
)) RETURN(FALSE
);
907 message
= msg
->message
;
908 /* Note: windows has no concept of a non-client wheel message */
909 if (message
!= WM_MOUSEWHEEL
)
911 if (hittest
!= HTCLIENT
)
913 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
914 msg
->wParam
= hittest
;
918 /* coordinates don't get translated while tracking a menu */
919 /* FIXME: should differentiate popups and top-level menus */
920 if (!(MessageQueue
->MenuOwner
))
922 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
923 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
927 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
929 /* translate double clicks */
931 if ((msg
->message
== WM_LBUTTONDOWN
) ||
932 (msg
->message
== WM_RBUTTONDOWN
) ||
933 (msg
->message
== WM_MBUTTONDOWN
) ||
934 (msg
->message
== WM_XBUTTONDOWN
))
936 BOOL update
= *RemoveMessages
;
938 /* translate double clicks -
939 * note that ...MOUSEMOVEs can slip in between
940 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
942 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
943 hittest
!= HTCLIENT
||
944 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
946 if ((msg
->message
== clk_msg
.message
) &&
947 (msg
->hwnd
== clk_msg
.hwnd
) &&
948 (msg
->wParam
== clk_msg
.wParam
) &&
949 (msg
->time
- clk_msg
.time
< gspv
.iDblClickTime
) &&
950 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
951 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
953 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
956 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
962 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
964 DPRINT("Message out of range!!!\n");
968 /* update static double click conditions */
969 if (update
) MessageQueue
->msgDblClk
= *msg
;
973 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
975 DPRINT("Message out of range!!!\n");
980 if(gspv
.bMouseClickLock
)
982 BOOL IsClkLck
= FALSE
;
984 if(msg
->message
== WM_LBUTTONUP
)
986 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
987 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
989 CurInfo
->ClickLockActive
= TRUE
;
992 else if (msg
->message
== WM_LBUTTONDOWN
)
994 if (CurInfo
->ClickLockActive
)
997 CurInfo
->ClickLockActive
= FALSE
;
1000 CurInfo
->ClickLockTime
= msg
->time
;
1005 /* Remove and ignore the message */
1006 *RemoveMessages
= TRUE
;
1011 /* message is accepted now (but may still get dropped) */
1013 pti
->rpdesk
->htEx
= hittest
; /* Now set the capture hit. */
1015 event
.message
= msg
->message
;
1016 event
.time
= msg
->time
;
1017 event
.hwnd
= msg
->hwnd
;
1018 event
.paramL
= msg
->pt
.x
;
1019 event
.paramH
= msg
->pt
.y
;
1020 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1023 hook
.hwnd
= msg
->hwnd
;
1024 hook
.wHitTestCode
= hittest
;
1025 hook
.dwExtraInfo
= 0/*extra_info*/;
1026 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1027 message
, (LPARAM
)&hook
))
1030 hook
.hwnd
= msg
->hwnd
;
1031 hook
.wHitTestCode
= hittest
;
1032 hook
.dwExtraInfo
= 0/*extra_info*/;
1033 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1035 DPRINT1("WH_MOUSE dorpped mouse message!\n");
1037 /* Remove and skip message */
1038 *RemoveMessages
= TRUE
;
1042 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1044 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1045 MAKELONG( hittest
, msg
->message
));
1047 /* Remove and skip message */
1048 *RemoveMessages
= TRUE
;
1052 if ((*RemoveMessages
== FALSE
) || MessageQueue
->CaptureWindow
)
1054 /* Accept the message */
1055 msg
->message
= message
;
1061 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1062 (msg
->message
== WM_RBUTTONDOWN
) ||
1063 (msg
->message
== WM_MBUTTONDOWN
) ||
1064 (msg
->message
== WM_XBUTTONDOWN
))
1066 /* Send the WM_PARENTNOTIFY,
1067 * note that even for double/nonclient clicks
1068 * notification message is still WM_L/M/RBUTTONDOWN.
1070 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1072 /* Activate the window if needed */
1074 if (msg
->hwnd
!= UserGetForegroundWindow())
1076 PWND pwndTop
= pwndMsg
;
1079 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
1080 pwndTop
= IntGetParent( pwndTop
);
1083 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1085 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1087 (WPARAM
)UserHMGetHandle(pwndTop
),
1088 MAKELONG( hittest
, msg
->message
));
1091 case MA_NOACTIVATEANDEAT
:
1096 case MA_ACTIVATEANDEAT
:
1101 if(!co_IntMouseActivateWindow(pwndMsg
)) eatMsg
= TRUE
;
1104 DPRINT1( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1111 /* send the WM_SETCURSOR message */
1113 /* Windows sends the normal mouse message as the message parameter
1114 in the WM_SETCURSOR message even if it's non-client mouse message */
1115 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1117 msg
->message
= message
;
1122 UserDereferenceObject(pwndMsg
);
1127 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1131 Event
.message
= Msg
->message
;
1132 Event
.hwnd
= Msg
->hwnd
;
1133 Event
.time
= Msg
->time
;
1134 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1135 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1136 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1137 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1139 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1140 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1141 LOWORD(Msg
->wParam
),
1144 /* skip this message */
1145 co_HOOK_CallHooks( WH_CBT
,
1147 LOWORD(Msg
->wParam
),
1149 DPRINT1("KeyboardMessage WH_CBT Call Hook return!\n");
1155 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1157 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1159 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1161 else if ( IS_KBD_MESSAGE(Msg
->message
))
1163 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1170 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1173 IN UINT MsgFilterLow
,
1174 IN UINT MsgFilterHigh
,
1180 if(!(MessageQueue
->MouseMoved
))
1183 msg
= MessageQueue
->MouseMoveMsg
;
1185 AcceptMessage
= co_IntProcessMouseMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1192 ClearMsgBitsMask(MessageQueue
, QS_MOUSEMOVE
);
1193 MessageQueue
->MouseMoved
= FALSE
;
1196 return AcceptMessage
;
1199 /* check whether a message filter contains at least one potential hardware message */
1201 filter_contains_hw_range( UINT first
, UINT last
)
1203 /* hardware message ranges are (in numerical order):
1204 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1205 * WM_KEYFIRST .. WM_KEYLAST
1206 * WM_MOUSEFIRST .. WM_MOUSELAST
1209 if (last
< WM_NCMOUSEFIRST
) return 0;
1210 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1211 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1212 if (first
> WM_MOUSELAST
) return 0;
1217 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1220 IN UINT MsgFilterLow
,
1221 IN UINT MsgFilterHigh
,
1227 PUSER_MESSAGE CurrentMessage
;
1228 PLIST_ENTRY ListHead
, CurrentEntry
= NULL
;
1231 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1233 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
1234 CurrentEntry
= ListHead
->Flink
;
1236 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1238 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1242 if (IsListEmpty(CurrentEntry
)) break;
1243 if (!CurrentMessage
) break;
1244 CurrentEntry
= CurrentMessage
->ListEntry
.Flink
;
1246 if ( (( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && (CurrentMessage
->QS_Flags
& QSflags
)) ||
1247 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) )
1249 msg
= CurrentMessage
->Msg
;
1251 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1255 RemoveEntryList(&CurrentMessage
->ListEntry
);
1256 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1257 MsqDestroyMessage(CurrentMessage
);
1266 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1269 while(CurrentEntry
!= ListHead
);
1275 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue
,
1278 IN UINT MsgFilterLow
,
1279 IN UINT MsgFilterHigh
,
1283 PLIST_ENTRY CurrentEntry
;
1284 PUSER_MESSAGE CurrentMessage
;
1285 PLIST_ENTRY ListHead
;
1287 CurrentEntry
= MessageQueue
->PostedMessagesListHead
.Flink
;
1288 ListHead
= &MessageQueue
->PostedMessagesListHead
;
1290 if (IsListEmpty(CurrentEntry
)) return FALSE
;
1292 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1296 if (IsListEmpty(CurrentEntry
)) break;
1297 if (!CurrentMessage
) break;
1298 CurrentEntry
= CurrentEntry
->Flink
;
1300 if ( ( !Window
|| Window
== HWND_BOTTOM
|| Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) &&
1301 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1302 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1304 *Message
= CurrentMessage
->Msg
;
1308 RemoveEntryList(&CurrentMessage
->ListEntry
);
1309 ClearMsgBitsMask(MessageQueue
, CurrentMessage
->QS_Flags
);
1310 MsqDestroyMessage(CurrentMessage
);
1314 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1317 while (CurrentEntry
!= ListHead
);
1323 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue
, PWND WndFilter
,
1324 UINT MsgFilterMin
, UINT MsgFilterMax
)
1329 ret
= KeWaitForSingleObject(MessageQueue
->NewMessages
,
1339 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue
)
1341 LARGE_INTEGER LargeTickCount
;
1343 KeQueryTickCount(&LargeTickCount
);
1344 return ((LargeTickCount
.u
.LowPart
- MessageQueue
->LastMsgRead
) > MSQ_HUNG
);
1348 MsqInitializeMessageQueue(struct _ETHREAD
*Thread
, PUSER_MESSAGE_QUEUE MessageQueue
)
1350 LARGE_INTEGER LargeTickCount
;
1353 MessageQueue
->Thread
= Thread
;
1354 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
1355 InitializeListHead(&MessageQueue
->PostedMessagesListHead
);
1356 InitializeListHead(&MessageQueue
->SentMessagesListHead
);
1357 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
);
1358 InitializeListHead(&MessageQueue
->DispatchingMessagesHead
);
1359 InitializeListHead(&MessageQueue
->LocalDispatchingMessagesHead
);
1360 KeInitializeMutex(&MessageQueue
->HardwareLock
, 0);
1361 MessageQueue
->QuitPosted
= FALSE
;
1362 MessageQueue
->QuitExitCode
= 0;
1363 KeQueryTickCount(&LargeTickCount
);
1364 MessageQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
1365 MessageQueue
->FocusWindow
= NULL
;
1366 MessageQueue
->NewMessagesHandle
= NULL
;
1368 Status
= ZwCreateEvent(&MessageQueue
->NewMessagesHandle
, EVENT_ALL_ACCESS
,
1369 NULL
, SynchronizationEvent
, FALSE
);
1370 if (!NT_SUCCESS(Status
))
1375 Status
= ObReferenceObjectByHandle(MessageQueue
->NewMessagesHandle
, 0,
1376 ExEventObjectType
, KernelMode
,
1377 (PVOID
*)&MessageQueue
->NewMessages
, NULL
);
1378 if (!NT_SUCCESS(Status
))
1380 ZwClose(MessageQueue
->NewMessagesHandle
);
1381 MessageQueue
->NewMessagesHandle
= NULL
;
1389 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1391 PLIST_ENTRY CurrentEntry
;
1392 PUSER_MESSAGE CurrentMessage
;
1393 PUSER_SENT_MESSAGE CurrentSentMessage
;
1396 pti
= MessageQueue
->Thread
->Tcb
.Win32Thread
;
1399 /* cleanup posted messages */
1400 while (!IsListEmpty(&MessageQueue
->PostedMessagesListHead
))
1402 CurrentEntry
= RemoveHeadList(&MessageQueue
->PostedMessagesListHead
);
1403 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
1405 MsqDestroyMessage(CurrentMessage
);
1408 /* remove the messages that have not yet been dispatched */
1409 while (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
1411 CurrentEntry
= RemoveHeadList(&MessageQueue
->SentMessagesListHead
);
1412 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1415 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1417 MsqDestroySentMessage(MessageQueue
, CurrentSentMessage
);
1420 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1421 ExitThread() was called in a SendMessage() umode callback */
1422 while (!IsListEmpty(&MessageQueue
->LocalDispatchingMessagesHead
))
1424 CurrentEntry
= RemoveHeadList(&MessageQueue
->LocalDispatchingMessagesHead
);
1425 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1428 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1430 MsqDestroySentMessage(MessageQueue
, CurrentSentMessage
);
1433 /* tell other threads not to bother returning any info to us */
1434 while (! IsListEmpty(&MessageQueue
->DispatchingMessagesHead
))
1436 CurrentEntry
= RemoveHeadList(&MessageQueue
->DispatchingMessagesHead
);
1437 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
1438 DispatchingListEntry
);
1439 CurrentSentMessage
->CompletionEvent
= NULL
;
1440 CurrentSentMessage
->Result
= NULL
;
1441 CurrentSentMessage
->DispatchingListEntry
.Flink
= NULL
; // yeah!
1443 /* do NOT dereference our message queue as it might get attempted to be
1447 // Clear it all out.
1448 pti
->pcti
->fsWakeBits
= 0;
1449 pti
->pcti
->fsChangeBits
= 0;
1451 MessageQueue
->nCntsQBits
[QSRosKey
] = 0;
1452 MessageQueue
->nCntsQBits
[QSRosMouseMove
] = 0;
1453 MessageQueue
->nCntsQBits
[QSRosMouseButton
] = 0;
1454 MessageQueue
->nCntsQBits
[QSRosPostMessage
] = 0;
1455 MessageQueue
->nCntsQBits
[QSRosSendMessage
] = 0;
1456 MessageQueue
->nCntsQBits
[QSRosHotKey
] = 0;
1459 PUSER_MESSAGE_QUEUE FASTCALL
1460 MsqCreateMessageQueue(struct _ETHREAD
*Thread
)
1462 PUSER_MESSAGE_QUEUE MessageQueue
;
1464 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
1465 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
1473 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
1474 /* hold at least one reference until it'll be destroyed */
1475 IntReferenceMessageQueue(MessageQueue
);
1476 /* initialize the queue */
1477 if (!MsqInitializeMessageQueue(Thread
, MessageQueue
))
1479 IntDereferenceMessageQueue(MessageQueue
);
1483 return MessageQueue
;
1487 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue
)
1491 /* remove the message queue from any desktops */
1492 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
1494 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
1495 IntDereferenceMessageQueue(MessageQueue
);
1499 MsqCleanupMessageQueue(MessageQueue
);
1501 /* decrease the reference counter, if it hits zero, the queue will be freed */
1502 IntDereferenceMessageQueue(MessageQueue
);
1506 MsqSetMessageExtraInfo(LPARAM lParam
)
1510 PUSER_MESSAGE_QUEUE MessageQueue
;
1512 pti
= PsGetCurrentThreadWin32Thread();
1513 MessageQueue
= pti
->MessageQueue
;
1519 Ret
= MessageQueue
->ExtraInfo
;
1520 MessageQueue
->ExtraInfo
= lParam
;
1526 MsqGetMessageExtraInfo(VOID
)
1529 PUSER_MESSAGE_QUEUE MessageQueue
;
1531 pti
= PsGetCurrentThreadWin32Thread();
1532 MessageQueue
= pti
->MessageQueue
;
1538 return MessageQueue
->ExtraInfo
;
1541 // ReplyMessage is called by the thread receiving the window message.
1543 co_MsqReplyMessage( LRESULT lResult
)
1545 PUSER_SENT_MESSAGE Message
;
1548 pti
= PsGetCurrentThreadWin32Thread();
1549 Message
= pti
->pusmCurrent
;
1551 if (!Message
) return FALSE
;
1553 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
1555 // SendMessageXxx || Callback msg and not a notify msg
1556 if (Message
->SenderQueue
|| Message
->CompletionCallback
)
1558 Message
->lResult
= lResult
;
1559 Message
->QS_Flags
|= QS_SMRESULT
;
1560 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
1566 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue
, ULONG Type
, HWND hWnd
)
1572 case MSQ_STATE_CAPTURE
:
1573 Prev
= MessageQueue
->CaptureWindow
;
1574 MessageQueue
->CaptureWindow
= hWnd
;
1576 case MSQ_STATE_ACTIVE
:
1577 Prev
= MessageQueue
->ActiveWindow
;
1578 MessageQueue
->ActiveWindow
= hWnd
;
1580 case MSQ_STATE_FOCUS
:
1581 Prev
= MessageQueue
->FocusWindow
;
1582 MessageQueue
->FocusWindow
= hWnd
;
1584 case MSQ_STATE_MENUOWNER
:
1585 Prev
= MessageQueue
->MenuOwner
;
1586 MessageQueue
->MenuOwner
= hWnd
;
1588 case MSQ_STATE_MOVESIZE
:
1589 Prev
= MessageQueue
->MoveSize
;
1590 MessageQueue
->MoveSize
= hWnd
;
1592 case MSQ_STATE_CARET
:
1593 ASSERT(MessageQueue
->CaretInfo
);
1594 Prev
= MessageQueue
->CaretInfo
->hWnd
;
1595 MessageQueue
->CaretInfo
->hWnd
= hWnd
;