update for HEAD-2003091401
[reactos.git] / subsys / 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 <ddk/ntddk.h>
33 #include <win32k/win32k.h>
34 #include <include/msgqueue.h>
35 #include <include/callback.h>
36 #include <include/window.h>
37 #include <include/winpos.h>
38 #include <include/class.h>
39
40 #define NDEBUG
41 #include <debug.h>
42
43 /* GLOBALS *******************************************************************/
44
45 #define SYSTEM_MESSAGE_QUEUE_SIZE           (256)
46
47 static MSG SystemMessageQueue[SYSTEM_MESSAGE_QUEUE_SIZE];
48 static ULONG SystemMessageQueueHead = 0;
49 static ULONG SystemMessageQueueTail = 0;
50 static ULONG SystemMessageQueueCount = 0;
51 static ULONG SystemMessageQueueMouseMove = -1;
52 static KSPIN_LOCK SystemMessageQueueLock;
53
54 static ULONG HardwareMessageQueueStamp = 0;
55 static LIST_ENTRY HardwareMessageQueueHead;
56 static FAST_MUTEX HardwareMessageQueueLock;
57
58 static KEVENT HardwareMessageEvent;
59
60 static PAGED_LOOKASIDE_LIST MessageLookasideList;
61
62 /* FUNCTIONS *****************************************************************/
63
64 /* check the queue status */
65 inline BOOL MsqIsSignaled( PUSER_MESSAGE_QUEUE Queue )
66 {
67     return ((Queue->WakeBits & Queue->WakeMask) || (Queue->ChangedBits & Queue->ChangedMask));
68 }
69
70 /* set some queue bits */
71 inline VOID MsqSetQueueBits( PUSER_MESSAGE_QUEUE Queue, WORD Bits )
72 {
73     Queue->WakeBits |= Bits;
74     Queue->ChangedBits |= Bits;
75     if (MsqIsSignaled( Queue )) KeSetEvent(&Queue->NewMessages, IO_NO_INCREMENT, FALSE);
76 }
77
78 /* clear some queue bits */
79 inline VOID MsqClearQueueBits( PUSER_MESSAGE_QUEUE Queue, WORD Bits )
80 {
81     Queue->WakeBits &= ~Bits;
82     Queue->ChangedBits &= ~Bits;
83 }
84
85 VOID FASTCALL
86 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
87 {
88   ExAcquireFastMutex(&Queue->Lock);
89   Queue->PaintCount++;
90   Queue->PaintPosted = TRUE;
91   KeSetEvent(&Queue->NewMessages, IO_NO_INCREMENT, FALSE);
92   ExReleaseFastMutex(&Queue->Lock);
93 }
94
95 VOID FASTCALL
96 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
97 {
98   ExAcquireFastMutex(&Queue->Lock);
99   Queue->PaintCount--;
100   if (Queue->PaintCount == 0)
101     {
102       Queue->PaintPosted = FALSE;
103     }
104   ExReleaseFastMutex(&Queue->Lock);
105 }
106
107
108 NTSTATUS FASTCALL
109 MsqInitializeImpl(VOID)
110 {
111   /*CurrentFocusMessageQueue = NULL;*/
112   InitializeListHead(&HardwareMessageQueueHead);
113   KeInitializeEvent(&HardwareMessageEvent, NotificationEvent, 0);
114   KeInitializeSpinLock(&SystemMessageQueueLock);
115   ExInitializeFastMutex(&HardwareMessageQueueLock);
116
117   ExInitializePagedLookasideList(&MessageLookasideList,
118                                  NULL,
119                                  NULL,
120                                  0,
121                                  sizeof(USER_MESSAGE),
122                                  0,
123                                  256);
124
125   return(STATUS_SUCCESS);
126 }
127
128 VOID FASTCALL
129 MsqInsertSystemMessage(MSG* Msg, BOOL RemMouseMoveMsg)
130 {
131   KIRQL OldIrql;
132   ULONG mmov = (ULONG)-1;
133
134   KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
135
136   /* only insert WM_MOUSEMOVE messages if not already in system message queue */
137   if((Msg->message == WM_MOUSEMOVE) && RemMouseMoveMsg)
138     mmov = SystemMessageQueueMouseMove;
139
140   if(mmov != (ULONG)-1)
141   {
142     /* insert message at the queue head */
143     while (mmov != SystemMessageQueueHead )
144     {
145       ULONG prev = mmov ? mmov - 1 : SYSTEM_MESSAGE_QUEUE_SIZE - 1;
146       SystemMessageQueue[mmov] = SystemMessageQueue[prev];
147       mmov = prev;
148     }
149     SystemMessageQueue[SystemMessageQueueHead] = *Msg;
150   }
151   else
152   {
153     if (SystemMessageQueueCount == SYSTEM_MESSAGE_QUEUE_SIZE)
154     {
155       KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
156       return;
157     }
158     SystemMessageQueue[SystemMessageQueueTail] = *Msg;
159     if(Msg->message == WM_MOUSEMOVE)
160       SystemMessageQueueMouseMove = SystemMessageQueueTail;
161     SystemMessageQueueTail =
162       (SystemMessageQueueTail + 1) % SYSTEM_MESSAGE_QUEUE_SIZE;
163     SystemMessageQueueCount++;
164   }
165   KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
166   KeSetEvent(&HardwareMessageEvent, IO_NO_INCREMENT, FALSE);
167 }
168
169 BOOL STATIC STDCALL
170 MsqTranslateMouseMessage(HWND hWnd, UINT FilterLow, UINT FilterHigh,
171                          PUSER_MESSAGE Message, BOOL Remove,
172                          PWINDOW_OBJECT ScopeWin, PUSHORT HitTest,
173                          PPOINT ScreenPoint, PBOOL MouseClick)
174 {
175   USHORT Msg = Message->Msg.message;
176   PWINDOW_OBJECT Window;
177   POINT Point;
178
179   if ((Window = IntGetCaptureWindow()) == NULL)
180   {
181     *HitTest = WinPosWindowFromPoint(ScopeWin, Message->Msg.pt, &Window);
182   }
183   else
184   {
185     *HitTest = HTCLIENT;
186   }
187
188   if (Window == NULL)
189   {
190     ExFreePool(Message);
191     return(FALSE);
192   }
193   if (Window->MessageQueue != PsGetWin32Thread()->MessageQueue)
194   {
195     ExAcquireFastMutex(&Window->MessageQueue->Lock);
196     InsertTailList(&Window->MessageQueue->HardwareMessagesListHead,
197                    &Message->ListEntry);
198     ExReleaseFastMutex(&Window->MessageQueue->Lock);
199     KeSetEvent(&Window->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
200     return(FALSE);
201   }
202
203   if (hWnd != NULL && Window->Self != hWnd &&
204       !IntIsChildWindow(hWnd, Window->Self))
205   {
206     return(FALSE);
207   }
208
209   if (Msg == WM_LBUTTONDBLCLK || Msg == WM_RBUTTONDBLCLK || Msg == WM_MBUTTONDBLCLK)
210   {
211     if (((*HitTest) != HTCLIENT) || !(IntGetClassLong(Window, GCL_STYLE, FALSE) & CS_DBLCLKS))
212         {
213       Msg -= (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
214       /* FIXME set WindowStation's system cursor variables:
215                LastBtnDown to Msg.time
216       */
217         }
218         else
219         {
220           /* FIXME check if the dblclick was made in the same window, if
221                    not, change it to a normal click message */
222         }
223   }
224
225   *ScreenPoint = Message->Msg.pt;
226   Point = Message->Msg.pt;
227
228   if ((*HitTest) != HTCLIENT)
229   {
230     Msg += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
231     Message->Msg.wParam = *HitTest;
232   }
233   else
234   {
235     Point.x -= Window->ClientRect.left;
236     Point.y -= Window->ClientRect.top;
237   }
238
239   /* FIXME: Check message filter. */
240
241   if (Remove)
242     {
243       Message->Msg.hwnd = Window->Self;
244       Message->Msg.message = Msg;
245       Message->Msg.lParam = MAKELONG(Point.x, Point.y);
246     }
247
248   return(TRUE);
249 }
250
251 BOOL STDCALL
252 MsqPeekHardwareMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND hWnd,
253                        UINT FilterLow, UINT FilterHigh, BOOL Remove,
254                        PUSER_MESSAGE* Message)
255 {
256   KIRQL OldIrql;
257   USHORT HitTest;
258   POINT ScreenPoint;
259   BOOL Accept;
260   BOOL MouseClick;
261   PLIST_ENTRY CurrentEntry;
262   ULONG ActiveStamp;
263   PWINDOW_OBJECT DesktopWindow;
264
265   DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
266
267   /* Process messages in the message queue itself. */
268   ExAcquireFastMutex(&MessageQueue->Lock);
269   CurrentEntry = MessageQueue->HardwareMessagesListHead.Flink;
270   while (CurrentEntry != &MessageQueue->HardwareMessagesListHead)
271     {
272       PUSER_MESSAGE Current =
273         CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
274       CurrentEntry = CurrentEntry->Flink;
275       if (Current->Msg.message >= WM_MOUSEFIRST &&
276           Current->Msg.message <= WM_MOUSELAST)
277         {
278           Accept = MsqTranslateMouseMessage(hWnd, FilterLow, FilterHigh,
279                                             Current, Remove,
280                                             DesktopWindow, &HitTest,
281                                             &ScreenPoint, &MouseClick);
282           if (Accept)
283             {
284               if (Remove)
285                 {
286                   RemoveEntryList(&Current->ListEntry);
287                 }
288               ExReleaseFastMutex(&MessageQueue->Lock);
289               *Message = Current;
290               IntReleaseWindowObject(DesktopWindow);
291               return(TRUE);
292             }
293         }
294     }
295   ExReleaseFastMutex(&MessageQueue->Lock);
296
297   /* Now try the global queue. */
298   ExAcquireFastMutex(&HardwareMessageQueueLock);
299   /* Transfer all messages from the DPC accessible queue to the main queue. */
300   KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
301   while (SystemMessageQueueCount > 0)
302     {
303       PUSER_MESSAGE UserMsg;
304       MSG Msg;
305
306       Msg = SystemMessageQueue[SystemMessageQueueHead];
307       SystemMessageQueueHead =
308         (SystemMessageQueueHead + 1) % SYSTEM_MESSAGE_QUEUE_SIZE;
309       SystemMessageQueueCount--;
310       KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
311       UserMsg = ExAllocateFromPagedLookasideList(&MessageLookasideList);
312       UserMsg->Msg = Msg;
313       InsertTailList(&HardwareMessageQueueHead, &UserMsg->ListEntry);
314       KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
315     }
316   /*
317    * we could set this to -1 conditionally if we find one, but
318    * this is more efficient and just as effective.
319    */
320   SystemMessageQueueMouseMove = -1;
321   KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
322   HardwareMessageQueueStamp++;
323
324   /* Process messages in the queue until we find one to return. */
325   CurrentEntry = HardwareMessageQueueHead.Flink;
326   while (CurrentEntry != &HardwareMessageQueueHead)
327     {
328       PUSER_MESSAGE Current =
329         CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
330       CurrentEntry = CurrentEntry->Flink;
331       RemoveEntryList(&Current->ListEntry);
332       if (Current->Msg.message >= WM_MOUSEFIRST &&
333           Current->Msg.message <= WM_MOUSELAST)
334         {
335           ActiveStamp = HardwareMessageQueueStamp;
336           ExReleaseFastMutex(&HardwareMessageQueueLock);
337           /* Translate the message. */
338           Accept = MsqTranslateMouseMessage(hWnd, FilterLow, FilterHigh,
339                                             Current, Remove,
340                                             DesktopWindow, &HitTest,
341                                             &ScreenPoint, &MouseClick);
342           ExAcquireFastMutex(&HardwareMessageQueueLock);
343           if (Accept)
344             {
345               /* Check for no more messages in the system queue. */
346               KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
347               if (SystemMessageQueueCount == 0 &&
348                   IsListEmpty(&HardwareMessageQueueHead))
349                 {
350                   KeClearEvent(&HardwareMessageEvent);
351                 }
352               KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
353
354               /*
355                  If we aren't removing the message then add it to the private
356                  queue.
357               */
358               if (!Remove)
359                 {
360                   InsertTailList(&MessageQueue->HardwareMessagesListHead,
361                                  &Current->ListEntry);
362                 }
363               ExReleaseFastMutex(&HardwareMessageQueueLock);
364               *Message = Current;
365               IntReleaseWindowObject(DesktopWindow);
366               return(TRUE);
367             }
368           /* If the contents of the queue changed then restart processing. */
369           if (HardwareMessageQueueStamp != ActiveStamp)
370             {
371               CurrentEntry = HardwareMessageQueueHead.Flink;
372               continue;
373             }
374         }
375     }
376   /* Check if the system message queue is now empty. */
377   KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
378   if (SystemMessageQueueCount == 0 && IsListEmpty(&HardwareMessageQueueHead))
379     {
380       KeClearEvent(&HardwareMessageEvent);
381     }
382   KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
383   ExReleaseFastMutex(&HardwareMessageQueueLock);
384
385   return(FALSE);
386 }
387
388 VOID STDCALL
389 MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
390 {
391   PUSER_MESSAGE_QUEUE FocusMessageQueue;
392   PUSER_MESSAGE Message;
393   MSG Msg;
394
395   DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
396     uMsg, wParam, lParam);
397
398   FocusMessageQueue = IntGetFocusMessageQueue();
399   if (FocusMessageQueue == NULL)
400     {
401       DPRINT("No focus message queue\n");
402       return;
403     }
404
405   if (FocusMessageQueue->FocusWindow != (HWND)0)
406     {
407       Msg.hwnd = FocusMessageQueue->FocusWindow;
408       Msg.message = uMsg;
409       Msg.wParam = wParam;
410       Msg.lParam = lParam;
411       /* FIXME: Initialize time and point. */
412
413       Message = MsqCreateMessage(&Msg);
414       MsqPostMessage(FocusMessageQueue, Message);
415     }
416   else
417     {
418       DPRINT("Invalid focus window handle\n");
419     }
420 }
421
422 VOID FASTCALL
423 MsqInitializeMessage(PUSER_MESSAGE Message,
424                      LPMSG Msg)
425 {
426   RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
427 }
428
429 PUSER_MESSAGE FASTCALL
430 MsqCreateMessage(LPMSG Msg)
431 {
432   PUSER_MESSAGE Message;
433
434   Message = ExAllocateFromPagedLookasideList(&MessageLookasideList);
435   if (!Message)
436     {
437       return NULL;
438     }
439
440   MsqInitializeMessage(Message, Msg);
441
442   return Message;
443 }
444
445 VOID FASTCALL
446 MsqDestroyMessage(PUSER_MESSAGE Message)
447 {
448   ExFreeToPagedLookasideList(&MessageLookasideList, Message);
449 }
450
451 VOID FASTCALL
452 MsqDispatchSentNotifyMessages(PUSER_MESSAGE_QUEUE MessageQueue)
453 {
454   PLIST_ENTRY ListEntry;
455   PUSER_SENT_MESSAGE_NOTIFY Message;
456
457   while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
458   {
459     ExAcquireFastMutex(&MessageQueue->Lock);
460     ListEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
461     Message = CONTAINING_RECORD(ListEntry, USER_SENT_MESSAGE_NOTIFY,
462                                 ListEntry);
463     ExReleaseFastMutex(&MessageQueue->Lock);
464
465     IntCallSentMessageCallback(Message->CompletionCallback,
466                                 Message->hWnd,
467                                 Message->Msg,
468                                 Message->CompletionCallbackContext,
469                                 Message->Result);
470   }
471 }
472
473 BOOLEAN FASTCALL
474 MsqPeekSentMessages(PUSER_MESSAGE_QUEUE MessageQueue)
475 {
476   return(!IsListEmpty(&MessageQueue->SentMessagesListHead));
477 }
478
479 BOOLEAN FASTCALL
480 MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
481 {
482   PUSER_SENT_MESSAGE Message;
483   PLIST_ENTRY Entry;
484   LRESULT Result;
485   PUSER_SENT_MESSAGE_NOTIFY NotifyMessage;
486
487   ExAcquireFastMutex(&MessageQueue->Lock);
488   if (IsListEmpty(&MessageQueue->SentMessagesListHead))
489     {
490       ExReleaseFastMutex(&MessageQueue->Lock);
491       return(FALSE);
492     }
493   Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
494   Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
495   ExReleaseFastMutex(&MessageQueue->Lock);
496
497   /* Call the window procedure. */
498   Result = IntCallWindowProc(NULL,
499                               Message->Msg.hwnd,
500                               Message->Msg.message,
501                               Message->Msg.wParam,
502                               Message->Msg.lParam);
503
504   /* Let the sender know the result. */
505   if (Message->Result != NULL)
506     {
507       *Message->Result = Result;
508     }
509
510   /* Notify the sender. */
511   if (Message->CompletionEvent != NULL)
512     {
513       KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
514     }
515
516   /* Notify the sender if they specified a callback. */
517   if (Message->CompletionCallback != NULL)
518     {
519       NotifyMessage = ExAllocatePool(NonPagedPool,
520                                      sizeof(USER_SENT_MESSAGE_NOTIFY));
521       NotifyMessage->CompletionCallback =
522         Message->CompletionCallback;
523       NotifyMessage->CompletionCallbackContext =
524         Message->CompletionCallbackContext;
525       NotifyMessage->Result = Result;
526       NotifyMessage->hWnd = Message->Msg.hwnd;
527       NotifyMessage->Msg = Message->Msg.message;
528       MsqSendNotifyMessage(Message->CompletionQueue, NotifyMessage);
529     }
530
531   ExFreePool(Message);
532   return(TRUE);
533 }
534
535 VOID FASTCALL
536 MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue,
537                      PUSER_SENT_MESSAGE_NOTIFY NotifyMessage)
538 {
539   ExAcquireFastMutex(&MessageQueue->Lock);
540   InsertTailList(&MessageQueue->NotifyMessagesListHead,
541                  &NotifyMessage->ListEntry);
542   KeSetEvent(&MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
543   ExReleaseFastMutex(&MessageQueue->Lock);
544 }
545
546 VOID FASTCALL
547 MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
548                PUSER_SENT_MESSAGE Message)
549 {
550   ExAcquireFastMutex(&MessageQueue->Lock);
551   InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry);
552   KeSetEvent(&MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
553   ExReleaseFastMutex(&MessageQueue->Lock);
554 }
555
556 VOID FASTCALL
557 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue, PUSER_MESSAGE Message)
558 {
559   ExAcquireFastMutex(&MessageQueue->Lock);
560   InsertTailList(&MessageQueue->PostedMessagesListHead,
561                  &Message->ListEntry);
562   KeSetEvent(&MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
563   ExReleaseFastMutex(&MessageQueue->Lock);
564 }
565
566 VOID FASTCALL
567 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode)
568 {
569   ExAcquireFastMutex(&MessageQueue->Lock);
570   MessageQueue->QuitPosted = TRUE;
571   MessageQueue->QuitExitCode = ExitCode;
572   KeSetEvent(&MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
573   ExReleaseFastMutex(&MessageQueue->Lock);
574 }
575
576 BOOLEAN STDCALL
577 MsqFindMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
578                IN BOOLEAN Hardware,
579                IN BOOLEAN Remove,
580                IN HWND Wnd,
581                IN UINT MsgFilterLow,
582                IN UINT MsgFilterHigh,
583                OUT PUSER_MESSAGE* Message)
584 {
585   PLIST_ENTRY CurrentEntry;
586   PUSER_MESSAGE CurrentMessage;
587   PLIST_ENTRY ListHead;
588
589   if (Hardware)
590     {
591       return(MsqPeekHardwareMessage(MessageQueue, Wnd,
592                                     MsgFilterLow, MsgFilterHigh,
593                                     Remove, Message));
594     }
595
596   ExAcquireFastMutex(&MessageQueue->Lock);
597   CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
598   ListHead = &MessageQueue->PostedMessagesListHead;
599   while (CurrentEntry != ListHead)
600     {
601       CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
602                                          ListEntry);
603       if ((Wnd == 0 || Wnd == CurrentMessage->Msg.hwnd) &&
604           ((MsgFilterLow == 0 && MsgFilterHigh == 0) ||
605            (MsgFilterLow <= CurrentMessage->Msg.message &&
606             MsgFilterHigh >= CurrentMessage->Msg.message)))
607         {
608           if (Remove)
609             {
610               RemoveEntryList(&CurrentMessage->ListEntry);
611             }
612           ExReleaseFastMutex(&MessageQueue->Lock);
613           *Message = CurrentMessage;
614           return(TRUE);
615         }
616       CurrentEntry = CurrentEntry->Flink;
617     }
618   ExReleaseFastMutex(&MessageQueue->Lock);
619   return(FALSE);
620 }
621
622 NTSTATUS FASTCALL
623 MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue)
624 {
625   PVOID WaitObjects[2] = {&MessageQueue->NewMessages, &HardwareMessageEvent};
626   return(KeWaitForMultipleObjects(2,
627                                   WaitObjects,
628                                   WaitAny,
629                                   Executive,
630                                   UserMode,
631                                   TRUE,
632                                   NULL,
633                                   NULL));
634 }
635
636 VOID FASTCALL
637 MsqInitializeMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
638 {
639   InitializeListHead(&MessageQueue->PostedMessagesListHead);
640   InitializeListHead(&MessageQueue->SentMessagesListHead);
641   InitializeListHead(&MessageQueue->HardwareMessagesListHead);
642   ExInitializeFastMutex(&MessageQueue->Lock);
643   MessageQueue->QuitPosted = FALSE;
644   MessageQueue->QuitExitCode = 0;
645   KeInitializeEvent(&MessageQueue->NewMessages, SynchronizationEvent, FALSE);
646   MessageQueue->QueueStatus = 0;
647   MessageQueue->FocusWindow = NULL;
648 }
649
650 VOID FASTCALL
651 MsqFreeMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
652 {
653   PLIST_ENTRY CurrentEntry;
654   PUSER_MESSAGE CurrentMessage;
655
656   CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
657   while (CurrentEntry != &MessageQueue->PostedMessagesListHead)
658     {
659       CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
660                                          ListEntry);
661       CurrentEntry = CurrentEntry->Flink;
662       MsqDestroyMessage(CurrentMessage);
663     }
664 }
665
666 PUSER_MESSAGE_QUEUE FASTCALL
667 MsqCreateMessageQueue(VOID)
668 {
669   PUSER_MESSAGE_QUEUE MessageQueue;
670
671   MessageQueue = (PUSER_MESSAGE_QUEUE)ExAllocatePool(PagedPool,
672                                    sizeof(USER_MESSAGE_QUEUE));
673   if (!MessageQueue)
674     {
675       return NULL;
676     }
677
678   MsqInitializeMessageQueue(MessageQueue);
679
680   return MessageQueue;
681 }
682
683 VOID FASTCALL
684 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
685 {
686   MsqFreeMessageQueue(MessageQueue);
687   ExFreePool(MessageQueue);
688 }
689
690 /* EOF */