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