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