[Win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / msgqueue.c
1 /*
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)
7 Alexandre Julliard
8 Maarten Lankhorst
9 * REVISION HISTORY:
10 * 06-06-2001 CSH Created
11 */
12
13 /* INCLUDES ******************************************************************/
14
15 #include <win32k.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20 /* GLOBALS *******************************************************************/
21
22 static PAGED_LOOKASIDE_LIST MessageLookasideList;
23 MOUSEMOVEPOINT MouseHistoryOfMoves[64];
24 INT gcur_count = 0;
25
26 /* FUNCTIONS *****************************************************************/
27
28 INIT_FUNCTION
29 NTSTATUS
30 NTAPI
31 MsqInitializeImpl(VOID)
32 {
33 ExInitializePagedLookasideList(&MessageLookasideList,
34 NULL,
35 NULL,
36 0,
37 sizeof(USER_MESSAGE),
38 TAG_USRMSG,
39 256);
40
41 return(STATUS_SUCCESS);
42 }
43
44 DWORD FASTCALL UserGetKeyState(DWORD key)
45 {
46 DWORD ret = 0;
47 PTHREADINFO pti;
48 PUSER_MESSAGE_QUEUE MessageQueue;
49
50 pti = PsGetCurrentThreadWin32Thread();
51 MessageQueue = pti->MessageQueue;
52
53 if( key < 0x100 )
54 {
55 ret = ((DWORD)(MessageQueue->KeyState[key] & KS_DOWN_BIT) << 8 ) |
56 (MessageQueue->KeyState[key] & KS_LOCK_BIT);
57 }
58
59 return ret;
60 }
61
62 /* change the input key state for a given key */
63 static void set_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue, UCHAR key, BOOL down )
64 {
65 if (down)
66 {
67 if (!(MessageQueue->KeyState[key] & KS_DOWN_BIT))
68 {
69 MessageQueue->KeyState[key] ^= KS_LOCK_BIT;
70 }
71 MessageQueue->KeyState[key] |= KS_DOWN_BIT;
72 }
73 else
74 {
75 MessageQueue->KeyState[key] &= ~KS_DOWN_BIT;
76 }
77 }
78
79 /* update the input key state for a keyboard message */
80 static void update_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue, MSG* msg )
81 {
82 UCHAR key;
83 BOOL down = 0;
84
85 switch (msg->message)
86 {
87 case WM_LBUTTONDOWN:
88 down = 1;
89 /* fall through */
90 case WM_LBUTTONUP:
91 set_input_key_state( MessageQueue, VK_LBUTTON, down );
92 break;
93 case WM_MBUTTONDOWN:
94 down = 1;
95 /* fall through */
96 case WM_MBUTTONUP:
97 set_input_key_state( MessageQueue, VK_MBUTTON, down );
98 break;
99 case WM_RBUTTONDOWN:
100 down = 1;
101 /* fall through */
102 case WM_RBUTTONUP:
103 set_input_key_state( MessageQueue, VK_RBUTTON, down );
104 break;
105 case WM_XBUTTONDOWN:
106 down = 1;
107 /* fall through */
108 case WM_XBUTTONUP:
109 if (msg->wParam == XBUTTON1)
110 set_input_key_state( MessageQueue, VK_XBUTTON1, down );
111 else if (msg->wParam == XBUTTON2)
112 set_input_key_state( MessageQueue, VK_XBUTTON2, down );
113 break;
114 case WM_KEYDOWN:
115 case WM_SYSKEYDOWN:
116 down = 1;
117 /* fall through */
118 case WM_KEYUP:
119 case WM_SYSKEYUP:
120 key = (UCHAR)msg->wParam;
121 set_input_key_state( MessageQueue, key, down );
122 switch(key)
123 {
124 case VK_LCONTROL:
125 case VK_RCONTROL:
126 down = (MessageQueue->KeyState[VK_LCONTROL] | MessageQueue->KeyState[VK_RCONTROL]) & KS_DOWN_BIT;
127 set_input_key_state( MessageQueue, VK_CONTROL, down );
128 break;
129 case VK_LMENU:
130 case VK_RMENU:
131 down = (MessageQueue->KeyState[VK_LMENU] | MessageQueue->KeyState[VK_RMENU]) & KS_DOWN_BIT;
132 set_input_key_state( MessageQueue, VK_MENU, down );
133 break;
134 case VK_LSHIFT:
135 case VK_RSHIFT:
136 down = (MessageQueue->KeyState[VK_LSHIFT] | MessageQueue->KeyState[VK_RSHIFT]) & KS_DOWN_BIT;
137 set_input_key_state( MessageQueue, VK_SHIFT, down );
138 break;
139 }
140 break;
141 }
142 }
143
144 HANDLE FASTCALL
145 IntMsqSetWakeMask(DWORD WakeMask)
146 {
147 PTHREADINFO Win32Thread;
148 PUSER_MESSAGE_QUEUE MessageQueue;
149 HANDLE MessageEventHandle;
150 DWORD dwFlags = HIWORD(WakeMask);
151
152 Win32Thread = PsGetCurrentThreadWin32Thread();
153 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
154 return 0;
155
156 MessageQueue = Win32Thread->MessageQueue;
157 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
158 MessageEventHandle = MessageQueue->NewMessagesHandle;
159
160 if (Win32Thread->pcti)
161 {
162 if ( (Win32Thread->pcti->fsChangeBits & LOWORD(WakeMask)) ||
163 ( (dwFlags & MWMO_INPUTAVAILABLE) && (Win32Thread->pcti->fsWakeBits & LOWORD(WakeMask)) ) )
164 {
165 DPRINT1("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread->pcti->fsChangeBits, Win32Thread->pcti->fsWakeBits, WakeMask);
166 KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE); // Wake it up!
167 return MessageEventHandle;
168 }
169 }
170
171 IdlePing();
172
173 return MessageEventHandle;
174 }
175
176 BOOL FASTCALL
177 IntMsqClearWakeMask(VOID)
178 {
179 PTHREADINFO Win32Thread;
180
181 Win32Thread = PsGetCurrentThreadWin32Thread();
182 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
183 return FALSE;
184 // Very hacky, but that is what they do.
185 Win32Thread->pcti->fsWakeBits = 0;
186
187 IdlePong();
188
189 return TRUE;
190 }
191
192 /*
193 Due to the uncertainty of knowing what was set in our multilevel message queue,
194 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
195 I think this is the best solution... (jt) */
196 VOID FASTCALL
197 MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue, DWORD MessageBits, BOOL KeyEvent)
198 {
199 PTHREADINFO pti;
200
201 pti = Queue->Thread->Tcb.Win32Thread;
202 pti->pcti->fsWakeBits |= MessageBits;
203 pti->pcti->fsChangeBits |= MessageBits;
204
205 // Start bit accounting to help clear the main set of bits.
206 if (MessageBits & QS_KEY) Queue->nCntsQBits[QSRosKey]++;
207 if (MessageBits & QS_MOUSEMOVE) Queue->nCntsQBits[QSRosMouseMove]++;
208 if (MessageBits & QS_MOUSEBUTTON) Queue->nCntsQBits[QSRosMouseButton]++;
209 if (MessageBits & QS_POSTMESSAGE) Queue->nCntsQBits[QSRosPostMessage]++;
210 if (MessageBits & QS_SENDMESSAGE) Queue->nCntsQBits[QSRosSendMessage]++;
211 if (MessageBits & QS_HOTKEY) Queue->nCntsQBits[QSRosHotKey]++;
212
213 if (KeyEvent)
214 KeSetEvent(Queue->NewMessages, IO_NO_INCREMENT, FALSE);
215 }
216
217 VOID FASTCALL
218 ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue, UINT MessageBits)
219 {
220 PTHREADINFO pti;
221 UINT ClrMask = 0;
222
223 pti = Queue->Thread->Tcb.Win32Thread;
224
225 if (MessageBits & QS_KEY)
226 {
227 if (--Queue->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY;
228 }
229 if (MessageBits & QS_MOUSEMOVE) // ReactOS hard coded.
230 { // Account for tracking mouse moves..
231 if (--Queue->nCntsQBits[QSRosMouseMove] == 0) ClrMask |= QS_MOUSEMOVE;
232 // Handle mouse move bits here.
233 if (Queue->MouseMoved) ClrMask |= QS_MOUSEMOVE;
234 }
235 if (MessageBits & QS_MOUSEBUTTON)
236 {
237 if (--Queue->nCntsQBits[QSRosMouseButton] == 0) ClrMask |= QS_MOUSEBUTTON;
238 }
239 if (MessageBits & QS_POSTMESSAGE)
240 {
241 if (--Queue->nCntsQBits[QSRosPostMessage] == 0) ClrMask |= QS_POSTMESSAGE;
242 }
243 if (MessageBits & QS_TIMER) // ReactOS hard coded.
244 { // Handle timer bits here.
245 if ( pti->cTimersReady )
246 {
247 if (--pti->cTimersReady == 0) ClrMask |= QS_TIMER;
248 }
249 }
250 if (MessageBits & QS_PAINT) // ReactOS hard coded.
251 { // Handle paint bits here.
252 if ( pti->cPaintsReady )
253 {
254 if (--pti->cPaintsReady == 0) ClrMask |= QS_PAINT;
255 }
256 }
257 if (MessageBits & QS_SENDMESSAGE)
258 {
259 if (--Queue->nCntsQBits[QSRosSendMessage] == 0) ClrMask |= QS_SENDMESSAGE;
260 }
261 if (MessageBits & QS_HOTKEY)
262 {
263 if (--Queue->nCntsQBits[QSRosHotKey] == 0) ClrMask |= QS_HOTKEY;
264 }
265
266 pti->pcti->fsWakeBits &= ~ClrMask;
267 pti->pcti->fsChangeBits &= ~ClrMask;
268 }
269
270 VOID FASTCALL
271 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
272 {
273 PTHREADINFO pti;
274 pti = Queue->Thread->Tcb.Win32Thread;
275 pti->cPaintsReady++;
276 MsqWakeQueue(Queue, QS_PAINT, TRUE);
277 }
278
279 VOID FASTCALL
280 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
281 {
282 ClearMsgBitsMask(Queue, QS_PAINT);
283 }
284
285 VOID FASTCALL
286 MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg)
287 {
288 MessageQueue->MouseMoveMsg = *Msg;
289 MessageQueue->MouseMoved = TRUE;
290 MsqWakeQueue(MessageQueue, QS_MOUSEMOVE, TRUE);
291 }
292
293 VOID FASTCALL
294 co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
295 {
296 LARGE_INTEGER LargeTickCount;
297 MSLLHOOKSTRUCT MouseHookData;
298 PDESKTOP pDesk;
299 PWND pwnd, pwndDesktop;
300
301 KeQueryTickCount(&LargeTickCount);
302 Msg->time = MsqCalculateMessageTime(&LargeTickCount);
303
304 MouseHookData.pt.x = LOWORD(Msg->lParam);
305 MouseHookData.pt.y = HIWORD(Msg->lParam);
306 switch(Msg->message)
307 {
308 case WM_MOUSEWHEEL:
309 MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg->wParam));
310 break;
311 case WM_XBUTTONDOWN:
312 case WM_XBUTTONUP:
313 case WM_XBUTTONDBLCLK:
314 case WM_NCXBUTTONDOWN:
315 case WM_NCXBUTTONUP:
316 case WM_NCXBUTTONDBLCLK:
317 MouseHookData.mouseData = MAKELONG(0, HIWORD(Msg->wParam));
318 break;
319 default:
320 MouseHookData.mouseData = 0;
321 break;
322 }
323
324 MouseHookData.flags = flags; // LLMHF_INJECTED
325 MouseHookData.time = Msg->time;
326 MouseHookData.dwExtraInfo = dwExtraInfo;
327
328 /* If the hook procedure returned non zero, dont send the message */
329 if (Hook)
330 {
331 if (co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION, Msg->message, (LPARAM) &MouseHookData))
332 return;
333 }
334
335 /* Get the desktop window */
336 pwndDesktop = UserGetDesktopWindow();
337 if(!pwndDesktop)
338 return;
339
340 /* Set hit somewhere on the desktop */
341 pDesk = pwndDesktop->head.rpdesk;
342 pDesk->htEx = HTNOWHERE;
343 pDesk->spwndTrack = pwndDesktop;
344
345 /* Check if the mouse is captured */
346 Msg->hwnd = IntGetCaptureWindow();
347 if(Msg->hwnd != NULL)
348 {
349 pwnd = UserGetWindowObject(Msg->hwnd);
350 if ((pwnd->style & WS_VISIBLE) &&
351 IntPtInWindow(pwnd, Msg->pt.x, Msg->pt.y))
352 {
353 pDesk->htEx = HTCLIENT;
354 pDesk->spwndTrack = pwnd;
355 }
356 }
357 else
358 {
359 /* Loop all top level windows to find which one should receive input */
360 for( pwnd = pwndDesktop->spwndChild;
361 pwnd != NULL;
362 pwnd = pwnd->spwndNext )
363 {
364 if ( pwnd->state2 & WNDS2_INDESTROY || pwnd->state & WNDS_DESTROYED )
365 {
366 DPRINT("The Window is in DESTROY!\n");
367 continue;
368 }
369
370 if((pwnd->style & WS_VISIBLE) &&
371 IntPtInWindow(pwnd, Msg->pt.x, Msg->pt.y))
372 {
373 Msg->hwnd = pwnd->head.h;
374 pDesk->htEx = HTCLIENT;
375 pDesk->spwndTrack = pwnd;
376 break;
377 }
378 }
379 }
380
381 /* Check if we found a window */
382 if(Msg->hwnd != NULL && pwnd != NULL)
383 {
384 if(Msg->message == WM_MOUSEMOVE)
385 {
386 /* Mouse move is a special case*/
387 MsqPostMouseMove(pwnd->head.pti->MessageQueue, Msg);
388 }
389 else
390 {
391 DPRINT("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd));
392 MsqPostMessage(pwnd->head.pti->MessageQueue, Msg, TRUE, QS_MOUSEBUTTON);
393 }
394 }
395
396 /* Do GetMouseMovePointsEx FIFO. */
397 MouseHistoryOfMoves[gcur_count].x = Msg->pt.x;
398 MouseHistoryOfMoves[gcur_count].y = Msg->pt.y;
399 MouseHistoryOfMoves[gcur_count].time = Msg->time;
400 MouseHistoryOfMoves[gcur_count].dwExtraInfo = dwExtraInfo;
401 if (gcur_count++ == 64) gcur_count = 0; // 0 - 63 is 64, FIFO forwards.
402 }
403
404 //
405 // Note: Only called from input.c.
406 //
407 VOID FASTCALL
408 co_MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
409 {
410 PUSER_MESSAGE_QUEUE FocusMessageQueue;
411 MSG Msg;
412 LARGE_INTEGER LargeTickCount;
413 KBDLLHOOKSTRUCT KbdHookData;
414
415 DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
416 uMsg, wParam, lParam);
417
418 // Condition may arise when calling MsqPostMessage and waiting for an event.
419 ASSERT(UserIsEntered());
420
421 FocusMessageQueue = IntGetFocusMessageQueue();
422
423 Msg.hwnd = 0;
424
425 if (FocusMessageQueue && (FocusMessageQueue->FocusWindow != (HWND)0))
426 Msg.hwnd = FocusMessageQueue->FocusWindow;
427
428 Msg.message = uMsg;
429 Msg.wParam = wParam;
430 Msg.lParam = lParam;
431
432 KeQueryTickCount(&LargeTickCount);
433 Msg.time = MsqCalculateMessageTime(&LargeTickCount);
434
435 /* We can't get the Msg.pt point here since we don't know thread
436 (and thus the window station) the message will end up in yet. */
437
438 KbdHookData.vkCode = Msg.wParam;
439 KbdHookData.scanCode = (Msg.lParam >> 16) & 0xff;
440 KbdHookData.flags = (0 == (Msg.lParam & 0x01000000) ? 0 : LLKHF_EXTENDED) |
441 (0 == (Msg.lParam & 0x20000000) ? 0 : LLKHF_ALTDOWN) |
442 (0 == (Msg.lParam & 0x80000000) ? 0 : LLKHF_UP);
443 KbdHookData.time = Msg.time;
444 KbdHookData.dwExtraInfo = 0;
445 if (co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData))
446 {
447 DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
448 Msg.message, Msg.wParam, Msg.lParam);
449 return;
450 }
451
452 if (FocusMessageQueue == NULL)
453 {
454 DPRINT("No focus message queue\n");
455 return;
456 }
457
458 if (FocusMessageQueue->FocusWindow != (HWND)0)
459 {
460 Msg.hwnd = FocusMessageQueue->FocusWindow;
461 DPRINT("Msg.hwnd = %x\n", Msg.hwnd);
462
463 FocusMessageQueue->Desktop->pDeskInfo->LastInputWasKbd = TRUE;
464
465 Msg.pt = gpsi->ptCursor;
466 MsqPostMessage(FocusMessageQueue, &Msg, TRUE, QS_KEY);
467 }
468 else
469 {
470 DPRINT("Invalid focus window handle\n");
471 }
472
473 return;
474 }
475
476 VOID FASTCALL
477 MsqPostHotKeyMessage(PVOID Thread, HWND hWnd, WPARAM wParam, LPARAM lParam)
478 {
479 PWND Window;
480 PTHREADINFO Win32Thread;
481 MSG Mesg;
482 LARGE_INTEGER LargeTickCount;
483 NTSTATUS Status;
484
485 Status = ObReferenceObjectByPointer (Thread,
486 THREAD_ALL_ACCESS,
487 PsThreadType,
488 KernelMode);
489 if (!NT_SUCCESS(Status))
490 return;
491
492 Win32Thread = ((PETHREAD)Thread)->Tcb.Win32Thread;
493 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
494 {
495 ObDereferenceObject ((PETHREAD)Thread);
496 return;
497 }
498
499 Window = IntGetWindowObject(hWnd);
500 if (!Window)
501 {
502 ObDereferenceObject ((PETHREAD)Thread);
503 return;
504 }
505
506 Mesg.hwnd = hWnd;
507 Mesg.message = WM_HOTKEY;
508 Mesg.wParam = wParam;
509 Mesg.lParam = lParam;
510 KeQueryTickCount(&LargeTickCount);
511 Mesg.time = MsqCalculateMessageTime(&LargeTickCount);
512 Mesg.pt = gpsi->ptCursor;
513 MsqPostMessage(Window->head.pti->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
514 UserDereferenceObject(Window);
515 ObDereferenceObject (Thread);
516
517 }
518
519 PUSER_MESSAGE FASTCALL
520 MsqCreateMessage(LPMSG Msg)
521 {
522 PUSER_MESSAGE Message;
523
524 Message = ExAllocateFromPagedLookasideList(&MessageLookasideList);
525 if (!Message)
526 {
527 return NULL;
528 }
529
530 RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
531
532 return Message;
533 }
534
535 VOID FASTCALL
536 MsqDestroyMessage(PUSER_MESSAGE Message)
537 {
538 ExFreeToPagedLookasideList(&MessageLookasideList, Message);
539 }
540
541 BOOLEAN FASTCALL
542 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
543 {
544 PUSER_SENT_MESSAGE SaveMsg, Message;
545 PLIST_ENTRY Entry;
546 LRESULT Result;
547 PTHREADINFO pti;
548
549 if (IsListEmpty(&MessageQueue->SentMessagesListHead))
550 {
551 return(FALSE);
552 }
553
554 /* remove it from the list of pending messages */
555 Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
556 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
557
558 pti = MessageQueue->Thread->Tcb.Win32Thread;
559
560 SaveMsg = pti->pusmCurrent;
561 pti->pusmCurrent = Message;
562
563 // Processing a message sent to it from another thread.
564 if ( ( Message->SenderQueue && MessageQueue != Message->SenderQueue) ||
565 ( Message->CallBackSenderQueue && MessageQueue != Message->CallBackSenderQueue ))
566 { // most likely, but, to be sure.
567 pti->pcti->CTI_flags |= CTI_INSENDMESSAGE; // Let the user know...
568 }
569
570 /* insert it to the list of messages that are currently dispatched by this
571 message queue */
572 InsertTailList(&MessageQueue->LocalDispatchingMessagesHead,
573 &Message->ListEntry);
574
575 ClearMsgBitsMask(MessageQueue, Message->QS_Flags);
576
577 if (Message->HookMessage == MSQ_ISHOOK)
578 { // Direct Hook Call processor
579 Result = co_CallHook( Message->Msg.message, // HookId
580 (INT)(INT_PTR)Message->Msg.hwnd, // Code
581 Message->Msg.wParam,
582 Message->Msg.lParam);
583 }
584 else if (Message->HookMessage == MSQ_ISEVENT)
585 { // Direct Event Call processor
586 Result = co_EVENT_CallEvents( Message->Msg.message,
587 Message->Msg.hwnd,
588 Message->Msg.wParam,
589 Message->Msg.lParam);
590 }
591 else if ((Message->CompletionCallback)
592 && (Message->CallBackSenderQueue == MessageQueue))
593 { /* Call the callback routine */
594 if (Message->QS_Flags & QS_SMRESULT)
595 {
596 co_IntCallSentMessageCallback(Message->CompletionCallback,
597 Message->Msg.hwnd,
598 Message->Msg.message,
599 Message->CompletionCallbackContext,
600 Message->lResult);
601 /* Set callback to NULL to prevent reentry */
602 Message->CompletionCallback = NULL;
603 }
604 else
605 {
606 /* The message has not been processed yet, reinsert it. */
607 RemoveEntryList(&Message->ListEntry);
608 InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead, &Message->ListEntry);
609 DPRINT("Callback Message not processed yet. Requeuing the message\n");
610 return (FALSE);
611 }
612 }
613 else
614 { /* Call the window procedure. */
615 Result = co_IntSendMessage( Message->Msg.hwnd,
616 Message->Msg.message,
617 Message->Msg.wParam,
618 Message->Msg.lParam);
619 }
620
621 /* remove the message from the local dispatching list, because it doesn't need
622 to be cleaned up on thread termination anymore */
623 RemoveEntryList(&Message->ListEntry);
624
625 /* If the message is a callback, insert it in the callback senders MessageQueue */
626 if (Message->CompletionCallback)
627 {
628 if (Message->CallBackSenderQueue)
629 {
630 Message->lResult = Result;
631 Message->QS_Flags |= QS_SMRESULT;
632
633 /* insert it in the callers message queue */
634 InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead, &Message->ListEntry);
635 MsqWakeQueue(Message->CallBackSenderQueue, QS_SENDMESSAGE, TRUE);
636 IntDereferenceMessageQueue(Message->CallBackSenderQueue);
637 }
638 return (TRUE);
639 }
640
641 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
642 if (Message->SenderQueue)
643 {
644 if (Message->DispatchingListEntry.Flink != NULL)
645 {
646 /* only remove it from the dispatching list if not already removed by a timeout */
647 RemoveEntryList(&Message->DispatchingListEntry);
648 }
649 }
650 /* still keep the sender's message queue locked, so the sender can't exit the
651 MsqSendMessage() function (if timed out) */
652
653 if (Message->QS_Flags & QS_SMRESULT)
654 {
655 Result = Message->lResult;
656 }
657
658 /* Let the sender know the result. */
659 if (Message->Result != NULL)
660 {
661 *Message->Result = Result;
662 }
663
664 if (Message->HasPackedLParam == TRUE)
665 {
666 if (Message->Msg.lParam)
667 ExFreePool((PVOID)Message->Msg.lParam);
668 }
669
670 /* Notify the sender. */
671 if (Message->CompletionEvent != NULL)
672 {
673 KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
674 }
675
676 /* if the message has a sender */
677 if (Message->SenderQueue)
678 {
679 /* dereference our and the sender's message queue */
680 IntDereferenceMessageQueue(Message->SenderQueue);
681 IntDereferenceMessageQueue(MessageQueue);
682 }
683
684 /* free the message */
685 ExFreePoolWithTag(Message, TAG_USRMSG);
686
687 /* do not hangup on the user if this is reentering */
688 if (!SaveMsg) pti->pcti->CTI_flags &= ~CTI_INSENDMESSAGE;
689 pti->pusmCurrent = SaveMsg;
690
691 return(TRUE);
692 }
693
694 VOID APIENTRY
695 MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
696 {
697 PUSER_SENT_MESSAGE SentMessage;
698 PUSER_MESSAGE PostedMessage;
699 PUSER_MESSAGE_QUEUE MessageQueue;
700 PLIST_ENTRY CurrentEntry, ListHead;
701 PWND Window = pWindow;
702
703 ASSERT(Window);
704
705 MessageQueue = Window->head.pti->MessageQueue;
706 ASSERT(MessageQueue);
707
708 /* remove the posted messages for this window */
709 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
710 ListHead = &MessageQueue->PostedMessagesListHead;
711 while (CurrentEntry != ListHead)
712 {
713 PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
714 ListEntry);
715 if (PostedMessage->Msg.hwnd == Window->head.h)
716 {
717 RemoveEntryList(&PostedMessage->ListEntry);
718 ClearMsgBitsMask(MessageQueue, PostedMessage->QS_Flags);
719 MsqDestroyMessage(PostedMessage);
720 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
721 }
722 else
723 {
724 CurrentEntry = CurrentEntry->Flink;
725 }
726 }
727
728 /* remove the sent messages for this window */
729 CurrentEntry = MessageQueue->SentMessagesListHead.Flink;
730 ListHead = &MessageQueue->SentMessagesListHead;
731 while (CurrentEntry != ListHead)
732 {
733 SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
734 ListEntry);
735 if(SentMessage->Msg.hwnd == Window->head.h)
736 {
737 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
738
739 RemoveEntryList(&SentMessage->ListEntry);
740 ClearMsgBitsMask(MessageQueue, SentMessage->QS_Flags);
741
742 /* if it is a callback and this queue is not the sender queue, dereference queue */
743 if ((SentMessage->CompletionCallback) && (SentMessage->CallBackSenderQueue != MessageQueue))
744 {
745 IntDereferenceMessageQueue(SentMessage->CallBackSenderQueue);
746 }
747 /* Only if the message has a sender was the queue referenced */
748 if ((SentMessage->SenderQueue)
749 && (SentMessage->DispatchingListEntry.Flink != NULL))
750 {
751 RemoveEntryList(&SentMessage->DispatchingListEntry);
752 }
753
754 /* wake the sender's thread */
755 if (SentMessage->CompletionEvent != NULL)
756 {
757 KeSetEvent(SentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
758 }
759
760 if (SentMessage->HasPackedLParam == TRUE)
761 {
762 if (SentMessage->Msg.lParam)
763 ExFreePool((PVOID)SentMessage->Msg.lParam);
764 }
765
766 /* if the message has a sender */
767 if (SentMessage->SenderQueue)
768 {
769 /* dereference our and the sender's message queue */
770 IntDereferenceMessageQueue(MessageQueue);
771 IntDereferenceMessageQueue(SentMessage->SenderQueue);
772 }
773
774 /* free the message */
775 ExFreePoolWithTag(SentMessage, TAG_USRMSG);
776
777 CurrentEntry = MessageQueue->SentMessagesListHead.Flink;
778 }
779 else
780 {
781 CurrentEntry = CurrentEntry->Flink;
782 }
783 }
784 }
785
786 NTSTATUS FASTCALL
787 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
788 HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
789 UINT uTimeout, BOOL Block, INT HookMessage,
790 ULONG_PTR *uResult)
791 {
792 PTHREADINFO pti, ptirec;
793 PUSER_SENT_MESSAGE Message;
794 KEVENT CompletionEvent;
795 NTSTATUS WaitStatus;
796 PUSER_MESSAGE_QUEUE ThreadQueue;
797 LARGE_INTEGER Timeout;
798 PLIST_ENTRY Entry;
799 LRESULT Result = 0; //// Result could be trashed. ////
800
801 if(!(Message = ExAllocatePoolWithTag(PagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
802 {
803 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
804 return STATUS_INSUFFICIENT_RESOURCES;
805 }
806
807 KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE);
808
809 pti = PsGetCurrentThreadWin32Thread();
810 ThreadQueue = pti->MessageQueue;
811 ptirec = MessageQueue->Thread->Tcb.Win32Thread;
812 ASSERT(ThreadQueue != MessageQueue);
813 ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!!
814
815 Timeout.QuadPart = (LONGLONG) uTimeout * (LONGLONG) -10000;
816
817 /* FIXME - increase reference counter of sender's message queue here */
818
819 Message->Msg.hwnd = Wnd;
820 Message->Msg.message = Msg;
821 Message->Msg.wParam = wParam;
822 Message->Msg.lParam = lParam;
823 Message->CompletionEvent = &CompletionEvent;
824 Message->Result = &Result;
825 Message->lResult = 0;
826 Message->QS_Flags = 0;
827 Message->SenderQueue = ThreadQueue;
828 Message->CallBackSenderQueue = NULL;
829 IntReferenceMessageQueue(ThreadQueue);
830 Message->CompletionCallback = NULL;
831 Message->CompletionCallbackContext = 0;
832 Message->HookMessage = HookMessage;
833 Message->HasPackedLParam = FALSE;
834
835 IntReferenceMessageQueue(MessageQueue);
836
837 /* add it to the list of pending messages */
838 InsertTailList(&ThreadQueue->DispatchingMessagesHead, &Message->DispatchingListEntry);
839
840 /* queue it in the destination's message queue */
841 InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry);
842
843 Message->QS_Flags = QS_SENDMESSAGE;
844 MsqWakeQueue(MessageQueue, QS_SENDMESSAGE, TRUE);
845
846 /* we can't access the Message anymore since it could have already been deleted! */
847
848 if(Block)
849 {
850 UserLeaveCo();
851
852 /* don't process messages sent to the thread */
853 WaitStatus = KeWaitForSingleObject(&CompletionEvent, UserRequest, UserMode,
854 FALSE, (uTimeout ? &Timeout : NULL));
855
856 UserEnterCo();
857
858 if(WaitStatus == STATUS_TIMEOUT)
859 {
860 /* look up if the message has not yet dispatched, if so
861 make sure it can't pass a result and it must not set the completion event anymore */
862 Entry = MessageQueue->SentMessagesListHead.Flink;
863 while (Entry != &MessageQueue->SentMessagesListHead)
864 {
865 if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
866 == Message)
867 {
868 /* we can access Message here, it's secure because the message queue is locked
869 and the message is still hasn't been dispatched */
870 Message->CompletionEvent = NULL;
871 Message->Result = NULL;
872 break;
873 }
874 Entry = Entry->Flink;
875 }
876
877 /* remove from the local dispatching list so the other thread knows,
878 it can't pass a result and it must not set the completion event anymore */
879 Entry = ThreadQueue->DispatchingMessagesHead.Flink;
880 while (Entry != &ThreadQueue->DispatchingMessagesHead)
881 {
882 if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
883 == Message)
884 {
885 /* we can access Message here, it's secure because the sender's message is locked
886 and the message has definitely not yet been destroyed, otherwise it would
887 have been removed from this list by the dispatching routine right after
888 dispatching the message */
889 Message->CompletionEvent = NULL;
890 Message->Result = NULL;
891 RemoveEntryList(&Message->DispatchingListEntry);
892 Message->DispatchingListEntry.Flink = NULL;
893 break;
894 }
895 Entry = Entry->Flink;
896 }
897
898 DPRINT("MsqSendMessage (blocked) timed out 1\n");
899 }
900 while (co_MsqDispatchOneSentMessage(ThreadQueue))
901 ;
902 }
903 else
904 {
905 PVOID WaitObjects[2];
906
907 WaitObjects[0] = &CompletionEvent;
908 WaitObjects[1] = ThreadQueue->NewMessages;
909 do
910 {
911 UserLeaveCo();
912
913 WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
914 UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL);
915
916 UserEnterCo();
917
918 if(WaitStatus == STATUS_TIMEOUT)
919 {
920 /* look up if the message has not yet been dispatched, if so
921 make sure it can't pass a result and it must not set the completion event anymore */
922 Entry = MessageQueue->SentMessagesListHead.Flink;
923 while (Entry != &MessageQueue->SentMessagesListHead)
924 {
925 if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
926 == Message)
927 {
928 /* we can access Message here, it's secure because the message queue is locked
929 and the message is still hasn't been dispatched */
930 Message->CompletionEvent = NULL;
931 Message->Result = NULL;
932 break;
933 }
934 Entry = Entry->Flink;
935 }
936
937 /* remove from the local dispatching list so the other thread knows,
938 it can't pass a result and it must not set the completion event anymore */
939 Entry = ThreadQueue->DispatchingMessagesHead.Flink;
940 while (Entry != &ThreadQueue->DispatchingMessagesHead)
941 {
942 if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
943 == Message)
944 {
945 /* we can access Message here, it's secure because the sender's message is locked
946 and the message has definitely not yet been destroyed, otherwise it would
947 have been removed from this list by the dispatching routine right after
948 dispatching the message */
949 Message->CompletionEvent = NULL;
950 Message->Result = NULL;
951 RemoveEntryList(&Message->DispatchingListEntry);
952 Message->DispatchingListEntry.Flink = NULL;
953 break;
954 }
955 Entry = Entry->Flink;
956 }
957
958 DPRINT("MsqSendMessage timed out 2\n");
959 break;
960 }
961 while (co_MsqDispatchOneSentMessage(ThreadQueue))
962 ;
963 }
964 while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
965 }
966
967 if(WaitStatus != STATUS_TIMEOUT)
968 *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1);
969
970 return WaitStatus;
971 }
972
973 VOID FASTCALL
974 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg, BOOLEAN HardwareMessage,
975 DWORD MessageBits)
976 {
977 PUSER_MESSAGE Message;
978
979 if(!(Message = MsqCreateMessage(Msg)))
980 {
981 return;
982 }
983
984 if(!HardwareMessage)
985 {
986 InsertTailList(&MessageQueue->PostedMessagesListHead,
987 &Message->ListEntry);
988 }
989 else
990 {
991 InsertTailList(&MessageQueue->HardwareMessagesListHead,
992 &Message->ListEntry);
993 }
994
995 Message->QS_Flags = MessageBits;
996 MsqWakeQueue(MessageQueue, MessageBits, (MessageBits & QS_TIMER ? FALSE : TRUE));
997 }
998
999 VOID FASTCALL
1000 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode)
1001 {
1002 MessageQueue->QuitPosted = TRUE;
1003 MessageQueue->QuitExitCode = ExitCode;
1004 MsqWakeQueue(MessageQueue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE);
1005 }
1006
1007 /***********************************************************************
1008 * MsqSendParentNotify
1009 *
1010 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1011 * the window has the WS_EX_NOPARENTNOTIFY style.
1012 */
1013 static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt )
1014 {
1015 PWND pwndDesktop = UserGetWindowObject(IntGetDesktopWindow());
1016
1017 /* pt has to be in the client coordinates of the parent window */
1018 pt.x += pwndDesktop->rcClient.left - pwnd->rcClient.left;
1019 pt.y += pwndDesktop->rcClient.top - pwnd->rcClient.top;
1020
1021 for (;;)
1022 {
1023 PWND pwndParent;
1024
1025 if (!(pwnd->style & WS_CHILD)) break;
1026 if (pwnd->ExStyle & WS_EX_NOPARENTNOTIFY) break;
1027 if (!(pwndParent = IntGetParent(pwnd))) break;
1028 if (pwndParent == pwndDesktop) break;
1029 pt.x += pwnd->rcClient.left - pwndParent->rcClient.left;
1030 pt.y += pwnd->rcClient.top - pwndParent->rcClient.top;
1031
1032 pwnd = pwndParent;
1033 co_IntSendMessage( UserHMGetHandle(pwnd), WM_PARENTNOTIFY,
1034 MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) );
1035 }
1036 }
1037
1038 BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT last)
1039 {
1040 MSG clk_msg;
1041 POINT pt;
1042 UINT message;
1043 USHORT hittest;
1044 EVENTMSG event;
1045 MOUSEHOOKSTRUCT hook;
1046 BOOL eatMsg;
1047
1048 PWND pwndMsg, pwndDesktop;
1049 PUSER_MESSAGE_QUEUE MessageQueue;
1050 PTHREADINFO pti;
1051 PSYSTEM_CURSORINFO CurInfo;
1052 DECLARE_RETURN(BOOL);
1053
1054 pti = PsGetCurrentThreadWin32Thread();
1055 pwndDesktop = UserGetDesktopWindow();
1056 MessageQueue = pti->MessageQueue;
1057 CurInfo = IntGetSysCursorInfo();
1058 pwndMsg = UserGetWindowObject(msg->hwnd);
1059 clk_msg = MessageQueue->msgDblClk;
1060
1061 /* find the window to dispatch this mouse message to */
1062 if (MessageQueue->CaptureWindow)
1063 {
1064 hittest = HTCLIENT;
1065 pwndMsg = IntGetWindowObject(MessageQueue->CaptureWindow);
1066 }
1067 else
1068 {
1069 pwndMsg = co_WinPosWindowFromPoint(pwndMsg, &msg->pt, &hittest);
1070 }
1071
1072 DPRINT("Got mouse message for 0x%x, hittest: 0x%x\n", msg->hwnd, hittest );
1073
1074 if (pwndMsg == NULL || pwndMsg->head.pti != pti)
1075 {
1076 /* Remove and ignore the message */
1077 *RemoveMessages = TRUE;
1078 RETURN(FALSE);
1079 }
1080
1081 msg->hwnd = UserHMGetHandle(pwndMsg);
1082
1083 #if 0
1084 if (!check_hwnd_filter( msg, hwnd_filter )) RETURN(FALSE);
1085 #endif
1086
1087 pt = msg->pt;
1088 message = msg->message;
1089 /* Note: windows has no concept of a non-client wheel message */
1090 if (message != WM_MOUSEWHEEL)
1091 {
1092 if (hittest != HTCLIENT)
1093 {
1094 message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
1095 msg->wParam = hittest;
1096 }
1097 else
1098 {
1099 /* coordinates don't get translated while tracking a menu */
1100 /* FIXME: should differentiate popups and top-level menus */
1101 if (!(MessageQueue->MenuOwner))
1102 {
1103 pt.x += pwndDesktop->rcClient.left - pwndMsg->rcClient.left;
1104 pt.y += pwndDesktop->rcClient.top - pwndMsg->rcClient.top;
1105 }
1106 }
1107 }
1108 msg->lParam = MAKELONG( pt.x, pt.y );
1109
1110 /* translate double clicks */
1111
1112 if ((msg->message == WM_LBUTTONDOWN) ||
1113 (msg->message == WM_RBUTTONDOWN) ||
1114 (msg->message == WM_MBUTTONDOWN) ||
1115 (msg->message == WM_XBUTTONDOWN))
1116 {
1117 BOOL update = *RemoveMessages;
1118
1119 /* translate double clicks -
1120 * note that ...MOUSEMOVEs can slip in between
1121 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1122
1123 if ((MessageQueue->MenuOwner || MessageQueue->MoveSize) ||
1124 hittest != HTCLIENT ||
1125 (pwndMsg->pcls->style & CS_DBLCLKS))
1126 {
1127 if ((msg->message == clk_msg.message) &&
1128 (msg->hwnd == clk_msg.hwnd) &&
1129 (msg->wParam == clk_msg.wParam) &&
1130 (msg->time - clk_msg.time < gspv.iDblClickTime) &&
1131 (abs(msg->pt.x - clk_msg.pt.x) < UserGetSystemMetrics(SM_CXDOUBLECLK)/2) &&
1132 (abs(msg->pt.y - clk_msg.pt.y) < UserGetSystemMetrics(SM_CYDOUBLECLK)/2))
1133 {
1134 message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
1135 if (update)
1136 {
1137 MessageQueue->msgDblClk.message = 0; /* clear the double click conditions */
1138 update = FALSE;
1139 }
1140 }
1141 }
1142
1143 if (!((first == 0 && last == 0) || (message >= first || message <= last)))
1144 {
1145 DPRINT("Message out of range!!!\n");
1146 RETURN(FALSE);
1147 }
1148
1149 /* update static double click conditions */
1150 if (update) MessageQueue->msgDblClk = *msg;
1151 }
1152 else
1153 {
1154 if (!((first == 0 && last == 0) || (message >= first || message <= last)))
1155 {
1156 DPRINT("Message out of range!!!\n");
1157 RETURN(FALSE);
1158 }
1159 }
1160
1161 if(gspv.bMouseClickLock)
1162 {
1163 BOOL IsClkLck = FALSE;
1164
1165 if(msg->message == WM_LBUTTONUP)
1166 {
1167 IsClkLck = ((msg->time - CurInfo->ClickLockTime) >= gspv.dwMouseClickLockTime);
1168 if (IsClkLck && (!CurInfo->ClickLockActive))
1169 {
1170 CurInfo->ClickLockActive = TRUE;
1171 }
1172 }
1173 else if (msg->message == WM_LBUTTONDOWN)
1174 {
1175 if (CurInfo->ClickLockActive)
1176 {
1177 IsClkLck = TRUE;
1178 CurInfo->ClickLockActive = FALSE;
1179 }
1180
1181 CurInfo->ClickLockTime = msg->time;
1182 }
1183
1184 if(IsClkLck)
1185 {
1186 /* Remove and ignore the message */
1187 *RemoveMessages = TRUE;
1188 RETURN(FALSE);
1189 }
1190 }
1191
1192 /* message is accepted now (but may still get dropped) */
1193
1194 event.message = msg->message;
1195 event.time = msg->time;
1196 event.hwnd = msg->hwnd;
1197 event.paramL = msg->pt.x;
1198 event.paramH = msg->pt.y;
1199 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
1200
1201 hook.pt = msg->pt;
1202 hook.hwnd = msg->hwnd;
1203 hook.wHitTestCode = hittest;
1204 hook.dwExtraInfo = 0/*extra_info*/;
1205 if (co_HOOK_CallHooks( WH_MOUSE, *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
1206 message, (LPARAM)&hook ))
1207 {
1208 hook.pt = msg->pt;
1209 hook.hwnd = msg->hwnd;
1210 hook.wHitTestCode = hittest;
1211 hook.dwExtraInfo = 0/*extra_info*/;
1212 co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook );
1213
1214 DPRINT1("WH_MOUSE dorpped mouse message!\n");
1215
1216 /* Remove and skip message */
1217 *RemoveMessages = TRUE;
1218 RETURN(FALSE);
1219 }
1220
1221 if ((hittest == HTERROR) || (hittest == HTNOWHERE))
1222 {
1223 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
1224 MAKELONG( hittest, msg->message ));
1225
1226 /* Remove and skip message */
1227 *RemoveMessages = TRUE;
1228 RETURN(FALSE);
1229 }
1230
1231 if ((*RemoveMessages == FALSE) || MessageQueue->CaptureWindow)
1232 {
1233 /* Accept the message */
1234 msg->message = message;
1235 RETURN(TRUE);
1236 }
1237
1238 eatMsg = FALSE;
1239
1240 if ((msg->message == WM_LBUTTONDOWN) ||
1241 (msg->message == WM_RBUTTONDOWN) ||
1242 (msg->message == WM_MBUTTONDOWN) ||
1243 (msg->message == WM_XBUTTONDOWN))
1244 {
1245 /* Send the WM_PARENTNOTIFY,
1246 * note that even for double/nonclient clicks
1247 * notification message is still WM_L/M/RBUTTONDOWN.
1248 */
1249 MsqSendParentNotify(pwndMsg, msg->message, 0, msg->pt );
1250
1251 /* Activate the window if needed */
1252
1253 if (msg->hwnd != UserGetForegroundWindow())
1254 {
1255 PWND pwndTop = pwndMsg;
1256 while (pwndTop)
1257 {
1258 if ((pwndTop->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
1259 pwndTop = IntGetParent( pwndTop );
1260 }
1261
1262 if (pwndTop && pwndTop != pwndDesktop)
1263 {
1264 LONG ret = co_IntSendMessage( msg->hwnd,
1265 WM_MOUSEACTIVATE,
1266 (WPARAM)UserHMGetHandle(pwndTop),
1267 MAKELONG( hittest, msg->message));
1268 switch(ret)
1269 {
1270 case MA_NOACTIVATEANDEAT:
1271 eatMsg = TRUE;
1272 /* fall through */
1273 case MA_NOACTIVATE:
1274 break;
1275 case MA_ACTIVATEANDEAT:
1276 eatMsg = TRUE;
1277 /* fall through */
1278 case MA_ACTIVATE:
1279 case 0:
1280 if(!co_IntMouseActivateWindow(pwndMsg)) eatMsg = TRUE;
1281 break;
1282 default:
1283 DPRINT1( "unknown WM_MOUSEACTIVATE code %d\n", ret );
1284 break;
1285 }
1286 }
1287 }
1288 }
1289
1290 /* send the WM_SETCURSOR message */
1291
1292 /* Windows sends the normal mouse message as the message parameter
1293 in the WM_SETCURSOR message even if it's non-client mouse message */
1294 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
1295
1296 msg->message = message;
1297 RETURN(!eatMsg);
1298
1299 CLEANUP:
1300 if(pwndMsg)
1301 UserDereferenceObject(pwndMsg);
1302
1303 END_CLEANUP;
1304 }
1305
1306 BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
1307 {
1308 EVENTMSG Event;
1309
1310 Event.message = Msg->message;
1311 Event.hwnd = Msg->hwnd;
1312 Event.time = Msg->time;
1313 Event.paramL = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8);
1314 Event.paramH = Msg->lParam & 0x7FFF;
1315 if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
1316 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
1317
1318 if (co_HOOK_CallHooks( WH_KEYBOARD,
1319 *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
1320 LOWORD(Msg->wParam),
1321 Msg->lParam))
1322 {
1323 /* skip this message */
1324 co_HOOK_CallHooks( WH_CBT,
1325 HCBT_KEYSKIPPED,
1326 LOWORD(Msg->wParam),
1327 Msg->lParam );
1328 DPRINT1("KeyboardMessage WH_CBT Call Hook return!\n");
1329 return FALSE;
1330 }
1331 return TRUE;
1332 }
1333
1334 BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, UINT first, UINT last)
1335 {
1336 if ( IS_MOUSE_MESSAGE(Msg->message))
1337 {
1338 return co_IntProcessMouseMessage(Msg, RemoveMessages, first, last);
1339 }
1340 else if ( IS_KBD_MESSAGE(Msg->message))
1341 {
1342 return co_IntProcessKeyboardMessage(Msg, RemoveMessages);
1343 }
1344
1345 return TRUE;
1346 }
1347
1348 BOOL APIENTRY
1349 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue,
1350 IN BOOL Remove,
1351 IN PWND Window,
1352 IN UINT MsgFilterLow,
1353 IN UINT MsgFilterHigh,
1354 OUT MSG* pMsg)
1355 {
1356 BOOL AcceptMessage;
1357 MSG msg;
1358
1359 if(!(MessageQueue->MouseMoved))
1360 return FALSE;
1361
1362 msg = MessageQueue->MouseMoveMsg;
1363
1364 AcceptMessage = co_IntProcessMouseMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
1365
1366 if(AcceptMessage)
1367 *pMsg = msg;
1368
1369 if(Remove)
1370 {
1371 ClearMsgBitsMask(MessageQueue, QS_MOUSEMOVE);
1372 MessageQueue->MouseMoved = FALSE;
1373 }
1374
1375 return AcceptMessage;
1376 }
1377
1378 /* check whether a message filter contains at least one potential hardware message */
1379 static INT FASTCALL
1380 filter_contains_hw_range( UINT first, UINT last )
1381 {
1382 /* hardware message ranges are (in numerical order):
1383 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1384 * WM_KEYFIRST .. WM_KEYLAST
1385 * WM_MOUSEFIRST .. WM_MOUSELAST
1386 */
1387 if (!last) --last;
1388 if (last < WM_NCMOUSEFIRST) return 0;
1389 if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0;
1390 if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0;
1391 if (first > WM_MOUSELAST) return 0;
1392 return 1;
1393 }
1394
1395 BOOL APIENTRY
1396 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
1397 IN BOOL Remove,
1398 IN PWND Window,
1399 IN UINT MsgFilterLow,
1400 IN UINT MsgFilterHigh,
1401 IN UINT QSflags,
1402 OUT MSG* pMsg)
1403 {
1404
1405 BOOL AcceptMessage;
1406 PUSER_MESSAGE CurrentMessage;
1407 PLIST_ENTRY ListHead, CurrentEntry = NULL;
1408 MSG msg;
1409
1410 if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE;
1411
1412 ListHead = &MessageQueue->HardwareMessagesListHead;
1413 CurrentEntry = ListHead->Flink;
1414
1415 if (IsListEmpty(CurrentEntry)) return FALSE;
1416
1417 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
1418 ListEntry);
1419 do
1420 {
1421 if (IsListEmpty(CurrentEntry)) break;
1422 if (!CurrentMessage) break;
1423 CurrentEntry = CurrentMessage->ListEntry.Flink;
1424
1425 if ( (( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && (CurrentMessage->QS_Flags & QSflags)) ||
1426 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) )
1427 {
1428 msg = CurrentMessage->Msg;
1429
1430 AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
1431
1432 if (Remove)
1433 {
1434 update_input_key_state(MessageQueue, pMsg);
1435 RemoveEntryList(&CurrentMessage->ListEntry);
1436 ClearMsgBitsMask(MessageQueue, QS_INPUT);
1437 MsqDestroyMessage(CurrentMessage);
1438 }
1439
1440 if (AcceptMessage)
1441 {
1442 *pMsg = msg;
1443 return TRUE;
1444 }
1445 }
1446 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
1447 ListEntry);
1448 }
1449 while(CurrentEntry != ListHead);
1450
1451 return FALSE;
1452 }
1453
1454 BOOLEAN APIENTRY
1455 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
1456 IN BOOLEAN Remove,
1457 IN PWND Window,
1458 IN UINT MsgFilterLow,
1459 IN UINT MsgFilterHigh,
1460 IN UINT QSflags,
1461 OUT PMSG Message)
1462 {
1463 PLIST_ENTRY CurrentEntry;
1464 PUSER_MESSAGE CurrentMessage;
1465 PLIST_ENTRY ListHead;
1466
1467 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
1468 ListHead = &MessageQueue->PostedMessagesListHead;
1469
1470 if (IsListEmpty(CurrentEntry)) return FALSE;
1471
1472 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
1473 ListEntry);
1474 do
1475 {
1476 if (IsListEmpty(CurrentEntry)) break;
1477 if (!CurrentMessage) break;
1478 CurrentEntry = CurrentEntry->Flink;
1479 /*
1480 MSDN:
1481 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1482 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1483 3: handle to the window whose messages are to be retrieved.
1484 */
1485 if ( ( !Window || // 1
1486 ( Window == HWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
1487 ( Window != HWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3
1488 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
1489 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
1490 {
1491 *Message = CurrentMessage->Msg;
1492
1493 if (Remove)
1494 {
1495 RemoveEntryList(&CurrentMessage->ListEntry);
1496 ClearMsgBitsMask(MessageQueue, QS_POSTMESSAGE);
1497 MsqDestroyMessage(CurrentMessage);
1498 }
1499 return(TRUE);
1500 }
1501 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
1502 ListEntry);
1503 }
1504 while (CurrentEntry != ListHead);
1505
1506 return(FALSE);
1507 }
1508
1509 NTSTATUS FASTCALL
1510 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, PWND WndFilter,
1511 UINT MsgFilterMin, UINT MsgFilterMax)
1512 {
1513 NTSTATUS ret;
1514 UserLeaveCo();
1515 ret = KeWaitForSingleObject( MessageQueue->NewMessages,
1516 UserRequest,
1517 UserMode,
1518 FALSE,
1519 NULL );
1520 UserEnterCo();
1521 return ret;
1522 }
1523
1524 BOOL FASTCALL
1525 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue)
1526 {
1527 LARGE_INTEGER LargeTickCount;
1528
1529 KeQueryTickCount(&LargeTickCount);
1530 return ((LargeTickCount.u.LowPart - MessageQueue->LastMsgRead) > MSQ_HUNG);
1531 }
1532
1533 VOID
1534 CALLBACK
1535 HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
1536 {
1537 //DoTheScreenSaver();
1538 DPRINT("HungAppSysTimerProc\n");
1539 // Process list of windows that are hung and waiting.
1540 }
1541
1542 BOOLEAN FASTCALL
1543 MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQueue)
1544 {
1545 LARGE_INTEGER LargeTickCount;
1546 NTSTATUS Status;
1547
1548 MessageQueue->Thread = Thread;
1549 MessageQueue->CaretInfo = (PTHRDCARETINFO)(MessageQueue + 1);
1550 InitializeListHead(&MessageQueue->PostedMessagesListHead);
1551 InitializeListHead(&MessageQueue->SentMessagesListHead);
1552 InitializeListHead(&MessageQueue->HardwareMessagesListHead);
1553 InitializeListHead(&MessageQueue->DispatchingMessagesHead);
1554 InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead);
1555 KeInitializeMutex(&MessageQueue->HardwareLock, 0);
1556 MessageQueue->QuitPosted = FALSE;
1557 MessageQueue->QuitExitCode = 0;
1558 KeQueryTickCount(&LargeTickCount);
1559 MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
1560 MessageQueue->FocusWindow = NULL;
1561 MessageQueue->NewMessagesHandle = NULL;
1562
1563 Status = ZwCreateEvent(&MessageQueue->NewMessagesHandle, EVENT_ALL_ACCESS,
1564 NULL, SynchronizationEvent, FALSE);
1565 if (!NT_SUCCESS(Status))
1566 {
1567 return FALSE;
1568 }
1569
1570 Status = ObReferenceObjectByHandle(MessageQueue->NewMessagesHandle, 0,
1571 ExEventObjectType, KernelMode,
1572 (PVOID*)&MessageQueue->NewMessages, NULL);
1573 if (!NT_SUCCESS(Status))
1574 {
1575 ZwClose(MessageQueue->NewMessagesHandle);
1576 MessageQueue->NewMessagesHandle = NULL;
1577 return FALSE;
1578 }
1579
1580 return TRUE;
1581 }
1582
1583 VOID FASTCALL
1584 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
1585 {
1586 PLIST_ENTRY CurrentEntry;
1587 PUSER_MESSAGE CurrentMessage;
1588 PUSER_SENT_MESSAGE CurrentSentMessage;
1589 PTHREADINFO pti;
1590
1591 pti = MessageQueue->Thread->Tcb.Win32Thread;
1592
1593
1594 /* cleanup posted messages */
1595 while (!IsListEmpty(&MessageQueue->PostedMessagesListHead))
1596 {
1597 CurrentEntry = RemoveHeadList(&MessageQueue->PostedMessagesListHead);
1598 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
1599 ListEntry);
1600 MsqDestroyMessage(CurrentMessage);
1601 }
1602
1603 /* remove the messages that have not yet been dispatched */
1604 while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
1605 {
1606 CurrentEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
1607 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
1608 ListEntry);
1609
1610 /* if it is a callback and this queue is not the sender queue, dereference queue */
1611 if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue))
1612 {
1613 IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue);
1614 }
1615
1616 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1617 /* Only if the message has a sender was the message in the DispatchingList */
1618 if ((CurrentSentMessage->SenderQueue)
1619 && (CurrentSentMessage->DispatchingListEntry.Flink != NULL))
1620 {
1621 RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
1622 }
1623
1624 /* wake the sender's thread */
1625 if (CurrentSentMessage->CompletionEvent != NULL)
1626 {
1627 KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
1628 }
1629
1630 if (CurrentSentMessage->HasPackedLParam == TRUE)
1631 {
1632 if (CurrentSentMessage->Msg.lParam)
1633 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
1634 }
1635
1636 /* if the message has a sender */
1637 if (CurrentSentMessage->SenderQueue)
1638 {
1639 /* dereference our and the sender's message queue */
1640 IntDereferenceMessageQueue(MessageQueue);
1641 IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);
1642 }
1643
1644 /* free the message */
1645 ExFreePool(CurrentSentMessage);
1646 }
1647
1648 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1649 ExitThread() was called in a SendMessage() umode callback */
1650 while (!IsListEmpty(&MessageQueue->LocalDispatchingMessagesHead))
1651 {
1652 CurrentEntry = RemoveHeadList(&MessageQueue->LocalDispatchingMessagesHead);
1653 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
1654 ListEntry);
1655
1656 /* if it is a callback and this queue is not the sender queue, dereference queue */
1657 if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue))
1658 {
1659 IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue);
1660 }
1661
1662 /* remove the message from the dispatching list */
1663 if(CurrentSentMessage->DispatchingListEntry.Flink != NULL)
1664 {
1665 RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
1666 }
1667
1668 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1669
1670 /* wake the sender's thread */
1671 if (CurrentSentMessage->CompletionEvent != NULL)
1672 {
1673 KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
1674 }
1675
1676 if (CurrentSentMessage->HasPackedLParam == TRUE)
1677 {
1678 if (CurrentSentMessage->Msg.lParam)
1679 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
1680 }
1681
1682 /* if the message has a sender */
1683 if (CurrentSentMessage->SenderQueue)
1684 {
1685 /* dereference our and the sender's message queue */
1686 IntDereferenceMessageQueue(MessageQueue);
1687 IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);
1688 }
1689
1690 /* free the message */
1691 ExFreePool(CurrentSentMessage);
1692 }
1693
1694 /* tell other threads not to bother returning any info to us */
1695 while (! IsListEmpty(&MessageQueue->DispatchingMessagesHead))
1696 {
1697 CurrentEntry = RemoveHeadList(&MessageQueue->DispatchingMessagesHead);
1698 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
1699 DispatchingListEntry);
1700 CurrentSentMessage->CompletionEvent = NULL;
1701 CurrentSentMessage->Result = NULL;
1702
1703 /* do NOT dereference our message queue as it might get attempted to be
1704 locked later */
1705 }
1706
1707 // Clear it all out.
1708 pti->pcti->fsWakeBits = 0;
1709 pti->pcti->fsChangeBits = 0;
1710
1711 MessageQueue->nCntsQBits[QSRosKey] = 0;
1712 MessageQueue->nCntsQBits[QSRosMouseMove] = 0;
1713 MessageQueue->nCntsQBits[QSRosMouseButton] = 0;
1714 MessageQueue->nCntsQBits[QSRosPostMessage] = 0;
1715 MessageQueue->nCntsQBits[QSRosSendMessage] = 0;
1716 MessageQueue->nCntsQBits[QSRosHotKey] = 0;
1717 }
1718
1719 PUSER_MESSAGE_QUEUE FASTCALL
1720 MsqCreateMessageQueue(struct _ETHREAD *Thread)
1721 {
1722 PUSER_MESSAGE_QUEUE MessageQueue;
1723
1724 MessageQueue = (PUSER_MESSAGE_QUEUE)ExAllocatePoolWithTag(NonPagedPool,
1725 sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO),
1726 USERTAG_Q);
1727
1728 if (!MessageQueue)
1729 {
1730 return NULL;
1731 }
1732
1733 RtlZeroMemory(MessageQueue, sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO));
1734 /* hold at least one reference until it'll be destroyed */
1735 IntReferenceMessageQueue(MessageQueue);
1736 /* initialize the queue */
1737 if (!MsqInitializeMessageQueue(Thread, MessageQueue))
1738 {
1739 IntDereferenceMessageQueue(MessageQueue);
1740 return NULL;
1741 }
1742
1743 return MessageQueue;
1744 }
1745
1746 VOID FASTCALL
1747 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
1748 {
1749 PDESKTOP desk;
1750
1751 MessageQueue->QF_flags |= QF_INDESTROY;
1752
1753 /* remove the message queue from any desktops */
1754 if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0)))
1755 {
1756 (void)InterlockedExchangePointer((PVOID*)&desk->ActiveMessageQueue, 0);
1757 IntDereferenceMessageQueue(MessageQueue);
1758 }
1759
1760 /* clean it up */
1761 MsqCleanupMessageQueue(MessageQueue);
1762
1763 if (MessageQueue->NewMessagesHandle != NULL)
1764 ZwClose(MessageQueue->NewMessagesHandle);
1765 MessageQueue->NewMessagesHandle = NULL;
1766 /* decrease the reference counter, if it hits zero, the queue will be freed */
1767 IntDereferenceMessageQueue(MessageQueue);
1768 }
1769
1770 LPARAM FASTCALL
1771 MsqSetMessageExtraInfo(LPARAM lParam)
1772 {
1773 LPARAM Ret;
1774 PTHREADINFO pti;
1775 PUSER_MESSAGE_QUEUE MessageQueue;
1776
1777 pti = PsGetCurrentThreadWin32Thread();
1778 MessageQueue = pti->MessageQueue;
1779 if(!MessageQueue)
1780 {
1781 return 0;
1782 }
1783
1784 Ret = MessageQueue->ExtraInfo;
1785 MessageQueue->ExtraInfo = lParam;
1786
1787 return Ret;
1788 }
1789
1790 LPARAM FASTCALL
1791 MsqGetMessageExtraInfo(VOID)
1792 {
1793 PTHREADINFO pti;
1794 PUSER_MESSAGE_QUEUE MessageQueue;
1795
1796 pti = PsGetCurrentThreadWin32Thread();
1797 MessageQueue = pti->MessageQueue;
1798 if(!MessageQueue)
1799 {
1800 return 0;
1801 }
1802
1803 return MessageQueue->ExtraInfo;
1804 }
1805
1806 // ReplyMessage is called by the thread receiving the window message.
1807 BOOL FASTCALL
1808 co_MsqReplyMessage( LRESULT lResult )
1809 {
1810 PUSER_SENT_MESSAGE Message;
1811 PTHREADINFO pti;
1812
1813 pti = PsGetCurrentThreadWin32Thread();
1814 Message = pti->pusmCurrent;
1815
1816 if (!Message) return FALSE;
1817
1818 if (Message->QS_Flags & QS_SMRESULT) return FALSE;
1819
1820 // SendMessageXxx || Callback msg and not a notify msg
1821 if (Message->SenderQueue || Message->CompletionCallback)
1822 {
1823 Message->lResult = lResult;
1824 Message->QS_Flags |= QS_SMRESULT;
1825 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
1826 }
1827 return TRUE;
1828 }
1829
1830 HWND FASTCALL
1831 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd)
1832 {
1833 HWND Prev;
1834
1835 switch(Type)
1836 {
1837 case MSQ_STATE_CAPTURE:
1838 Prev = MessageQueue->CaptureWindow;
1839 MessageQueue->CaptureWindow = hWnd;
1840 return Prev;
1841 case MSQ_STATE_ACTIVE:
1842 Prev = MessageQueue->ActiveWindow;
1843 MessageQueue->ActiveWindow = hWnd;
1844 return Prev;
1845 case MSQ_STATE_FOCUS:
1846 Prev = MessageQueue->FocusWindow;
1847 MessageQueue->FocusWindow = hWnd;
1848 return Prev;
1849 case MSQ_STATE_MENUOWNER:
1850 Prev = MessageQueue->MenuOwner;
1851 MessageQueue->MenuOwner = hWnd;
1852 return Prev;
1853 case MSQ_STATE_MOVESIZE:
1854 Prev = MessageQueue->MoveSize;
1855 MessageQueue->MoveSize = hWnd;
1856 return Prev;
1857 case MSQ_STATE_CARET:
1858 ASSERT(MessageQueue->CaretInfo);
1859 Prev = MessageQueue->CaretInfo->hWnd;
1860 MessageQueue->CaretInfo->hWnd = hWnd;
1861 return Prev;
1862 }
1863
1864 return NULL;
1865 }
1866
1867 SHORT
1868 APIENTRY
1869 NtUserGetKeyState(INT key)
1870 {
1871 DWORD Ret;
1872
1873 UserEnterExclusive();
1874
1875 Ret = UserGetKeyState(key);
1876
1877 UserLeave();
1878
1879 return Ret;
1880 }
1881
1882 /* EOF */