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