Win32 structure cleanup part 2 / x:
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / msgqueue.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Message queues
24 * FILE: subsys/win32k/ntuser/msgqueue.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29
30 /* INCLUDES ******************************************************************/
31
32 #include <w32k.h>
33
34 #define NDEBUG
35 #include <debug.h>
36
37 /* GLOBALS *******************************************************************/
38
39 #define SYSTEM_MESSAGE_QUEUE_SIZE (256)
40
41 static MSG SystemMessageQueue[SYSTEM_MESSAGE_QUEUE_SIZE];
42 static ULONG SystemMessageQueueHead = 0;
43 static ULONG SystemMessageQueueTail = 0;
44 static ULONG SystemMessageQueueCount = 0;
45 static KSPIN_LOCK SystemMessageQueueLock;
46
47 static ULONG volatile HardwareMessageQueueStamp = 0;
48 static LIST_ENTRY HardwareMessageQueueHead;
49 static KMUTANT HardwareMessageQueueLock;
50
51 static KEVENT HardwareMessageEvent;
52
53 static PAGED_LOOKASIDE_LIST MessageLookasideList;
54 static PAGED_LOOKASIDE_LIST TimerLookasideList;
55
56 #define IntLockSystemMessageQueue(OldIrql) \
57 KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql)
58
59 #define IntUnLockSystemMessageQueue(OldIrql) \
60 KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql)
61
62 #define IntUnLockSystemHardwareMessageQueueLock(Wait) \
63 KeReleaseMutant(&HardwareMessageQueueLock, IO_NO_INCREMENT, FALSE, Wait)
64
65 /* FUNCTIONS *****************************************************************/
66
67 //
68 // Wakeup any thread/process waiting on idle input.
69 //
70 static VOID FASTCALL
71 IdlePing(VOID)
72 {
73 HWND hWnd;
74 PWINDOW_OBJECT Window;
75 PW32PROCESS W32d = PsGetCurrentProcessWin32Process();
76
77 hWnd = UserGetForegroundWindow();
78
79 Window = UserGetWindowObject(hWnd);
80
81 if (Window && Window->ti)
82 {
83 if (Window->ti->Hooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE))
84 {
85 co_HOOK_CallHooks(WH_FOREGROUNDIDLE,HC_ACTION,0,0);
86 }
87 }
88
89 if (W32d && W32d->InputIdleEvent)
90 KePulseEvent( W32d->InputIdleEvent, EVENT_INCREMENT, TRUE);
91 }
92
93 HANDLE FASTCALL
94 IntMsqSetWakeMask(DWORD WakeMask)
95 {
96 PTHREADINFO Win32Thread;
97 PUSER_MESSAGE_QUEUE MessageQueue;
98 HANDLE MessageEventHandle;
99
100 Win32Thread = PsGetCurrentThreadWin32Thread();
101 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
102 return 0;
103
104 MessageQueue = Win32Thread->MessageQueue;
105 MessageQueue->WakeMask = WakeMask;
106 MessageEventHandle = MessageQueue->NewMessagesHandle;
107
108 return MessageEventHandle;
109 }
110
111 BOOL FASTCALL
112 IntMsqClearWakeMask(VOID)
113 {
114 PTHREADINFO Win32Thread;
115 PUSER_MESSAGE_QUEUE MessageQueue;
116
117 Win32Thread = PsGetCurrentThreadWin32Thread();
118 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
119 return FALSE;
120
121 MessageQueue = Win32Thread->MessageQueue;
122 MessageQueue->WakeMask = ~0;
123
124 return TRUE;
125 }
126
127 VOID FASTCALL
128 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
129 {
130 Queue->PaintCount++;
131 Queue->QueueBits |= QS_PAINT;
132 Queue->ChangedBits |= QS_PAINT;
133 if (Queue->WakeMask & QS_PAINT)
134 KeSetEvent(Queue->NewMessages, IO_NO_INCREMENT, FALSE);
135 }
136
137 VOID FASTCALL
138 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
139 {
140 Queue->PaintCount--;
141 }
142
143
144 NTSTATUS FASTCALL
145 MsqInitializeImpl(VOID)
146 {
147 /*CurrentFocusMessageQueue = NULL;*/
148 InitializeListHead(&HardwareMessageQueueHead);
149 KeInitializeEvent(&HardwareMessageEvent, NotificationEvent, 0);
150 KeInitializeSpinLock(&SystemMessageQueueLock);
151 KeInitializeMutant(&HardwareMessageQueueLock, 0);
152
153 ExInitializePagedLookasideList(&MessageLookasideList,
154 NULL,
155 NULL,
156 0,
157 sizeof(USER_MESSAGE),
158 TAG_USRMSG,
159 256);
160 ExInitializePagedLookasideList(&TimerLookasideList,
161 NULL,
162 NULL,
163 0,
164 sizeof(TIMER_ENTRY),
165 TAG_TIMER,
166 64);
167
168 return(STATUS_SUCCESS);
169 }
170
171 VOID FASTCALL
172 MsqInsertSystemMessage(MSG* Msg)
173 {
174 LARGE_INTEGER LargeTickCount;
175 KIRQL OldIrql;
176 ULONG Prev;
177 EVENTMSG Event;
178
179 IntLockSystemMessageQueue(OldIrql);
180
181 /*
182 * Bail out if the queue is full. FIXME: We should handle this case
183 * more gracefully.
184 */
185
186 if (SystemMessageQueueCount == SYSTEM_MESSAGE_QUEUE_SIZE)
187 {
188 IntUnLockSystemMessageQueue(OldIrql);
189 return;
190 }
191
192 KeQueryTickCount(&LargeTickCount);
193 Msg->time = MsqCalculateMessageTime(&LargeTickCount);
194
195 Event.message = Msg->message;
196 Event.time = Msg->time;
197 Event.hwnd = Msg->hwnd;
198 Event.paramL = Msg->pt.x;
199 Event.paramH = Msg->pt.y;
200 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
201
202 /*
203 * If we got WM_MOUSEMOVE and there are already messages in the
204 * system message queue, check if the last message is mouse move
205 * and if it is then just overwrite it.
206 */
207
208 if (Msg->message == WM_MOUSEMOVE && SystemMessageQueueCount)
209 {
210 if (SystemMessageQueueTail == 0)
211 Prev = SYSTEM_MESSAGE_QUEUE_SIZE - 1;
212 else
213 Prev = SystemMessageQueueTail - 1;
214 if (SystemMessageQueue[Prev].message == WM_MOUSEMOVE)
215 {
216 SystemMessageQueueTail = Prev;
217 SystemMessageQueueCount--;
218 }
219 }
220
221 /*
222 * Actually insert the message into the system message queue.
223 */
224
225 SystemMessageQueue[SystemMessageQueueTail] = *Msg;
226 SystemMessageQueueTail =
227 (SystemMessageQueueTail + 1) % SYSTEM_MESSAGE_QUEUE_SIZE;
228 SystemMessageQueueCount++;
229
230 IntUnLockSystemMessageQueue(OldIrql);
231
232 KeSetEvent(&HardwareMessageEvent, IO_NO_INCREMENT, FALSE);
233 }
234
235 BOOL FASTCALL
236 MsqIsDblClk(LPMSG Msg, BOOL Remove)
237 {
238 PTHREADINFO pti;
239 PWINSTATION_OBJECT WinStaObject;
240 PSYSTEM_CURSORINFO CurInfo;
241 LONG dX, dY;
242 BOOL Res;
243
244 pti = PsGetCurrentThreadWin32Thread();
245 if (pti->Desktop == NULL)
246 {
247 return FALSE;
248 }
249
250 WinStaObject = pti->Desktop->WindowStation;
251
252 CurInfo = IntGetSysCursorInfo(WinStaObject);
253 Res = (Msg->hwnd == (HWND)CurInfo->LastClkWnd) &&
254 ((Msg->time - CurInfo->LastBtnDown) < CurInfo->DblClickSpeed);
255 if(Res)
256 {
257
258 dX = CurInfo->LastBtnDownX - Msg->pt.x;
259 dY = CurInfo->LastBtnDownY - Msg->pt.y;
260 if(dX < 0)
261 dX = -dX;
262 if(dY < 0)
263 dY = -dY;
264
265 Res = (dX <= CurInfo->DblClickWidth) &&
266 (dY <= CurInfo->DblClickHeight);
267
268 if(Res)
269 {
270 if(CurInfo->ButtonsDown)
271 Res = (CurInfo->ButtonsDown == Msg->message);
272 }
273 }
274
275 if(Remove)
276 {
277 if (Res)
278 {
279 CurInfo->LastBtnDown = 0;
280 CurInfo->LastBtnDownX = Msg->pt.x;
281 CurInfo->LastBtnDownY = Msg->pt.y;
282 CurInfo->LastClkWnd = NULL;
283 CurInfo->ButtonsDown = Msg->message;
284 }
285 else
286 {
287 CurInfo->LastBtnDownX = Msg->pt.x;
288 CurInfo->LastBtnDownY = Msg->pt.y;
289 CurInfo->LastClkWnd = (HANDLE)Msg->hwnd;
290 CurInfo->LastBtnDown = Msg->time;
291 CurInfo->ButtonsDown = Msg->message;
292 }
293 }
294
295 return Res;
296 }
297
298 BOOL static STDCALL
299 co_MsqTranslateMouseMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND hWnd, UINT FilterLow, UINT FilterHigh,
300 PUSER_MESSAGE Message, BOOL Remove, PBOOL Freed,
301 PWINDOW_OBJECT ScopeWin, PPOINT ScreenPoint, BOOL FromGlobalQueue, PLIST_ENTRY *Next)
302 {
303 USHORT Msg = Message->Msg.message;
304 PWINDOW_OBJECT Window = NULL;
305 HWND hCaptureWin;
306
307 ASSERT_REFS_CO(ScopeWin);
308
309 /*
310 co_WinPosWindowFromPoint can return a Window, and in that case
311 that window has a ref that we need to deref. Thats why we add "dummy"
312 refs in all other cases.
313 */
314
315 hCaptureWin = IntGetCaptureWindow();
316 if (hCaptureWin == NULL)
317 {
318 if(Msg == WM_MOUSEWHEEL)
319 {
320 Window = UserGetWindowObject(IntGetFocusWindow());
321 if (Window) UserReferenceObject(Window);
322 }
323 else
324 {
325 co_WinPosWindowFromPoint(ScopeWin, NULL, &Message->Msg.pt, &Window);
326 if(Window == NULL)
327 {
328 Window = ScopeWin;
329 if (Window) UserReferenceObject(Window);
330 }
331 else
332 {
333 /* this is the one case where we dont add a ref, since the returned
334 window is already referenced */
335 }
336 }
337 }
338 else
339 {
340 /* FIXME - window messages should go to the right window if no buttons are
341 pressed */
342 Window = UserGetWindowObject(hCaptureWin);
343 if (Window) UserReferenceObject(Window);
344 }
345
346
347
348 if (Window == NULL)
349 {
350 if(!FromGlobalQueue)
351 {
352 RemoveEntryList(&Message->ListEntry);
353 if(MessageQueue->MouseMoveMsg == Message)
354 {
355 MessageQueue->MouseMoveMsg = NULL;
356 }
357 }
358 // when FromGlobalQueue is true, the caller has already removed the Message
359 ExFreePool(Message);
360 *Freed = TRUE;
361 return(FALSE);
362 }
363
364 if (Window->MessageQueue != MessageQueue)
365 {
366 if (! FromGlobalQueue)
367 {
368 DPRINT("Moving msg between private queues\n");
369 /* This message is already queued in a private queue, but we need
370 * to move it to a different queue, perhaps because a new window
371 * was created which now covers the screen area previously taken
372 * by another window. To move it, we need to take it out of the
373 * old queue. Note that we're already holding the lock mutexes of the
374 * old queue */
375 RemoveEntryList(&Message->ListEntry);
376
377 /* remove the pointer for the current WM_MOUSEMOVE message in case we
378 just removed it */
379 if(MessageQueue->MouseMoveMsg == Message)
380 {
381 MessageQueue->MouseMoveMsg = NULL;
382 }
383 }
384
385 /* lock the destination message queue, so we don't get in trouble with other
386 threads, messing with it at the same time */
387 IntLockHardwareMessageQueue(Window->MessageQueue);
388 InsertTailList(&Window->MessageQueue->HardwareMessagesListHead,
389 &Message->ListEntry);
390 if(Message->Msg.message == WM_MOUSEMOVE)
391 {
392 if(Window->MessageQueue->MouseMoveMsg)
393 {
394 /* remove the old WM_MOUSEMOVE message, we're processing a more recent
395 one */
396 RemoveEntryList(&Window->MessageQueue->MouseMoveMsg->ListEntry);
397 ExFreePool(Window->MessageQueue->MouseMoveMsg);
398 }
399 /* save the pointer to the WM_MOUSEMOVE message in the new queue */
400 Window->MessageQueue->MouseMoveMsg = Message;
401
402 Window->MessageQueue->QueueBits |= QS_MOUSEMOVE;
403 Window->MessageQueue->ChangedBits |= QS_MOUSEMOVE;
404 if (Window->MessageQueue->WakeMask & QS_MOUSEMOVE)
405 KeSetEvent(Window->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
406 }
407 else
408 {
409 Window->MessageQueue->QueueBits |= QS_MOUSEBUTTON;
410 Window->MessageQueue->ChangedBits |= QS_MOUSEBUTTON;
411 if (Window->MessageQueue->WakeMask & QS_MOUSEBUTTON)
412 KeSetEvent(Window->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
413 }
414 IntUnLockHardwareMessageQueue(Window->MessageQueue);
415
416 *Freed = FALSE;
417 UserDereferenceObject(Window);
418 return(FALSE);
419 }
420
421 /* From here on, we're in the same message queue as the caller! */
422
423 *ScreenPoint = Message->Msg.pt;
424
425 if((hWnd != NULL && Window->hSelf != hWnd) ||
426 ((FilterLow != 0 || FilterHigh != 0) && (Msg < FilterLow || Msg > FilterHigh)))
427 {
428 /* Reject the message because it doesn't match the filter */
429
430 if(FromGlobalQueue)
431 {
432 /* Lock the message queue so no other thread can mess with it.
433 Our own message queue is not locked while fetching from the global
434 queue, so we have to make sure nothing interferes! */
435 IntLockHardwareMessageQueue(Window->MessageQueue);
436 /* if we're from the global queue, we need to add our message to our
437 private queue so we don't loose it! */
438 InsertTailList(&Window->MessageQueue->HardwareMessagesListHead,
439 &Message->ListEntry);
440 }
441
442 if (Message->Msg.message == WM_MOUSEMOVE)
443 {
444 if(Window->MessageQueue->MouseMoveMsg &&
445 (Window->MessageQueue->MouseMoveMsg != Message))
446 {
447 /* delete the old message */
448 RemoveEntryList(&Window->MessageQueue->MouseMoveMsg->ListEntry);
449 ExFreePool(Window->MessageQueue->MouseMoveMsg);
450 if (!FromGlobalQueue)
451 {
452 // We might have deleted the next one in our queue, so fix next
453 *Next = Message->ListEntry.Flink;
454 }
455 }
456 /* always save a pointer to this WM_MOUSEMOVE message here because we're
457 sure that the message is in the private queue */
458 Window->MessageQueue->MouseMoveMsg = Message;
459 }
460 if(FromGlobalQueue)
461 {
462 IntUnLockHardwareMessageQueue(Window->MessageQueue);
463 }
464
465 UserDereferenceObject(Window);
466 *Freed = FALSE;
467 return(FALSE);
468 }
469
470 /* FIXME - only assign if removing? */
471 Message->Msg.hwnd = Window->hSelf;
472 Message->Msg.message = Msg;
473 Message->Msg.lParam = MAKELONG(Message->Msg.pt.x, Message->Msg.pt.y);
474
475 /* remove the reference to the current WM_(NC)MOUSEMOVE message, if this message
476 is it */
477 if (Message->Msg.message == WM_MOUSEMOVE ||
478 Message->Msg.message == WM_NCMOUSEMOVE)
479 {
480 if(FromGlobalQueue)
481 {
482 /* Lock the message queue so no other thread can mess with it.
483 Our own message queue is not locked while fetching from the global
484 queue, so we have to make sure nothing interferes! */
485 IntLockHardwareMessageQueue(Window->MessageQueue);
486 if(Window->MessageQueue->MouseMoveMsg)
487 {
488 /* delete the WM_(NC)MOUSEMOVE message in the private queue, we're dealing
489 with one that's been sent later */
490 RemoveEntryList(&Window->MessageQueue->MouseMoveMsg->ListEntry);
491 ExFreePool(Window->MessageQueue->MouseMoveMsg);
492 /* our message is not in the private queue so we can remove the pointer
493 instead of setting it to the current message we're processing */
494 Window->MessageQueue->MouseMoveMsg = NULL;
495 }
496 IntUnLockHardwareMessageQueue(Window->MessageQueue);
497 }
498 else if(Window->MessageQueue->MouseMoveMsg == Message)
499 {
500 Window->MessageQueue->MouseMoveMsg = NULL;
501 }
502 }
503
504 UserDereferenceObject(Window);
505 *Freed = FALSE;
506 return(TRUE);
507 }
508
509 BOOL STDCALL
510 co_MsqPeekHardwareMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND hWnd,
511 UINT FilterLow, UINT FilterHigh, BOOL Remove,
512 PUSER_MESSAGE* Message)
513 {
514 KIRQL OldIrql;
515 POINT ScreenPoint;
516 BOOL Accept, Freed;
517 PLIST_ENTRY CurrentEntry;
518 PWINDOW_OBJECT DesktopWindow = NULL;
519 PVOID WaitObjects[2];
520 NTSTATUS WaitStatus;
521 DECLARE_RETURN(BOOL);
522 USER_REFERENCE_ENTRY Ref;
523 PDESKTOPINFO Desk = NULL;
524
525 WaitObjects[1] = MessageQueue->NewMessages;
526 WaitObjects[0] = &HardwareMessageQueueLock;
527 do
528 {
529 IdlePing();
530
531 UserLeaveCo();
532
533 WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
534 UserMode, FALSE, NULL, NULL);
535
536 UserEnterCo();
537
538 while (co_MsqDispatchOneSentMessage(MessageQueue))
539 {
540 ;
541 }
542 }
543 while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
544
545 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
546
547 if (DesktopWindow)
548 {
549 UserRefObjectCo(DesktopWindow, &Ref);//can DesktopWindow be NULL?
550 Desk = DesktopWindow->ti->Desktop;
551 }
552
553 /* Process messages in the message queue itself. */
554 IntLockHardwareMessageQueue(MessageQueue);
555 CurrentEntry = MessageQueue->HardwareMessagesListHead.Flink;
556 while (CurrentEntry != &MessageQueue->HardwareMessagesListHead)
557 {
558 PUSER_MESSAGE Current =
559 CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
560 CurrentEntry = CurrentEntry->Flink;
561 if (Current->Msg.message >= WM_MOUSEFIRST &&
562 Current->Msg.message <= WM_MOUSELAST)
563 {
564
565
566 Accept = co_MsqTranslateMouseMessage(MessageQueue, hWnd, FilterLow, FilterHigh,
567 Current, Remove, &Freed,
568 DesktopWindow, &ScreenPoint, FALSE, &CurrentEntry);
569 if (Accept)
570 {
571 if (Remove)
572 {
573 RemoveEntryList(&Current->ListEntry);
574 }
575 IntUnLockHardwareMessageQueue(MessageQueue);
576 IntUnLockSystemHardwareMessageQueueLock(FALSE);
577 *Message = Current;
578
579 if (Desk)
580 Desk->LastInputWasKbd = FALSE;
581
582 RETURN(TRUE);
583 }
584
585 }
586 }
587 IntUnLockHardwareMessageQueue(MessageQueue);
588
589 /* Now try the global queue. */
590
591 /* Transfer all messages from the DPC accessible queue to the main queue. */
592 IntLockSystemMessageQueue(OldIrql);
593 while (SystemMessageQueueCount > 0)
594 {
595 PUSER_MESSAGE UserMsg;
596 MSG Msg;
597 BOOL ProcessMessage;
598
599 ASSERT(SystemMessageQueueHead < SYSTEM_MESSAGE_QUEUE_SIZE);
600 Msg = SystemMessageQueue[SystemMessageQueueHead];
601 SystemMessageQueueHead =
602 (SystemMessageQueueHead + 1) % SYSTEM_MESSAGE_QUEUE_SIZE;
603 SystemMessageQueueCount--;
604 IntUnLockSystemMessageQueue(OldIrql);
605 if (WM_MOUSEFIRST <= Msg.message && Msg.message <= WM_MOUSELAST)
606 {
607 MSLLHOOKSTRUCT MouseHookData;
608
609 MouseHookData.pt.x = LOWORD(Msg.lParam);
610 MouseHookData.pt.y = HIWORD(Msg.lParam);
611 switch(Msg.message)
612 {
613 case WM_MOUSEWHEEL:
614 MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg.wParam));
615 break;
616 case WM_XBUTTONDOWN:
617 case WM_XBUTTONUP:
618 case WM_XBUTTONDBLCLK:
619 case WM_NCXBUTTONDOWN:
620 case WM_NCXBUTTONUP:
621 case WM_NCXBUTTONDBLCLK:
622 MouseHookData.mouseData = MAKELONG(0, HIWORD(Msg.wParam));
623 break;
624 default:
625 MouseHookData.mouseData = 0;
626 break;
627 }
628 MouseHookData.flags = 0;
629 MouseHookData.time = Msg.time;
630 MouseHookData.dwExtraInfo = 0;
631 ProcessMessage = (0 == co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION,
632 Msg.message, (LPARAM) &MouseHookData));
633 }
634 else
635 {
636 ProcessMessage = TRUE;
637 }
638 if (ProcessMessage)
639 {
640 UserMsg = ExAllocateFromPagedLookasideList(&MessageLookasideList);
641 /* What to do if out of memory? For now we just panic a bit in debug */
642 ASSERT(UserMsg);
643 UserMsg->FreeLParam = FALSE;
644 UserMsg->Msg = Msg;
645 InsertTailList(&HardwareMessageQueueHead, &UserMsg->ListEntry);
646 }
647 IntLockSystemMessageQueue(OldIrql);
648 }
649 HardwareMessageQueueStamp++;
650 IntUnLockSystemMessageQueue(OldIrql);
651
652 /* Process messages in the queue until we find one to return. */
653 CurrentEntry = HardwareMessageQueueHead.Flink;
654 while (CurrentEntry != &HardwareMessageQueueHead)
655 {
656 PUSER_MESSAGE Current =
657 CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
658 CurrentEntry = CurrentEntry->Flink;
659 RemoveEntryList(&Current->ListEntry);
660 HardwareMessageQueueStamp++;
661 if (Current->Msg.message >= WM_MOUSEFIRST &&
662 Current->Msg.message <= WM_MOUSELAST)
663 {
664 const ULONG ActiveStamp = HardwareMessageQueueStamp;
665 /* Translate the message. */
666 Accept = co_MsqTranslateMouseMessage(MessageQueue, hWnd, FilterLow, FilterHigh,
667 Current, Remove, &Freed,
668 DesktopWindow, &ScreenPoint, TRUE, NULL);
669 if (Accept)
670 {
671 /* Check for no more messages in the system queue. */
672 IntLockSystemMessageQueue(OldIrql);
673 if (SystemMessageQueueCount == 0 &&
674 IsListEmpty(&HardwareMessageQueueHead))
675 {
676 KeClearEvent(&HardwareMessageEvent);
677 }
678 IntUnLockSystemMessageQueue(OldIrql);
679
680 /*
681 If we aren't removing the message then add it to the private
682 queue.
683 */
684 if (!Remove)
685 {
686 IntLockHardwareMessageQueue(MessageQueue);
687 if(Current->Msg.message == WM_MOUSEMOVE)
688 {
689 if(MessageQueue->MouseMoveMsg)
690 {
691 RemoveEntryList(&MessageQueue->MouseMoveMsg->ListEntry);
692 ExFreePool(MessageQueue->MouseMoveMsg);
693 }
694 MessageQueue->MouseMoveMsg = Current;
695 }
696 InsertTailList(&MessageQueue->HardwareMessagesListHead,
697 &Current->ListEntry);
698 IntUnLockHardwareMessageQueue(MessageQueue);
699 }
700 IntUnLockSystemHardwareMessageQueueLock(FALSE);
701 *Message = Current;
702
703 RETURN(TRUE);
704 }
705 /* If the contents of the queue changed then restart processing. */
706 if (HardwareMessageQueueStamp != ActiveStamp)
707 {
708 CurrentEntry = HardwareMessageQueueHead.Flink;
709 continue;
710 }
711 }
712 }
713
714 /* Check if the system message queue is now empty. */
715 IntLockSystemMessageQueue(OldIrql);
716 if (SystemMessageQueueCount == 0 && IsListEmpty(&HardwareMessageQueueHead))
717 {
718 KeClearEvent(&HardwareMessageEvent);
719 }
720 IntUnLockSystemMessageQueue(OldIrql);
721 IntUnLockSystemHardwareMessageQueueLock(FALSE);
722
723 RETURN(FALSE);
724
725 CLEANUP:
726 if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
727
728 END_CLEANUP;
729 }
730
731 //
732 // Note: Only called from input.c.
733 //
734 VOID FASTCALL
735 co_MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
736 {
737 PUSER_MESSAGE_QUEUE FocusMessageQueue;
738 MSG Msg;
739 LARGE_INTEGER LargeTickCount;
740 KBDLLHOOKSTRUCT KbdHookData;
741 EVENTMSG Event;
742
743 DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
744 uMsg, wParam, lParam);
745
746 // Condition may arise when calling MsqPostMessage and waiting for an event.
747 if (!UserIsEntered()) UserEnterExclusive(); // Fixme: Not sure ATM if this thread is locked.
748
749 FocusMessageQueue = IntGetFocusMessageQueue();
750
751 Msg.hwnd = 0;
752
753 if (FocusMessageQueue && (FocusMessageQueue->FocusWindow != (HWND)0))
754 Msg.hwnd = FocusMessageQueue->FocusWindow;
755
756 Msg.message = uMsg;
757 Msg.wParam = wParam;
758 Msg.lParam = lParam;
759
760 KeQueryTickCount(&LargeTickCount);
761 Msg.time = MsqCalculateMessageTime(&LargeTickCount);
762
763 Event.message = Msg.message;
764 Event.hwnd = Msg.hwnd;
765 Event.time = Msg.time;
766 Event.paramL = (Msg.wParam & 0xFF) | (HIWORD(Msg.lParam) << 8);
767 Event.paramH = Msg.lParam & 0x7FFF;
768 if (HIWORD(Msg.lParam) & 0x0100) Event.paramH |= 0x8000;
769 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
770
771 /* We can't get the Msg.pt point here since we don't know thread
772 (and thus the window station) the message will end up in yet. */
773
774 KbdHookData.vkCode = Msg.wParam;
775 KbdHookData.scanCode = (Msg.lParam >> 16) & 0xff;
776 KbdHookData.flags = (0 == (Msg.lParam & 0x01000000) ? 0 : LLKHF_EXTENDED) |
777 (0 == (Msg.lParam & 0x20000000) ? 0 : LLKHF_ALTDOWN) |
778 (0 == (Msg.lParam & 0x80000000) ? 0 : LLKHF_UP);
779 KbdHookData.time = Msg.time;
780 KbdHookData.dwExtraInfo = 0;
781 if (co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData))
782 {
783 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
784 Msg.message, Msg.wParam, Msg.lParam);
785 return;
786 }
787
788 if (FocusMessageQueue == NULL)
789 {
790 DPRINT("No focus message queue\n");
791 return;
792 }
793
794 if (FocusMessageQueue->FocusWindow != (HWND)0)
795 {
796 Msg.hwnd = FocusMessageQueue->FocusWindow;
797 DPRINT("Msg.hwnd = %x\n", Msg.hwnd);
798
799 FocusMessageQueue->Desktop->DesktopInfo->LastInputWasKbd = TRUE;
800
801 IntGetCursorLocation(FocusMessageQueue->Desktop->WindowStation,
802 &Msg.pt);
803 MsqPostMessage(FocusMessageQueue, &Msg, FALSE, QS_KEY);
804 }
805 else
806 {
807 DPRINT("Invalid focus window handle\n");
808 }
809 if (UserIsEntered()) UserLeave();
810 }
811
812 VOID FASTCALL
813 MsqPostHotKeyMessage(PVOID Thread, HWND hWnd, WPARAM wParam, LPARAM lParam)
814 {
815 PWINDOW_OBJECT Window;
816 PTHREADINFO Win32Thread;
817 PWINSTATION_OBJECT WinSta;
818 MSG Mesg;
819 LARGE_INTEGER LargeTickCount;
820 NTSTATUS Status;
821
822 Status = ObReferenceObjectByPointer (Thread,
823 THREAD_ALL_ACCESS,
824 PsThreadType,
825 KernelMode);
826 if (!NT_SUCCESS(Status))
827 return;
828
829 Win32Thread = ((PETHREAD)Thread)->Tcb.Win32Thread;
830 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
831 {
832 ObDereferenceObject ((PETHREAD)Thread);
833 return;
834 }
835
836 WinSta = Win32Thread->Desktop->WindowStation;
837 Window = IntGetWindowObject(hWnd);
838 if (!Window)
839 {
840 ObDereferenceObject ((PETHREAD)Thread);
841 return;
842 }
843
844 Mesg.hwnd = hWnd;
845 Mesg.message = WM_HOTKEY;
846 Mesg.wParam = wParam;
847 Mesg.lParam = lParam;
848 KeQueryTickCount(&LargeTickCount);
849 Mesg.time = MsqCalculateMessageTime(&LargeTickCount);
850 IntGetCursorLocation(WinSta, &Mesg.pt);
851 MsqPostMessage(Window->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
852 UserDereferenceObject(Window);
853 ObDereferenceObject (Thread);
854
855 // InsertHeadList(&pThread->MessageQueue->PostedMessagesListHead,
856 // &Message->ListEntry);
857 // KeSetEvent(pThread->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
858 }
859
860 PUSER_MESSAGE FASTCALL
861 MsqCreateMessage(LPMSG Msg, BOOLEAN FreeLParam)
862 {
863 PUSER_MESSAGE Message;
864
865 Message = ExAllocateFromPagedLookasideList(&MessageLookasideList);
866 if (!Message)
867 {
868 return NULL;
869 }
870
871 Message->FreeLParam = FreeLParam;
872 RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
873
874 return Message;
875 }
876
877 VOID FASTCALL
878 MsqDestroyMessage(PUSER_MESSAGE Message)
879 {
880 ExFreeToPagedLookasideList(&MessageLookasideList, Message);
881 }
882
883 VOID FASTCALL
884 co_MsqDispatchSentNotifyMessages(PUSER_MESSAGE_QUEUE MessageQueue)
885 {
886 PLIST_ENTRY ListEntry;
887 PUSER_SENT_MESSAGE_NOTIFY Message;
888
889 while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
890 {
891 ListEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
892 Message = CONTAINING_RECORD(ListEntry, USER_SENT_MESSAGE_NOTIFY,
893 ListEntry);
894
895 co_IntCallSentMessageCallback(Message->CompletionCallback,
896 Message->hWnd,
897 Message->Msg,
898 Message->CompletionCallbackContext,
899 Message->Result);
900
901 }
902
903 }
904
905 BOOLEAN FASTCALL
906 MsqPeekSentMessages(PUSER_MESSAGE_QUEUE MessageQueue)
907 {
908 return(!IsListEmpty(&MessageQueue->SentMessagesListHead));
909 }
910
911 BOOLEAN FASTCALL
912 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
913 {
914 PUSER_SENT_MESSAGE Message;
915 PLIST_ENTRY Entry;
916 LRESULT Result;
917 BOOL SenderReturned;
918 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage;
919
920 if (IsListEmpty(&MessageQueue->SentMessagesListHead))
921 {
922 return(FALSE);
923 }
924
925 /* remove it from the list of pending messages */
926 Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
927 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
928
929 /* insert it to the list of messages that are currently dispatched by this
930 message queue */
931 InsertTailList(&MessageQueue->LocalDispatchingMessagesHead,
932 &Message->ListEntry);
933
934 if (Message->HookMessage == MSQ_ISHOOK)
935 {
936 Result = co_HOOK_CallHooks(Message->Msg.message,
937 (INT)(INT_PTR)Message->Msg.hwnd,
938 Message->Msg.wParam,
939 Message->Msg.lParam);
940 }
941 else if (Message->HookMessage == MSQ_ISEVENT)
942 {
943 Result = co_EVENT_CallEvents( Message->Msg.message,
944 Message->Msg.hwnd,
945 (LONG) Message->Msg.wParam,
946 (LONG) Message->Msg.lParam);
947 }
948 else
949 {
950 /* Call the window procedure. */
951 Result = co_IntSendMessage(Message->Msg.hwnd,
952 Message->Msg.message,
953 Message->Msg.wParam,
954 Message->Msg.lParam);
955 }
956
957 /* remove the message from the local dispatching list, because it doesn't need
958 to be cleaned up on thread termination anymore */
959 RemoveEntryList(&Message->ListEntry);
960
961 /* remove the message from the dispatching list, so lock the sender's message queue */
962 SenderReturned = (Message->DispatchingListEntry.Flink == NULL);
963 if(!SenderReturned)
964 {
965 /* only remove it from the dispatching list if not already removed by a timeout */
966 RemoveEntryList(&Message->DispatchingListEntry);
967 }
968 /* still keep the sender's message queue locked, so the sender can't exit the
969 MsqSendMessage() function (if timed out) */
970
971 /* Let the sender know the result. */
972 if (Message->Result != NULL)
973 {
974 *Message->Result = Result;
975 }
976
977 /* Notify the sender. */
978 if (Message->CompletionEvent != NULL)
979 {
980 KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
981 }
982
983 /* Notify the sender if they specified a callback. */
984 if (!SenderReturned && Message->CompletionCallback != NULL)
985 {
986 if(!(NotifyMessage = ExAllocatePoolWithTag(NonPagedPool,
987 sizeof(USER_SENT_MESSAGE_NOTIFY), TAG_USRMSG)))
988 {
989 DPRINT1("MsqDispatchOneSentMessage(): Not enough memory to create a callback notify message\n");
990 goto Notified;
991 }
992 NotifyMessage->CompletionCallback =
993 Message->CompletionCallback;
994 NotifyMessage->CompletionCallbackContext =
995 Message->CompletionCallbackContext;
996 NotifyMessage->Result = Result;
997 NotifyMessage->hWnd = Message->Msg.hwnd;
998 NotifyMessage->Msg = Message->Msg.message;
999 MsqSendNotifyMessage(Message->SenderQueue, NotifyMessage);
1000 }
1001
1002 Notified:
1003
1004 /* dereference both sender and our queue */
1005 IntDereferenceMessageQueue(MessageQueue);
1006 IntDereferenceMessageQueue(Message->SenderQueue);
1007
1008 /* free the message */
1009 ExFreePool(Message);
1010 return(TRUE);
1011 }
1012
1013 VOID STDCALL
1014 MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
1015 {
1016 PUSER_SENT_MESSAGE SentMessage;
1017 PUSER_MESSAGE PostedMessage;
1018 PUSER_MESSAGE_QUEUE MessageQueue;
1019 PLIST_ENTRY CurrentEntry, ListHead;
1020 PWINDOW_OBJECT Window = pWindow;
1021
1022 ASSERT(Window);
1023
1024 MessageQueue = Window->MessageQueue;
1025 ASSERT(MessageQueue);
1026
1027 /* remove the posted messages for this window */
1028 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
1029 ListHead = &MessageQueue->PostedMessagesListHead;
1030 while (CurrentEntry != ListHead)
1031 {
1032 PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
1033 ListEntry);
1034 if (PostedMessage->Msg.hwnd == Window->hSelf)
1035 {
1036 RemoveEntryList(&PostedMessage->ListEntry);
1037 MsqDestroyMessage(PostedMessage);
1038 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
1039 }
1040 else
1041 {
1042 CurrentEntry = CurrentEntry->Flink;
1043 }
1044 }
1045
1046 /* remove the sent messages for this window */
1047 CurrentEntry = MessageQueue->SentMessagesListHead.Flink;
1048 ListHead = &MessageQueue->SentMessagesListHead;
1049 while (CurrentEntry != ListHead)
1050 {
1051 SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
1052 ListEntry);
1053 if(SentMessage->Msg.hwnd == Window->hSelf)
1054 {
1055 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1056
1057 RemoveEntryList(&SentMessage->ListEntry);
1058
1059 /* remove the message from the dispatching list */
1060 if(SentMessage->DispatchingListEntry.Flink != NULL)
1061 {
1062 RemoveEntryList(&SentMessage->DispatchingListEntry);
1063 }
1064
1065 /* wake the sender's thread */
1066 if (SentMessage->CompletionEvent != NULL)
1067 {
1068 KeSetEvent(SentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
1069 }
1070
1071 /* dereference our and the sender's message queue */
1072 IntDereferenceMessageQueue(MessageQueue);
1073 IntDereferenceMessageQueue(SentMessage->SenderQueue);
1074
1075 /* free the message */
1076 ExFreePool(SentMessage);
1077
1078 CurrentEntry = MessageQueue->SentMessagesListHead.Flink;
1079 }
1080 else
1081 {
1082 CurrentEntry = CurrentEntry->Flink;
1083 }
1084 }
1085 }
1086
1087 VOID FASTCALL
1088 MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue,
1089 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage)
1090 {
1091 InsertTailList(&MessageQueue->NotifyMessagesListHead,
1092 &NotifyMessage->ListEntry);
1093 MessageQueue->QueueBits |= QS_SENDMESSAGE;
1094 MessageQueue->ChangedBits |= QS_SENDMESSAGE;
1095 if (MessageQueue->WakeMask & QS_SENDMESSAGE)
1096 KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
1097 }
1098
1099 NTSTATUS FASTCALL
1100 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
1101 HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
1102 UINT uTimeout, BOOL Block, INT HookMessage,
1103 ULONG_PTR *uResult)
1104 {
1105 PTHREADINFO pti;
1106 PUSER_SENT_MESSAGE Message;
1107 KEVENT CompletionEvent;
1108 NTSTATUS WaitStatus;
1109 LRESULT Result;
1110 PUSER_MESSAGE_QUEUE ThreadQueue;
1111 LARGE_INTEGER Timeout;
1112 PLIST_ENTRY Entry;
1113
1114 if(!(Message = ExAllocatePoolWithTag(PagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
1115 {
1116 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1117 return STATUS_INSUFFICIENT_RESOURCES;
1118 }
1119
1120 KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE);
1121
1122 pti = PsGetCurrentThreadWin32Thread();
1123 ThreadQueue = pti->MessageQueue;
1124 ASSERT(ThreadQueue != MessageQueue);
1125
1126 Timeout.QuadPart = (LONGLONG) uTimeout * (LONGLONG) -10000;
1127
1128 /* FIXME - increase reference counter of sender's message queue here */
1129
1130 Result = 0;
1131 Message->Msg.hwnd = Wnd;
1132 Message->Msg.message = Msg;
1133 Message->Msg.wParam = wParam;
1134 Message->Msg.lParam = lParam;
1135 Message->CompletionEvent = &CompletionEvent;
1136 Message->Result = &Result;
1137 Message->SenderQueue = ThreadQueue;
1138 IntReferenceMessageQueue(ThreadQueue);
1139 Message->CompletionCallback = NULL;
1140 Message->HookMessage = HookMessage;
1141
1142 IntReferenceMessageQueue(MessageQueue);
1143
1144 /* add it to the list of pending messages */
1145 InsertTailList(&ThreadQueue->DispatchingMessagesHead, &Message->DispatchingListEntry);
1146
1147 /* queue it in the destination's message queue */
1148 InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry);
1149
1150 MessageQueue->QueueBits |= QS_SENDMESSAGE;
1151 MessageQueue->ChangedBits |= QS_SENDMESSAGE;
1152 if (MessageQueue->WakeMask & QS_SENDMESSAGE)
1153 KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
1154
1155 /* we can't access the Message anymore since it could have already been deleted! */
1156
1157 if(Block)
1158 {
1159 IdlePing();
1160
1161 UserLeaveCo();
1162
1163 /* don't process messages sent to the thread */
1164 WaitStatus = KeWaitForSingleObject(&CompletionEvent, UserRequest, UserMode,
1165 FALSE, (uTimeout ? &Timeout : NULL));
1166
1167 UserEnterCo();
1168
1169 if(WaitStatus == STATUS_TIMEOUT)
1170 {
1171 /* look up if the message has not yet dispatched, if so
1172 make sure it can't pass a result and it must not set the completion event anymore */
1173 Entry = MessageQueue->SentMessagesListHead.Flink;
1174 while (Entry != &MessageQueue->SentMessagesListHead)
1175 {
1176 if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
1177 == Message)
1178 {
1179 /* we can access Message here, it's secure because the message queue is locked
1180 and the message is still hasn't been dispatched */
1181 Message->CompletionEvent = NULL;
1182 Message->Result = NULL;
1183 break;
1184 }
1185 Entry = Entry->Flink;
1186 }
1187
1188 /* remove from the local dispatching list so the other thread knows,
1189 it can't pass a result and it must not set the completion event anymore */
1190 Entry = ThreadQueue->DispatchingMessagesHead.Flink;
1191 while (Entry != &ThreadQueue->DispatchingMessagesHead)
1192 {
1193 if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
1194 == Message)
1195 {
1196 /* we can access Message here, it's secure because the sender's message is locked
1197 and the message has definitely not yet been destroyed, otherwise it would
1198 have been removed from this list by the dispatching routine right after
1199 dispatching the message */
1200 Message->CompletionEvent = NULL;
1201 Message->Result = NULL;
1202 RemoveEntryList(&Message->DispatchingListEntry);
1203 Message->DispatchingListEntry.Flink = NULL;
1204 break;
1205 }
1206 Entry = Entry->Flink;
1207 }
1208
1209 DPRINT("MsqSendMessage (blocked) timed out\n");
1210 }
1211 while (co_MsqDispatchOneSentMessage(ThreadQueue))
1212 ;
1213 }
1214 else
1215 {
1216 PVOID WaitObjects[2];
1217
1218 WaitObjects[0] = &CompletionEvent;
1219 WaitObjects[1] = ThreadQueue->NewMessages;
1220 do
1221 {
1222 IdlePing();
1223
1224 UserLeaveCo();
1225
1226 WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
1227 UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL);
1228
1229 UserEnterCo();
1230
1231 if(WaitStatus == STATUS_TIMEOUT)
1232 {
1233 /* look up if the message has not yet been dispatched, if so
1234 make sure it can't pass a result and it must not set the completion event anymore */
1235 Entry = MessageQueue->SentMessagesListHead.Flink;
1236 while (Entry != &MessageQueue->SentMessagesListHead)
1237 {
1238 if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
1239 == Message)
1240 {
1241 /* we can access Message here, it's secure because the message queue is locked
1242 and the message is still hasn't been dispatched */
1243 Message->CompletionEvent = NULL;
1244 Message->Result = NULL;
1245 break;
1246 }
1247 Entry = Entry->Flink;
1248 }
1249
1250 /* remove from the local dispatching list so the other thread knows,
1251 it can't pass a result and it must not set the completion event anymore */
1252 Entry = ThreadQueue->DispatchingMessagesHead.Flink;
1253 while (Entry != &ThreadQueue->DispatchingMessagesHead)
1254 {
1255 if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
1256 == Message)
1257 {
1258 /* we can access Message here, it's secure because the sender's message is locked
1259 and the message has definitely not yet been destroyed, otherwise it would
1260 have been removed from this list by the dispatching routine right after
1261 dispatching the message */
1262 Message->CompletionEvent = NULL;
1263 Message->Result = NULL;
1264 RemoveEntryList(&Message->DispatchingListEntry);
1265 Message->DispatchingListEntry.Flink = NULL;
1266 break;
1267 }
1268 Entry = Entry->Flink;
1269 }
1270
1271 DPRINT("MsqSendMessage timed out\n");
1272 break;
1273 }
1274 while (co_MsqDispatchOneSentMessage(ThreadQueue))
1275 ;
1276 }
1277 while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
1278 }
1279
1280 if(WaitStatus != STATUS_TIMEOUT)
1281 *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1);
1282
1283 return WaitStatus;
1284 }
1285
1286 VOID FASTCALL
1287 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg, BOOLEAN FreeLParam,
1288 DWORD MessageBits)
1289 {
1290 PUSER_MESSAGE Message;
1291
1292 if(!(Message = MsqCreateMessage(Msg, FreeLParam)))
1293 {
1294 return;
1295 }
1296 InsertTailList(&MessageQueue->PostedMessagesListHead,
1297 &Message->ListEntry);
1298 MessageQueue->QueueBits |= MessageBits;
1299 MessageQueue->ChangedBits |= MessageBits;
1300 if (MessageQueue->WakeMask & MessageBits)
1301 KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
1302 }
1303
1304 VOID FASTCALL
1305 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode)
1306 {
1307 MessageQueue->QuitPosted = TRUE;
1308 MessageQueue->QuitExitCode = ExitCode;
1309 MessageQueue->QueueBits |= QS_POSTMESSAGE;
1310 MessageQueue->ChangedBits |= QS_POSTMESSAGE;
1311 if (MessageQueue->WakeMask & QS_POSTMESSAGE)
1312 KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
1313 }
1314
1315 BOOLEAN STDCALL
1316 co_MsqFindMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
1317 IN BOOLEAN Hardware,
1318 IN BOOLEAN Remove,
1319 IN HWND Wnd,
1320 IN UINT MsgFilterLow,
1321 IN UINT MsgFilterHigh,
1322 OUT PUSER_MESSAGE* Message)
1323 {
1324 PLIST_ENTRY CurrentEntry;
1325 PUSER_MESSAGE CurrentMessage;
1326 PLIST_ENTRY ListHead;
1327
1328 if (Hardware)
1329 {
1330 return(co_MsqPeekHardwareMessage(MessageQueue, Wnd,
1331 MsgFilterLow, MsgFilterHigh,
1332 Remove, Message));
1333 }
1334
1335 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
1336 ListHead = &MessageQueue->PostedMessagesListHead;
1337 while (CurrentEntry != ListHead)
1338 {
1339 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
1340 ListEntry);
1341 if ((Wnd == 0 || Wnd == CurrentMessage->Msg.hwnd) &&
1342 ((MsgFilterLow == 0 && MsgFilterHigh == 0) ||
1343 (MsgFilterLow <= CurrentMessage->Msg.message &&
1344 MsgFilterHigh >= CurrentMessage->Msg.message)))
1345 {
1346 if (Remove)
1347 {
1348 RemoveEntryList(&CurrentMessage->ListEntry);
1349 }
1350
1351 *Message = CurrentMessage;
1352 return(TRUE);
1353 }
1354 CurrentEntry = CurrentEntry->Flink;
1355 }
1356
1357 return(FALSE);
1358 }
1359
1360 NTSTATUS FASTCALL
1361 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, HWND WndFilter,
1362 UINT MsgFilterMin, UINT MsgFilterMax)
1363 {
1364 PVOID WaitObjects[2] = {MessageQueue->NewMessages, &HardwareMessageEvent};
1365 LARGE_INTEGER TimerExpiry;
1366 PLARGE_INTEGER Timeout;
1367 NTSTATUS ret;
1368
1369 if (MsqGetFirstTimerExpiry(MessageQueue, WndFilter, MsgFilterMin, MsgFilterMax, &TimerExpiry))
1370 {
1371 Timeout = &TimerExpiry;
1372 }
1373 else
1374 {
1375 Timeout = NULL;
1376 }
1377
1378 IdlePing(); // Going to wait so send Idle ping.
1379
1380 UserLeaveCo();
1381
1382 ret = KeWaitForMultipleObjects(2,
1383 WaitObjects,
1384 WaitAny,
1385 Executive,
1386 UserMode,
1387 FALSE,
1388 Timeout,
1389 NULL);
1390
1391 UserEnterCo();
1392
1393 return ret;
1394 }
1395
1396 BOOL FASTCALL
1397 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue)
1398 {
1399 LARGE_INTEGER LargeTickCount;
1400
1401 KeQueryTickCount(&LargeTickCount);
1402 return ((LargeTickCount.u.LowPart - MessageQueue->LastMsgRead) > MSQ_HUNG);
1403 }
1404
1405 BOOLEAN FASTCALL
1406 MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQueue)
1407 {
1408 LARGE_INTEGER LargeTickCount;
1409 NTSTATUS Status;
1410
1411 MessageQueue->Thread = Thread;
1412 MessageQueue->CaretInfo = (PTHRDCARETINFO)(MessageQueue + 1);
1413 InitializeListHead(&MessageQueue->PostedMessagesListHead);
1414 InitializeListHead(&MessageQueue->SentMessagesListHead);
1415 InitializeListHead(&MessageQueue->HardwareMessagesListHead);
1416 InitializeListHead(&MessageQueue->TimerListHead);
1417 InitializeListHead(&MessageQueue->DispatchingMessagesHead);
1418 InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead);
1419 KeInitializeMutex(&MessageQueue->HardwareLock, 0);
1420 MessageQueue->QuitPosted = FALSE;
1421 MessageQueue->QuitExitCode = 0;
1422 KeQueryTickCount(&LargeTickCount);
1423 MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
1424 MessageQueue->FocusWindow = NULL;
1425 MessageQueue->PaintCount = 0;
1426 MessageQueue->WakeMask = ~0;
1427 MessageQueue->NewMessagesHandle = NULL;
1428
1429 Status = ZwCreateEvent(&MessageQueue->NewMessagesHandle, EVENT_ALL_ACCESS,
1430 NULL, SynchronizationEvent, FALSE);
1431 if (!NT_SUCCESS(Status))
1432 {
1433 return FALSE;
1434 }
1435
1436 Status = ObReferenceObjectByHandle(MessageQueue->NewMessagesHandle, 0,
1437 ExEventObjectType, KernelMode,
1438 (PVOID*)&MessageQueue->NewMessages, NULL);
1439 if (!NT_SUCCESS(Status))
1440 {
1441 ZwClose(MessageQueue->NewMessagesHandle);
1442 MessageQueue->NewMessagesHandle = NULL;
1443 return FALSE;
1444 }
1445
1446 return TRUE;
1447 }
1448
1449 VOID FASTCALL
1450 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
1451 {
1452 PLIST_ENTRY CurrentEntry;
1453 PUSER_MESSAGE CurrentMessage;
1454 PTIMER_ENTRY CurrentTimer;
1455 PUSER_SENT_MESSAGE CurrentSentMessage;
1456
1457 /* cleanup posted messages */
1458 while (!IsListEmpty(&MessageQueue->PostedMessagesListHead))
1459 {
1460 CurrentEntry = RemoveHeadList(&MessageQueue->PostedMessagesListHead);
1461 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
1462 ListEntry);
1463 MsqDestroyMessage(CurrentMessage);
1464 }
1465
1466 /* remove the messages that have not yet been dispatched */
1467 while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
1468 {
1469 CurrentEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
1470 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
1471 ListEntry);
1472
1473 DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
1474
1475 /* remove the message from the dispatching list */
1476 if(CurrentSentMessage->DispatchingListEntry.Flink != NULL)
1477 {
1478 RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
1479 }
1480
1481 /* wake the sender's thread */
1482 if (CurrentSentMessage->CompletionEvent != NULL)
1483 {
1484 KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
1485 }
1486
1487 /* dereference our and the sender's message queue */
1488 IntDereferenceMessageQueue(MessageQueue);
1489 IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);
1490
1491 /* free the message */
1492 ExFreePool(CurrentSentMessage);
1493 }
1494
1495 /* cleanup timers */
1496 while (! IsListEmpty(&MessageQueue->TimerListHead))
1497 {
1498 CurrentEntry = RemoveHeadList(&MessageQueue->TimerListHead);
1499 CurrentTimer = CONTAINING_RECORD(CurrentEntry, TIMER_ENTRY, ListEntry);
1500 ExFreeToPagedLookasideList(&TimerLookasideList, CurrentTimer);
1501 }
1502
1503 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
1504 ExitThread() was called in a SendMessage() umode callback */
1505 while (!IsListEmpty(&MessageQueue->LocalDispatchingMessagesHead))
1506 {
1507 CurrentEntry = RemoveHeadList(&MessageQueue->LocalDispatchingMessagesHead);
1508 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
1509 ListEntry);
1510
1511 /* remove the message from the dispatching list */
1512 if(CurrentSentMessage->DispatchingListEntry.Flink != NULL)
1513 {
1514 RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
1515 }
1516
1517 DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
1518
1519 /* wake the sender's thread */
1520 if (CurrentSentMessage->CompletionEvent != NULL)
1521 {
1522 KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
1523 }
1524
1525 /* dereference our and the sender's message queue */
1526 IntDereferenceMessageQueue(MessageQueue);
1527 IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);
1528
1529 /* free the message */
1530 ExFreePool(CurrentSentMessage);
1531 }
1532
1533 /* tell other threads not to bother returning any info to us */
1534 while (! IsListEmpty(&MessageQueue->DispatchingMessagesHead))
1535 {
1536 CurrentEntry = RemoveHeadList(&MessageQueue->DispatchingMessagesHead);
1537 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
1538 DispatchingListEntry);
1539 CurrentSentMessage->CompletionEvent = NULL;
1540 CurrentSentMessage->Result = NULL;
1541
1542 /* do NOT dereference our message queue as it might get attempted to be
1543 locked later */
1544 }
1545
1546 }
1547
1548 PUSER_MESSAGE_QUEUE FASTCALL
1549 MsqCreateMessageQueue(struct _ETHREAD *Thread)
1550 {
1551 PUSER_MESSAGE_QUEUE MessageQueue;
1552
1553 MessageQueue = (PUSER_MESSAGE_QUEUE)ExAllocatePoolWithTag(PagedPool,
1554 sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO),
1555 TAG_MSGQ);
1556
1557 if (!MessageQueue)
1558 {
1559 return NULL;
1560 }
1561
1562 RtlZeroMemory(MessageQueue, sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO));
1563 /* hold at least one reference until it'll be destroyed */
1564 IntReferenceMessageQueue(MessageQueue);
1565 /* initialize the queue */
1566 if (!MsqInitializeMessageQueue(Thread, MessageQueue))
1567 {
1568 IntDereferenceMessageQueue(MessageQueue);
1569 return NULL;
1570 }
1571
1572 return MessageQueue;
1573 }
1574
1575 VOID FASTCALL
1576 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
1577 {
1578 PDESKTOP_OBJECT desk;
1579
1580 /* remove the message queue from any desktops */
1581 if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0)))
1582 {
1583 (void)InterlockedExchangePointer((PVOID*)&desk->ActiveMessageQueue, 0);
1584 IntDereferenceMessageQueue(MessageQueue);
1585 }
1586
1587 /* clean it up */
1588 MsqCleanupMessageQueue(MessageQueue);
1589
1590 /* decrease the reference counter, if it hits zero, the queue will be freed */
1591 IntDereferenceMessageQueue(MessageQueue);
1592 }
1593
1594 PHOOKTABLE FASTCALL
1595 MsqGetHooks(PUSER_MESSAGE_QUEUE Queue)
1596 {
1597 return Queue->Hooks;
1598 }
1599
1600 VOID FASTCALL
1601 MsqSetHooks(PUSER_MESSAGE_QUEUE Queue, PHOOKTABLE Hooks)
1602 {
1603 Queue->Hooks = Hooks;
1604 }
1605
1606 LPARAM FASTCALL
1607 MsqSetMessageExtraInfo(LPARAM lParam)
1608 {
1609 LPARAM Ret;
1610 PTHREADINFO pti;
1611 PUSER_MESSAGE_QUEUE MessageQueue;
1612
1613 pti = PsGetCurrentThreadWin32Thread();
1614 MessageQueue = pti->MessageQueue;
1615 if(!MessageQueue)
1616 {
1617 return 0;
1618 }
1619
1620 Ret = MessageQueue->ExtraInfo;
1621 MessageQueue->ExtraInfo = lParam;
1622
1623 return Ret;
1624 }
1625
1626 LPARAM FASTCALL
1627 MsqGetMessageExtraInfo(VOID)
1628 {
1629 PTHREADINFO pti;
1630 PUSER_MESSAGE_QUEUE MessageQueue;
1631
1632 pti = PsGetCurrentThreadWin32Thread();
1633 MessageQueue = pti->MessageQueue;
1634 if(!MessageQueue)
1635 {
1636 return 0;
1637 }
1638
1639 return MessageQueue->ExtraInfo;
1640 }
1641
1642 HWND FASTCALL
1643 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd)
1644 {
1645 HWND Prev;
1646
1647 switch(Type)
1648 {
1649 case MSQ_STATE_CAPTURE:
1650 Prev = MessageQueue->CaptureWindow;
1651 MessageQueue->CaptureWindow = hWnd;
1652 return Prev;
1653 case MSQ_STATE_ACTIVE:
1654 Prev = MessageQueue->ActiveWindow;
1655 MessageQueue->ActiveWindow = hWnd;
1656 return Prev;
1657 case MSQ_STATE_FOCUS:
1658 Prev = MessageQueue->FocusWindow;
1659 MessageQueue->FocusWindow = hWnd;
1660 return Prev;
1661 case MSQ_STATE_MENUOWNER:
1662 Prev = MessageQueue->MenuOwner;
1663 MessageQueue->MenuOwner = hWnd;
1664 return Prev;
1665 case MSQ_STATE_MOVESIZE:
1666 Prev = MessageQueue->MoveSize;
1667 MessageQueue->MoveSize = hWnd;
1668 return Prev;
1669 case MSQ_STATE_CARET:
1670 ASSERT(MessageQueue->CaretInfo);
1671 Prev = MessageQueue->CaretInfo->hWnd;
1672 MessageQueue->CaretInfo->hWnd = hWnd;
1673 return Prev;
1674 }
1675
1676 return NULL;
1677 }
1678
1679 #ifndef NDEBUG
1680 static VOID FASTCALL
1681 DumpTimerList(PUSER_MESSAGE_QUEUE MessageQueue)
1682 {
1683 PLIST_ENTRY Current;
1684 PTIMER_ENTRY Timer;
1685
1686 Current = MessageQueue->TimerListHead.Flink;
1687 if (Current == &MessageQueue->TimerListHead)
1688 {
1689 DPRINT("timer list is empty for queue %p\n", MessageQueue);
1690 }
1691 while (Current != &MessageQueue->TimerListHead)
1692 {
1693 Timer = CONTAINING_RECORD(Current, TIMER_ENTRY, ListEntry);
1694 DPRINT("queue %p timer %p expiry %I64d wnd %x id %p period %u timerproc %p msg %u\n",
1695 MessageQueue, Timer, Timer->ExpiryTime.QuadPart, Timer->Wnd, Timer->IDEvent,
1696 Timer->Period, Timer->TimerFunc, Timer->Msg);
1697 Current = Current->Flink;
1698 }
1699 }
1700 #endif /* ! defined(NDEBUG) */
1701
1702 /* Must have the message queue locked while calling this */
1703 static VOID FASTCALL
1704 InsertTimer(PUSER_MESSAGE_QUEUE MessageQueue, PTIMER_ENTRY NewTimer)
1705 {
1706 PLIST_ENTRY Current;
1707
1708 Current = MessageQueue->TimerListHead.Flink;
1709 while (Current != &MessageQueue->TimerListHead)
1710 {
1711 if (NewTimer->ExpiryTime.QuadPart <
1712 CONTAINING_RECORD(Current, TIMER_ENTRY, ListEntry)->ExpiryTime.QuadPart)
1713 {
1714 break;
1715 }
1716 Current = Current->Flink;
1717 }
1718
1719 InsertTailList(Current, &NewTimer->ListEntry);
1720 }
1721
1722 /* Must have the message queue locked while calling this */
1723 static PTIMER_ENTRY FASTCALL
1724 RemoveTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd, UINT_PTR IDEvent, UINT Msg)
1725 {
1726 PTIMER_ENTRY Timer;
1727 PLIST_ENTRY EnumEntry;
1728
1729 /* Remove timer if already in the queue */
1730 EnumEntry = MessageQueue->TimerListHead.Flink;
1731 while (EnumEntry != &MessageQueue->TimerListHead)
1732 {
1733 Timer = CONTAINING_RECORD(EnumEntry, TIMER_ENTRY, ListEntry);
1734 EnumEntry = EnumEntry->Flink;
1735
1736 if (Timer->Wnd == Wnd &&
1737 Timer->IDEvent == IDEvent &&
1738 Timer->Msg == Msg)
1739 {
1740 RemoveEntryList(&Timer->ListEntry);
1741 return Timer;
1742 }
1743 }
1744
1745 return NULL;
1746 }
1747
1748 BOOLEAN FASTCALL
1749 MsqSetTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd,
1750 UINT_PTR IDEvent, UINT Period, TIMERPROC TimerFunc,
1751 UINT Msg)
1752 {
1753 PTIMER_ENTRY Timer;
1754 LARGE_INTEGER CurrentTime;
1755
1756 DPRINT("MsqSetTimer queue %p wnd %x id %p period %u timerproc %p msg %d\n",
1757 MessageQueue, Wnd, IDEvent, Period, TimerFunc, Msg);
1758
1759 Timer = RemoveTimer(MessageQueue, Wnd, IDEvent, Msg);
1760 if (NULL == Timer)
1761 {
1762 Timer = ExAllocateFromPagedLookasideList(&TimerLookasideList);
1763 if (NULL == Timer)
1764 {
1765 DPRINT1("Failed to allocate timer entry\n");
1766 return FALSE;
1767 }
1768 DPRINT("Allocated new timer entry %p\n", Timer);
1769 Timer->Wnd = Wnd;
1770 Timer->IDEvent = IDEvent;
1771 Timer->Msg = Msg;
1772 }
1773 else
1774 {
1775 DPRINT("Updating existing timer entry %p\n", Timer);
1776 }
1777
1778 KeQuerySystemTime(&CurrentTime);
1779 Timer->ExpiryTime.QuadPart = CurrentTime.QuadPart +
1780 (ULONGLONG) Period * (ULONGLONG) 10000;
1781 Timer->Period = Period;
1782 Timer->TimerFunc = TimerFunc;
1783 DPRINT("Insert timer now %I64d expiry %I64d\n", CurrentTime.QuadPart,
1784 Timer->ExpiryTime.QuadPart);
1785
1786 InsertTimer(MessageQueue, Timer);
1787
1788 #ifndef NDEBUG
1789
1790 DumpTimerList(MessageQueue);
1791 #endif /* ! defined(NDEBUG) */
1792
1793 return TRUE;
1794 }
1795
1796 BOOLEAN FASTCALL
1797 MsqKillTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd,
1798 UINT_PTR IDEvent, UINT Msg)
1799 {
1800 PTIMER_ENTRY Timer;
1801
1802 DPRINT("MsqKillTimer queue %p wnd %x id %p msg %d\n",
1803 MessageQueue, Wnd, IDEvent, Msg);
1804
1805 Timer = RemoveTimer(MessageQueue, Wnd, IDEvent, Msg);
1806
1807 if (NULL == Timer)
1808 {
1809 DPRINT("Failed to remove timer from list, not found\n");
1810 }
1811 else
1812 {
1813 ExFreeToPagedLookasideList(&TimerLookasideList, Timer);
1814 }
1815
1816 #ifndef NDEBUG
1817 DumpTimerList(MessageQueue);
1818 #endif /* ! defined(NDEBUG) */
1819
1820 return NULL != Timer;
1821 }
1822
1823 BOOLEAN FASTCALL
1824 MsqGetTimerMessage(PUSER_MESSAGE_QUEUE MessageQueue,
1825 HWND WndFilter, UINT MsgFilterMin, UINT MsgFilterMax,
1826 MSG *Msg, BOOLEAN Restart)
1827 {
1828 PTIMER_ENTRY Timer;
1829 LARGE_INTEGER CurrentTime;
1830 LARGE_INTEGER LargeTickCount;
1831 PLIST_ENTRY EnumEntry;
1832 BOOLEAN GotMessage;
1833 PTHREADINFO pti;
1834
1835 DPRINT("MsqGetTimerMessage queue %p msg %p restart %s\n",
1836 MessageQueue, Msg, Restart ? "TRUE" : "FALSE");
1837
1838 KeQuerySystemTime(&CurrentTime);
1839 DPRINT("Current time %I64d\n", CurrentTime.QuadPart);
1840 EnumEntry = MessageQueue->TimerListHead.Flink;
1841 GotMessage = FALSE;
1842 while (EnumEntry != &MessageQueue->TimerListHead)
1843 {
1844 Timer = CONTAINING_RECORD(MessageQueue->TimerListHead.Flink,
1845 TIMER_ENTRY, ListEntry);
1846 DPRINT("Checking timer %p wnd %x expiry %I64d\n", Timer, Timer->Wnd,
1847 Timer->ExpiryTime.QuadPart);
1848 EnumEntry = EnumEntry->Flink;
1849 if ((NULL == WndFilter || Timer->Wnd == WndFilter) &&
1850 ((MsgFilterMin == 0 && MsgFilterMax == 0) ||
1851 (MsgFilterMin <= Timer->Msg &&
1852 Timer->Msg <= MsgFilterMax)))
1853 {
1854 if (Timer->ExpiryTime.QuadPart <= CurrentTime.QuadPart)
1855 {
1856 DPRINT("Timer is expired\n");
1857 GotMessage = TRUE;
1858 break;
1859 }
1860 else
1861 {
1862 DPRINT("No need to check later timers\n");
1863 break;
1864 }
1865 }
1866 else
1867 {
1868 DPRINT("timer %p (wnd %x msg %d) failed filter wnd %x msgmin %d msgmax %d\n",
1869 Timer, Timer->Wnd, Timer->Msg, WndFilter, MsgFilterMin, MsgFilterMax);
1870 }
1871 }
1872
1873 if (! GotMessage)
1874 {
1875 DPRINT("No timer pending\n");
1876 return FALSE;
1877 }
1878
1879 Msg->hwnd = Timer->Wnd;
1880 Msg->message = Timer->Msg;
1881 Msg->wParam = (WPARAM) Timer->IDEvent;
1882 Msg->lParam = (LPARAM) Timer->TimerFunc;
1883 KeQueryTickCount(&LargeTickCount);
1884 Msg->time = MsqCalculateMessageTime(&LargeTickCount);
1885 pti = PsGetCurrentThreadWin32Thread();
1886 IntGetCursorLocation(pti->Desktop->WindowStation,
1887 &Msg->pt);
1888
1889 if (Restart)
1890 {
1891 RemoveEntryList(&Timer->ListEntry);
1892 Timer->ExpiryTime.QuadPart = CurrentTime.QuadPart +
1893 (ULONGLONG) Timer->Period * (ULONGLONG) 10000;
1894 DPRINT("Restarting timer %p expires %I64d\n", Timer, Timer->ExpiryTime.QuadPart);
1895 InsertTimer(MessageQueue, Timer);
1896
1897 #ifndef NDEBUG
1898
1899 DumpTimerList(MessageQueue);
1900 #endif /* ! defined(NDEBUG) */
1901
1902 }
1903
1904 DPRINT("Created message wnd %x msg %d wParam %u lParam %u\n", Msg->hwnd, Msg->message,
1905 Msg->wParam, Msg->lParam);
1906
1907 return TRUE;
1908 }
1909
1910 VOID FASTCALL
1911 MsqRemoveTimersWindow(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd)
1912 {
1913 PTIMER_ENTRY Timer;
1914 PLIST_ENTRY EnumEntry;
1915
1916 DPRINT("MsqRemoveTimersWindow queue %p wnd %x\n", MessageQueue, Wnd);
1917
1918 EnumEntry = MessageQueue->TimerListHead.Flink;
1919 while (EnumEntry != &MessageQueue->TimerListHead)
1920 {
1921 Timer = CONTAINING_RECORD(EnumEntry, TIMER_ENTRY, ListEntry);
1922 EnumEntry = EnumEntry->Flink;
1923 if (Timer->Wnd == Wnd)
1924 {
1925 DPRINT("Removing timer %p because its window is going away\n", Timer);
1926 RemoveEntryList(&Timer->ListEntry);
1927 ExFreeToPagedLookasideList(&TimerLookasideList, Timer);
1928 }
1929 }
1930
1931 #ifndef NDEBUG
1932 DumpTimerList(MessageQueue);
1933 #endif /* ! defined(NDEBUG) */
1934
1935 }
1936
1937 BOOLEAN FASTCALL
1938 MsqGetFirstTimerExpiry(PUSER_MESSAGE_QUEUE MessageQueue,
1939 HWND WndFilter, UINT MsgFilterMin, UINT MsgFilterMax,
1940 PLARGE_INTEGER FirstTimerExpiry)
1941 {
1942 PTIMER_ENTRY Timer;
1943 PLIST_ENTRY EnumEntry;
1944
1945 DPRINT("MsqGetFirstTimerExpiry queue %p wndfilter %x msgfiltermin %d msgfiltermax %d expiry %p\n",
1946 MessageQueue, WndFilter, MsgFilterMin, MsgFilterMax, FirstTimerExpiry);
1947
1948 EnumEntry = MessageQueue->TimerListHead.Flink;
1949 while (EnumEntry != &MessageQueue->TimerListHead)
1950 {
1951 Timer = CONTAINING_RECORD(MessageQueue->TimerListHead.Flink,
1952 TIMER_ENTRY, ListEntry);
1953 EnumEntry = EnumEntry->Flink;
1954 if ((NULL == WndFilter || Timer->Wnd == WndFilter) &&
1955 ((MsgFilterMin == 0 && MsgFilterMax == 0) ||
1956 (MsgFilterMin <= Timer->Msg &&
1957 Timer->Msg <= MsgFilterMax)))
1958 {
1959 *FirstTimerExpiry = Timer->ExpiryTime;
1960 DPRINT("First timer expires %I64d\n", Timer->ExpiryTime);
1961 return TRUE;
1962 }
1963 }
1964
1965 return FALSE;
1966 }
1967
1968 /* EOF */