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