Fixed Filesystem documentation.
[wine] / windows / queue.c
1 /* * Message queues related functions
2  *
3  * Copyright 1993, 1994 Alexandre Julliard
4  */
5
6 #include <stdlib.h>
7 #include <signal.h>
8 #include "wine/winbase16.h"
9 #include "wine/winuser16.h"
10 #include "miscemu.h"
11 #include "module.h"
12 #include "queue.h"
13 #include "task.h"
14 #include "win.h"
15 #include "clipboard.h"
16 #include "hook.h"
17 #include "heap.h"
18 #include "thread.h"
19 #include "process.h"
20 #include <assert.h>
21 #include "debug.h"
22 #include "spy.h"
23
24 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
25
26 static HQUEUE16 hFirstQueue = 0;
27 static HQUEUE16 hExitingQueue = 0;
28 static HQUEUE16 hmemSysMsgQueue = 0;
29 static MESSAGEQUEUE *sysMsgQueue = NULL;
30 static PERQUEUEDATA *pQDataWin16 = NULL;  /* Global perQData for Win16 tasks */
31
32 static MESSAGEQUEUE *pMouseQueue = NULL;  /* Queue for last mouse message */
33 static MESSAGEQUEUE *pKbdQueue = NULL;    /* Queue for last kbd message */
34
35 HQUEUE16 hCursorQueue = 0;
36 HQUEUE16 hActiveQueue = 0;
37
38
39 /***********************************************************************
40  *           PERQDATA_CreateInstance
41  *
42  * Creates an instance of a reference counted PERQUEUEDATA element
43  * for the message queue. perQData is stored globally for 16 bit tasks.
44  *
45  * Note: We don't implement perQdata exactly the same way Windows does.
46  * Each perQData element is reference counted since it may be potentially
47  * shared by multiple message Queues (via AttachThreadInput).
48  * We only store the current values for Active, Capture and focus windows
49  * currently.
50  */
51 PERQUEUEDATA * PERQDATA_CreateInstance( )
52 {
53     PERQUEUEDATA *pQData;
54     
55     BOOL16 bIsWin16 = 0;
56     
57     TRACE(msg,"()\n");
58
59     /* Share a single instance of perQData for all 16 bit tasks */
60     if ( ( bIsWin16 = THREAD_IsWin16( THREAD_Current() ) ) )
61     {
62         /* If previously allocated, just bump up ref count */
63         if ( pQDataWin16 )
64         {
65             PERQDATA_Addref( pQDataWin16 );
66             return pQDataWin16;
67         }
68     }
69
70     /* Allocate PERQUEUEDATA from the system heap */
71     if (!( pQData = (PERQUEUEDATA *) HeapAlloc( SystemHeap, 0,
72                                                     sizeof(PERQUEUEDATA) ) ))
73         return 0;
74
75     /* Initialize */
76     pQData->hWndCapture = pQData->hWndFocus = pQData->hWndActive = 0;
77     pQData->ulRefCount = 1;
78     pQData->nCaptureHT = HTCLIENT;
79
80     /* Note: We have an independent critical section for the per queue data
81      * since this may be shared by different threads. see AttachThreadInput()
82      */
83     InitializeCriticalSection( &pQData->cSection );
84
85     /* Save perQData globally for 16 bit tasks */
86     if ( bIsWin16 )
87         pQDataWin16 = pQData;
88         
89     return pQData;
90 }
91
92
93 /***********************************************************************
94  *           PERQDATA_Addref
95  *
96  * Increment reference count for the PERQUEUEDATA instance
97  * Returns reference count for debugging purposes
98  */
99 ULONG PERQDATA_Addref( PERQUEUEDATA *pQData )
100 {
101     assert(pQData != 0 );
102     TRACE(msg,"(): current refcount %lu ...\n", pQData->ulRefCount);
103
104     EnterCriticalSection( &pQData->cSection );
105     ++pQData->ulRefCount;
106     LeaveCriticalSection( &pQData->cSection );
107
108     return pQData->ulRefCount;
109 }
110
111
112 /***********************************************************************
113  *           PERQDATA_Release
114  *
115  * Release a reference to a PERQUEUEDATA instance.
116  * Destroy the instance if no more references exist
117  * Returns reference count for debugging purposes
118  */
119 ULONG PERQDATA_Release( PERQUEUEDATA *pQData )
120 {
121     assert(pQData != 0 );
122     TRACE(msg,"(): current refcount %lu ...\n",
123           (LONG)pQData->ulRefCount );
124
125     EnterCriticalSection( &pQData->cSection );
126     if ( --pQData->ulRefCount == 0 )
127     {
128         LeaveCriticalSection( &pQData->cSection );
129         DeleteCriticalSection( &pQData->cSection );
130
131         TRACE(msg,"(): deleting PERQUEUEDATA instance ...\n" );
132
133         /* Deleting our global 16 bit perQData? */
134         if ( pQData == pQDataWin16 )
135             pQDataWin16 = 0;
136             
137         /* Free the PERQUEUEDATA instance */
138         HeapFree( SystemHeap, 0, pQData );
139
140         return 0;
141     }
142     LeaveCriticalSection( &pQData->cSection );
143
144     return pQData->ulRefCount;
145 }
146
147
148 /***********************************************************************
149  *           PERQDATA_GetFocusWnd
150  *
151  * Get the focus hwnd member in a threadsafe manner
152  */
153 HWND PERQDATA_GetFocusWnd( PERQUEUEDATA *pQData )
154 {
155     HWND hWndFocus;
156     assert(pQData != 0 );
157
158     EnterCriticalSection( &pQData->cSection );
159     hWndFocus = pQData->hWndFocus;
160     LeaveCriticalSection( &pQData->cSection );
161
162     return hWndFocus;
163 }
164
165
166 /***********************************************************************
167  *           PERQDATA_SetFocusWnd
168  *
169  * Set the focus hwnd member in a threadsafe manner
170  */
171 HWND PERQDATA_SetFocusWnd( PERQUEUEDATA *pQData, HWND hWndFocus )
172 {
173     HWND hWndFocusPrv;
174     assert(pQData != 0 );
175
176     EnterCriticalSection( &pQData->cSection );
177     hWndFocusPrv = pQData->hWndFocus;
178     pQData->hWndFocus = hWndFocus;
179     LeaveCriticalSection( &pQData->cSection );
180
181     return hWndFocusPrv;
182 }
183
184
185 /***********************************************************************
186  *           PERQDATA_GetActiveWnd
187  *
188  * Get the active hwnd member in a threadsafe manner
189  */
190 HWND PERQDATA_GetActiveWnd( PERQUEUEDATA *pQData )
191 {
192     HWND hWndActive;
193     assert(pQData != 0 );
194
195     EnterCriticalSection( &pQData->cSection );
196     hWndActive = pQData->hWndActive;
197     LeaveCriticalSection( &pQData->cSection );
198
199     return hWndActive;
200 }
201
202
203 /***********************************************************************
204  *           PERQDATA_SetActiveWnd
205  *
206  * Set the active focus hwnd member in a threadsafe manner
207  */
208 HWND PERQDATA_SetActiveWnd( PERQUEUEDATA *pQData, HWND hWndActive )
209 {
210     HWND hWndActivePrv;
211     assert(pQData != 0 );
212
213     EnterCriticalSection( &pQData->cSection );
214     hWndActivePrv = pQData->hWndActive;
215     pQData->hWndActive = hWndActive;
216     LeaveCriticalSection( &pQData->cSection );
217
218     return hWndActivePrv;
219 }
220
221
222 /***********************************************************************
223  *           PERQDATA_GetCaptureWnd
224  *
225  * Get the capture hwnd member in a threadsafe manner
226  */
227 HWND PERQDATA_GetCaptureWnd( PERQUEUEDATA *pQData )
228 {
229     HWND hWndCapture;
230     assert(pQData != 0 );
231
232     EnterCriticalSection( &pQData->cSection );
233     hWndCapture = pQData->hWndCapture;
234     LeaveCriticalSection( &pQData->cSection );
235
236     return hWndCapture;
237 }
238
239
240 /***********************************************************************
241  *           PERQDATA_SetCaptureWnd
242  *
243  * Set the capture hwnd member in a threadsafe manner
244  */
245 HWND PERQDATA_SetCaptureWnd( PERQUEUEDATA *pQData, HWND hWndCapture )
246 {
247     HWND hWndCapturePrv;
248     assert(pQData != 0 );
249
250     EnterCriticalSection( &pQData->cSection );
251     hWndCapturePrv = pQData->hWndCapture;
252     pQData->hWndCapture = hWndCapture;
253     LeaveCriticalSection( &pQData->cSection );
254
255     return hWndCapturePrv;
256 }
257
258
259 /***********************************************************************
260  *           PERQDATA_GetCaptureInfo
261  *
262  * Get the capture info member in a threadsafe manner
263  */
264 INT16 PERQDATA_GetCaptureInfo( PERQUEUEDATA *pQData )
265 {
266     INT16 nCaptureHT;
267     assert(pQData != 0 );
268
269     EnterCriticalSection( &pQData->cSection );
270     nCaptureHT = pQData->nCaptureHT;
271     LeaveCriticalSection( &pQData->cSection );
272
273     return nCaptureHT;
274 }
275
276
277 /***********************************************************************
278  *           PERQDATA_SetCaptureInfo
279  *
280  * Set the capture info member in a threadsafe manner
281  */
282 INT16 PERQDATA_SetCaptureInfo( PERQUEUEDATA *pQData, INT16 nCaptureHT )
283 {
284     INT16 nCaptureHTPrv;
285     assert(pQData != 0 );
286
287     EnterCriticalSection( &pQData->cSection );
288     nCaptureHTPrv = pQData->nCaptureHT;
289     pQData->nCaptureHT = nCaptureHT;
290     LeaveCriticalSection( &pQData->cSection );
291
292     return nCaptureHTPrv;
293 }
294
295
296 /***********************************************************************
297  *           QUEUE_Lock
298  *
299  * Function for getting a 32 bit pointer on queue strcture. For thread
300  * safeness programmers should use this function instead of GlobalLock to
301  * retrieve a pointer on the structure. QUEUE_Unlock should also be called
302  * when access to the queue structure is not required anymore.
303  */
304 MESSAGEQUEUE *QUEUE_Lock( HQUEUE16 hQueue )
305 {
306     MESSAGEQUEUE *queue;
307
308     SYSTEM_LOCK();
309     queue = GlobalLock16( hQueue );
310     if ( !queue || (queue->magic != QUEUE_MAGIC) )
311     {
312         SYSTEM_UNLOCK();
313         return NULL;
314     }
315
316     queue->lockCount++;
317     SYSTEM_UNLOCK();
318
319     return queue;
320 }
321
322
323 /***********************************************************************
324  *           QUEUE_Unlock
325  *
326  * Use with QUEUE_Lock to get a thread safe acces to message queue
327  * structure
328  */
329 void QUEUE_Unlock( MESSAGEQUEUE *queue )
330 {
331     if (queue)
332     {
333         SYSTEM_LOCK();
334
335         if ( --queue->lockCount == 0 )
336         {
337             DeleteCriticalSection ( &queue->cSection );
338             if (queue->hEvent)
339                 CloseHandle( queue->hEvent );
340             GlobalFree16( queue->self );
341         }
342     
343         SYSTEM_UNLOCK();
344     }
345 }
346
347
348 /***********************************************************************
349  *           QUEUE_DumpQueue
350  */
351 void QUEUE_DumpQueue( HQUEUE16 hQueue )
352 {
353     MESSAGEQUEUE *pq; 
354
355     if (!(pq = (MESSAGEQUEUE*) QUEUE_Lock( hQueue )) )
356     {
357         WARN(msg, "%04x is not a queue handle\n", hQueue );
358         return;
359     }
360
361     DUMP(    "next: %12.4x  Intertask SendMessage:\n"
362              "thread: %10p  ----------------------\n"
363              "firstMsg: %8p   smWaiting:     %10p\n"
364              "lastMsg:  %8p   smPending:     %10p\n"
365              "msgCount: %8.4x   smProcessing:  %10p\n"
366              "lockCount: %7.4x\n"
367              "wWinVer: %9.4x\n"
368              "paints: %10.4x\n"
369              "timers: %10.4x\n"
370              "wakeBits: %8.4x\n"
371              "wakeMask: %8.4x\n"
372              "hCurHook: %8.4x\n",
373              pq->next, pq->thdb, pq->firstMsg, pq->smWaiting, pq->lastMsg,
374              pq->smPending, pq->msgCount, pq->smProcessing,
375              (unsigned)pq->lockCount, pq->wWinVersion,
376              pq->wPaintCount, pq->wTimerCount,
377              pq->wakeBits, pq->wakeMask, pq->hCurHook);
378
379     QUEUE_Unlock( pq );
380 }
381
382
383 /***********************************************************************
384  *           QUEUE_WalkQueues
385  */
386 void QUEUE_WalkQueues(void)
387 {
388     char module[10];
389     HQUEUE16 hQueue = hFirstQueue;
390
391     DUMP( "Queue Msgs Thread   Task Module\n" );
392     while (hQueue)
393     {
394         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
395         if (!queue)
396         {
397             WARN( msg, "Bad queue handle %04x\n", hQueue );
398             return;
399         }
400         if (!GetModuleName16( queue->thdb->process->task, module, sizeof(module )))
401             strcpy( module, "???" );
402         DUMP( "%04x %4d %p %04x %s\n", hQueue,queue->msgCount,
403               queue->thdb, queue->thdb->process->task, module );
404         hQueue = queue->next;
405         QUEUE_Unlock( queue );
406     }
407     DUMP( "\n" );
408 }
409
410
411 /***********************************************************************
412  *           QUEUE_IsExitingQueue
413  */
414 BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue )
415 {
416     return (hExitingQueue && (hQueue == hExitingQueue));
417 }
418
419
420 /***********************************************************************
421  *           QUEUE_SetExitingQueue
422  */
423 void QUEUE_SetExitingQueue( HQUEUE16 hQueue )
424 {
425     hExitingQueue = hQueue;
426 }
427
428
429 /***********************************************************************
430  *           QUEUE_CreateMsgQueue
431  *
432  * Creates a message queue. Doesn't link it into queue list!
433  */
434 static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
435 {
436     HQUEUE16 hQueue;
437     MESSAGEQUEUE * msgQueue;
438     TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
439
440     TRACE(msg,"(): Creating message queue...\n");
441
442     if (!(hQueue = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT,
443                                   sizeof(MESSAGEQUEUE) )))
444         return 0;
445
446     msgQueue = (MESSAGEQUEUE *) GlobalLock16( hQueue );
447     if ( !msgQueue )
448         return 0;
449
450     msgQueue->self        = hQueue;
451     msgQueue->wakeBits    = msgQueue->changeBits = 0;
452     msgQueue->wWinVersion = pTask ? pTask->version : 0;
453     
454     InitializeCriticalSection( &msgQueue->cSection );
455     MakeCriticalSectionGlobal( &msgQueue->cSection );
456
457     /* Create an Event object for waiting on message, used by win32 thread
458        only */
459     if ( !THREAD_IsWin16( THREAD_Current() ) )
460     {
461         msgQueue->hEvent = CreateEventA( NULL, FALSE, FALSE, NULL);
462
463         if (msgQueue->hEvent == 0)
464         {
465             WARN(msg, "CreateEvent32A is not able to create an event object");
466             return 0;
467         }
468         msgQueue->hEvent = ConvertToGlobalHandle( msgQueue->hEvent );
469     }
470     else
471         msgQueue->hEvent = 0;
472          
473     msgQueue->lockCount = 1;
474     msgQueue->magic = QUEUE_MAGIC;
475     
476     /* Create and initialize our per queue data */
477     msgQueue->pQData = bCreatePerQData ? PERQDATA_CreateInstance() : NULL;
478     
479     return hQueue;
480 }
481
482
483 /***********************************************************************
484  *           QUEUE_FlushMessage
485  * 
486  * Try to reply to all pending sent messages on exit.
487  */
488 void QUEUE_FlushMessages( MESSAGEQUEUE *queue )
489 {
490     SMSG *smsg;
491     MESSAGEQUEUE *senderQ = 0;
492
493     if( queue )
494     {
495         EnterCriticalSection( &queue->cSection );
496
497         /* empty the list of pending SendMessage waiting to be received */
498         while (queue->smPending)
499         {
500             smsg = QUEUE_RemoveSMSG( queue, SM_PENDING_LIST, 0);
501
502             senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
503             if ( !senderQ )
504                 continue;
505
506             /* return 0, to unblock other thread */
507             smsg->lResult = 0;
508             smsg->flags |= SMSG_HAVE_RESULT;
509             QUEUE_SetWakeBit( senderQ, QS_SMRESULT);
510             
511             QUEUE_Unlock( senderQ );
512         }
513
514         QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
515         
516         LeaveCriticalSection( &queue->cSection );
517     }
518 }
519
520
521 /***********************************************************************
522  *           QUEUE_DeleteMsgQueue
523  *
524  * Unlinks and deletes a message queue.
525  *
526  * Note: We need to mask asynchronous events to make sure PostMessage works
527  * even in the signal handler.
528  */
529 BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue )
530 {
531     MESSAGEQUEUE * msgQueue = (MESSAGEQUEUE*)QUEUE_Lock(hQueue);
532     HQUEUE16 *pPrev;
533
534     TRACE(msg,"(): Deleting message queue %04x\n", hQueue);
535
536     if (!hQueue || !msgQueue)
537     {
538         WARN(msg, "invalid argument.\n");
539         return 0;
540     }
541
542     msgQueue->magic = 0;
543     
544     if( hCursorQueue == hQueue ) hCursorQueue = 0;
545     if( hActiveQueue == hQueue ) hActiveQueue = 0;
546
547     /* flush sent messages */
548     QUEUE_FlushMessages( msgQueue );
549
550     SYSTEM_LOCK();
551
552     /* Release per queue data if present */
553     if ( msgQueue->pQData )
554     {
555         PERQDATA_Release( msgQueue->pQData );
556         msgQueue->pQData = 0;
557     }
558     
559     /* remove the message queue from the global link list */
560     pPrev = &hFirstQueue;
561     while (*pPrev && (*pPrev != hQueue))
562     {
563         MESSAGEQUEUE *msgQ = (MESSAGEQUEUE*)GlobalLock16(*pPrev);
564
565         /* sanity check */
566         if ( !msgQ || (msgQ->magic != QUEUE_MAGIC) )
567         {
568             /* HQUEUE link list is corrupted, try to exit gracefully */
569             WARN( msg, "HQUEUE link list corrupted!\n");
570             pPrev = 0;
571             break;
572         }
573         pPrev = &msgQ->next;
574     }
575     if (pPrev && *pPrev) *pPrev = msgQueue->next;
576     msgQueue->self = 0;
577
578     SYSTEM_UNLOCK();
579
580     /* free up resource used by MESSAGEQUEUE strcture */
581     msgQueue->lockCount--;
582     QUEUE_Unlock( msgQueue );
583     
584     return 1;
585 }
586
587
588 /***********************************************************************
589  *           QUEUE_CreateSysMsgQueue
590  *
591  * Create the system message queue, and set the double-click speed.
592  * Must be called only once.
593  */
594 BOOL QUEUE_CreateSysMsgQueue( int size )
595 {
596     /* Note: We dont need perQ data for the system message queue */
597     if (!(hmemSysMsgQueue = QUEUE_CreateMsgQueue( FALSE )))
598         return FALSE;
599     
600     sysMsgQueue = (MESSAGEQUEUE *) GlobalLock16( hmemSysMsgQueue );
601     return TRUE;
602 }
603
604
605 /***********************************************************************
606  *           QUEUE_GetSysQueue
607  */
608 MESSAGEQUEUE *QUEUE_GetSysQueue(void)
609 {
610     return sysMsgQueue;
611 }
612
613
614 /***********************************************************************
615  *           QUEUE_Wait
616  */
617 static void QUEUE_Wait( DWORD wait_mask )
618 {
619     if ( THREAD_IsWin16( THREAD_Current() ) )
620         WaitEvent16( 0 );
621     else
622     {
623         TRACE(msg, "current task is 32-bit, calling SYNC_DoWait\n");
624         MsgWaitForMultipleObjects( 0, NULL, FALSE, INFINITE, wait_mask );
625     }
626 }
627
628
629 /***********************************************************************
630  *           QUEUE_SetWakeBit
631  *
632  * See "Windows Internals", p.449
633  */
634 void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit )
635 {
636     TRACE(msg,"queue = %04x (wm=%04x), bit = %04x\n", 
637                         queue->self, queue->wakeMask, bit );
638
639     if (bit & QS_MOUSE) pMouseQueue = queue;
640     if (bit & QS_KEY) pKbdQueue = queue;
641     queue->changeBits |= bit;
642     queue->wakeBits   |= bit;
643     if (queue->wakeMask & bit)
644     {
645         queue->wakeMask = 0;
646         
647         /* Wake up thread waiting for message */
648         if ( THREAD_IsWin16( queue->thdb ) )
649             PostEvent16( queue->thdb->process->task );
650         else
651         {
652             SetEvent( queue->hEvent );
653         }
654     }
655 }
656
657
658 /***********************************************************************
659  *           QUEUE_ClearWakeBit
660  */
661 void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
662 {
663     queue->changeBits &= ~bit;
664     queue->wakeBits   &= ~bit;
665 }
666
667
668 /***********************************************************************
669  *           QUEUE_WaitBits
670  *
671  * See "Windows Internals", p.447
672  */
673 void QUEUE_WaitBits( WORD bits )
674 {
675     MESSAGEQUEUE *queue;
676
677     TRACE(msg,"q %04x waiting for %04x\n", GetFastQueue16(), bits);
678
679     for (;;)
680     {
681         if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return;
682
683         if (queue->changeBits & bits)
684         {
685             /* One of the bits is set; we can return */
686             queue->wakeMask = 0;
687             QUEUE_Unlock( queue );
688             return;
689         }
690         if (queue->wakeBits & QS_SENDMESSAGE)
691         {
692             /* Process the sent message immediately */
693
694             queue->wakeMask = 0;
695             QUEUE_ReceiveMessage( queue );
696             QUEUE_Unlock( queue );
697             continue;                           /* nested sm crux */
698         }
699
700         queue->wakeMask = bits | QS_SENDMESSAGE;
701         if(queue->changeBits & bits)
702         {
703             QUEUE_Unlock( queue );
704             continue;
705         }
706         
707         TRACE(msg,"%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask);
708
709         QUEUE_Wait( queue->wakeMask );
710
711         QUEUE_Unlock( queue );
712     }
713 }
714
715
716 /***********************************************************************
717  *           QUEUE_AddSMSG
718  *
719  * This routine is called when a SMSG need to be added to one of the three
720  * SM list.  (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
721  */
722 BOOL QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
723 {
724     TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
725           smsg, SPY_GetMsgName(smsg->msg));
726     
727     switch (list)
728     {
729         case SM_PROCESSING_LIST:
730             /* don't need to be thread safe, only accessed by the
731              thread associated with the sender queue */
732             smsg->nextProcessing = queue->smProcessing;
733             queue->smProcessing = smsg;
734             break;
735             
736         case SM_WAITING_LIST:
737             /* don't need to be thread safe, only accessed by the
738              thread associated with the receiver queue */
739             smsg->nextWaiting = queue->smWaiting;
740             queue->smWaiting = smsg;
741             break;
742             
743         case SM_PENDING_LIST:
744             /* make it thread safe, could be accessed by the sender and
745              receiver thread */
746
747             EnterCriticalSection( &queue->cSection );
748             smsg->nextPending = queue->smPending;
749             queue->smPending = smsg;
750             QUEUE_SetWakeBit( queue, QS_SENDMESSAGE );
751             LeaveCriticalSection( &queue->cSection );
752             break;
753
754         default:
755             WARN(sendmsg, "Invalid list: %d", list);
756             break;
757     }
758
759     return TRUE;
760 }
761
762
763 /***********************************************************************
764  *           QUEUE_RemoveSMSG
765  *
766  * This routine is called when a SMSG need to be remove from one of the three
767  * SM list.  (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
768  * If smsg == 0, remove the first smsg from the specified list
769  */
770 SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
771 {
772
773     switch (list)
774     {
775         case SM_PROCESSING_LIST:
776             /* don't need to be thread safe, only accessed by the
777              thread associated with the sender queue */
778
779             /* if smsg is equal to null, it means the first in the list */
780             if (!smsg)
781                 smsg = queue->smProcessing;
782
783             TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
784                   smsg, SPY_GetMsgName(smsg->msg));
785             /* In fact SM_PROCESSING_LIST is a stack, and smsg
786              should be always at the top of the list */
787             if ( (smsg != queue->smProcessing) || !queue->smProcessing )
788         {
789                 ERR( sendmsg, "smsg not at the top of Processing list, smsg=0x%p queue=0x%p", smsg, queue);
790                 return 0;
791             }
792             else
793             {
794                 queue->smProcessing = smsg->nextProcessing;
795                 smsg->nextProcessing = 0;
796         }
797             return smsg;
798
799         case SM_WAITING_LIST:
800             /* don't need to be thread safe, only accessed by the
801              thread associated with the receiver queue */
802
803             /* if smsg is equal to null, it means the first in the list */
804             if (!smsg)
805                 smsg = queue->smWaiting;
806             
807             TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
808                   smsg, SPY_GetMsgName(smsg->msg));
809             /* In fact SM_WAITING_LIST is a stack, and smsg
810              should be always at the top of the list */
811             if ( (smsg != queue->smWaiting) || !queue->smWaiting )
812             {
813                 ERR( sendmsg, "smsg not at the top of Waiting list, smsg=0x%p queue=0x%p", smsg, queue);
814                 return 0;
815             }
816             else
817             {
818                 queue->smWaiting = smsg->nextWaiting;
819                 smsg->nextWaiting = 0;
820     }
821             return smsg;
822
823         case SM_PENDING_LIST:
824             /* make it thread safe, could be accessed by the sender and
825              receiver thread */
826             EnterCriticalSection( &queue->cSection );
827     
828             if (!smsg || !queue->smPending)
829                 smsg = queue->smPending;
830             else
831             {
832                 ERR( sendmsg, "should always remove the top one in Pending list, smsg=0x%p queue=0x%p", smsg, queue);
833                 return 0;
834             }
835             
836             TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
837                   smsg, SPY_GetMsgName(smsg->msg));
838
839             queue->smPending = smsg->nextPending;
840             smsg->nextPending = 0;
841
842             /* if no more SMSG in Pending list, clear QS_SENDMESSAGE flag */
843             if (!queue->smPending)
844                 QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
845             
846             LeaveCriticalSection( &queue->cSection );
847             return smsg;
848
849         default:
850             WARN(sendmsg, "Invalid list: %d", list);
851             break;
852     }
853
854     return 0;
855 }
856
857
858 /***********************************************************************
859  *           QUEUE_ReceiveMessage
860  * 
861  * This routine is called when a sent message is waiting for the queue.
862  */
863 void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
864 {
865     LRESULT       result = 0;
866     SMSG          *smsg;
867     MESSAGEQUEUE  *senderQ;
868
869     TRACE(sendmsg, "queue %04x\n", queue->self );
870
871     if ( !(queue->wakeBits & QS_SENDMESSAGE) && queue->smPending )
872     {
873         TRACE(sendmsg,"\trcm: nothing to do\n");
874         return;
875     }
876
877     /* remove smsg on the top of the pending list and put it in the processing list */
878     smsg = QUEUE_RemoveSMSG(queue, SM_PENDING_LIST, 0);
879     QUEUE_AddSMSG(queue, SM_WAITING_LIST, smsg);
880
881     TRACE(sendmsg,"RM: %s [%04x] (%04x -> %04x)\n",
882             SPY_GetMsgName(smsg->msg), smsg->msg, smsg->hSrcQueue, smsg->hDstQueue );
883
884     if (IsWindow( smsg->hWnd ))
885     {
886         WND *wndPtr = WIN_FindWndPtr( smsg->hWnd );
887         DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */
888
889         /* use sender queue extra info value while calling the window proc */
890         senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
891         if (senderQ)
892   {
893             queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
894             QUEUE_Unlock( senderQ );
895         }
896
897         /* call the right version of CallWindowProcXX */
898         if (smsg->flags & SMSG_WIN32)
899         {
900             TRACE(sendmsg, "\trcm: msg is Win32\n" );
901             if (smsg->flags & SMSG_UNICODE)
902                 result = CallWindowProcW( wndPtr->winproc,
903                                             smsg->hWnd, smsg->msg,
904                                             smsg->wParam, smsg->lParam );
905             else
906                 result = CallWindowProcA( wndPtr->winproc,
907                                             smsg->hWnd, smsg->msg,
908                                             smsg->wParam, smsg->lParam );
909         }
910         else  /* Win16 message */
911             result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
912                                        (HWND16) smsg->hWnd,
913                                        (UINT16) smsg->msg,
914                                        LOWORD (smsg->wParam),
915                                        smsg->lParam );
916
917         queue->GetMessageExtraInfoVal = extraInfo;  /* Restore extra info */
918         TRACE(sendmsg,"result =  %08x\n", (unsigned)result );
919     }
920     else WARN(sendmsg, "\trcm: bad hWnd\n");
921
922     /* sometimes when we got early reply, the receiver is in charge of
923      freeing up memory associated with smsg */
924     /* when there is an early reply the sender will not release smsg
925      before SMSG_RECEIVED is set */
926     if ( smsg->flags & SMSG_EARLY_REPLY )
927     {
928         /* remove smsg from the waiting list */
929         QUEUE_RemoveSMSG( queue, SM_WAITING_LIST, smsg );
930
931         /* make thread safe when accessing SMSG_SENT_REPLY and
932          SMSG_RECEIVER_CLEANS_UP. Those fleags are used by both thread,
933          the sender and receiver, to find out which thread should released
934          smsg structure. The critical section of the sender queue is used. */
935
936         senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
937
938         /* synchronize with the sender */
939         if (senderQ)
940             EnterCriticalSection( &senderQ->cSection );
941       
942         /* tell the sender we're all done with smsg structure */
943         smsg->flags |= SMSG_RECEIVED;
944
945         /* sender will set SMSG_RECEIVER_CLEANS_UP if it wants the
946          receiver to clean up smsg, it could only happens when there is
947          an early reply */
948         if ( smsg->flags & SMSG_RECEIVER_CLEANS )
949         {
950             TRACE( sendmsg,"Receiver cleans up!\n" );
951             HeapFree( SystemHeap, 0, smsg );
952         }
953
954         /* release lock */
955         if (senderQ)
956         {
957             LeaveCriticalSection( &senderQ->cSection );
958       QUEUE_Unlock( senderQ );
959         }
960     }
961     else
962     {
963         /* no early reply, so do it now */
964     
965         /* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not
966          an early reply */
967         smsg->flags |= SMSG_SENDING_REPLY;
968         ReplyMessage( result );
969   }  
970
971     TRACE( sendmsg,"done! \n" );
972 }
973
974
975
976 /***********************************************************************
977  *           QUEUE_AddMsg
978  *
979  * Add a message to the queue. Return FALSE if queue is full.
980  */
981 BOOL QUEUE_AddMsg( HQUEUE16 hQueue, MSG *msg, DWORD extraInfo )
982 {
983     MESSAGEQUEUE *msgQueue;
984     QMSG         *qmsg;
985
986
987     if (!(msgQueue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return FALSE;
988
989     /* allocate new message in global heap for now */
990     if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
991     {
992         QUEUE_Unlock( msgQueue );
993         return 0;
994     }
995
996     EnterCriticalSection( &msgQueue->cSection );
997
998       /* Store message */
999     qmsg->msg = *msg;
1000     qmsg->extraInfo = extraInfo;
1001
1002     /* insert the message in the link list */
1003     qmsg->nextMsg = 0;
1004     qmsg->prevMsg = msgQueue->lastMsg;
1005
1006     if (msgQueue->lastMsg)
1007         msgQueue->lastMsg->nextMsg = qmsg;
1008
1009     /* update first and last anchor in message queue */
1010     msgQueue->lastMsg = qmsg;
1011     if (!msgQueue->firstMsg)
1012         msgQueue->firstMsg = qmsg;
1013     
1014     msgQueue->msgCount++;
1015
1016     LeaveCriticalSection( &msgQueue->cSection );
1017
1018     QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE );
1019     QUEUE_Unlock( msgQueue );
1020     
1021     return TRUE;
1022 }
1023
1024
1025
1026 /***********************************************************************
1027  *           QUEUE_FindMsg
1028  *
1029  * Find a message matching the given parameters. Return -1 if none available.
1030  */
1031 QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last )
1032 {
1033     QMSG* qmsg;
1034
1035     EnterCriticalSection( &msgQueue->cSection );
1036
1037     if (!msgQueue->msgCount)
1038         qmsg = 0;
1039     else if (!hwnd && !first && !last)
1040         qmsg = msgQueue->firstMsg;
1041     else
1042     {
1043         /* look in linked list for message matching first and last criteria */
1044         for (qmsg = msgQueue->firstMsg; qmsg; qmsg = qmsg->nextMsg)
1045     {
1046             MSG *msg = &(qmsg->msg);
1047
1048         if (!hwnd || (msg->hwnd == hwnd))
1049         {
1050                 if (!first && !last)
1051                     break;   /* found it */
1052                 
1053                 if ((msg->message >= first) && (!last || (msg->message <= last)))
1054                     break;   /* found it */
1055             }
1056         }
1057     }
1058     
1059     LeaveCriticalSection( &msgQueue->cSection );
1060
1061     return qmsg;
1062 }
1063
1064
1065
1066 /***********************************************************************
1067  *           QUEUE_RemoveMsg
1068  *
1069  * Remove a message from the queue (pos must be a valid position).
1070  */
1071 void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg )
1072 {
1073     EnterCriticalSection( &msgQueue->cSection );
1074
1075     /* set the linked list */
1076     if (qmsg->prevMsg)
1077         qmsg->prevMsg->nextMsg = qmsg->nextMsg;
1078
1079     if (qmsg->nextMsg)
1080         qmsg->nextMsg->prevMsg = qmsg->prevMsg;
1081
1082     if (msgQueue->firstMsg == qmsg)
1083         msgQueue->firstMsg = qmsg->nextMsg;
1084
1085     if (msgQueue->lastMsg == qmsg)
1086         msgQueue->lastMsg = qmsg->prevMsg;
1087
1088     /* deallocate the memory for the message */
1089     HeapFree( SystemHeap, 0, qmsg );
1090     
1091     msgQueue->msgCount--;
1092     if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE;
1093
1094     LeaveCriticalSection( &msgQueue->cSection );
1095 }
1096
1097
1098 /***********************************************************************
1099  *           QUEUE_WakeSomeone
1100  *
1101  * Wake a queue upon reception of a hardware event.
1102  */
1103 static void QUEUE_WakeSomeone( UINT message )
1104 {
1105     WND*          wndPtr = NULL;
1106     WORD          wakeBit;
1107     HWND hwnd;
1108     HQUEUE16     hQueue = 0;
1109     MESSAGEQUEUE *queue = NULL;
1110
1111     if (hCursorQueue)
1112         hQueue = hCursorQueue;
1113
1114     if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) )
1115     {
1116        wakeBit = QS_KEY;
1117        if( hActiveQueue )
1118            hQueue = hActiveQueue;
1119     }
1120     else 
1121     {
1122        wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
1123        if( (hwnd = GetCapture()) )
1124          if( (wndPtr = WIN_FindWndPtr( hwnd )) ) 
1125            {
1126                hQueue = wndPtr->hmemTaskQ;
1127            }
1128     }
1129
1130     if( (hwnd = GetSysModalWindow16()) )
1131     {
1132       if( (wndPtr = WIN_FindWndPtr( hwnd )) )
1133             hQueue = wndPtr->hmemTaskQ;
1134     }
1135
1136     if (hQueue)
1137         queue = QUEUE_Lock( hQueue );
1138     
1139     if( !queue ) 
1140     {
1141         queue = QUEUE_Lock( hFirstQueue );
1142       while( queue )
1143       {
1144         if (queue->wakeMask & wakeBit) break;
1145           
1146             QUEUE_Unlock(queue);
1147             queue = QUEUE_Lock( queue->next );
1148       }
1149       if( !queue )
1150       { 
1151         WARN(msg, "couldn't find queue\n"); 
1152         return; 
1153       }
1154     }
1155
1156     QUEUE_SetWakeBit( queue, wakeBit );
1157
1158     QUEUE_Unlock( queue );
1159 }
1160
1161
1162 /***********************************************************************
1163  *           hardware_event
1164  *
1165  * Add an event to the system message queue.
1166  * Note: the position is relative to the desktop window.
1167  */
1168 void hardware_event( WORD message, WORD wParam, LONG lParam,
1169                      int xPos, int yPos, DWORD time, DWORD extraInfo )
1170 {
1171     MSG *msg;
1172     QMSG  *qmsg = sysMsgQueue->lastMsg;
1173     int  mergeMsg = 0;
1174
1175     if (!sysMsgQueue) return;
1176
1177       /* Merge with previous event if possible */
1178
1179     if ((message == WM_MOUSEMOVE) && sysMsgQueue->lastMsg)
1180     {
1181         msg = &(sysMsgQueue->lastMsg->msg);
1182         
1183         if ((msg->message == message) && (msg->wParam == wParam))
1184         {
1185             /* Merge events */
1186             qmsg = sysMsgQueue->lastMsg;
1187             mergeMsg = 1;
1188     }
1189     }
1190
1191     if (!mergeMsg)
1192     {
1193         /* Should I limit the number of message in
1194           the system message queue??? */
1195
1196         /* Don't merge allocate a new msg in the global heap */
1197         
1198         if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
1199         return;
1200         
1201         /* put message at the end of the linked list */
1202         qmsg->nextMsg = 0;
1203         qmsg->prevMsg = sysMsgQueue->lastMsg;
1204
1205         if (sysMsgQueue->lastMsg)
1206             sysMsgQueue->lastMsg->nextMsg = qmsg;
1207
1208         /* set last and first anchor index in system message queue */
1209         sysMsgQueue->lastMsg = qmsg;
1210         if (!sysMsgQueue->firstMsg)
1211             sysMsgQueue->firstMsg = qmsg;
1212         
1213         sysMsgQueue->msgCount++;
1214     }
1215
1216       /* Store message */
1217     msg = &(qmsg->msg);
1218     msg->hwnd    = 0;
1219     msg->message = message;
1220     msg->wParam  = wParam;
1221     msg->lParam  = lParam;
1222     msg->time    = time;
1223     msg->pt.x    = xPos;
1224     msg->pt.y    = yPos;
1225     qmsg->extraInfo = extraInfo;
1226
1227     QUEUE_WakeSomeone( message );
1228 }
1229
1230                     
1231 /***********************************************************************
1232  *           QUEUE_GetQueueTask
1233  */
1234 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
1235 {
1236     HTASK16 hTask = 0;
1237     
1238     MESSAGEQUEUE *queue = QUEUE_Lock( hQueue );
1239
1240     if (queue)
1241 {
1242         hTask = queue->thdb->process->task;
1243         QUEUE_Unlock( queue );
1244 }
1245
1246     return hTask;
1247 }
1248
1249
1250
1251 /***********************************************************************
1252  *           QUEUE_IncPaintCount
1253  */
1254 void QUEUE_IncPaintCount( HQUEUE16 hQueue )
1255 {
1256     MESSAGEQUEUE *queue;
1257
1258     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1259     queue->wPaintCount++;
1260     QUEUE_SetWakeBit( queue, QS_PAINT );
1261     QUEUE_Unlock( queue );
1262 }
1263
1264
1265 /***********************************************************************
1266  *           QUEUE_DecPaintCount
1267  */
1268 void QUEUE_DecPaintCount( HQUEUE16 hQueue )
1269 {
1270     MESSAGEQUEUE *queue;
1271
1272     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1273     queue->wPaintCount--;
1274     if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
1275     QUEUE_Unlock( queue );
1276 }
1277
1278
1279 /***********************************************************************
1280  *           QUEUE_IncTimerCount
1281  */
1282 void QUEUE_IncTimerCount( HQUEUE16 hQueue )
1283 {
1284     MESSAGEQUEUE *queue;
1285
1286     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1287     queue->wTimerCount++;
1288     QUEUE_SetWakeBit( queue, QS_TIMER );
1289     QUEUE_Unlock( queue );
1290 }
1291
1292
1293 /***********************************************************************
1294  *           QUEUE_DecTimerCount
1295  */
1296 void QUEUE_DecTimerCount( HQUEUE16 hQueue )
1297 {
1298     MESSAGEQUEUE *queue;
1299
1300     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1301     queue->wTimerCount--;
1302     if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
1303     QUEUE_Unlock( queue );
1304 }
1305
1306
1307 /***********************************************************************
1308  *           PostQuitMessage16   (USER.6)
1309  */
1310 void WINAPI PostQuitMessage16( INT16 exitCode )
1311 {
1312     PostQuitMessage( exitCode );
1313 }
1314
1315
1316 /***********************************************************************
1317  *           PostQuitMessage32   (USER32.421)
1318  *
1319  * PostQuitMessage() posts a message to the system requesting an
1320  * application to terminate execution. As a result of this function,
1321  * the WM_QUIT message is posted to the application, and
1322  * PostQuitMessage() returns immediately.  The exitCode parameter
1323  * specifies an application-defined exit code, which appears in the
1324  * _wParam_ parameter of the WM_QUIT message posted to the application.  
1325  *
1326  * CONFORMANCE
1327  *
1328  *  ECMA-234, Win32
1329  */
1330 void WINAPI PostQuitMessage( INT exitCode )
1331 {
1332     MESSAGEQUEUE *queue;
1333
1334     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return;
1335     queue->wPostQMsg = TRUE;
1336     queue->wExitCode = (WORD)exitCode;
1337     QUEUE_Unlock( queue );
1338 }
1339
1340
1341 /***********************************************************************
1342  *           GetWindowTask16   (USER.224)
1343  */
1344 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
1345 {
1346     WND *wndPtr = WIN_FindWndPtr( hwnd );
1347
1348     if (!wndPtr) return 0;
1349     return QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1350 }
1351
1352 /***********************************************************************
1353  *           GetWindowThreadProcessId   (USER32.313)
1354  */
1355 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
1356 {
1357     HTASK16 htask;
1358     TDB *tdb;
1359
1360     WND *wndPtr = WIN_FindWndPtr( hwnd );
1361
1362     if (!wndPtr) return 0;
1363     htask=QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1364     tdb = (TDB*)GlobalLock16(htask);
1365     if (!tdb || !tdb->thdb) return 0;
1366     if (process) *process = PDB_TO_PROCESS_ID( tdb->thdb->process );
1367     return THDB_TO_THREAD_ID( tdb->thdb );
1368 }
1369
1370
1371 /***********************************************************************
1372  *           SetMessageQueue16   (USER.266)
1373  */
1374 BOOL16 WINAPI SetMessageQueue16( INT16 size )
1375 {
1376     return SetMessageQueue( size );
1377 }
1378
1379
1380 /***********************************************************************
1381  *           SetMessageQueue32   (USER32.494)
1382  */
1383 BOOL WINAPI SetMessageQueue( INT size )
1384 {
1385     /* now obsolete the message queue will be expanded dynamically
1386      as necessary */
1387
1388     /* access the queue to create it if it's not existing */
1389     GetFastQueue16();
1390
1391     return TRUE;
1392 }
1393
1394 /***********************************************************************
1395  *           InitThreadInput   (USER.409)
1396  */
1397 HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags )
1398 {
1399     HQUEUE16 hQueue;
1400     MESSAGEQUEUE *queuePtr;
1401
1402     THDB *thdb = THREAD_Current();
1403
1404     if (!thdb)
1405         return 0;
1406
1407     hQueue = thdb->teb.queue;
1408     
1409     if ( !hQueue )
1410     {
1411         /* Create thread message queue */
1412         if( !(hQueue = QUEUE_CreateMsgQueue( TRUE )))
1413         {
1414             WARN(msg, "failed!\n");
1415             return FALSE;
1416     }
1417         
1418         /* Link new queue into list */
1419         queuePtr = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
1420         queuePtr->thdb = THREAD_Current();
1421
1422         SYSTEM_LOCK();
1423         SetThreadQueue16( 0, hQueue );
1424         thdb->teb.queue = hQueue;
1425             
1426         queuePtr->next  = hFirstQueue;
1427         hFirstQueue = hQueue;
1428         SYSTEM_UNLOCK();
1429         
1430         QUEUE_Unlock( queuePtr );
1431     }
1432
1433     return hQueue;
1434 }
1435
1436 /***********************************************************************
1437  *           GetQueueStatus16   (USER.334)
1438  */
1439 DWORD WINAPI GetQueueStatus16( UINT16 flags )
1440 {
1441     MESSAGEQUEUE *queue;
1442     DWORD ret;
1443
1444     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1445     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1446     queue->changeBits = 0;
1447     QUEUE_Unlock( queue );
1448     
1449     return ret & MAKELONG( flags, flags );
1450 }
1451
1452 /***********************************************************************
1453  *           GetQueueStatus32   (USER32.283)
1454  */
1455 DWORD WINAPI GetQueueStatus( UINT flags )
1456 {
1457     MESSAGEQUEUE *queue;
1458     DWORD ret;
1459
1460     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1461     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1462     queue->changeBits = 0;
1463     QUEUE_Unlock( queue );
1464     
1465     return ret & MAKELONG( flags, flags );
1466 }
1467
1468
1469 /***********************************************************************
1470  *           GetInputState16   (USER.335)
1471  */
1472 BOOL16 WINAPI GetInputState16(void)
1473 {
1474     return GetInputState();
1475 }
1476
1477 /***********************************************************************
1478  *           WaitForInputIdle   (USER32.577)
1479  */
1480 DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
1481 {
1482   FIXME (msg, "(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut);
1483
1484   return WAIT_TIMEOUT;
1485 }
1486
1487
1488 /***********************************************************************
1489  *           GetInputState32   (USER32.244)
1490  */
1491 BOOL WINAPI GetInputState(void)
1492 {
1493     MESSAGEQUEUE *queue;
1494     BOOL ret;
1495
1496     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
1497         return FALSE;
1498     ret = queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
1499     QUEUE_Unlock( queue );
1500
1501     return ret;
1502 }
1503
1504 /***********************************************************************
1505  *           UserYield  (USER.332)
1506  */
1507 void WINAPI UserYield16(void)
1508 {
1509     TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
1510     MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( pCurTask->hQueue );
1511
1512     if ( !THREAD_IsWin16( THREAD_Current() ) )
1513     {
1514         FIXME(task, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel);
1515         QUEUE_Unlock( queue );
1516         return;
1517     }
1518
1519     /* Handle sent messages */
1520     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1521         QUEUE_ReceiveMessage( queue );
1522
1523     QUEUE_Unlock( queue );
1524     
1525     OldYield16();
1526
1527     queue = (MESSAGEQUEUE *)QUEUE_Lock( pCurTask->hQueue );
1528     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1529         QUEUE_ReceiveMessage( queue );
1530
1531     QUEUE_Unlock( queue );
1532 }
1533
1534 /***********************************************************************
1535  *           GetMessagePos   (USER.119) (USER32.272)
1536  * 
1537  * The GetMessagePos() function returns a long value representing a
1538  * cursor position, in screen coordinates, when the last message
1539  * retrieved by the GetMessage() function occurs. The x-coordinate is
1540  * in the low-order word of the return value, the y-coordinate is in
1541  * the high-order word. The application can use the MAKEPOINT()
1542  * macro to obtain a POINT structure from the return value. 
1543  *
1544  * For the current cursor position, use GetCursorPos().
1545  *
1546  * RETURNS
1547  *
1548  * Cursor position of last message on success, zero on failure.
1549  *
1550  * CONFORMANCE
1551  *
1552  * ECMA-234, Win32
1553  *
1554  */
1555 DWORD WINAPI GetMessagePos(void)
1556 {
1557     MESSAGEQUEUE *queue;
1558     DWORD ret;
1559
1560     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1561     ret = queue->GetMessagePosVal;
1562     QUEUE_Unlock( queue );
1563
1564     return ret;
1565 }
1566
1567
1568 /***********************************************************************
1569  *           GetMessageTime   (USER.120) (USER32.273)
1570  *
1571  * GetMessageTime() returns the message time for the last message
1572  * retrieved by the function. The time is measured in milliseconds with
1573  * the same offset as GetTickCount().
1574  *
1575  * Since the tick count wraps, this is only useful for moderately short
1576  * relative time comparisons.
1577  *
1578  * RETURNS
1579  *
1580  * Time of last message on success, zero on failure.
1581  *
1582  * CONFORMANCE
1583  *
1584  * ECMA-234, Win32
1585  *  
1586  */
1587 LONG WINAPI GetMessageTime(void)
1588 {
1589     MESSAGEQUEUE *queue;
1590     LONG ret;
1591
1592     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1593     ret = queue->GetMessageTimeVal;
1594     QUEUE_Unlock( queue );
1595     
1596     return ret;
1597 }
1598
1599
1600 /***********************************************************************
1601  *           GetMessageExtraInfo   (USER.288) (USER32.271)
1602  */
1603 LONG WINAPI GetMessageExtraInfo(void)
1604 {
1605     MESSAGEQUEUE *queue;
1606     LONG ret;
1607
1608     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1609     ret = queue->GetMessageExtraInfoVal;
1610     QUEUE_Unlock( queue );
1611
1612     return ret;
1613 }