[CMAKE]
[reactos.git] / 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 if (Msg->message == WM_KEYDOWN || Msg->message == WM_SYSKEYDOWN ||
1311 Msg->message == WM_KEYUP || Msg->message == WM_SYSKEYUP)
1312 {
1313 switch (Msg->wParam)
1314 {
1315 case VK_LSHIFT: case VK_RSHIFT:
1316 Msg->wParam = VK_SHIFT;
1317 break;
1318 case VK_LCONTROL: case VK_RCONTROL:
1319 Msg->wParam = VK_CONTROL;
1320 break;
1321 case VK_LMENU: case VK_RMENU:
1322 Msg->wParam = VK_MENU;
1323 break;
1324 }
1325 }
1326
1327 Event.message = Msg->message;
1328 Event.hwnd = Msg->hwnd;
1329 Event.time = Msg->time;
1330 Event.paramL = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8);
1331 Event.paramH = Msg->lParam & 0x7FFF;
1332 if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
1333 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
1334
1335 if (co_HOOK_CallHooks( WH_KEYBOARD,
1336 *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
1337 LOWORD(Msg->wParam),
1338 Msg->lParam))
1339 {
1340 /* skip this message */
1341 co_HOOK_CallHooks( WH_CBT,
1342 HCBT_KEYSKIPPED,
1343 LOWORD(Msg->wParam),
1344 Msg->lParam );
1345 DPRINT1("KeyboardMessage WH_CBT Call Hook return!\n");
1346 return FALSE;
1347 }
1348 return TRUE;
1349 }
1350
1351 BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, UINT first, UINT last)
1352 {
1353 if ( IS_MOUSE_MESSAGE(Msg->message))
1354 {
1355 return co_IntProcessMouseMessage(Msg, RemoveMessages, first, last);
1356 }
1357 else if ( IS_KBD_MESSAGE(Msg->message))
1358 {
1359 return co_IntProcessKeyboardMessage(Msg, RemoveMessages);
1360 }
1361
1362 return TRUE;
1363 }
1364
1365 BOOL APIENTRY
1366 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue,
1367 IN BOOL Remove,
1368 IN PWND Window,
1369 IN UINT MsgFilterLow,
1370 IN UINT MsgFilterHigh,
1371 OUT MSG* pMsg)
1372 {
1373 BOOL AcceptMessage;
1374 MSG msg;
1375
1376 if(!(MessageQueue->MouseMoved))
1377 return FALSE;
1378
1379 msg = MessageQueue->MouseMoveMsg;
1380
1381 AcceptMessage = co_IntProcessMouseMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
1382
1383 if(AcceptMessage)
1384 *pMsg = msg;
1385
1386 if(Remove)
1387 {
1388 ClearMsgBitsMask(MessageQueue, QS_MOUSEMOVE);
1389 MessageQueue->MouseMoved = FALSE;
1390 }
1391
1392 return AcceptMessage;
1393 }
1394
1395 /* check whether a message filter contains at least one potential hardware message */
1396 static INT FASTCALL
1397 filter_contains_hw_range( UINT first, UINT last )
1398 {
1399 /* hardware message ranges are (in numerical order):
1400 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1401 * WM_KEYFIRST .. WM_KEYLAST
1402 * WM_MOUSEFIRST .. WM_MOUSELAST
1403 */
1404 if (!last) --last;
1405 if (last < WM_NCMOUSEFIRST) return 0;
1406 if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0;
1407 if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0;
1408 if (first > WM_MOUSELAST) return 0;
1409 return 1;
1410 }
1411
1412 BOOL APIENTRY
1413 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
1414 IN BOOL Remove,
1415 IN PWND Window,
1416 IN UINT MsgFilterLow,
1417 IN UINT MsgFilterHigh,
1418 IN UINT QSflags,
1419 OUT MSG* pMsg)
1420 {
1421
1422 BOOL AcceptMessage;
1423 PUSER_MESSAGE CurrentMessage;
1424 PLIST_ENTRY ListHead, CurrentEntry = NULL;
1425 MSG msg;
1426
1427 if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE;
1428
1429 ListHead = &MessageQueue->HardwareMessagesListHead;
1430 CurrentEntry = ListHead->Flink;
1431
1432 if (IsListEmpty(CurrentEntry)) return FALSE;
1433
1434 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
1435 ListEntry);
1436 do
1437 {
1438 if (IsListEmpty(CurrentEntry)) break;
1439 if (!CurrentMessage) break;
1440 CurrentEntry = CurrentMessage->ListEntry.Flink;
1441
1442 if ( (( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && (CurrentMessage->QS_Flags & QSflags)) ||
1443 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) )
1444 {
1445 msg = CurrentMessage->Msg;
1446
1447 AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
1448
1449 if (Remove)
1450 {
1451 update_input_key_state(MessageQueue, pMsg);
1452 RemoveEntryList(&CurrentMessage->ListEntry);
1453 ClearMsgBitsMask(MessageQueue, QS_INPUT);
1454 MsqDestroyMessage(CurrentMessage);
1455 }
1456
1457 if (AcceptMessage)
1458 {
1459 *pMsg = msg;
1460 return TRUE;
1461 }
1462 }
1463 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
1464 ListEntry);
1465 }
1466 while(CurrentEntry != ListHead);
1467
1468 return FALSE;
1469 }
1470
1471 BOOLEAN APIENTRY
1472 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
1473 IN BOOLEAN Remove,
1474 IN PWND Window,
1475 IN UINT MsgFilterLow,
1476 IN UINT MsgFilterHigh,
1477 IN UINT QSflags,
1478 OUT PMSG Message)
1479 {
1480 PLIST_ENTRY CurrentEntry;
1481 PUSER_MESSAGE CurrentMessage;
1482 PLIST_ENTRY ListHead;
1483
1484 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
1485 ListHead = &MessageQueue->PostedMessagesListHead;
1486
1487 if (IsListEmpty(CurrentEntry)) return FALSE;
1488
1489 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
1490 ListEntry);
1491 do
1492 {
1493 if (IsListEmpty(CurrentEntry)) break;
1494 if (!CurrentMessage) break;
1495 CurrentEntry = CurrentEntry->Flink;
1496 /*
1497 MSDN:
1498 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1499 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1500 3: handle to the window whose messages are to be retrieved.
1501 */
1502 if ( ( !Window || // 1
1503 ( Window == HWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
1504 ( Window != HWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3
1505 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
1506 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
1507 {
1508 *Message = CurrentMessage->Msg;
1509
1510 if (Remove)
1511 {
1512 RemoveEntryList(&CurrentMessage->ListEntry);
1513 ClearMsgBitsMask(MessageQueue, QS_POSTMESSAGE);
1514 MsqDestroyMessage(CurrentMessage);
1515 }
1516 return(TRUE);
1517 }
1518 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
1519 ListEntry);
1520 }
1521 while (CurrentEntry != ListHead);
1522
1523 return(FALSE);
1524 }
1525
1526 NTSTATUS FASTCALL
1527 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, PWND WndFilter,
1528 UINT MsgFilterMin, UINT MsgFilterMax)
1529 {
1530 NTSTATUS ret;
1531 UserLeaveCo();
1532 ret = KeWaitForSingleObject( MessageQueue->NewMessages,
1533 UserRequest,
1534 UserMode,
1535 FALSE,
1536 NULL );
1537 UserEnterCo();
1538 return ret;
1539 }
1540
1541 BOOL FASTCALL
1542 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue)
1543 {
1544 LARGE_INTEGER LargeTickCount;
1545
1546 KeQueryTickCount(&LargeTickCount);
1547 return ((LargeTickCount.u.LowPart - MessageQueue->LastMsgRead) > MSQ_HUNG);
1548 }
1549
1550 VOID
1551 CALLBACK
1552 HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
1553 {
1554 //DoTheScreenSaver();
1555 DPRINT("HungAppSysTimerProc\n");
1556 // Process list of windows that are hung and waiting.
1557 }
1558
1559 BOOLEAN FASTCALL
1560 MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQueue)
1561 {
1562 LARGE_INTEGER LargeTickCount;
1563 NTSTATUS Status;
1564
1565 MessageQueue->Thread = Thread;
1566 MessageQueue->CaretInfo = (PTHRDCARETINFO)(MessageQueue + 1);
1567 InitializeListHead(&MessageQueue->PostedMessagesListHead);
1568 InitializeListHead(&MessageQueue->SentMessagesListHead);
1569 InitializeListHead(&MessageQueue->HardwareMessagesListHead);
1570 InitializeListHead(&MessageQueue->DispatchingMessagesHead);
1571 InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead);
1572 KeInitializeMutex(&MessageQueue->HardwareLock, 0);
1573 MessageQueue->QuitPosted = FALSE;
1574 MessageQueue->QuitExitCode = 0;
1575 KeQueryTickCount(&LargeTickCount);
1576 MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
1577 MessageQueue->FocusWindow = NULL;
1578 MessageQueue->NewMessagesHandle = NULL;
1579
1580 Status = ZwCreateEvent(&MessageQueue->NewMessagesHandle, EVENT_ALL_ACCESS,
1581 NULL, SynchronizationEvent, FALSE);
1582 if (!NT_SUCCESS(Status))
1583 {
1584 return FALSE;
1585 }
1586
1587 Status = ObReferenceObjectByHandle(MessageQueue->NewMessagesHandle, 0,
1588 ExEventObjectType, KernelMode,
1589 (PVOID*)&MessageQueue->NewMessages, NULL);
1590 if (!NT_SUCCESS(Status))
1591 {
1592 ZwClose(MessageQueue->NewMessagesHandle);
1593 MessageQueue->NewMessagesHandle = NULL;
1594 return FALSE;
1595 }
1596
1597 return TRUE;
1598 }
1599
1600 VOID FASTCALL
1601 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
1602 {
1603 PLIST_ENTRY CurrentEntry;
1604 PUSER_MESSAGE CurrentMessage;
1605 PUSER_SENT_MESSAGE CurrentSentMessage;
1606 PTHREADINFO pti;
1607
1608 pti = MessageQueue->Thread->Tcb.Win32Thread;
1609
1610
1611 /* cleanup posted messages */
1612 while (!IsListEmpty(&MessageQueue->PostedMessagesListHead))
1613 {
1614 CurrentEntry = RemoveHeadList(&MessageQueue->PostedMessagesListHead);
1615 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
1616 ListEntry);
1617 MsqDestroyMessage(CurrentMessage);
1618 }
1619
1620 /* remove the messages that have not yet been dispatched */
1621 while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
1622 {
1623 CurrentEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
1624 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
1625 ListEntry);
1626
1627 /* if it is a callback and this queue is not the sender queue, dereference queue */
1628 if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue))
1629 {
1630 IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue);
1631 }
1632
1633 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1634 /* Only if the message has a sender was the message in the DispatchingList */
1635 if ((CurrentSentMessage->SenderQueue)
1636 && (CurrentSentMessage->DispatchingListEntry.Flink != NULL))
1637 {
1638 RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
1639 }
1640
1641 /* wake the sender's thread */
1642 if (CurrentSentMessage->CompletionEvent != NULL)
1643 {
1644 KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
1645 }
1646
1647 if (CurrentSentMessage->HasPackedLParam == TRUE)
1648 {
1649 if (CurrentSentMessage->Msg.lParam)
1650 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
1651 }
1652
1653 /* if the message has a sender */
1654 if (CurrentSentMessage->SenderQueue)
1655 {
1656 /* dereference our and the sender's message queue */
1657 IntDereferenceMessageQueue(MessageQueue);
1658 IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);
1659 }
1660
1661 /* free the message */
1662 ExFreePool(CurrentSentMessage);
1663 }
1664
1665 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1666 ExitThread() was called in a SendMessage() umode callback */
1667 while (!IsListEmpty(&MessageQueue->LocalDispatchingMessagesHead))
1668 {
1669 CurrentEntry = RemoveHeadList(&MessageQueue->LocalDispatchingMessagesHead);
1670 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
1671 ListEntry);
1672
1673 /* if it is a callback and this queue is not the sender queue, dereference queue */
1674 if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue))
1675 {
1676 IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue);
1677 }
1678
1679 /* remove the message from the dispatching list */
1680 if(CurrentSentMessage->DispatchingListEntry.Flink != NULL)
1681 {
1682 RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
1683 }
1684
1685 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1686
1687 /* wake the sender's thread */
1688 if (CurrentSentMessage->CompletionEvent != NULL)
1689 {
1690 KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
1691 }
1692
1693 if (CurrentSentMessage->HasPackedLParam == TRUE)
1694 {
1695 if (CurrentSentMessage->Msg.lParam)
1696 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
1697 }
1698
1699 /* if the message has a sender */
1700 if (CurrentSentMessage->SenderQueue)
1701 {
1702 /* dereference our and the sender's message queue */
1703 IntDereferenceMessageQueue(MessageQueue);
1704 IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);
1705 }
1706
1707 /* free the message */
1708 ExFreePool(CurrentSentMessage);
1709 }
1710
1711 /* tell other threads not to bother returning any info to us */
1712 while (! IsListEmpty(&MessageQueue->DispatchingMessagesHead))
1713 {
1714 CurrentEntry = RemoveHeadList(&MessageQueue->DispatchingMessagesHead);
1715 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
1716 DispatchingListEntry);
1717 CurrentSentMessage->CompletionEvent = NULL;
1718 CurrentSentMessage->Result = NULL;
1719
1720 /* do NOT dereference our message queue as it might get attempted to be
1721 locked later */
1722 }
1723
1724 // Clear it all out.
1725 pti->pcti->fsWakeBits = 0;
1726 pti->pcti->fsChangeBits = 0;
1727
1728 MessageQueue->nCntsQBits[QSRosKey] = 0;
1729 MessageQueue->nCntsQBits[QSRosMouseMove] = 0;
1730 MessageQueue->nCntsQBits[QSRosMouseButton] = 0;
1731 MessageQueue->nCntsQBits[QSRosPostMessage] = 0;
1732 MessageQueue->nCntsQBits[QSRosSendMessage] = 0;
1733 MessageQueue->nCntsQBits[QSRosHotKey] = 0;
1734 }
1735
1736 PUSER_MESSAGE_QUEUE FASTCALL
1737 MsqCreateMessageQueue(struct _ETHREAD *Thread)
1738 {
1739 PUSER_MESSAGE_QUEUE MessageQueue;
1740
1741 MessageQueue = (PUSER_MESSAGE_QUEUE)ExAllocatePoolWithTag(NonPagedPool,
1742 sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO),
1743 USERTAG_Q);
1744
1745 if (!MessageQueue)
1746 {
1747 return NULL;
1748 }
1749
1750 RtlZeroMemory(MessageQueue, sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO));
1751 /* hold at least one reference until it'll be destroyed */
1752 IntReferenceMessageQueue(MessageQueue);
1753 /* initialize the queue */
1754 if (!MsqInitializeMessageQueue(Thread, MessageQueue))
1755 {
1756 IntDereferenceMessageQueue(MessageQueue);
1757 return NULL;
1758 }
1759
1760 return MessageQueue;
1761 }
1762
1763 VOID FASTCALL
1764 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
1765 {
1766 PDESKTOP desk;
1767
1768 MessageQueue->QF_flags |= QF_INDESTROY;
1769
1770 /* remove the message queue from any desktops */
1771 if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0)))
1772 {
1773 (void)InterlockedExchangePointer((PVOID*)&desk->ActiveMessageQueue, 0);
1774 IntDereferenceMessageQueue(MessageQueue);
1775 }
1776
1777 /* clean it up */
1778 MsqCleanupMessageQueue(MessageQueue);
1779
1780 if (MessageQueue->NewMessagesHandle != NULL)
1781 ZwClose(MessageQueue->NewMessagesHandle);
1782 MessageQueue->NewMessagesHandle = NULL;
1783 /* decrease the reference counter, if it hits zero, the queue will be freed */
1784 IntDereferenceMessageQueue(MessageQueue);
1785 }
1786
1787 LPARAM FASTCALL
1788 MsqSetMessageExtraInfo(LPARAM lParam)
1789 {
1790 LPARAM Ret;
1791 PTHREADINFO pti;
1792 PUSER_MESSAGE_QUEUE MessageQueue;
1793
1794 pti = PsGetCurrentThreadWin32Thread();
1795 MessageQueue = pti->MessageQueue;
1796 if(!MessageQueue)
1797 {
1798 return 0;
1799 }
1800
1801 Ret = MessageQueue->ExtraInfo;
1802 MessageQueue->ExtraInfo = lParam;
1803
1804 return Ret;
1805 }
1806
1807 LPARAM FASTCALL
1808 MsqGetMessageExtraInfo(VOID)
1809 {
1810 PTHREADINFO pti;
1811 PUSER_MESSAGE_QUEUE MessageQueue;
1812
1813 pti = PsGetCurrentThreadWin32Thread();
1814 MessageQueue = pti->MessageQueue;
1815 if(!MessageQueue)
1816 {
1817 return 0;
1818 }
1819
1820 return MessageQueue->ExtraInfo;
1821 }
1822
1823 // ReplyMessage is called by the thread receiving the window message.
1824 BOOL FASTCALL
1825 co_MsqReplyMessage( LRESULT lResult )
1826 {
1827 PUSER_SENT_MESSAGE Message;
1828 PTHREADINFO pti;
1829
1830 pti = PsGetCurrentThreadWin32Thread();
1831 Message = pti->pusmCurrent;
1832
1833 if (!Message) return FALSE;
1834
1835 if (Message->QS_Flags & QS_SMRESULT) return FALSE;
1836
1837 // SendMessageXxx || Callback msg and not a notify msg
1838 if (Message->SenderQueue || Message->CompletionCallback)
1839 {
1840 Message->lResult = lResult;
1841 Message->QS_Flags |= QS_SMRESULT;
1842 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
1843 }
1844 return TRUE;
1845 }
1846
1847 HWND FASTCALL
1848 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd)
1849 {
1850 HWND Prev;
1851
1852 switch(Type)
1853 {
1854 case MSQ_STATE_CAPTURE:
1855 Prev = MessageQueue->CaptureWindow;
1856 MessageQueue->CaptureWindow = hWnd;
1857 return Prev;
1858 case MSQ_STATE_ACTIVE:
1859 Prev = MessageQueue->ActiveWindow;
1860 MessageQueue->ActiveWindow = hWnd;
1861 return Prev;
1862 case MSQ_STATE_FOCUS:
1863 Prev = MessageQueue->FocusWindow;
1864 MessageQueue->FocusWindow = hWnd;
1865 return Prev;
1866 case MSQ_STATE_MENUOWNER:
1867 Prev = MessageQueue->MenuOwner;
1868 MessageQueue->MenuOwner = hWnd;
1869 return Prev;
1870 case MSQ_STATE_MOVESIZE:
1871 Prev = MessageQueue->MoveSize;
1872 MessageQueue->MoveSize = hWnd;
1873 return Prev;
1874 case MSQ_STATE_CARET:
1875 ASSERT(MessageQueue->CaretInfo);
1876 Prev = MessageQueue->CaretInfo->hWnd;
1877 MessageQueue->CaretInfo->hWnd = hWnd;
1878 return Prev;
1879 }
1880
1881 return NULL;
1882 }
1883
1884 SHORT
1885 APIENTRY
1886 NtUserGetKeyState(INT key)
1887 {
1888 DWORD Ret;
1889
1890 UserEnterExclusive();
1891
1892 Ret = UserGetKeyState(key);
1893
1894 UserLeave();
1895
1896 return Ret;
1897 }
1898
1899
1900 DWORD
1901 APIENTRY
1902 NtUserGetKeyboardState(LPBYTE lpKeyState)
1903 {
1904 DWORD ret = TRUE;
1905 PTHREADINFO pti;
1906 PUSER_MESSAGE_QUEUE MessageQueue;
1907
1908 UserEnterShared();
1909
1910 pti = PsGetCurrentThreadWin32Thread();
1911 MessageQueue = pti->MessageQueue;
1912
1913 _SEH2_TRY
1914 {
1915 ProbeForWrite(lpKeyState,sizeof(MessageQueue->KeyState) ,1);
1916 RtlCopyMemory(lpKeyState,MessageQueue->KeyState,sizeof(MessageQueue->KeyState));
1917 }
1918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1919 {
1920 SetLastNtError(_SEH2_GetExceptionCode());
1921 ret = FALSE;
1922 }
1923 _SEH2_END;
1924
1925 UserLeave();
1926
1927 return ret;
1928 }
1929
1930 BOOL
1931 APIENTRY
1932 NtUserSetKeyboardState(LPBYTE lpKeyState)
1933 {
1934 DWORD ret = TRUE;
1935 PTHREADINFO pti;
1936 PUSER_MESSAGE_QUEUE MessageQueue;
1937
1938 UserEnterExclusive();
1939
1940 pti = PsGetCurrentThreadWin32Thread();
1941 MessageQueue = pti->MessageQueue;
1942
1943 _SEH2_TRY
1944 {
1945 ProbeForRead(lpKeyState,sizeof(MessageQueue->KeyState) ,1);
1946 RtlCopyMemory(MessageQueue->KeyState,lpKeyState,sizeof(MessageQueue->KeyState));
1947 }
1948 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1949 {
1950 SetLastNtError(_SEH2_GetExceptionCode());
1951 ret = FALSE;
1952 }
1953 _SEH2_END;
1954
1955 UserLeave();
1956
1957 return ret;
1958 }
1959
1960
1961 /* EOF */