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