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