Inter-thread SendMessage() bugfixes:
[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         {
754             /* make it thread safe, could be accessed by the sender and
755              receiver thread */
756             SMSG **prev;
757
758             EnterCriticalSection( &queue->cSection );
759             smsg->nextPending = NULL;
760             prev = &queue->smPending;
761             while ( *prev )
762                 prev = &(*prev)->nextPending;
763             *prev = smsg;
764             LeaveCriticalSection( &queue->cSection );
765
766             QUEUE_SetWakeBit( queue, QS_SENDMESSAGE );
767             break;
768         }
769
770         default:
771             WARN(sendmsg, "Invalid list: %d", list);
772             break;
773     }
774
775     return TRUE;
776 }
777
778
779 /***********************************************************************
780  *           QUEUE_RemoveSMSG
781  *
782  * This routine is called when a SMSG need to be remove from one of the three
783  * SM list.  (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
784  * If smsg == 0, remove the first smsg from the specified list
785  */
786 SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
787 {
788
789     switch (list)
790     {
791         case SM_PROCESSING_LIST:
792             /* don't need to be thread safe, only accessed by the
793              thread associated with the sender queue */
794
795             /* if smsg is equal to null, it means the first in the list */
796             if (!smsg)
797                 smsg = queue->smProcessing;
798
799             TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
800                   smsg, SPY_GetMsgName(smsg->msg));
801             /* In fact SM_PROCESSING_LIST is a stack, and smsg
802              should be always at the top of the list */
803             if ( (smsg != queue->smProcessing) || !queue->smProcessing )
804         {
805                 ERR( sendmsg, "smsg not at the top of Processing list, smsg=0x%p queue=0x%p", smsg, queue);
806                 return 0;
807             }
808             else
809             {
810                 queue->smProcessing = smsg->nextProcessing;
811                 smsg->nextProcessing = 0;
812         }
813             return smsg;
814
815         case SM_WAITING_LIST:
816             /* don't need to be thread safe, only accessed by the
817              thread associated with the receiver queue */
818
819             /* if smsg is equal to null, it means the first in the list */
820             if (!smsg)
821                 smsg = queue->smWaiting;
822             
823             TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
824                   smsg, SPY_GetMsgName(smsg->msg));
825             /* In fact SM_WAITING_LIST is a stack, and smsg
826              should be always at the top of the list */
827             if ( (smsg != queue->smWaiting) || !queue->smWaiting )
828             {
829                 ERR( sendmsg, "smsg not at the top of Waiting list, smsg=0x%p queue=0x%p", smsg, queue);
830                 return 0;
831             }
832             else
833             {
834                 queue->smWaiting = smsg->nextWaiting;
835                 smsg->nextWaiting = 0;
836     }
837             return smsg;
838
839         case SM_PENDING_LIST:
840             /* make it thread safe, could be accessed by the sender and
841              receiver thread */
842             EnterCriticalSection( &queue->cSection );
843     
844             if (!smsg || !queue->smPending)
845                 smsg = queue->smPending;
846             else
847             {
848                 ERR( sendmsg, "should always remove the top one in Pending list, smsg=0x%p queue=0x%p", smsg, queue);
849                 return 0;
850             }
851             
852             TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
853                   smsg, SPY_GetMsgName(smsg->msg));
854
855             queue->smPending = smsg->nextPending;
856             smsg->nextPending = 0;
857
858             /* if no more SMSG in Pending list, clear QS_SENDMESSAGE flag */
859             if (!queue->smPending)
860                 QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
861             
862             LeaveCriticalSection( &queue->cSection );
863             return smsg;
864
865         default:
866             WARN(sendmsg, "Invalid list: %d", list);
867             break;
868     }
869
870     return 0;
871 }
872
873
874 /***********************************************************************
875  *           QUEUE_ReceiveMessage
876  * 
877  * This routine is called when a sent message is waiting for the queue.
878  */
879 void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
880 {
881     LRESULT       result = 0;
882     SMSG          *smsg;
883     MESSAGEQUEUE  *senderQ;
884
885     TRACE(sendmsg, "queue %04x\n", queue->self );
886
887     if ( !(queue->wakeBits & QS_SENDMESSAGE) && queue->smPending )
888     {
889         TRACE(sendmsg,"\trcm: nothing to do\n");
890         return;
891     }
892
893     /* remove smsg on the top of the pending list and put it in the processing list */
894     smsg = QUEUE_RemoveSMSG(queue, SM_PENDING_LIST, 0);
895     QUEUE_AddSMSG(queue, SM_WAITING_LIST, smsg);
896
897     TRACE(sendmsg,"RM: %s [%04x] (%04x -> %04x)\n",
898             SPY_GetMsgName(smsg->msg), smsg->msg, smsg->hSrcQueue, smsg->hDstQueue );
899
900     if (IsWindow( smsg->hWnd ))
901     {
902         WND *wndPtr = WIN_FindWndPtr( smsg->hWnd );
903         DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */
904
905         /* use sender queue extra info value while calling the window proc */
906         senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
907         if (senderQ)
908   {
909             queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
910             QUEUE_Unlock( senderQ );
911         }
912
913         /* call the right version of CallWindowProcXX */
914         if (smsg->flags & SMSG_WIN32)
915         {
916             TRACE(sendmsg, "\trcm: msg is Win32\n" );
917             if (smsg->flags & SMSG_UNICODE)
918                 result = CallWindowProcW( wndPtr->winproc,
919                                             smsg->hWnd, smsg->msg,
920                                             smsg->wParam, smsg->lParam );
921             else
922                 result = CallWindowProcA( wndPtr->winproc,
923                                             smsg->hWnd, smsg->msg,
924                                             smsg->wParam, smsg->lParam );
925         }
926         else  /* Win16 message */
927             result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
928                                        (HWND16) smsg->hWnd,
929                                        (UINT16) smsg->msg,
930                                        LOWORD (smsg->wParam),
931                                        smsg->lParam );
932
933         queue->GetMessageExtraInfoVal = extraInfo;  /* Restore extra info */
934         WIN_ReleaseWndPtr(wndPtr);
935         TRACE(sendmsg,"result =  %08x\n", (unsigned)result );
936     }
937     else WARN(sendmsg, "\trcm: bad hWnd\n");
938
939     
940         /* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not
941          an early reply */
942         smsg->flags |= SMSG_SENDING_REPLY;
943         ReplyMessage( result );
944
945     TRACE( sendmsg,"done! \n" );
946 }
947
948
949
950 /***********************************************************************
951  *           QUEUE_AddMsg
952  *
953  * Add a message to the queue. Return FALSE if queue is full.
954  */
955 BOOL QUEUE_AddMsg( HQUEUE16 hQueue, MSG *msg, DWORD extraInfo )
956 {
957     MESSAGEQUEUE *msgQueue;
958     QMSG         *qmsg;
959
960
961     if (!(msgQueue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return FALSE;
962
963     /* allocate new message in global heap for now */
964     if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
965     {
966         QUEUE_Unlock( msgQueue );
967         return 0;
968     }
969
970     EnterCriticalSection( &msgQueue->cSection );
971
972       /* Store message */
973     qmsg->msg = *msg;
974     qmsg->extraInfo = extraInfo;
975
976     /* insert the message in the link list */
977     qmsg->nextMsg = 0;
978     qmsg->prevMsg = msgQueue->lastMsg;
979
980     if (msgQueue->lastMsg)
981         msgQueue->lastMsg->nextMsg = qmsg;
982
983     /* update first and last anchor in message queue */
984     msgQueue->lastMsg = qmsg;
985     if (!msgQueue->firstMsg)
986         msgQueue->firstMsg = qmsg;
987     
988     msgQueue->msgCount++;
989
990     LeaveCriticalSection( &msgQueue->cSection );
991
992     QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE );
993     QUEUE_Unlock( msgQueue );
994     
995     return TRUE;
996 }
997
998
999
1000 /***********************************************************************
1001  *           QUEUE_FindMsg
1002  *
1003  * Find a message matching the given parameters. Return -1 if none available.
1004  */
1005 QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last )
1006 {
1007     QMSG* qmsg;
1008
1009     EnterCriticalSection( &msgQueue->cSection );
1010
1011     if (!msgQueue->msgCount)
1012         qmsg = 0;
1013     else if (!hwnd && !first && !last)
1014         qmsg = msgQueue->firstMsg;
1015     else
1016     {
1017         /* look in linked list for message matching first and last criteria */
1018         for (qmsg = msgQueue->firstMsg; qmsg; qmsg = qmsg->nextMsg)
1019     {
1020             MSG *msg = &(qmsg->msg);
1021
1022         if (!hwnd || (msg->hwnd == hwnd))
1023         {
1024                 if (!first && !last)
1025                     break;   /* found it */
1026                 
1027                 if ((msg->message >= first) && (!last || (msg->message <= last)))
1028                     break;   /* found it */
1029             }
1030         }
1031     }
1032     
1033     LeaveCriticalSection( &msgQueue->cSection );
1034
1035     return qmsg;
1036 }
1037
1038
1039
1040 /***********************************************************************
1041  *           QUEUE_RemoveMsg
1042  *
1043  * Remove a message from the queue (pos must be a valid position).
1044  */
1045 void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg )
1046 {
1047     EnterCriticalSection( &msgQueue->cSection );
1048
1049     /* set the linked list */
1050     if (qmsg->prevMsg)
1051         qmsg->prevMsg->nextMsg = qmsg->nextMsg;
1052
1053     if (qmsg->nextMsg)
1054         qmsg->nextMsg->prevMsg = qmsg->prevMsg;
1055
1056     if (msgQueue->firstMsg == qmsg)
1057         msgQueue->firstMsg = qmsg->nextMsg;
1058
1059     if (msgQueue->lastMsg == qmsg)
1060         msgQueue->lastMsg = qmsg->prevMsg;
1061
1062     /* deallocate the memory for the message */
1063     HeapFree( SystemHeap, 0, qmsg );
1064     
1065     msgQueue->msgCount--;
1066     if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE;
1067
1068     LeaveCriticalSection( &msgQueue->cSection );
1069 }
1070
1071
1072 /***********************************************************************
1073  *           QUEUE_WakeSomeone
1074  *
1075  * Wake a queue upon reception of a hardware event.
1076  */
1077 static void QUEUE_WakeSomeone( UINT message )
1078 {
1079     WND*          wndPtr = NULL;
1080     WORD          wakeBit;
1081     HWND hwnd;
1082     HQUEUE16     hQueue = 0;
1083     MESSAGEQUEUE *queue = NULL;
1084
1085     if (hCursorQueue)
1086         hQueue = hCursorQueue;
1087
1088     if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) )
1089     {
1090        wakeBit = QS_KEY;
1091        if( hActiveQueue )
1092            hQueue = hActiveQueue;
1093     }
1094     else 
1095     {
1096        wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
1097        if( (hwnd = GetCapture()) )
1098          if( (wndPtr = WIN_FindWndPtr( hwnd )) ) 
1099            {
1100                hQueue = wndPtr->hmemTaskQ;
1101                WIN_ReleaseWndPtr(wndPtr);
1102            }
1103     }
1104
1105     if( (hwnd = GetSysModalWindow16()) )
1106     {
1107       if( (wndPtr = WIN_FindWndPtr( hwnd )) )
1108         {
1109             hQueue = wndPtr->hmemTaskQ;
1110             WIN_ReleaseWndPtr(wndPtr);
1111         }
1112     }
1113
1114     if (hQueue)
1115         queue = QUEUE_Lock( hQueue );
1116     
1117     if( !queue ) 
1118     {
1119         queue = QUEUE_Lock( hFirstQueue );
1120       while( queue )
1121       {
1122         if (queue->wakeMask & wakeBit) break;
1123           
1124             QUEUE_Unlock(queue);
1125             queue = QUEUE_Lock( queue->next );
1126       }
1127       if( !queue )
1128       { 
1129         WARN(msg, "couldn't find queue\n"); 
1130         return; 
1131       }
1132     }
1133
1134     QUEUE_SetWakeBit( queue, wakeBit );
1135
1136     QUEUE_Unlock( queue );
1137 }
1138
1139
1140 /***********************************************************************
1141  *           hardware_event
1142  *
1143  * Add an event to the system message queue.
1144  * Note: the position is relative to the desktop window.
1145  */
1146 void hardware_event( WORD message, WORD wParam, LONG lParam,
1147                      int xPos, int yPos, DWORD time, DWORD extraInfo )
1148 {
1149     MSG *msg;
1150     QMSG  *qmsg = sysMsgQueue->lastMsg;
1151     int  mergeMsg = 0;
1152
1153     if (!sysMsgQueue) return;
1154
1155       /* Merge with previous event if possible */
1156
1157     if ((message == WM_MOUSEMOVE) && sysMsgQueue->lastMsg)
1158     {
1159         msg = &(sysMsgQueue->lastMsg->msg);
1160         
1161         if ((msg->message == message) && (msg->wParam == wParam))
1162         {
1163             /* Merge events */
1164             qmsg = sysMsgQueue->lastMsg;
1165             mergeMsg = 1;
1166     }
1167     }
1168
1169     if (!mergeMsg)
1170     {
1171         /* Should I limit the number of message in
1172           the system message queue??? */
1173
1174         /* Don't merge allocate a new msg in the global heap */
1175         
1176         if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
1177         return;
1178         
1179         /* put message at the end of the linked list */
1180         qmsg->nextMsg = 0;
1181         qmsg->prevMsg = sysMsgQueue->lastMsg;
1182
1183         if (sysMsgQueue->lastMsg)
1184             sysMsgQueue->lastMsg->nextMsg = qmsg;
1185
1186         /* set last and first anchor index in system message queue */
1187         sysMsgQueue->lastMsg = qmsg;
1188         if (!sysMsgQueue->firstMsg)
1189             sysMsgQueue->firstMsg = qmsg;
1190         
1191         sysMsgQueue->msgCount++;
1192     }
1193
1194       /* Store message */
1195     msg = &(qmsg->msg);
1196     msg->hwnd    = 0;
1197     msg->message = message;
1198     msg->wParam  = wParam;
1199     msg->lParam  = lParam;
1200     msg->time    = time;
1201     msg->pt.x    = xPos;
1202     msg->pt.y    = yPos;
1203     qmsg->extraInfo = extraInfo;
1204
1205     QUEUE_WakeSomeone( message );
1206 }
1207
1208                     
1209 /***********************************************************************
1210  *           QUEUE_GetQueueTask
1211  */
1212 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
1213 {
1214     HTASK16 hTask = 0;
1215     
1216     MESSAGEQUEUE *queue = QUEUE_Lock( hQueue );
1217
1218     if (queue)
1219 {
1220         hTask = queue->thdb->process->task;
1221         QUEUE_Unlock( queue );
1222 }
1223
1224     return hTask;
1225 }
1226
1227
1228
1229 /***********************************************************************
1230  *           QUEUE_IncPaintCount
1231  */
1232 void QUEUE_IncPaintCount( HQUEUE16 hQueue )
1233 {
1234     MESSAGEQUEUE *queue;
1235
1236     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1237     queue->wPaintCount++;
1238     QUEUE_SetWakeBit( queue, QS_PAINT );
1239     QUEUE_Unlock( queue );
1240 }
1241
1242
1243 /***********************************************************************
1244  *           QUEUE_DecPaintCount
1245  */
1246 void QUEUE_DecPaintCount( HQUEUE16 hQueue )
1247 {
1248     MESSAGEQUEUE *queue;
1249
1250     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1251     queue->wPaintCount--;
1252     if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
1253     QUEUE_Unlock( queue );
1254 }
1255
1256
1257 /***********************************************************************
1258  *           QUEUE_IncTimerCount
1259  */
1260 void QUEUE_IncTimerCount( HQUEUE16 hQueue )
1261 {
1262     MESSAGEQUEUE *queue;
1263
1264     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1265     queue->wTimerCount++;
1266     QUEUE_SetWakeBit( queue, QS_TIMER );
1267     QUEUE_Unlock( queue );
1268 }
1269
1270
1271 /***********************************************************************
1272  *           QUEUE_DecTimerCount
1273  */
1274 void QUEUE_DecTimerCount( HQUEUE16 hQueue )
1275 {
1276     MESSAGEQUEUE *queue;
1277
1278     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1279     queue->wTimerCount--;
1280     if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
1281     QUEUE_Unlock( queue );
1282 }
1283
1284
1285 /***********************************************************************
1286  *           PostQuitMessage16   (USER.6)
1287  */
1288 void WINAPI PostQuitMessage16( INT16 exitCode )
1289 {
1290     PostQuitMessage( exitCode );
1291 }
1292
1293
1294 /***********************************************************************
1295  *           PostQuitMessage32   (USER32.421)
1296  *
1297  * PostQuitMessage() posts a message to the system requesting an
1298  * application to terminate execution. As a result of this function,
1299  * the WM_QUIT message is posted to the application, and
1300  * PostQuitMessage() returns immediately.  The exitCode parameter
1301  * specifies an application-defined exit code, which appears in the
1302  * _wParam_ parameter of the WM_QUIT message posted to the application.  
1303  *
1304  * CONFORMANCE
1305  *
1306  *  ECMA-234, Win32
1307  */
1308 void WINAPI PostQuitMessage( INT exitCode )
1309 {
1310     MESSAGEQUEUE *queue;
1311
1312     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return;
1313     queue->wPostQMsg = TRUE;
1314     queue->wExitCode = (WORD)exitCode;
1315     QUEUE_Unlock( queue );
1316 }
1317
1318
1319 /***********************************************************************
1320  *           GetWindowTask16   (USER.224)
1321  */
1322 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
1323 {
1324     HTASK16 retvalue;
1325     WND *wndPtr = WIN_FindWndPtr( hwnd );
1326
1327     if (!wndPtr) return 0;
1328     retvalue = QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1329     WIN_ReleaseWndPtr(wndPtr);
1330     return retvalue;
1331 }
1332
1333 /***********************************************************************
1334  *           GetWindowThreadProcessId   (USER32.313)
1335  */
1336 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
1337 {
1338     HTASK16 htask;
1339     DWORD retvalue;
1340     TDB *tdb;
1341
1342     WND *wndPtr = WIN_FindWndPtr( hwnd );
1343
1344     if (!wndPtr) return 0;
1345     htask=QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1346     WIN_ReleaseWndPtr(wndPtr);
1347     tdb = (TDB*)GlobalLock16(htask);
1348     if (!tdb || !tdb->thdb) return 0;
1349     if (process) *process = (DWORD)tdb->thdb->process->server_pid;
1350     return (DWORD)tdb->thdb->server_tid;
1351 }
1352
1353
1354 /***********************************************************************
1355  *           SetMessageQueue16   (USER.266)
1356  */
1357 BOOL16 WINAPI SetMessageQueue16( INT16 size )
1358 {
1359     return SetMessageQueue( size );
1360 }
1361
1362
1363 /***********************************************************************
1364  *           SetMessageQueue32   (USER32.494)
1365  */
1366 BOOL WINAPI SetMessageQueue( INT size )
1367 {
1368     /* now obsolete the message queue will be expanded dynamically
1369      as necessary */
1370
1371     /* access the queue to create it if it's not existing */
1372     GetFastQueue16();
1373
1374     return TRUE;
1375 }
1376
1377 /***********************************************************************
1378  *           InitThreadInput   (USER.409)
1379  */
1380 HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags )
1381 {
1382     HQUEUE16 hQueue;
1383     MESSAGEQUEUE *queuePtr;
1384
1385     THDB *thdb = THREAD_Current();
1386
1387     if (!thdb)
1388         return 0;
1389
1390     hQueue = thdb->teb.queue;
1391     
1392     if ( !hQueue )
1393     {
1394         /* Create thread message queue */
1395         if( !(hQueue = QUEUE_CreateMsgQueue( TRUE )))
1396         {
1397             WARN(msg, "failed!\n");
1398             return FALSE;
1399     }
1400         
1401         /* Link new queue into list */
1402         queuePtr = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
1403         queuePtr->thdb = THREAD_Current();
1404
1405         SYSTEM_LOCK();
1406         SetThreadQueue16( 0, hQueue );
1407         thdb->teb.queue = hQueue;
1408             
1409         queuePtr->next  = hFirstQueue;
1410         hFirstQueue = hQueue;
1411         SYSTEM_UNLOCK();
1412         
1413         QUEUE_Unlock( queuePtr );
1414     }
1415
1416     return hQueue;
1417 }
1418
1419 /***********************************************************************
1420  *           GetQueueStatus16   (USER.334)
1421  */
1422 DWORD WINAPI GetQueueStatus16( UINT16 flags )
1423 {
1424     MESSAGEQUEUE *queue;
1425     DWORD ret;
1426
1427     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1428     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1429     queue->changeBits = 0;
1430     QUEUE_Unlock( queue );
1431     
1432     return ret & MAKELONG( flags, flags );
1433 }
1434
1435 /***********************************************************************
1436  *           GetQueueStatus32   (USER32.283)
1437  */
1438 DWORD WINAPI GetQueueStatus( UINT flags )
1439 {
1440     MESSAGEQUEUE *queue;
1441     DWORD ret;
1442
1443     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1444     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1445     queue->changeBits = 0;
1446     QUEUE_Unlock( queue );
1447     
1448     return ret & MAKELONG( flags, flags );
1449 }
1450
1451
1452 /***********************************************************************
1453  *           GetInputState16   (USER.335)
1454  */
1455 BOOL16 WINAPI GetInputState16(void)
1456 {
1457     return GetInputState();
1458 }
1459
1460 /***********************************************************************
1461  *           WaitForInputIdle   (USER32.577)
1462  */
1463 DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
1464 {
1465   FIXME (msg, "(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut);
1466
1467   return WAIT_TIMEOUT;
1468 }
1469
1470
1471 /***********************************************************************
1472  *           GetInputState32   (USER32.244)
1473  */
1474 BOOL WINAPI GetInputState(void)
1475 {
1476     MESSAGEQUEUE *queue;
1477     BOOL ret;
1478
1479     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
1480         return FALSE;
1481     ret = queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
1482     QUEUE_Unlock( queue );
1483
1484     return ret;
1485 }
1486
1487 /***********************************************************************
1488  *           UserYield  (USER.332)
1489  */
1490 void WINAPI UserYield16(void)
1491 {
1492     TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
1493     MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( pCurTask->hQueue );
1494
1495     if ( !THREAD_IsWin16( THREAD_Current() ) )
1496     {
1497         FIXME(task, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel);
1498         QUEUE_Unlock( queue );
1499         return;
1500     }
1501
1502     /* Handle sent messages */
1503     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1504         QUEUE_ReceiveMessage( queue );
1505
1506     QUEUE_Unlock( queue );
1507     
1508     OldYield16();
1509
1510     queue = (MESSAGEQUEUE *)QUEUE_Lock( pCurTask->hQueue );
1511     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1512         QUEUE_ReceiveMessage( queue );
1513
1514     QUEUE_Unlock( queue );
1515 }
1516
1517 /***********************************************************************
1518  *           GetMessagePos   (USER.119) (USER32.272)
1519  * 
1520  * The GetMessagePos() function returns a long value representing a
1521  * cursor position, in screen coordinates, when the last message
1522  * retrieved by the GetMessage() function occurs. The x-coordinate is
1523  * in the low-order word of the return value, the y-coordinate is in
1524  * the high-order word. The application can use the MAKEPOINT()
1525  * macro to obtain a POINT structure from the return value. 
1526  *
1527  * For the current cursor position, use GetCursorPos().
1528  *
1529  * RETURNS
1530  *
1531  * Cursor position of last message on success, zero on failure.
1532  *
1533  * CONFORMANCE
1534  *
1535  * ECMA-234, Win32
1536  *
1537  */
1538 DWORD WINAPI GetMessagePos(void)
1539 {
1540     MESSAGEQUEUE *queue;
1541     DWORD ret;
1542
1543     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1544     ret = queue->GetMessagePosVal;
1545     QUEUE_Unlock( queue );
1546
1547     return ret;
1548 }
1549
1550
1551 /***********************************************************************
1552  *           GetMessageTime   (USER.120) (USER32.273)
1553  *
1554  * GetMessageTime() returns the message time for the last message
1555  * retrieved by the function. The time is measured in milliseconds with
1556  * the same offset as GetTickCount().
1557  *
1558  * Since the tick count wraps, this is only useful for moderately short
1559  * relative time comparisons.
1560  *
1561  * RETURNS
1562  *
1563  * Time of last message on success, zero on failure.
1564  *
1565  * CONFORMANCE
1566  *
1567  * ECMA-234, Win32
1568  *  
1569  */
1570 LONG WINAPI GetMessageTime(void)
1571 {
1572     MESSAGEQUEUE *queue;
1573     LONG ret;
1574
1575     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1576     ret = queue->GetMessageTimeVal;
1577     QUEUE_Unlock( queue );
1578     
1579     return ret;
1580 }
1581
1582
1583 /***********************************************************************
1584  *           GetMessageExtraInfo   (USER.288) (USER32.271)
1585  */
1586 LONG WINAPI GetMessageExtraInfo(void)
1587 {
1588     MESSAGEQUEUE *queue;
1589     LONG ret;
1590
1591     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1592     ret = queue->GetMessageExtraInfoVal;
1593     QUEUE_Unlock( queue );
1594
1595     return ret;
1596 }