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