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