Documentation ordinal fixes.
[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 <assert.h>
9 #include "windef.h"
10 #include "wingdi.h"
11 #include "winerror.h"
12 #include "wine/winbase16.h"
13 #include "wine/winuser16.h"
14 #include "queue.h"
15 #include "win.h"
16 #include "hook.h"
17 #include "heap.h"
18 #include "thread.h"
19 #include "debugtools.h"
20 #include "server.h"
21 #include "spy.h"
22
23 DECLARE_DEBUG_CHANNEL(msg);
24 DECLARE_DEBUG_CHANNEL(sendmsg);
25
26 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
27
28 static HQUEUE16 hFirstQueue = 0;
29 static HQUEUE16 hExitingQueue = 0;
30 static HQUEUE16 hmemSysMsgQueue = 0;
31 static MESSAGEQUEUE *sysMsgQueue = NULL;
32 static PERQUEUEDATA *pQDataWin16 = NULL;  /* Global perQData for Win16 tasks */
33
34 static MESSAGEQUEUE *pMouseQueue = NULL;  /* Queue for last mouse message */
35 static MESSAGEQUEUE *pKbdQueue = NULL;    /* Queue for last kbd message */
36
37 HQUEUE16 hCursorQueue = 0;
38 HQUEUE16 hActiveQueue = 0;
39
40
41 /***********************************************************************
42  *           PERQDATA_CreateInstance
43  *
44  * Creates an instance of a reference counted PERQUEUEDATA element
45  * for the message queue. perQData is stored globally for 16 bit tasks.
46  *
47  * Note: We don't implement perQdata exactly the same way Windows does.
48  * Each perQData element is reference counted since it may be potentially
49  * shared by multiple message Queues (via AttachThreadInput).
50  * We only store the current values for Active, Capture and focus windows
51  * currently.
52  */
53 PERQUEUEDATA * PERQDATA_CreateInstance( )
54 {
55     PERQUEUEDATA *pQData;
56     
57     BOOL16 bIsWin16 = 0;
58     
59     TRACE_(msg)("()\n");
60
61     /* Share a single instance of perQData for all 16 bit tasks */
62     if ( ( bIsWin16 = THREAD_IsWin16( NtCurrentTeb() ) ) )
63     {
64         /* If previously allocated, just bump up ref count */
65         if ( pQDataWin16 )
66         {
67             PERQDATA_Addref( pQDataWin16 );
68             return pQDataWin16;
69         }
70     }
71
72     /* Allocate PERQUEUEDATA from the system heap */
73     if (!( pQData = (PERQUEUEDATA *) HeapAlloc( SystemHeap, 0,
74                                                     sizeof(PERQUEUEDATA) ) ))
75         return 0;
76
77     /* Initialize */
78     pQData->hWndCapture = pQData->hWndFocus = pQData->hWndActive = 0;
79     pQData->ulRefCount = 1;
80     pQData->nCaptureHT = HTCLIENT;
81
82     /* Note: We have an independent critical section for the per queue data
83      * since this may be shared by different threads. see AttachThreadInput()
84      */
85     InitializeCriticalSection( &pQData->cSection );
86     /* FIXME: not all per queue data critical sections should be global */
87     MakeCriticalSectionGlobal( &pQData->cSection );
88
89     /* Save perQData globally for 16 bit tasks */
90     if ( bIsWin16 )
91         pQDataWin16 = pQData;
92         
93     return pQData;
94 }
95
96
97 /***********************************************************************
98  *           PERQDATA_Addref
99  *
100  * Increment reference count for the PERQUEUEDATA instance
101  * Returns reference count for debugging purposes
102  */
103 ULONG PERQDATA_Addref( PERQUEUEDATA *pQData )
104 {
105     assert(pQData != 0 );
106     TRACE_(msg)("(): current refcount %lu ...\n", pQData->ulRefCount);
107
108     EnterCriticalSection( &pQData->cSection );
109     ++pQData->ulRefCount;
110     LeaveCriticalSection( &pQData->cSection );
111
112     return pQData->ulRefCount;
113 }
114
115
116 /***********************************************************************
117  *           PERQDATA_Release
118  *
119  * Release a reference to a PERQUEUEDATA instance.
120  * Destroy the instance if no more references exist
121  * Returns reference count for debugging purposes
122  */
123 ULONG PERQDATA_Release( PERQUEUEDATA *pQData )
124 {
125     assert(pQData != 0 );
126     TRACE_(msg)("(): current refcount %lu ...\n",
127           (LONG)pQData->ulRefCount );
128
129     EnterCriticalSection( &pQData->cSection );
130     if ( --pQData->ulRefCount == 0 )
131     {
132         LeaveCriticalSection( &pQData->cSection );
133         DeleteCriticalSection( &pQData->cSection );
134
135         TRACE_(msg)("(): deleting PERQUEUEDATA instance ...\n" );
136
137         /* Deleting our global 16 bit perQData? */
138         if ( pQData == pQDataWin16 )
139             pQDataWin16 = 0;
140             
141         /* Free the PERQUEUEDATA instance */
142         HeapFree( SystemHeap, 0, pQData );
143
144         return 0;
145     }
146     LeaveCriticalSection( &pQData->cSection );
147
148     return pQData->ulRefCount;
149 }
150
151
152 /***********************************************************************
153  *           PERQDATA_GetFocusWnd
154  *
155  * Get the focus hwnd member in a threadsafe manner
156  */
157 HWND PERQDATA_GetFocusWnd( PERQUEUEDATA *pQData )
158 {
159     HWND hWndFocus;
160     assert(pQData != 0 );
161
162     EnterCriticalSection( &pQData->cSection );
163     hWndFocus = pQData->hWndFocus;
164     LeaveCriticalSection( &pQData->cSection );
165
166     return hWndFocus;
167 }
168
169
170 /***********************************************************************
171  *           PERQDATA_SetFocusWnd
172  *
173  * Set the focus hwnd member in a threadsafe manner
174  */
175 HWND PERQDATA_SetFocusWnd( PERQUEUEDATA *pQData, HWND hWndFocus )
176 {
177     HWND hWndFocusPrv;
178     assert(pQData != 0 );
179
180     EnterCriticalSection( &pQData->cSection );
181     hWndFocusPrv = pQData->hWndFocus;
182     pQData->hWndFocus = hWndFocus;
183     LeaveCriticalSection( &pQData->cSection );
184
185     return hWndFocusPrv;
186 }
187
188
189 /***********************************************************************
190  *           PERQDATA_GetActiveWnd
191  *
192  * Get the active hwnd member in a threadsafe manner
193  */
194 HWND PERQDATA_GetActiveWnd( PERQUEUEDATA *pQData )
195 {
196     HWND hWndActive;
197     assert(pQData != 0 );
198
199     EnterCriticalSection( &pQData->cSection );
200     hWndActive = pQData->hWndActive;
201     LeaveCriticalSection( &pQData->cSection );
202
203     return hWndActive;
204 }
205
206
207 /***********************************************************************
208  *           PERQDATA_SetActiveWnd
209  *
210  * Set the active focus hwnd member in a threadsafe manner
211  */
212 HWND PERQDATA_SetActiveWnd( PERQUEUEDATA *pQData, HWND hWndActive )
213 {
214     HWND hWndActivePrv;
215     assert(pQData != 0 );
216
217     EnterCriticalSection( &pQData->cSection );
218     hWndActivePrv = pQData->hWndActive;
219     pQData->hWndActive = hWndActive;
220     LeaveCriticalSection( &pQData->cSection );
221
222     return hWndActivePrv;
223 }
224
225
226 /***********************************************************************
227  *           PERQDATA_GetCaptureWnd
228  *
229  * Get the capture hwnd member in a threadsafe manner
230  */
231 HWND PERQDATA_GetCaptureWnd( PERQUEUEDATA *pQData )
232 {
233     HWND hWndCapture;
234     assert(pQData != 0 );
235
236     EnterCriticalSection( &pQData->cSection );
237     hWndCapture = pQData->hWndCapture;
238     LeaveCriticalSection( &pQData->cSection );
239
240     return hWndCapture;
241 }
242
243
244 /***********************************************************************
245  *           PERQDATA_SetCaptureWnd
246  *
247  * Set the capture hwnd member in a threadsafe manner
248  */
249 HWND PERQDATA_SetCaptureWnd( PERQUEUEDATA *pQData, HWND hWndCapture )
250 {
251     HWND hWndCapturePrv;
252     assert(pQData != 0 );
253
254     EnterCriticalSection( &pQData->cSection );
255     hWndCapturePrv = pQData->hWndCapture;
256     pQData->hWndCapture = hWndCapture;
257     LeaveCriticalSection( &pQData->cSection );
258
259     return hWndCapturePrv;
260 }
261
262
263 /***********************************************************************
264  *           PERQDATA_GetCaptureInfo
265  *
266  * Get the capture info member in a threadsafe manner
267  */
268 INT16 PERQDATA_GetCaptureInfo( PERQUEUEDATA *pQData )
269 {
270     INT16 nCaptureHT;
271     assert(pQData != 0 );
272
273     EnterCriticalSection( &pQData->cSection );
274     nCaptureHT = pQData->nCaptureHT;
275     LeaveCriticalSection( &pQData->cSection );
276
277     return nCaptureHT;
278 }
279
280
281 /***********************************************************************
282  *           PERQDATA_SetCaptureInfo
283  *
284  * Set the capture info member in a threadsafe manner
285  */
286 INT16 PERQDATA_SetCaptureInfo( PERQUEUEDATA *pQData, INT16 nCaptureHT )
287 {
288     INT16 nCaptureHTPrv;
289     assert(pQData != 0 );
290
291     EnterCriticalSection( &pQData->cSection );
292     nCaptureHTPrv = pQData->nCaptureHT;
293     pQData->nCaptureHT = nCaptureHT;
294     LeaveCriticalSection( &pQData->cSection );
295
296     return nCaptureHTPrv;
297 }
298
299
300 /***********************************************************************
301  *           QUEUE_Lock
302  *
303  * Function for getting a 32 bit pointer on queue structure. For thread
304  * safeness programmers should use this function instead of GlobalLock to
305  * retrieve a pointer on the structure. QUEUE_Unlock should also be called
306  * when access to the queue structure is not required anymore.
307  */
308 MESSAGEQUEUE *QUEUE_Lock( HQUEUE16 hQueue )
309 {
310     MESSAGEQUEUE *queue;
311
312     HeapLock( SystemHeap );  /* FIXME: a bit overkill */
313     queue = GlobalLock16( hQueue );
314     if ( !queue || (queue->magic != QUEUE_MAGIC) )
315     {
316         HeapUnlock( SystemHeap );
317         return NULL;
318     }
319
320     queue->lockCount++;
321     HeapUnlock( SystemHeap );
322     return queue;
323 }
324
325
326 /***********************************************************************
327  *           QUEUE_Unlock
328  *
329  * Use with QUEUE_Lock to get a thread safe access to message queue
330  * structure
331  */
332 void QUEUE_Unlock( MESSAGEQUEUE *queue )
333 {
334     if (queue)
335     {
336         HeapLock( SystemHeap );  /* FIXME: a bit overkill */
337
338         if ( --queue->lockCount == 0 )
339         {
340             DeleteCriticalSection ( &queue->cSection );
341             if (queue->server_queue)
342                 CloseHandle( queue->server_queue );
343             GlobalFree16( queue->self );
344         }
345     
346         HeapUnlock( SystemHeap );
347     }
348 }
349
350
351 /***********************************************************************
352  *           QUEUE_DumpQueue
353  */
354 void QUEUE_DumpQueue( HQUEUE16 hQueue )
355 {
356     MESSAGEQUEUE *pq; 
357
358     if (!(pq = (MESSAGEQUEUE*) QUEUE_Lock( hQueue )) )
359     {
360         WARN_(msg)("%04x is not a queue handle\n", hQueue );
361         return;
362     }
363
364     DPRINTF( "next: %12.4x  Intertask SendMessage:\n"
365              "thread: %10p  ----------------------\n"
366              "firstMsg: %8p   smWaiting:     %10p\n"
367              "lastMsg:  %8p   smPending:     %10p\n"
368              "msgCount: %8.4x   smProcessing:  %10p\n"
369              "lockCount: %7.4x\n"
370              "paints: %10.4x\n"
371              "timers: %10.4x\n"
372              "wakeBits: %8.4x\n"
373              "wakeMask: %8.4x\n"
374              "hCurHook: %8.4x\n",
375              pq->next, pq->teb, pq->firstMsg, pq->smWaiting, pq->lastMsg,
376              pq->smPending, pq->msgCount, pq->smProcessing,
377              (unsigned)pq->lockCount, pq->wPaintCount, pq->wTimerCount,
378              pq->wakeBits, pq->wakeMask, pq->hCurHook);
379
380     QUEUE_Unlock( pq );
381 }
382
383
384 /***********************************************************************
385  *           QUEUE_WalkQueues
386  */
387 void QUEUE_WalkQueues(void)
388 {
389     char module[10];
390     HQUEUE16 hQueue = hFirstQueue;
391
392     DPRINTF( "Queue Msgs Thread   Task Module\n" );
393     while (hQueue)
394     {
395         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
396         if (!queue)
397         {
398             WARN_(msg)("Bad queue handle %04x\n", hQueue );
399             return;
400         }
401         if (!GetModuleName16( queue->teb->htask16, module, sizeof(module )))
402             strcpy( module, "???" );
403         DPRINTF( "%04x %4d %p %04x %s\n", hQueue,queue->msgCount,
404                  queue->teb, queue->teb->htask16, module );
405         hQueue = queue->next;
406         QUEUE_Unlock( queue );
407     }
408     DPRINTF( "\n" );
409 }
410
411
412 /***********************************************************************
413  *           QUEUE_IsExitingQueue
414  */
415 BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue )
416 {
417     return (hExitingQueue && (hQueue == hExitingQueue));
418 }
419
420
421 /***********************************************************************
422  *           QUEUE_SetExitingQueue
423  */
424 void QUEUE_SetExitingQueue( HQUEUE16 hQueue )
425 {
426     hExitingQueue = hQueue;
427 }
428
429
430 /***********************************************************************
431  *           QUEUE_CreateMsgQueue
432  *
433  * Creates a message queue. Doesn't link it into queue list!
434  */
435 static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
436 {
437     HQUEUE16 hQueue;
438     HANDLE handle;
439     MESSAGEQUEUE * msgQueue;
440
441     TRACE_(msg)("(): Creating message queue...\n");
442
443     if (!(hQueue = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT,
444                                   sizeof(MESSAGEQUEUE) )))
445         return 0;
446
447     msgQueue = (MESSAGEQUEUE *) GlobalLock16( hQueue );
448     if ( !msgQueue )
449         return 0;
450
451     SERVER_START_REQ
452     {
453         struct get_msg_queue_request *req = server_alloc_req( sizeof(*req), 0 );
454         server_call( REQ_GET_MSG_QUEUE );
455         handle = req->handle;
456     }
457     SERVER_END_REQ;
458     if (!handle)
459     {
460         ERR_(msg)("Cannot get thread queue");
461         GlobalFree16( hQueue );
462         return 0;
463     }
464     msgQueue->server_queue = handle;
465     msgQueue->server_queue = ConvertToGlobalHandle( msgQueue->server_queue );
466
467     msgQueue->self        = hQueue;
468     msgQueue->wakeBits    = msgQueue->changeBits = 0;
469     
470     InitializeCriticalSection( &msgQueue->cSection );
471     MakeCriticalSectionGlobal( &msgQueue->cSection );
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 static 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         ERR_(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     HeapLock( SystemHeap );  /* FIXME: a bit overkill */
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             ERR_(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     HeapUnlock( SystemHeap );
579
580     /* free up resource used by MESSAGEQUEUE structure */
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->teb ) )
634         {
635             int iWndsLock = WIN_SuspendWndsLock();
636             PostEvent16( queue->teb->htask16 );
637             WIN_RestoreWndsLock( iWndsLock );
638         }
639         else
640         {
641             SERVER_START_REQ
642             {
643                 struct wake_queue_request *req = server_alloc_req( sizeof(*req), 0 );
644                 req->handle = queue->server_queue;
645                 req->bits   = bit;
646                 server_call( REQ_WAKE_QUEUE );
647             }
648             SERVER_END_REQ;
649         }
650     }
651 }
652
653
654 /***********************************************************************
655  *           QUEUE_ClearWakeBit
656  */
657 void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
658 {
659     queue->changeBits &= ~bit;
660     queue->wakeBits   &= ~bit;
661 }
662
663
664 /***********************************************************************
665  *           QUEUE_WaitBits
666  *
667  * See "Windows Internals", p.447
668  *
669  * return values:
670  *    0 if exit with timeout
671  *    1 otherwise
672  */
673 int QUEUE_WaitBits( WORD bits, DWORD timeout )
674 {
675     MESSAGEQUEUE *queue;
676     DWORD curTime = 0;
677     HQUEUE16 hQueue;
678
679     TRACE_(msg)("q %04x waiting for %04x\n", GetFastQueue16(), bits);
680
681     if ( THREAD_IsWin16( NtCurrentTeb() ) && (timeout != INFINITE) )
682         curTime = GetTickCount();
683
684     hQueue = GetFastQueue16();
685     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return 0;
686     
687     for (;;)
688     {
689         if (queue->changeBits & bits)
690         {
691             /* One of the bits is set; we can return */
692             queue->wakeMask = 0;
693             QUEUE_Unlock( queue );
694             return 1;
695         }
696         if (queue->wakeBits & QS_SENDMESSAGE)
697         {
698             /* Process the sent message immediately */
699
700             queue->wakeMask = 0;
701             QUEUE_ReceiveMessage( queue );
702             continue;                           /* nested sm crux */
703         }
704
705         queue->wakeMask = bits | QS_SENDMESSAGE;
706         if(queue->changeBits & bits)
707         {
708             continue;
709         }
710         
711         TRACE_(msg)("%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask);
712
713         if ( !THREAD_IsWin16( NtCurrentTeb() ) )
714         {
715             BOOL                bHasWin16Lock;
716             DWORD               dwlc;
717
718             if ( (bHasWin16Lock = _ConfirmWin16Lock()) )
719             {
720                 TRACE_(msg)("bHasWin16Lock=TRUE\n");
721                 ReleaseThunkLock( &dwlc );
722             }
723
724             WaitForSingleObject( queue->server_queue, timeout );
725
726             if ( bHasWin16Lock ) 
727             {
728                 RestoreThunkLock( dwlc );
729             }
730         }
731         else
732         {
733             if ( timeout == INFINITE )
734                 WaitEvent16( 0 );  /* win 16 thread, use WaitEvent */
735             else
736             {
737                 /* check for timeout, then give control to other tasks */
738                 if (GetTickCount() - curTime > timeout)
739                 {
740
741                     QUEUE_Unlock( queue );
742                     return 0;   /* exit with timeout */
743                 }
744                 K32WOWYield16();
745             }
746         }
747     }
748 }
749
750
751 /***********************************************************************
752  *           QUEUE_AddSMSG
753  *
754  * This routine is called when a SMSG need to be added to one of the three
755  * SM list.  (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
756  */
757 BOOL QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
758 {
759     TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
760           smsg, SPY_GetMsgName(smsg->msg));
761     
762     switch (list)
763     {
764         case SM_PROCESSING_LIST:
765             /* don't need to be thread safe, only accessed by the
766              thread associated with the sender queue */
767             smsg->nextProcessing = queue->smProcessing;
768             queue->smProcessing = smsg;
769             break;
770             
771         case SM_WAITING_LIST:
772             /* don't need to be thread safe, only accessed by the
773              thread associated with the receiver queue */
774             smsg->nextWaiting = queue->smWaiting;
775             queue->smWaiting = smsg;
776             break;
777             
778         case SM_PENDING_LIST:
779         {
780             /* make it thread safe, could be accessed by the sender and
781              receiver thread */
782             SMSG **prev;
783
784             EnterCriticalSection( &queue->cSection );
785             smsg->nextPending = NULL;
786             prev = &queue->smPending;
787             while ( *prev )
788                 prev = &(*prev)->nextPending;
789             *prev = smsg;
790             LeaveCriticalSection( &queue->cSection );
791
792             QUEUE_SetWakeBit( queue, QS_SENDMESSAGE );
793             break;
794         }
795
796         default:
797             ERR_(sendmsg)("Invalid list: %d", list);
798             break;
799     }
800
801     return TRUE;
802 }
803
804
805 /***********************************************************************
806  *           QUEUE_RemoveSMSG
807  *
808  * This routine is called when a SMSG needs to be removed from one of the three
809  * SM lists (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST).
810  * If smsg == 0, remove the first smsg from the specified list
811  */
812 SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
813 {
814
815     switch (list)
816     {
817         case SM_PROCESSING_LIST:
818             /* don't need to be thread safe, only accessed by the
819              thread associated with the sender queue */
820
821             /* if smsg is equal to null, it means the first in the list */
822             if (!smsg)
823                 smsg = queue->smProcessing;
824
825             TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
826                   smsg, SPY_GetMsgName(smsg->msg));
827             /* In fact SM_PROCESSING_LIST is a stack, and smsg
828              should be always at the top of the list */
829             if ( (smsg != queue->smProcessing) || !queue->smProcessing )
830         {
831                 ERR_(sendmsg)("smsg not at the top of Processing list, smsg=0x%p queue=0x%p\n", smsg, queue);
832                 return 0;
833             }
834             else
835             {
836                 queue->smProcessing = smsg->nextProcessing;
837                 smsg->nextProcessing = 0;
838         }
839             return smsg;
840
841         case SM_WAITING_LIST:
842             /* don't need to be thread safe, only accessed by the
843              thread associated with the receiver queue */
844
845             /* if smsg is equal to null, it means the first in the list */
846             if (!smsg)
847                 smsg = queue->smWaiting;
848             
849             TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
850                   smsg, SPY_GetMsgName(smsg->msg));
851             /* In fact SM_WAITING_LIST is a stack, and smsg
852              should be always at the top of the list */
853             if ( (smsg != queue->smWaiting) || !queue->smWaiting )
854             {
855                 ERR_(sendmsg)("smsg not at the top of Waiting list, smsg=0x%p queue=0x%p\n", smsg, queue);
856                 return 0;
857             }
858             else
859             {
860                 queue->smWaiting = smsg->nextWaiting;
861                 smsg->nextWaiting = 0;
862     }
863             return smsg;
864
865         case SM_PENDING_LIST:
866             /* make it thread safe, could be accessed by the sender and
867              receiver thread */
868             EnterCriticalSection( &queue->cSection );
869     
870             if (!smsg)
871                 smsg = queue->smPending;
872             if ( (smsg != queue->smPending) || !queue->smPending )
873             {
874                 ERR_(sendmsg)("should always remove the top one in Pending list, smsg=0x%p queue=0x%p\n", smsg, queue);
875                 LeaveCriticalSection( &queue->cSection );
876                 return 0;
877             }
878             
879             TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
880                   smsg, SPY_GetMsgName(smsg->msg));
881
882             queue->smPending = smsg->nextPending;
883             smsg->nextPending = 0;
884
885             /* if no more SMSG in Pending list, clear QS_SENDMESSAGE flag */
886             if (!queue->smPending)
887                 QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
888             
889             LeaveCriticalSection( &queue->cSection );
890             return smsg;
891
892         default:
893             ERR_(sendmsg)("Invalid list: %d\n", list);
894             break;
895     }
896
897     return 0;
898 }
899
900
901 /***********************************************************************
902  *           QUEUE_ReceiveMessage
903  * 
904  * This routine is called when a sent message is waiting for the queue.
905  */
906 void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
907 {
908     LRESULT       result = 0;
909     SMSG          *smsg;
910     MESSAGEQUEUE  *senderQ;
911
912     TRACE_(sendmsg)("queue %04x\n", queue->self );
913
914     if ( !((queue->wakeBits & QS_SENDMESSAGE) && queue->smPending) )
915     {
916         TRACE_(sendmsg)("\trcm: nothing to do\n");
917         return;
918     }
919
920     /* remove smsg on the top of the pending list and put it in the processing list */
921     smsg = QUEUE_RemoveSMSG(queue, SM_PENDING_LIST, 0);
922     QUEUE_AddSMSG(queue, SM_WAITING_LIST, smsg);
923
924     TRACE_(sendmsg)("RM: %s [%04x] (%04x -> %04x)\n",
925             SPY_GetMsgName(smsg->msg), smsg->msg, smsg->hSrcQueue, smsg->hDstQueue );
926
927     if (IsWindow( smsg->hWnd ))
928     {
929         WND *wndPtr = WIN_FindWndPtr( smsg->hWnd );
930         DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */
931
932         /* use sender queue extra info value while calling the window proc */
933         senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
934         if (senderQ)
935   {
936             queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
937             QUEUE_Unlock( senderQ );
938         }
939
940         /* call the right version of CallWindowProcXX */
941         if (smsg->flags & SMSG_WIN32)
942         {
943             TRACE_(sendmsg)("\trcm: msg is Win32\n" );
944             if (smsg->flags & SMSG_UNICODE)
945                 result = CallWindowProcW( wndPtr->winproc,
946                                             smsg->hWnd, smsg->msg,
947                                             smsg->wParam, smsg->lParam );
948             else
949                 result = CallWindowProcA( wndPtr->winproc,
950                                             smsg->hWnd, smsg->msg,
951                                             smsg->wParam, smsg->lParam );
952         }
953         else  /* Win16 message */
954             result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
955                                        (HWND16) smsg->hWnd,
956                                        (UINT16) smsg->msg,
957                                        LOWORD (smsg->wParam),
958                                        smsg->lParam );
959
960         queue->GetMessageExtraInfoVal = extraInfo;  /* Restore extra info */
961         WIN_ReleaseWndPtr(wndPtr);
962         TRACE_(sendmsg)("result =  %08x\n", (unsigned)result );
963     }
964     else WARN_(sendmsg)("\trcm: bad hWnd\n");
965
966     
967         /* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not
968          an early reply */
969         smsg->flags |= SMSG_SENDING_REPLY;
970         ReplyMessage( result );
971
972     TRACE_(sendmsg)("done!\n" );
973 }
974
975
976
977 /***********************************************************************
978  *           QUEUE_AddMsg
979  *
980  * Add a message to the queue. Return FALSE if queue is full.
981  */
982 BOOL QUEUE_AddMsg( HQUEUE16 hQueue, int type, MSG *msg, DWORD extraInfo )
983 {
984     MESSAGEQUEUE *msgQueue;
985     QMSG         *qmsg;
986
987
988     if (!(msgQueue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return FALSE;
989
990     /* allocate new message in global heap for now */
991     if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
992     {
993         QUEUE_Unlock( msgQueue );
994         return 0;
995     }
996
997     EnterCriticalSection( &msgQueue->cSection );
998
999       /* Store message */
1000     qmsg->type = type;
1001     qmsg->msg = *msg;
1002     qmsg->extraInfo = extraInfo;
1003
1004     /* insert the message in the link list */
1005     qmsg->nextMsg = 0;
1006     qmsg->prevMsg = msgQueue->lastMsg;
1007
1008     if (msgQueue->lastMsg)
1009         msgQueue->lastMsg->nextMsg = qmsg;
1010
1011     /* update first and last anchor in message queue */
1012     msgQueue->lastMsg = qmsg;
1013     if (!msgQueue->firstMsg)
1014         msgQueue->firstMsg = qmsg;
1015     
1016     msgQueue->msgCount++;
1017
1018     LeaveCriticalSection( &msgQueue->cSection );
1019
1020     QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE );
1021     QUEUE_Unlock( msgQueue );
1022     
1023     return TRUE;
1024 }
1025
1026
1027
1028 /***********************************************************************
1029  *           QUEUE_FindMsg
1030  *
1031  * Find a message matching the given parameters. Return -1 if none available.
1032  */
1033 QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last )
1034 {
1035     QMSG* qmsg;
1036
1037     EnterCriticalSection( &msgQueue->cSection );
1038
1039     if (!msgQueue->msgCount)
1040         qmsg = 0;
1041     else if (!hwnd && !first && !last)
1042         qmsg = msgQueue->firstMsg;
1043     else
1044     {
1045         /* look in linked list for message matching first and last criteria */
1046         for (qmsg = msgQueue->firstMsg; qmsg; qmsg = qmsg->nextMsg)
1047     {
1048             MSG *msg = &(qmsg->msg);
1049
1050         if (!hwnd || (msg->hwnd == hwnd))
1051         {
1052                 if (!first && !last)
1053                     break;   /* found it */
1054                 
1055                 if ((msg->message >= first) && (!last || (msg->message <= last)))
1056                     break;   /* found it */
1057             }
1058         }
1059     }
1060     
1061     LeaveCriticalSection( &msgQueue->cSection );
1062
1063     return qmsg;
1064 }
1065
1066
1067
1068 /***********************************************************************
1069  *           QUEUE_RemoveMsg
1070  *
1071  * Remove a message from the queue (pos must be a valid position).
1072  */
1073 void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg )
1074 {
1075     EnterCriticalSection( &msgQueue->cSection );
1076
1077     /* set the linked list */
1078     if (qmsg->prevMsg)
1079         qmsg->prevMsg->nextMsg = qmsg->nextMsg;
1080
1081     if (qmsg->nextMsg)
1082         qmsg->nextMsg->prevMsg = qmsg->prevMsg;
1083
1084     if (msgQueue->firstMsg == qmsg)
1085         msgQueue->firstMsg = qmsg->nextMsg;
1086
1087     if (msgQueue->lastMsg == qmsg)
1088         msgQueue->lastMsg = qmsg->prevMsg;
1089
1090     /* deallocate the memory for the message */
1091     HeapFree( SystemHeap, 0, qmsg );
1092     
1093     msgQueue->msgCount--;
1094     if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE;
1095
1096     LeaveCriticalSection( &msgQueue->cSection );
1097 }
1098
1099
1100 /***********************************************************************
1101  *           QUEUE_WakeSomeone
1102  *
1103  * Wake a queue upon reception of a hardware event.
1104  */
1105 static void QUEUE_WakeSomeone( UINT message )
1106 {
1107     WND*          wndPtr = NULL;
1108     WORD          wakeBit;
1109     HWND hwnd;
1110     HQUEUE16     hQueue = 0;
1111     MESSAGEQUEUE *queue = NULL;
1112
1113     if (hCursorQueue)
1114         hQueue = hCursorQueue;
1115
1116     if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) )
1117     {
1118        wakeBit = QS_KEY;
1119        if( hActiveQueue )
1120            hQueue = hActiveQueue;
1121     }
1122     else 
1123     {
1124        wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
1125        if( (hwnd = GetCapture()) )
1126          if( (wndPtr = WIN_FindWndPtr( hwnd )) ) 
1127            {
1128                hQueue = wndPtr->hmemTaskQ;
1129                WIN_ReleaseWndPtr(wndPtr);
1130            }
1131     }
1132
1133     if( (hwnd = GetSysModalWindow16()) )
1134     {
1135       if( (wndPtr = WIN_FindWndPtr( hwnd )) )
1136         {
1137             hQueue = wndPtr->hmemTaskQ;
1138             WIN_ReleaseWndPtr(wndPtr);
1139         }
1140     }
1141
1142     if (hQueue)
1143         queue = QUEUE_Lock( hQueue );
1144     
1145     if( !queue ) 
1146     {
1147         queue = QUEUE_Lock( hFirstQueue );
1148       while( queue )
1149       {
1150         if (queue->wakeMask & wakeBit) break;
1151           
1152             QUEUE_Unlock(queue);
1153             queue = QUEUE_Lock( queue->next );
1154       }
1155       if( !queue )
1156       { 
1157         WARN_(msg)("couldn't find queue\n"); 
1158         return; 
1159       }
1160     }
1161
1162     QUEUE_SetWakeBit( queue, wakeBit );
1163
1164     QUEUE_Unlock( queue );
1165 }
1166
1167
1168 /***********************************************************************
1169  *           hardware_event
1170  *
1171  * Add an event to the system message queue.
1172  * Note: the position is relative to the desktop window.
1173  */
1174 void hardware_event( UINT message, WPARAM wParam, LPARAM lParam,
1175                      int xPos, int yPos, DWORD time, DWORD extraInfo )
1176 {
1177     MSG *msg;
1178     QMSG  *qmsg;
1179     int  mergeMsg = 0;
1180
1181     if (!sysMsgQueue) return;
1182
1183     EnterCriticalSection( &sysMsgQueue->cSection );
1184
1185     /* Merge with previous event if possible */
1186     qmsg = sysMsgQueue->lastMsg;
1187
1188     if ((message == WM_MOUSEMOVE) && sysMsgQueue->lastMsg)
1189     {
1190         msg = &(sysMsgQueue->lastMsg->msg);
1191         
1192         if ((msg->message == message) && (msg->wParam == wParam))
1193         {
1194             /* Merge events */
1195             qmsg = sysMsgQueue->lastMsg;
1196             mergeMsg = 1;
1197     }
1198     }
1199
1200     if (!mergeMsg)
1201     {
1202         /* Should I limit the number of messages in
1203           the system message queue??? */
1204
1205         /* Don't merge allocate a new msg in the global heap */
1206         
1207         if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
1208         {
1209             LeaveCriticalSection( &sysMsgQueue->cSection );
1210             return;
1211         }
1212         
1213         /* put message at the end of the linked list */
1214         qmsg->nextMsg = 0;
1215         qmsg->prevMsg = sysMsgQueue->lastMsg;
1216
1217         if (sysMsgQueue->lastMsg)
1218             sysMsgQueue->lastMsg->nextMsg = qmsg;
1219
1220         /* set last and first anchor index in system message queue */
1221         sysMsgQueue->lastMsg = qmsg;
1222         if (!sysMsgQueue->firstMsg)
1223             sysMsgQueue->firstMsg = qmsg;
1224         
1225         sysMsgQueue->msgCount++;
1226     }
1227
1228       /* Store message */
1229     msg = &(qmsg->msg);
1230     msg->hwnd    = 0;
1231     msg->message = message;
1232     msg->wParam  = wParam;
1233     msg->lParam  = lParam;
1234     msg->time    = time;
1235     msg->pt.x    = xPos;
1236     msg->pt.y    = yPos;
1237     qmsg->extraInfo = extraInfo;
1238     qmsg->type      = QMSG_HARDWARE;
1239
1240     LeaveCriticalSection( &sysMsgQueue->cSection );
1241
1242     QUEUE_WakeSomeone( message );
1243 }
1244
1245                     
1246 /***********************************************************************
1247  *           QUEUE_GetQueueTask
1248  */
1249 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
1250 {
1251     HTASK16 hTask = 0;
1252     
1253     MESSAGEQUEUE *queue = QUEUE_Lock( hQueue );
1254
1255     if (queue)
1256     {
1257         hTask = queue->teb->htask16;
1258         QUEUE_Unlock( queue );
1259     }
1260
1261     return hTask;
1262 }
1263
1264
1265
1266 /***********************************************************************
1267  *           QUEUE_IncPaintCount
1268  */
1269 void QUEUE_IncPaintCount( HQUEUE16 hQueue )
1270 {
1271     MESSAGEQUEUE *queue;
1272
1273     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1274     queue->wPaintCount++;
1275     QUEUE_SetWakeBit( queue, QS_PAINT );
1276     QUEUE_Unlock( queue );
1277 }
1278
1279
1280 /***********************************************************************
1281  *           QUEUE_DecPaintCount
1282  */
1283 void QUEUE_DecPaintCount( HQUEUE16 hQueue )
1284 {
1285     MESSAGEQUEUE *queue;
1286
1287     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1288     queue->wPaintCount--;
1289     if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
1290     QUEUE_Unlock( queue );
1291 }
1292
1293
1294 /***********************************************************************
1295  *           QUEUE_IncTimerCount
1296  */
1297 void QUEUE_IncTimerCount( HQUEUE16 hQueue )
1298 {
1299     MESSAGEQUEUE *queue;
1300
1301     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1302     queue->wTimerCount++;
1303     QUEUE_SetWakeBit( queue, QS_TIMER );
1304     QUEUE_Unlock( queue );
1305 }
1306
1307
1308 /***********************************************************************
1309  *           QUEUE_DecTimerCount
1310  */
1311 void QUEUE_DecTimerCount( HQUEUE16 hQueue )
1312 {
1313     MESSAGEQUEUE *queue;
1314
1315     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1316     queue->wTimerCount--;
1317     if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
1318     QUEUE_Unlock( queue );
1319 }
1320
1321
1322 /***********************************************************************
1323  *              PostQuitMessage (USER.6)
1324  */
1325 void WINAPI PostQuitMessage16( INT16 exitCode )
1326 {
1327     PostQuitMessage( exitCode );
1328 }
1329
1330
1331 /***********************************************************************
1332  *              PostQuitMessage (USER32.@)
1333  *
1334  * PostQuitMessage() posts a message to the system requesting an
1335  * application to terminate execution. As a result of this function,
1336  * the WM_QUIT message is posted to the application, and
1337  * PostQuitMessage() returns immediately.  The exitCode parameter
1338  * specifies an application-defined exit code, which appears in the
1339  * _wParam_ parameter of the WM_QUIT message posted to the application.  
1340  *
1341  * CONFORMANCE
1342  *
1343  *  ECMA-234, Win32
1344  */
1345 void WINAPI PostQuitMessage( INT exitCode )
1346 {
1347     MESSAGEQUEUE *queue;
1348
1349     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return;
1350     queue->wPostQMsg = TRUE;
1351     queue->wExitCode = (WORD)exitCode;
1352     QUEUE_Unlock( queue );
1353 }
1354
1355
1356 /***********************************************************************
1357  *              GetWindowTask (USER.224)
1358  */
1359 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
1360 {
1361     HTASK16 retvalue;
1362     WND *wndPtr = WIN_FindWndPtr( hwnd );
1363
1364     if (!wndPtr) return 0;
1365     retvalue = QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1366     WIN_ReleaseWndPtr(wndPtr);
1367     return retvalue;
1368 }
1369
1370 /***********************************************************************
1371  *              GetWindowThreadProcessId (USER32.@)
1372  */
1373 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
1374 {
1375     DWORD retvalue;
1376     MESSAGEQUEUE *queue;
1377
1378     WND *wndPtr = WIN_FindWndPtr( hwnd );
1379     if (!wndPtr) return 0;
1380
1381     queue = QUEUE_Lock( wndPtr->hmemTaskQ );
1382     WIN_ReleaseWndPtr(wndPtr);
1383
1384     if (!queue) return 0;
1385
1386     if ( process ) *process = (DWORD)queue->teb->pid;
1387     retvalue = (DWORD)queue->teb->tid;
1388
1389     QUEUE_Unlock( queue );
1390     return retvalue;
1391 }
1392
1393
1394 /***********************************************************************
1395  *              SetMessageQueue (USER.266)
1396  */
1397 BOOL16 WINAPI SetMessageQueue16( INT16 size )
1398 {
1399     return SetMessageQueue( size );
1400 }
1401
1402
1403 /***********************************************************************
1404  *              SetMessageQueue (USER32.@)
1405  */
1406 BOOL WINAPI SetMessageQueue( INT size )
1407 {
1408     /* now obsolete the message queue will be expanded dynamically
1409      as necessary */
1410
1411     /* access the queue to create it if it's not existing */
1412     GetFastQueue16();
1413
1414     return TRUE;
1415 }
1416
1417 /***********************************************************************
1418  *              InitThreadInput (USER.409)
1419  */
1420 HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags )
1421 {
1422     HQUEUE16 hQueue;
1423     MESSAGEQUEUE *queuePtr;
1424
1425     TEB *teb = NtCurrentTeb();
1426
1427     if (!teb)
1428         return 0;
1429
1430     hQueue = teb->queue;
1431     
1432     if ( !hQueue )
1433     {
1434         /* Create thread message queue */
1435         if( !(hQueue = QUEUE_CreateMsgQueue( TRUE )))
1436         {
1437             ERR_(msg)("failed!\n");
1438             return FALSE;
1439         }
1440         
1441         /* Link new queue into list */
1442         queuePtr = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
1443         queuePtr->teb = NtCurrentTeb();
1444
1445         HeapLock( SystemHeap );  /* FIXME: a bit overkill */
1446         SetThreadQueue16( 0, hQueue );
1447         teb->queue = hQueue;
1448             
1449         queuePtr->next  = hFirstQueue;
1450         hFirstQueue = hQueue;
1451         HeapUnlock( SystemHeap );
1452         
1453         QUEUE_Unlock( queuePtr );
1454     }
1455
1456     return hQueue;
1457 }
1458
1459 /***********************************************************************
1460  *              GetQueueStatus (USER.334)
1461  */
1462 DWORD WINAPI GetQueueStatus16( UINT16 flags )
1463 {
1464     MESSAGEQUEUE *queue;
1465     DWORD ret;
1466
1467     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1468     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1469     queue->changeBits = 0;
1470     QUEUE_Unlock( queue );
1471     
1472     return ret & MAKELONG( flags, flags );
1473 }
1474
1475 /***********************************************************************
1476  *              GetQueueStatus (USER32.@)
1477  */
1478 DWORD WINAPI GetQueueStatus( UINT flags )
1479 {
1480     MESSAGEQUEUE *queue;
1481     DWORD ret;
1482
1483     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1484     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1485     queue->changeBits = 0;
1486     QUEUE_Unlock( queue );
1487     
1488     return ret & MAKELONG( flags, flags );
1489 }
1490
1491
1492 /***********************************************************************
1493  *              GetInputState (USER.335)
1494  */
1495 BOOL16 WINAPI GetInputState16(void)
1496 {
1497     return GetInputState();
1498 }
1499
1500 /***********************************************************************
1501  *              WaitForInputIdle (USER32.@)
1502  */
1503 DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
1504 {
1505     DWORD cur_time, ret;
1506     HANDLE idle_event = -1;
1507
1508     SERVER_START_REQ
1509     {
1510         struct wait_input_idle_request *req = server_alloc_req( sizeof(*req), 0 );
1511         req->handle = hProcess;
1512         req->timeout = dwTimeOut;
1513         if (!(ret = server_call( REQ_WAIT_INPUT_IDLE ))) idle_event = req->event;
1514     }
1515     SERVER_END_REQ;
1516     if (ret) return 0xffffffff;  /* error */
1517     if (!idle_event) return 0;  /* no event to wait on */
1518
1519   cur_time = GetTickCount();
1520
1521   TRACE_(msg)("waiting for %x\n", idle_event );
1522   while ( dwTimeOut > GetTickCount() - cur_time || dwTimeOut == INFINITE ) {
1523
1524     ret = MsgWaitForMultipleObjects ( 1, &idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE );
1525     if ( ret == ( WAIT_OBJECT_0 + 1 )) {
1526       MESSAGEQUEUE * queue;
1527       if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0xFFFFFFFF;
1528       QUEUE_ReceiveMessage ( queue );
1529       QUEUE_Unlock ( queue );
1530       continue; 
1531     }
1532     if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF ) {
1533       TRACE_(msg)("timeout or error\n");
1534       return ret;
1535     }
1536     else {
1537       TRACE_(msg)("finished\n");
1538       return 0;
1539     }
1540     
1541   }
1542   return WAIT_TIMEOUT;
1543 }
1544
1545 /***********************************************************************
1546  *              GetInputState (USER32.@)
1547  */
1548 BOOL WINAPI GetInputState(void)
1549 {
1550     MESSAGEQUEUE *queue;
1551     BOOL ret;
1552
1553     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
1554         return FALSE;
1555     ret = queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
1556     QUEUE_Unlock( queue );
1557
1558     return ret;
1559 }
1560
1561 /***********************************************************************
1562  *              UserYield (USER.332)
1563  *              UserYield16 (USER32.@)
1564  */
1565 void WINAPI UserYield16(void)
1566 {
1567     MESSAGEQUEUE *queue;
1568
1569     /* Handle sent messages */
1570     queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() );
1571
1572     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1573         QUEUE_ReceiveMessage( queue );
1574
1575     QUEUE_Unlock( queue );
1576     
1577     /* Yield */
1578     if ( THREAD_IsWin16( NtCurrentTeb() ) )
1579         OldYield16();
1580     else
1581         WIN32_OldYield16();
1582
1583     /* Handle sent messages again */
1584     queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() );
1585
1586     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1587         QUEUE_ReceiveMessage( queue );
1588
1589     QUEUE_Unlock( queue );
1590 }
1591
1592 /***********************************************************************
1593  *              GetMessagePos (USER.119) (USER32.@)
1594  * 
1595  * The GetMessagePos() function returns a long value representing a
1596  * cursor position, in screen coordinates, when the last message
1597  * retrieved by the GetMessage() function occurs. The x-coordinate is
1598  * in the low-order word of the return value, the y-coordinate is in
1599  * the high-order word. The application can use the MAKEPOINT()
1600  * macro to obtain a POINT structure from the return value. 
1601  *
1602  * For the current cursor position, use GetCursorPos().
1603  *
1604  * RETURNS
1605  *
1606  * Cursor position of last message on success, zero on failure.
1607  *
1608  * CONFORMANCE
1609  *
1610  * ECMA-234, Win32
1611  *
1612  */
1613 DWORD WINAPI GetMessagePos(void)
1614 {
1615     MESSAGEQUEUE *queue;
1616     DWORD ret;
1617
1618     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1619     ret = queue->GetMessagePosVal;
1620     QUEUE_Unlock( queue );
1621
1622     return ret;
1623 }
1624
1625
1626 /***********************************************************************
1627  *              GetMessageTime (USER.120) (USER32.@)
1628  *
1629  * GetMessageTime() returns the message time for the last message
1630  * retrieved by the function. The time is measured in milliseconds with
1631  * the same offset as GetTickCount().
1632  *
1633  * Since the tick count wraps, this is only useful for moderately short
1634  * relative time comparisons.
1635  *
1636  * RETURNS
1637  *
1638  * Time of last message on success, zero on failure.
1639  *
1640  * CONFORMANCE
1641  *
1642  * ECMA-234, Win32
1643  *  
1644  */
1645 LONG WINAPI GetMessageTime(void)
1646 {
1647     MESSAGEQUEUE *queue;
1648     LONG ret;
1649
1650     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1651     ret = queue->GetMessageTimeVal;
1652     QUEUE_Unlock( queue );
1653     
1654     return ret;
1655 }
1656
1657
1658 /***********************************************************************
1659  *              GetMessageExtraInfo (USER.288) (USER32.@)
1660  */
1661 LONG WINAPI GetMessageExtraInfo(void)
1662 {
1663     MESSAGEQUEUE *queue;
1664     LONG ret;
1665
1666     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1667     ret = queue->GetMessageExtraInfoVal;
1668     QUEUE_Unlock( queue );
1669
1670     return ret;
1671 }
1672
1673
1674 /**********************************************************************
1675  *              AttachThreadInput (USER32.@) Attaches input of 1 thread to other
1676  *
1677  * Attaches the input processing mechanism of one thread to that of
1678  * another thread.
1679  *
1680  * RETURNS
1681  *    Success: TRUE
1682  *    Failure: FALSE
1683  *
1684  * TODO:
1685  *    1. Reset the Key State (currenly per thread key state is not maintained)
1686  */
1687 BOOL WINAPI AttachThreadInput( 
1688     DWORD idAttach,   /* [in] Thread to attach */
1689     DWORD idAttachTo, /* [in] Thread to attach to */
1690     BOOL fAttach)   /* [in] Attach or detach */
1691 {
1692     MESSAGEQUEUE *pSrcMsgQ = 0, *pTgtMsgQ = 0;
1693     BOOL16 bRet = 0;
1694
1695     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1696
1697     /* A thread cannot attach to itself */
1698     if ( idAttach == idAttachTo )
1699         goto CLEANUP;
1700
1701     /* According to the docs this method should fail if a
1702      * "Journal record" hook is installed. (attaches all input queues together)
1703      */
1704     if ( HOOK_IsHooked( WH_JOURNALRECORD ) )
1705         goto CLEANUP;
1706         
1707     /* Retrieve message queues corresponding to the thread id's */
1708     pTgtMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetThreadQueue16( idAttach ) );
1709     pSrcMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetThreadQueue16( idAttachTo ) );
1710
1711     /* Ensure we have message queues and that Src and Tgt threads
1712      * are not system threads.
1713      */
1714     if ( !pSrcMsgQ || !pTgtMsgQ || !pSrcMsgQ->pQData || !pTgtMsgQ->pQData )
1715         goto CLEANUP;
1716
1717     if (fAttach)   /* Attach threads */
1718     {
1719         /* Only attach if currently detached  */
1720         if ( pTgtMsgQ->pQData != pSrcMsgQ->pQData )
1721         {
1722             /* First release the target threads perQData */
1723             PERQDATA_Release( pTgtMsgQ->pQData );
1724         
1725             /* Share a reference to the source threads perQDATA */
1726             PERQDATA_Addref( pSrcMsgQ->pQData );
1727             pTgtMsgQ->pQData = pSrcMsgQ->pQData;
1728         }
1729     }
1730     else    /* Detach threads */
1731     {
1732         /* Only detach if currently attached */
1733         if ( pTgtMsgQ->pQData == pSrcMsgQ->pQData )
1734         {
1735             /* First release the target threads perQData */
1736             PERQDATA_Release( pTgtMsgQ->pQData );
1737         
1738             /* Give the target thread its own private perQDATA once more */
1739             pTgtMsgQ->pQData = PERQDATA_CreateInstance();
1740         }
1741     }
1742
1743     /* TODO: Reset the Key State */
1744
1745     bRet = 1;      /* Success */
1746     
1747 CLEANUP:
1748
1749     /* Unlock the queues before returning */
1750     if ( pSrcMsgQ )
1751         QUEUE_Unlock( pSrcMsgQ );
1752     if ( pTgtMsgQ )
1753         QUEUE_Unlock( pTgtMsgQ );
1754     
1755     return bRet;
1756 }