Allow UserYield16 to be called from 32-bit thread.
[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 = sysMsgQueue->lastMsg;
1150     int  mergeMsg = 0;
1151
1152     if (!sysMsgQueue) return;
1153
1154       /* Merge with previous event if possible */
1155
1156     if ((message == WM_MOUSEMOVE) && sysMsgQueue->lastMsg)
1157     {
1158         msg = &(sysMsgQueue->lastMsg->msg);
1159         
1160         if ((msg->message == message) && (msg->wParam == wParam))
1161         {
1162             /* Merge events */
1163             qmsg = sysMsgQueue->lastMsg;
1164             mergeMsg = 1;
1165     }
1166     }
1167
1168     if (!mergeMsg)
1169     {
1170         /* Should I limit the number of message in
1171           the system message queue??? */
1172
1173         /* Don't merge allocate a new msg in the global heap */
1174         
1175         if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
1176         return;
1177         
1178         /* put message at the end of the linked list */
1179         qmsg->nextMsg = 0;
1180         qmsg->prevMsg = sysMsgQueue->lastMsg;
1181
1182         if (sysMsgQueue->lastMsg)
1183             sysMsgQueue->lastMsg->nextMsg = qmsg;
1184
1185         /* set last and first anchor index in system message queue */
1186         sysMsgQueue->lastMsg = qmsg;
1187         if (!sysMsgQueue->firstMsg)
1188             sysMsgQueue->firstMsg = qmsg;
1189         
1190         sysMsgQueue->msgCount++;
1191     }
1192
1193       /* Store message */
1194     msg = &(qmsg->msg);
1195     msg->hwnd    = 0;
1196     msg->message = message;
1197     msg->wParam  = wParam;
1198     msg->lParam  = lParam;
1199     msg->time    = time;
1200     msg->pt.x    = xPos;
1201     msg->pt.y    = yPos;
1202     qmsg->extraInfo = extraInfo;
1203
1204     QUEUE_WakeSomeone( message );
1205 }
1206
1207                     
1208 /***********************************************************************
1209  *           QUEUE_GetQueueTask
1210  */
1211 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
1212 {
1213     HTASK16 hTask = 0;
1214     
1215     MESSAGEQUEUE *queue = QUEUE_Lock( hQueue );
1216
1217     if (queue)
1218 {
1219         hTask = queue->thdb->process->task;
1220         QUEUE_Unlock( queue );
1221 }
1222
1223     return hTask;
1224 }
1225
1226
1227
1228 /***********************************************************************
1229  *           QUEUE_IncPaintCount
1230  */
1231 void QUEUE_IncPaintCount( HQUEUE16 hQueue )
1232 {
1233     MESSAGEQUEUE *queue;
1234
1235     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1236     queue->wPaintCount++;
1237     QUEUE_SetWakeBit( queue, QS_PAINT );
1238     QUEUE_Unlock( queue );
1239 }
1240
1241
1242 /***********************************************************************
1243  *           QUEUE_DecPaintCount
1244  */
1245 void QUEUE_DecPaintCount( HQUEUE16 hQueue )
1246 {
1247     MESSAGEQUEUE *queue;
1248
1249     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1250     queue->wPaintCount--;
1251     if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
1252     QUEUE_Unlock( queue );
1253 }
1254
1255
1256 /***********************************************************************
1257  *           QUEUE_IncTimerCount
1258  */
1259 void QUEUE_IncTimerCount( HQUEUE16 hQueue )
1260 {
1261     MESSAGEQUEUE *queue;
1262
1263     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1264     queue->wTimerCount++;
1265     QUEUE_SetWakeBit( queue, QS_TIMER );
1266     QUEUE_Unlock( queue );
1267 }
1268
1269
1270 /***********************************************************************
1271  *           QUEUE_DecTimerCount
1272  */
1273 void QUEUE_DecTimerCount( HQUEUE16 hQueue )
1274 {
1275     MESSAGEQUEUE *queue;
1276
1277     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1278     queue->wTimerCount--;
1279     if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
1280     QUEUE_Unlock( queue );
1281 }
1282
1283
1284 /***********************************************************************
1285  *           PostQuitMessage16   (USER.6)
1286  */
1287 void WINAPI PostQuitMessage16( INT16 exitCode )
1288 {
1289     PostQuitMessage( exitCode );
1290 }
1291
1292
1293 /***********************************************************************
1294  *           PostQuitMessage32   (USER32.421)
1295  *
1296  * PostQuitMessage() posts a message to the system requesting an
1297  * application to terminate execution. As a result of this function,
1298  * the WM_QUIT message is posted to the application, and
1299  * PostQuitMessage() returns immediately.  The exitCode parameter
1300  * specifies an application-defined exit code, which appears in the
1301  * _wParam_ parameter of the WM_QUIT message posted to the application.  
1302  *
1303  * CONFORMANCE
1304  *
1305  *  ECMA-234, Win32
1306  */
1307 void WINAPI PostQuitMessage( INT exitCode )
1308 {
1309     MESSAGEQUEUE *queue;
1310
1311     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return;
1312     queue->wPostQMsg = TRUE;
1313     queue->wExitCode = (WORD)exitCode;
1314     QUEUE_Unlock( queue );
1315 }
1316
1317
1318 /***********************************************************************
1319  *           GetWindowTask16   (USER.224)
1320  */
1321 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
1322 {
1323     HTASK16 retvalue;
1324     WND *wndPtr = WIN_FindWndPtr( hwnd );
1325
1326     if (!wndPtr) return 0;
1327     retvalue = QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1328     WIN_ReleaseWndPtr(wndPtr);
1329     return retvalue;
1330 }
1331
1332 /***********************************************************************
1333  *           GetWindowThreadProcessId   (USER32.313)
1334  */
1335 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
1336 {
1337     HTASK16 htask;
1338     TDB *tdb;
1339
1340     WND *wndPtr = WIN_FindWndPtr( hwnd );
1341
1342     if (!wndPtr) return 0;
1343     htask=QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1344     WIN_ReleaseWndPtr(wndPtr);
1345     tdb = (TDB*)GlobalLock16(htask);
1346     if (!tdb || !tdb->thdb) return 0;
1347     if (process) *process = (DWORD)tdb->thdb->process->server_pid;
1348     return (DWORD)tdb->thdb->server_tid;
1349 }
1350
1351
1352 /***********************************************************************
1353  *           SetMessageQueue16   (USER.266)
1354  */
1355 BOOL16 WINAPI SetMessageQueue16( INT16 size )
1356 {
1357     return SetMessageQueue( size );
1358 }
1359
1360
1361 /***********************************************************************
1362  *           SetMessageQueue32   (USER32.494)
1363  */
1364 BOOL WINAPI SetMessageQueue( INT size )
1365 {
1366     /* now obsolete the message queue will be expanded dynamically
1367      as necessary */
1368
1369     /* access the queue to create it if it's not existing */
1370     GetFastQueue16();
1371
1372     return TRUE;
1373 }
1374
1375 /***********************************************************************
1376  *           InitThreadInput   (USER.409)
1377  */
1378 HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags )
1379 {
1380     HQUEUE16 hQueue;
1381     MESSAGEQUEUE *queuePtr;
1382
1383     THDB *thdb = THREAD_Current();
1384
1385     if (!thdb)
1386         return 0;
1387
1388     hQueue = thdb->teb.queue;
1389     
1390     if ( !hQueue )
1391     {
1392         /* Create thread message queue */
1393         if( !(hQueue = QUEUE_CreateMsgQueue( TRUE )))
1394         {
1395             WARN(msg, "failed!\n");
1396             return FALSE;
1397     }
1398         
1399         /* Link new queue into list */
1400         queuePtr = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
1401         queuePtr->thdb = THREAD_Current();
1402
1403         HeapLock( SystemHeap );  /* FIXME: a bit overkill */
1404         SetThreadQueue16( 0, hQueue );
1405         thdb->teb.queue = hQueue;
1406             
1407         queuePtr->next  = hFirstQueue;
1408         hFirstQueue = hQueue;
1409         HeapUnlock( SystemHeap );
1410         
1411         QUEUE_Unlock( queuePtr );
1412     }
1413
1414     return hQueue;
1415 }
1416
1417 /***********************************************************************
1418  *           GetQueueStatus16   (USER.334)
1419  */
1420 DWORD WINAPI GetQueueStatus16( UINT16 flags )
1421 {
1422     MESSAGEQUEUE *queue;
1423     DWORD ret;
1424
1425     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1426     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1427     queue->changeBits = 0;
1428     QUEUE_Unlock( queue );
1429     
1430     return ret & MAKELONG( flags, flags );
1431 }
1432
1433 /***********************************************************************
1434  *           GetQueueStatus32   (USER32.283)
1435  */
1436 DWORD WINAPI GetQueueStatus( UINT flags )
1437 {
1438     MESSAGEQUEUE *queue;
1439     DWORD ret;
1440
1441     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1442     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1443     queue->changeBits = 0;
1444     QUEUE_Unlock( queue );
1445     
1446     return ret & MAKELONG( flags, flags );
1447 }
1448
1449
1450 /***********************************************************************
1451  *           GetInputState16   (USER.335)
1452  */
1453 BOOL16 WINAPI GetInputState16(void)
1454 {
1455     return GetInputState();
1456 }
1457
1458 /***********************************************************************
1459  *           WaitForInputIdle   (USER32.577)
1460  */
1461 DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
1462 {
1463   FIXME (msg, "(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut);
1464
1465   return WAIT_TIMEOUT;
1466 }
1467
1468
1469 /***********************************************************************
1470  *           GetInputState32   (USER32.244)
1471  */
1472 BOOL WINAPI GetInputState(void)
1473 {
1474     MESSAGEQUEUE *queue;
1475     BOOL ret;
1476
1477     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
1478         return FALSE;
1479     ret = queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
1480     QUEUE_Unlock( queue );
1481
1482     return ret;
1483 }
1484
1485 /***********************************************************************
1486  *           UserYield  (USER.332)
1487  */
1488 void WINAPI UserYield16(void)
1489 {
1490     MESSAGEQUEUE *queue;
1491
1492     /* Handle sent messages */
1493     queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() );
1494
1495     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1496         QUEUE_ReceiveMessage( queue );
1497
1498     QUEUE_Unlock( queue );
1499     
1500     /* Yield */
1501     if ( THREAD_IsWin16( THREAD_Current() ) )
1502         OldYield16();
1503     else
1504     {
1505         SYSLEVEL_LeaveWin16Lock();
1506         SYSLEVEL_EnterWin16Lock();
1507     }
1508
1509     /* Handle sent messages again */
1510     queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() );
1511
1512     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1513         QUEUE_ReceiveMessage( queue );
1514
1515     QUEUE_Unlock( queue );
1516 }
1517
1518 /***********************************************************************
1519  *           GetMessagePos   (USER.119) (USER32.272)
1520  * 
1521  * The GetMessagePos() function returns a long value representing a
1522  * cursor position, in screen coordinates, when the last message
1523  * retrieved by the GetMessage() function occurs. The x-coordinate is
1524  * in the low-order word of the return value, the y-coordinate is in
1525  * the high-order word. The application can use the MAKEPOINT()
1526  * macro to obtain a POINT structure from the return value. 
1527  *
1528  * For the current cursor position, use GetCursorPos().
1529  *
1530  * RETURNS
1531  *
1532  * Cursor position of last message on success, zero on failure.
1533  *
1534  * CONFORMANCE
1535  *
1536  * ECMA-234, Win32
1537  *
1538  */
1539 DWORD WINAPI GetMessagePos(void)
1540 {
1541     MESSAGEQUEUE *queue;
1542     DWORD ret;
1543
1544     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1545     ret = queue->GetMessagePosVal;
1546     QUEUE_Unlock( queue );
1547
1548     return ret;
1549 }
1550
1551
1552 /***********************************************************************
1553  *           GetMessageTime   (USER.120) (USER32.273)
1554  *
1555  * GetMessageTime() returns the message time for the last message
1556  * retrieved by the function. The time is measured in milliseconds with
1557  * the same offset as GetTickCount().
1558  *
1559  * Since the tick count wraps, this is only useful for moderately short
1560  * relative time comparisons.
1561  *
1562  * RETURNS
1563  *
1564  * Time of last message on success, zero on failure.
1565  *
1566  * CONFORMANCE
1567  *
1568  * ECMA-234, Win32
1569  *  
1570  */
1571 LONG WINAPI GetMessageTime(void)
1572 {
1573     MESSAGEQUEUE *queue;
1574     LONG ret;
1575
1576     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1577     ret = queue->GetMessageTimeVal;
1578     QUEUE_Unlock( queue );
1579     
1580     return ret;
1581 }
1582
1583
1584 /***********************************************************************
1585  *           GetMessageExtraInfo   (USER.288) (USER32.271)
1586  */
1587 LONG WINAPI GetMessageExtraInfo(void)
1588 {
1589     MESSAGEQUEUE *queue;
1590     LONG ret;
1591
1592     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1593     ret = queue->GetMessageExtraInfoVal;
1594     QUEUE_Unlock( queue );
1595
1596     return ret;
1597 }