- Cleaned up the message queue when a thread exit (but not the process).
[wine] / windows / queue.c
1 /* * Message queues related functions
2  *
3  * Copyright 1993, 1994 Alexandre Julliard
4  */
5
6 #include <stdlib.h>
7 #include <signal.h>
8 #include "miscemu.h"
9 #include "module.h"
10 #include "queue.h"
11 #include "task.h"
12 #include "win.h"
13 #include "clipboard.h"
14 #include "hook.h"
15 #include "heap.h"
16 #include "thread.h"
17 #include "process.h"
18 #include <assert.h>
19 #include "debug.h"
20
21 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
22
23 static HQUEUE16 hFirstQueue = 0;
24 static HQUEUE16 hExitingQueue = 0;
25 static HQUEUE16 hmemSysMsgQueue = 0;
26 static MESSAGEQUEUE *sysMsgQueue = NULL;
27 static PERQUEUEDATA *pQDataWin16 = NULL;  /* Global perQData for Win16 tasks */
28
29 static MESSAGEQUEUE *pMouseQueue = NULL;  /* Queue for last mouse message */
30 static MESSAGEQUEUE *pKbdQueue = NULL;    /* Queue for last kbd message */
31
32 HQUEUE16 hCursorQueue = 0;
33 HQUEUE16 hActiveQueue = 0;
34
35
36 /***********************************************************************
37  *           PERQDATA_CreateInstance
38  *
39  * Creates an instance of a reference counted PERQUEUEDATA element
40  * for the message queue. perQData is stored globally for 16 bit tasks.
41  *
42  * Note: We don't implement perQdata exactly the same way Windows does.
43  * Each perQData element is reference counted since it may be potentially
44  * shared by multiple message Queues (via AttachThreadInput).
45  * We only store the current values for Active, Capture and focus windows
46  * currently.
47  */
48 PERQUEUEDATA * PERQDATA_CreateInstance( )
49 {
50     PERQUEUEDATA *pQData;
51     
52     BOOL16 bIsWin16 = 0;
53     
54     TRACE(msg,"()\n");
55
56     /* Share a single instance of perQData for all 16 bit tasks */
57     if ( ( bIsWin16 = THREAD_IsWin16( THREAD_Current() ) ) )
58     {
59         /* If previously allocated, just bump up ref count */
60         if ( pQDataWin16 )
61         {
62             PERQDATA_Addref( pQDataWin16 );
63             return pQDataWin16;
64         }
65     }
66
67     /* Allocate PERQUEUEDATA from the system heap */
68     if (!( pQData = (PERQUEUEDATA *) HeapAlloc( SystemHeap, 0,
69                                                     sizeof(PERQUEUEDATA) ) ))
70         return 0;
71
72     /* Initialize */
73     pQData->hWndCapture = pQData->hWndFocus = pQData->hWndActive = 0;
74     pQData->ulRefCount = 1;
75     pQData->nCaptureHT = HTCLIENT;
76
77     /* Note: We have an independent critical section for the per queue data
78      * since this may be shared by different threads. see AttachThreadInput()
79      */
80     InitializeCriticalSection( &pQData->cSection );
81
82     /* Save perQData globally for 16 bit tasks */
83     if ( bIsWin16 )
84         pQDataWin16 = pQData;
85         
86     return pQData;
87 }
88
89
90 /***********************************************************************
91  *           PERQDATA_Addref
92  *
93  * Increment reference count for the PERQUEUEDATA instance
94  * Returns reference count for debugging purposes
95  */
96 ULONG PERQDATA_Addref( PERQUEUEDATA *pQData )
97 {
98     assert(pQData != 0 );
99     TRACE(msg,"(): current refcount %lu ...\n", pQData->ulRefCount);
100
101     EnterCriticalSection( &pQData->cSection );
102     ++pQData->ulRefCount;
103     LeaveCriticalSection( &pQData->cSection );
104
105     return pQData->ulRefCount;
106 }
107
108
109 /***********************************************************************
110  *           PERQDATA_Release
111  *
112  * Release a reference to a PERQUEUEDATA instance.
113  * Destroy the instance if no more references exist
114  * Returns reference count for debugging purposes
115  */
116 ULONG PERQDATA_Release( PERQUEUEDATA *pQData )
117 {
118     assert(pQData != 0 );
119     TRACE(msg,"(): current refcount %lu ...\n",
120           (LONG)pQData->ulRefCount );
121
122     EnterCriticalSection( &pQData->cSection );
123     if ( --pQData->ulRefCount == 0 )
124     {
125         LeaveCriticalSection( &pQData->cSection );
126         DeleteCriticalSection( &pQData->cSection );
127
128         TRACE(msg,"(): deleting PERQUEUEDATA instance ...\n" );
129
130         /* Deleting our global 16 bit perQData? */
131         if ( pQData == pQDataWin16 )
132             pQDataWin16 = 0;
133             
134         /* Free the PERQUEUEDATA instance */
135         HeapFree( SystemHeap, 0, pQData );
136
137         return 0;
138     }
139     LeaveCriticalSection( &pQData->cSection );
140
141     return pQData->ulRefCount;
142 }
143
144
145 /***********************************************************************
146  *           PERQDATA_GetFocusWnd
147  *
148  * Get the focus hwnd member in a threadsafe manner
149  */
150 HWND32 PERQDATA_GetFocusWnd( PERQUEUEDATA *pQData )
151 {
152     HWND32 hWndFocus;
153     assert(pQData != 0 );
154
155     EnterCriticalSection( &pQData->cSection );
156     hWndFocus = pQData->hWndFocus;
157     LeaveCriticalSection( &pQData->cSection );
158
159     return hWndFocus;
160 }
161
162
163 /***********************************************************************
164  *           PERQDATA_SetFocusWnd
165  *
166  * Set the focus hwnd member in a threadsafe manner
167  */
168 HWND32 PERQDATA_SetFocusWnd( PERQUEUEDATA *pQData, HWND32 hWndFocus )
169 {
170     HWND32 hWndFocusPrv;
171     assert(pQData != 0 );
172
173     EnterCriticalSection( &pQData->cSection );
174     hWndFocusPrv = pQData->hWndFocus;
175     pQData->hWndFocus = hWndFocus;
176     LeaveCriticalSection( &pQData->cSection );
177
178     return hWndFocusPrv;
179 }
180
181
182 /***********************************************************************
183  *           PERQDATA_GetActiveWnd
184  *
185  * Get the active hwnd member in a threadsafe manner
186  */
187 HWND32 PERQDATA_GetActiveWnd( PERQUEUEDATA *pQData )
188 {
189     HWND32 hWndActive;
190     assert(pQData != 0 );
191
192     EnterCriticalSection( &pQData->cSection );
193     hWndActive = pQData->hWndActive;
194     LeaveCriticalSection( &pQData->cSection );
195
196     return hWndActive;
197 }
198
199
200 /***********************************************************************
201  *           PERQDATA_SetActiveWnd
202  *
203  * Set the active focus hwnd member in a threadsafe manner
204  */
205 HWND32 PERQDATA_SetActiveWnd( PERQUEUEDATA *pQData, HWND32 hWndActive )
206 {
207     HWND32 hWndActivePrv;
208     assert(pQData != 0 );
209
210     EnterCriticalSection( &pQData->cSection );
211     hWndActivePrv = pQData->hWndActive;
212     pQData->hWndActive = hWndActive;
213     LeaveCriticalSection( &pQData->cSection );
214
215     return hWndActivePrv;
216 }
217
218
219 /***********************************************************************
220  *           PERQDATA_GetCaptureWnd
221  *
222  * Get the capture hwnd member in a threadsafe manner
223  */
224 HWND32 PERQDATA_GetCaptureWnd( PERQUEUEDATA *pQData )
225 {
226     HWND32 hWndCapture;
227     assert(pQData != 0 );
228
229     EnterCriticalSection( &pQData->cSection );
230     hWndCapture = pQData->hWndCapture;
231     LeaveCriticalSection( &pQData->cSection );
232
233     return hWndCapture;
234 }
235
236
237 /***********************************************************************
238  *           PERQDATA_SetCaptureWnd
239  *
240  * Set the capture hwnd member in a threadsafe manner
241  */
242 HWND32 PERQDATA_SetCaptureWnd( PERQUEUEDATA *pQData, HWND32 hWndCapture )
243 {
244     HWND32 hWndCapturePrv;
245     assert(pQData != 0 );
246
247     EnterCriticalSection( &pQData->cSection );
248     hWndCapturePrv = pQData->hWndCapture;
249     pQData->hWndCapture = hWndCapture;
250     LeaveCriticalSection( &pQData->cSection );
251
252     return hWndCapturePrv;
253 }
254
255
256 /***********************************************************************
257  *           PERQDATA_GetCaptureInfo
258  *
259  * Get the capture info member in a threadsafe manner
260  */
261 INT16 PERQDATA_GetCaptureInfo( PERQUEUEDATA *pQData )
262 {
263     INT16 nCaptureHT;
264     assert(pQData != 0 );
265
266     EnterCriticalSection( &pQData->cSection );
267     nCaptureHT = pQData->nCaptureHT;
268     LeaveCriticalSection( &pQData->cSection );
269
270     return nCaptureHT;
271 }
272
273
274 /***********************************************************************
275  *           PERQDATA_SetCaptureInfo
276  *
277  * Set the capture info member in a threadsafe manner
278  */
279 INT16 PERQDATA_SetCaptureInfo( PERQUEUEDATA *pQData, INT16 nCaptureHT )
280 {
281     INT16 nCaptureHTPrv;
282     assert(pQData != 0 );
283
284     EnterCriticalSection( &pQData->cSection );
285     nCaptureHTPrv = pQData->nCaptureHT;
286     pQData->nCaptureHT = nCaptureHT;
287     LeaveCriticalSection( &pQData->cSection );
288
289     return nCaptureHTPrv;
290 }
291
292
293 /***********************************************************************
294  *           QUEUE_Lock
295  *
296  * Function for getting a 32 bit pointer on queue strcture. For thread
297  * safeness programmers should use this function instead of GlobalLock to
298  * retrieve a pointer on the structure. QUEUE_Unlock should also be called
299  * when access to the queue structure is not required anymore.
300  */
301 MESSAGEQUEUE *QUEUE_Lock( HQUEUE16 hQueue )
302 {
303     MESSAGEQUEUE *queue;
304
305     SYSTEM_LOCK();
306     queue = GlobalLock16( hQueue );
307     if ( !queue || (queue->magic != QUEUE_MAGIC) )
308     {
309         SYSTEM_UNLOCK();
310         return NULL;
311     }
312
313     queue->lockCount++;
314     SYSTEM_UNLOCK();
315
316     return queue;
317 }
318
319
320 /***********************************************************************
321  *           QUEUE_Unlock
322  *
323  * Use with QUEUE_Lock to get a thread safe acces to message queue
324  * structure
325  */
326 void QUEUE_Unlock( MESSAGEQUEUE *queue )
327 {
328     if (queue)
329     {
330         SYSTEM_LOCK();
331
332         if ( --queue->lockCount == 0 )
333         {
334             DeleteCriticalSection ( &queue->cSection );
335             GlobalFree16( queue->self );
336         }
337     
338         SYSTEM_UNLOCK();
339     }
340 }
341
342
343 /***********************************************************************
344  *           QUEUE_DumpQueue
345  */
346 void QUEUE_DumpQueue( HQUEUE16 hQueue )
347 {
348     MESSAGEQUEUE *pq; 
349
350     if (!(pq = (MESSAGEQUEUE*) QUEUE_Lock( hQueue )) )
351     {
352         WARN(msg, "%04x is not a queue handle\n", hQueue );
353         return;
354     }
355
356     DUMP(    "next: %12.4x  Intertask SendMessage:\n"
357              "thread: %10p  ----------------------\n"
358              "hWnd: %12.8x\n"
359              "firstMsg: %8p   msg:     %11.8x\n"
360              "lastMsg:  %8p   wParam:   %10.8x\n"
361              "msgCount: %8.4x   lParam:   %10.8x\n"
362              "lockCount: %7.4x   lRet:   %12.8x\n"
363              "wWinVer: %9.4x  ISMH: %10.4x\n"
364              "paints: %10.4x  hSendTask: %5.4x\n"
365              "timers: %10.4x  hPrevSend: %5.4x\n"
366              "wakeBits: %8.4x\n"
367              "wakeMask: %8.4x\n"
368              "hCurHook: %8.4x\n",
369              pq->next, pq->thdb, pq->hWnd32, pq->firstMsg, pq->msg32,
370              pq->lastMsg, pq->wParam32, pq->msgCount, (unsigned)pq->lParam,
371              (unsigned)pq->lockCount, (unsigned)pq->SendMessageReturn,
372              pq->wWinVersion, pq->InSendMessageHandle,
373              pq->wPaintCount, pq->hSendingTask, pq->wTimerCount,
374              pq->hPrevSendingTask, pq->wakeBits, pq->wakeMask, pq->hCurHook);
375
376     QUEUE_Unlock( pq );
377 }
378
379
380 /***********************************************************************
381  *           QUEUE_WalkQueues
382  */
383 void QUEUE_WalkQueues(void)
384 {
385     char module[10];
386     HQUEUE16 hQueue = hFirstQueue;
387
388     DUMP( "Queue Msgs Thread   Task Module\n" );
389     while (hQueue)
390     {
391         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
392         if (!queue)
393         {
394             WARN( msg, "Bad queue handle %04x\n", hQueue );
395             return;
396         }
397         if (!GetModuleName( queue->thdb->process->task, module, sizeof(module )))
398             strcpy( module, "???" );
399         DUMP( "%04x %4d %p %04x %s\n", hQueue,queue->msgCount,
400               queue->thdb, queue->thdb->process->task, module );
401         hQueue = queue->next;
402         QUEUE_Unlock( queue );
403     }
404     DUMP( "\n" );
405 }
406
407
408 /***********************************************************************
409  *           QUEUE_IsExitingQueue
410  */
411 BOOL32 QUEUE_IsExitingQueue( HQUEUE16 hQueue )
412 {
413     return (hExitingQueue && (hQueue == hExitingQueue));
414 }
415
416
417 /***********************************************************************
418  *           QUEUE_SetExitingQueue
419  */
420 void QUEUE_SetExitingQueue( HQUEUE16 hQueue )
421 {
422     hExitingQueue = hQueue;
423 }
424
425
426 /***********************************************************************
427  *           QUEUE_CreateMsgQueue
428  *
429  * Creates a message queue. Doesn't link it into queue list!
430  */
431 static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
432 {
433     HQUEUE16 hQueue;
434     MESSAGEQUEUE * msgQueue;
435     TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
436
437     TRACE(msg,"(): Creating message queue...\n");
438
439     if (!(hQueue = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT,
440                                   sizeof(MESSAGEQUEUE) )))
441         return 0;
442
443     msgQueue = (MESSAGEQUEUE *) GlobalLock16( hQueue );
444     if ( !msgQueue )
445         return 0;
446
447     msgQueue->self        = hQueue;
448     msgQueue->wakeBits    = msgQueue->changeBits = QS_SMPARAMSFREE;
449     msgQueue->wWinVersion = pTask ? pTask->version : 0;
450     
451     InitializeCriticalSection( &msgQueue->cSection );
452     msgQueue->lockCount = 1;
453     msgQueue->magic = QUEUE_MAGIC;
454     
455     /* Create and initialize our per queue data */
456     msgQueue->pQData = bCreatePerQData ? PERQDATA_CreateInstance() : NULL;
457     
458     return hQueue;
459 }
460
461
462 /***********************************************************************
463  *           QUEUE_DeleteMsgQueue
464  *
465  * Unlinks and deletes a message queue.
466  *
467  * Note: We need to mask asynchronous events to make sure PostMessage works
468  * even in the signal handler.
469  */
470 BOOL32 QUEUE_DeleteMsgQueue( HQUEUE16 hQueue )
471 {
472     MESSAGEQUEUE * msgQueue = (MESSAGEQUEUE*)QUEUE_Lock(hQueue);
473     HQUEUE16  senderQ;
474     HQUEUE16 *pPrev;
475
476     TRACE(msg,"(): Deleting message queue %04x\n", hQueue);
477
478     if (!hQueue || !msgQueue)
479     {
480         WARN(msg, "invalid argument.\n");
481         return 0;
482     }
483
484     msgQueue->magic = 0;
485     
486     if( hCursorQueue == hQueue ) hCursorQueue = 0;
487     if( hActiveQueue == hQueue ) hActiveQueue = 0;
488
489     /* flush sent messages */
490     senderQ = msgQueue->hSendingTask;
491     while( senderQ )
492     {
493       MESSAGEQUEUE* sq = (MESSAGEQUEUE*)QUEUE_Lock(senderQ);
494       if( !sq ) break;
495       sq->SendMessageReturn = 0L;
496       QUEUE_SetWakeBit( sq, QS_SMRESULT );
497       senderQ = sq->hPrevSendingTask;
498       QUEUE_Unlock(sq);
499     }
500
501     SYSTEM_LOCK();
502
503     /* Release per queue data if present */
504     if ( msgQueue->pQData )
505     {
506         PERQDATA_Release( msgQueue->pQData );
507         msgQueue->pQData = 0;
508     }
509     
510     /* remove the message queue from the global link list */
511     pPrev = &hFirstQueue;
512     while (*pPrev && (*pPrev != hQueue))
513     {
514         MESSAGEQUEUE *msgQ = (MESSAGEQUEUE*)GlobalLock16(*pPrev);
515
516         /* sanity check */
517         if ( !msgQ || (msgQ->magic != QUEUE_MAGIC) )
518         {
519             /* HQUEUE link list is corrupted, try to exit gracefully */
520             WARN( msg, "HQUEUE link list corrupted!\n");
521             pPrev = 0;
522             break;
523         }
524         pPrev = &msgQ->next;
525     }
526     if (pPrev && *pPrev) *pPrev = msgQueue->next;
527     msgQueue->self = 0;
528
529     SYSTEM_UNLOCK();
530
531     /* free up resource used by MESSAGEQUEUE strcture */
532     msgQueue->lockCount--;
533     QUEUE_Unlock( msgQueue );
534     
535     return 1;
536 }
537
538
539 /***********************************************************************
540  *           QUEUE_CreateSysMsgQueue
541  *
542  * Create the system message queue, and set the double-click speed.
543  * Must be called only once.
544  */
545 BOOL32 QUEUE_CreateSysMsgQueue( int size )
546 {
547     /* Note: We dont need perQ data for the system message queue */
548     if (!(hmemSysMsgQueue = QUEUE_CreateMsgQueue( FALSE )))
549         return FALSE;
550     
551     sysMsgQueue = (MESSAGEQUEUE *) GlobalLock16( hmemSysMsgQueue );
552     return TRUE;
553 }
554
555
556 /***********************************************************************
557  *           QUEUE_GetSysQueue
558  */
559 MESSAGEQUEUE *QUEUE_GetSysQueue(void)
560 {
561     return sysMsgQueue;
562 }
563
564 /***********************************************************************
565  *           QUEUE_Signal
566  */
567 void QUEUE_Signal( THDB *thdb  )
568 {
569     /* Wake up thread waiting for message */
570     SetEvent( thdb->event );
571
572     PostEvent( thdb->process->task );
573 }
574
575 /***********************************************************************
576  *           QUEUE_Wait
577  */
578 static void QUEUE_Wait( DWORD wait_mask )
579 {
580     if ( THREAD_IsWin16( THREAD_Current() ) )
581         WaitEvent( 0 );
582     else
583     {
584         TRACE(msg, "current task is 32-bit, calling SYNC_DoWait\n");
585         MsgWaitForMultipleObjects( 0, NULL, FALSE, INFINITE32, wait_mask );
586     }
587 }
588
589
590 /***********************************************************************
591  *           QUEUE_SetWakeBit
592  *
593  * See "Windows Internals", p.449
594  */
595 void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit )
596 {
597     TRACE(msg,"queue = %04x (wm=%04x), bit = %04x\n", 
598                         queue->self, queue->wakeMask, bit );
599
600     if (bit & QS_MOUSE) pMouseQueue = queue;
601     if (bit & QS_KEY) pKbdQueue = queue;
602     queue->changeBits |= bit;
603     queue->wakeBits   |= bit;
604     if (queue->wakeMask & bit)
605     {
606         queue->wakeMask = 0;
607         QUEUE_Signal( queue->thdb );
608     }
609 }
610
611
612 /***********************************************************************
613  *           QUEUE_ClearWakeBit
614  */
615 void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
616 {
617     queue->changeBits &= ~bit;
618     queue->wakeBits   &= ~bit;
619 }
620
621
622 /***********************************************************************
623  *           QUEUE_WaitBits
624  *
625  * See "Windows Internals", p.447
626  */
627 void QUEUE_WaitBits( WORD bits )
628 {
629     MESSAGEQUEUE *queue;
630
631     TRACE(msg,"q %04x waiting for %04x\n", GetFastQueue(), bits);
632
633     for (;;)
634     {
635         if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return;
636
637         if (queue->changeBits & bits)
638         {
639             /* One of the bits is set; we can return */
640             queue->wakeMask = 0;
641             QUEUE_Unlock( queue );
642             return;
643         }
644         if (queue->wakeBits & QS_SENDMESSAGE)
645         {
646             /* Process the sent message immediately */
647
648             queue->wakeMask = 0;
649             QUEUE_ReceiveMessage( queue );
650             QUEUE_Unlock( queue );
651             continue;                           /* nested sm crux */
652         }
653
654         queue->wakeMask = bits | QS_SENDMESSAGE;
655         if(queue->changeBits & bits)
656         {
657             QUEUE_Unlock( queue );
658             continue;
659         }
660         
661         TRACE(msg,"%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask);
662
663         QUEUE_Wait( queue->wakeMask );
664
665         QUEUE_Unlock( queue );
666     }
667 }
668
669
670 /***********************************************************************
671  *           QUEUE_ReceiveMessage
672  *
673  * This routine is called when a sent message is waiting for the queue.
674  */
675 void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
676 {
677     MESSAGEQUEUE *senderQ = NULL;
678     HQUEUE16      prevSender = 0;
679     QSMCTRL*      prevCtrlPtr = NULL;
680     LRESULT       result = 0;
681
682     TRACE(msg, "ReceiveMessage, queue %04x\n", queue->self );
683     if (!(queue->wakeBits & QS_SENDMESSAGE) ||
684         !(senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->hSendingTask)))
685         { TRACE(msg,"\trcm: nothing to do\n"); return; }
686
687     if( !senderQ->hPrevSendingTask )
688         QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );   /* no more sent messages */
689
690     /* Save current state on stack */
691     prevSender                 = queue->InSendMessageHandle;
692     prevCtrlPtr                = queue->smResultCurrent;
693
694     /* Remove sending queue from the list */
695     queue->InSendMessageHandle = queue->hSendingTask;
696     queue->smResultCurrent     = senderQ->smResultInit;
697     queue->hSendingTask        = senderQ->hPrevSendingTask;
698
699     TRACE(msg, "\trcm: smResultCurrent = %08x, prevCtrl = %08x\n", 
700                                 (unsigned)queue->smResultCurrent, (unsigned)prevCtrlPtr );
701     QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
702
703     TRACE(msg, "\trcm: calling wndproc - %08x %08x %08x %08x\n",
704                 senderQ->hWnd32, senderQ->msg32,
705                 senderQ->wParam32, (unsigned)senderQ->lParam );
706
707     if (IsWindow32( senderQ->hWnd32 ))
708     {
709         WND *wndPtr = WIN_FindWndPtr( senderQ->hWnd32 );
710         DWORD extraInfo = queue->GetMessageExtraInfoVal;
711         queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
712
713         if (senderQ->flags & QUEUE_SM_WIN32)
714         {
715             TRACE(msg, "\trcm: msg is Win32\n" );
716             if (senderQ->flags & QUEUE_SM_UNICODE)
717                 result = CallWindowProc32W( wndPtr->winproc,
718                                             senderQ->hWnd32, senderQ->msg32,
719                                             senderQ->wParam32, senderQ->lParam );
720             else
721                 result = CallWindowProc32A( wndPtr->winproc,
722                                             senderQ->hWnd32, senderQ->msg32,
723                                             senderQ->wParam32, senderQ->lParam );
724         }
725         else  /* Win16 message */
726             result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
727                                        (HWND16) senderQ->hWnd32,
728                                        (UINT16) senderQ->msg32,
729                                        LOWORD (senderQ->wParam32),
730                                        senderQ->lParam );
731
732         queue->GetMessageExtraInfoVal = extraInfo;  /* Restore extra info */
733         TRACE(msg,"\trcm: result =  %08x\n", (unsigned)result );
734     }
735     else WARN(msg, "\trcm: bad hWnd\n");
736
737     QUEUE_Unlock( senderQ );
738     
739     /* Return the result to the sender task */
740     ReplyMessage16( result );
741
742     queue->InSendMessageHandle = prevSender;
743     queue->smResultCurrent     = prevCtrlPtr;
744
745     TRACE(msg,"done!\n");
746 }
747
748 /***********************************************************************
749  *           QUEUE_FlushMessage
750  * 
751  * Try to reply to all pending sent messages on exit.
752  */
753 void QUEUE_FlushMessages( HQUEUE16 hQueue )
754 {
755   MESSAGEQUEUE *queue = (MESSAGEQUEUE*)QUEUE_Lock( hQueue );
756
757   if( queue )
758   {
759     MESSAGEQUEUE *senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->hSendingTask );
760     QSMCTRL*      CtrlPtr = queue->smResultCurrent;
761
762     TRACE(msg,"Flushing queue %04x:\n", hQueue );
763
764     while( senderQ )
765     {
766       if( !CtrlPtr )
767            CtrlPtr = senderQ->smResultInit;
768
769       TRACE(msg,"\tfrom queue %04x, smResult %08x\n", queue->hSendingTask, (unsigned)CtrlPtr );
770
771       if( !(queue->hSendingTask = senderQ->hPrevSendingTask) )
772         QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
773
774       QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
775       
776       queue->smResultCurrent = CtrlPtr;
777       while( senderQ->wakeBits & QS_SMRESULT ) OldYield();
778
779       senderQ->SendMessageReturn = 0;
780       senderQ->smResult = queue->smResultCurrent;
781       QUEUE_SetWakeBit( senderQ, QS_SMRESULT);
782
783       QUEUE_Unlock( senderQ );
784
785       senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->hSendingTask );
786       CtrlPtr = NULL;
787     }
788     queue->InSendMessageHandle = 0;
789     
790     QUEUE_Unlock( queue );
791   }  
792
793 }
794
795 /***********************************************************************
796  *           QUEUE_AddMsg
797  *
798  * Add a message to the queue. Return FALSE if queue is full.
799  */
800 BOOL32 QUEUE_AddMsg( HQUEUE16 hQueue, MSG32 *msg, DWORD extraInfo )
801 {
802     MESSAGEQUEUE *msgQueue;
803     QMSG         *qmsg;
804
805
806     if (!(msgQueue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return FALSE;
807
808     /* allocate new message in global heap for now */
809     if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
810     {
811         QUEUE_Unlock( msgQueue );
812         return 0;
813     }
814
815     EnterCriticalSection( &msgQueue->cSection );
816
817       /* Store message */
818     qmsg->msg = *msg;
819     qmsg->extraInfo = extraInfo;
820
821     /* insert the message in the link list */
822     qmsg->nextMsg = 0;
823     qmsg->prevMsg = msgQueue->lastMsg;
824
825     if (msgQueue->lastMsg)
826         msgQueue->lastMsg->nextMsg = qmsg;
827
828     /* update first and last anchor in message queue */
829     msgQueue->lastMsg = qmsg;
830     if (!msgQueue->firstMsg)
831         msgQueue->firstMsg = qmsg;
832     
833     msgQueue->msgCount++;
834
835     LeaveCriticalSection( &msgQueue->cSection );
836
837     QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE );
838     QUEUE_Unlock( msgQueue );
839     
840     return TRUE;
841 }
842
843
844
845 /***********************************************************************
846  *           QUEUE_FindMsg
847  *
848  * Find a message matching the given parameters. Return -1 if none available.
849  */
850 QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND32 hwnd, int first, int last )
851 {
852     QMSG* qmsg;
853
854     EnterCriticalSection( &msgQueue->cSection );
855
856     if (!msgQueue->msgCount)
857         qmsg = 0;
858     else if (!hwnd && !first && !last)
859         qmsg = msgQueue->firstMsg;
860     else
861     {
862         /* look in linked list for message matching first and last criteria */
863         for (qmsg = msgQueue->firstMsg; qmsg; qmsg = qmsg->nextMsg)
864     {
865             MSG32 *msg = &(qmsg->msg);
866
867         if (!hwnd || (msg->hwnd == hwnd))
868         {
869                 if (!first && !last)
870                     break;   /* found it */
871                 
872                 if ((msg->message >= first) && (msg->message <= last))
873                     break;   /* found it */
874             }
875         }
876     }
877     
878     LeaveCriticalSection( &msgQueue->cSection );
879
880     return qmsg;
881 }
882
883
884
885 /***********************************************************************
886  *           QUEUE_RemoveMsg
887  *
888  * Remove a message from the queue (pos must be a valid position).
889  */
890 void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg )
891 {
892     EnterCriticalSection( &msgQueue->cSection );
893
894     /* set the linked list */
895     if (qmsg->prevMsg)
896         qmsg->prevMsg->nextMsg = qmsg->nextMsg;
897
898     if (qmsg->nextMsg)
899         qmsg->nextMsg->prevMsg = qmsg->prevMsg;
900
901     if (msgQueue->firstMsg == qmsg)
902         msgQueue->firstMsg = qmsg->nextMsg;
903
904     if (msgQueue->lastMsg == qmsg)
905         msgQueue->lastMsg = qmsg->prevMsg;
906
907     /* deallocate the memory for the message */
908     HeapFree( SystemHeap, 0, qmsg );
909     
910     msgQueue->msgCount--;
911     if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE;
912
913     LeaveCriticalSection( &msgQueue->cSection );
914 }
915
916
917 /***********************************************************************
918  *           QUEUE_WakeSomeone
919  *
920  * Wake a queue upon reception of a hardware event.
921  */
922 static void QUEUE_WakeSomeone( UINT32 message )
923 {
924     WND*          wndPtr = NULL;
925     WORD          wakeBit;
926     HWND32 hwnd;
927     HQUEUE16     hQueue = 0;
928     MESSAGEQUEUE *queue = NULL;
929
930     if (hCursorQueue)
931         hQueue = hCursorQueue;
932
933     if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) )
934     {
935        wakeBit = QS_KEY;
936        if( hActiveQueue )
937            hQueue = hActiveQueue;
938     }
939     else 
940     {
941        wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
942        if( (hwnd = GetCapture32()) )
943          if( (wndPtr = WIN_FindWndPtr( hwnd )) ) 
944            {
945                hQueue = wndPtr->hmemTaskQ;
946            }
947     }
948
949     if( (hwnd = GetSysModalWindow16()) )
950     {
951       if( (wndPtr = WIN_FindWndPtr( hwnd )) )
952             hQueue = wndPtr->hmemTaskQ;
953     }
954
955     if (hQueue)
956         queue = QUEUE_Lock( hQueue );
957     
958     if( !queue ) 
959     {
960         queue = QUEUE_Lock( hFirstQueue );
961       while( queue )
962       {
963         if (queue->wakeMask & wakeBit) break;
964           
965             QUEUE_Unlock(queue);
966             queue = QUEUE_Lock( queue->next );
967       }
968       if( !queue )
969       { 
970         WARN(msg, "couldn't find queue\n"); 
971         return; 
972       }
973     }
974
975     QUEUE_SetWakeBit( queue, wakeBit );
976
977     QUEUE_Unlock( queue );
978 }
979
980
981 /***********************************************************************
982  *           hardware_event
983  *
984  * Add an event to the system message queue.
985  * Note: the position is relative to the desktop window.
986  */
987 void hardware_event( WORD message, WORD wParam, LONG lParam,
988                      int xPos, int yPos, DWORD time, DWORD extraInfo )
989 {
990     MSG32 *msg;
991     QMSG  *qmsg = sysMsgQueue->lastMsg;
992     int  mergeMsg = 0;
993
994     if (!sysMsgQueue) return;
995
996       /* Merge with previous event if possible */
997
998     if ((message == WM_MOUSEMOVE) && sysMsgQueue->lastMsg)
999     {
1000         msg = &(sysMsgQueue->lastMsg->msg);
1001         
1002         if ((msg->message == message) && (msg->wParam == wParam))
1003         {
1004             /* Merge events */
1005             qmsg = sysMsgQueue->lastMsg;
1006             mergeMsg = 1;
1007     }
1008     }
1009
1010     if (!mergeMsg)
1011     {
1012         /* Should I limit the number of message in
1013           the system message queue??? */
1014
1015         /* Don't merge allocate a new msg in the global heap */
1016         
1017         if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
1018         return;
1019         
1020         /* put message at the end of the linked list */
1021         qmsg->nextMsg = 0;
1022         qmsg->prevMsg = sysMsgQueue->lastMsg;
1023
1024         if (sysMsgQueue->lastMsg)
1025             sysMsgQueue->lastMsg->nextMsg = qmsg;
1026
1027         /* set last and first anchor index in system message queue */
1028         sysMsgQueue->lastMsg = qmsg;
1029         if (!sysMsgQueue->firstMsg)
1030             sysMsgQueue->firstMsg = qmsg;
1031         
1032         sysMsgQueue->msgCount++;
1033     }
1034
1035       /* Store message */
1036     msg = &(qmsg->msg);
1037     msg->hwnd    = 0;
1038     msg->message = message;
1039     msg->wParam  = wParam;
1040     msg->lParam  = lParam;
1041     msg->time    = time;
1042     msg->pt.x    = xPos;
1043     msg->pt.y    = yPos;
1044     qmsg->extraInfo = extraInfo;
1045
1046     QUEUE_WakeSomeone( message );
1047 }
1048
1049                     
1050 /***********************************************************************
1051  *           QUEUE_GetQueueTask
1052  */
1053 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
1054 {
1055     HTASK16 hTask = 0;
1056     
1057     MESSAGEQUEUE *queue = QUEUE_Lock( hQueue );
1058
1059     if (queue)
1060 {
1061         hTask = queue->thdb->process->task;
1062         QUEUE_Unlock( queue );
1063 }
1064
1065     return hTask;
1066 }
1067
1068
1069
1070 /***********************************************************************
1071  *           QUEUE_IncPaintCount
1072  */
1073 void QUEUE_IncPaintCount( HQUEUE16 hQueue )
1074 {
1075     MESSAGEQUEUE *queue;
1076
1077     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1078     queue->wPaintCount++;
1079     QUEUE_SetWakeBit( queue, QS_PAINT );
1080     QUEUE_Unlock( queue );
1081 }
1082
1083
1084 /***********************************************************************
1085  *           QUEUE_DecPaintCount
1086  */
1087 void QUEUE_DecPaintCount( HQUEUE16 hQueue )
1088 {
1089     MESSAGEQUEUE *queue;
1090
1091     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1092     queue->wPaintCount--;
1093     if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
1094     QUEUE_Unlock( queue );
1095 }
1096
1097
1098 /***********************************************************************
1099  *           QUEUE_IncTimerCount
1100  */
1101 void QUEUE_IncTimerCount( HQUEUE16 hQueue )
1102 {
1103     MESSAGEQUEUE *queue;
1104
1105     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1106     queue->wTimerCount++;
1107     QUEUE_SetWakeBit( queue, QS_TIMER );
1108     QUEUE_Unlock( queue );
1109 }
1110
1111
1112 /***********************************************************************
1113  *           QUEUE_DecTimerCount
1114  */
1115 void QUEUE_DecTimerCount( HQUEUE16 hQueue )
1116 {
1117     MESSAGEQUEUE *queue;
1118
1119     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1120     queue->wTimerCount--;
1121     if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
1122     QUEUE_Unlock( queue );
1123 }
1124
1125
1126 /***********************************************************************
1127  *           PostQuitMessage16   (USER.6)
1128  */
1129 void WINAPI PostQuitMessage16( INT16 exitCode )
1130 {
1131     PostQuitMessage32( exitCode );
1132 }
1133
1134
1135 /***********************************************************************
1136  *           PostQuitMessage32   (USER32.421)
1137  *
1138  * PostQuitMessage() posts a message to the system requesting an
1139  * application to terminate execution. As a result of this function,
1140  * the WM_QUIT message is posted to the application, and
1141  * PostQuitMessage() returns immediately.  The exitCode parameter
1142  * specifies an application-defined exit code, which appears in the
1143  * _wParam_ parameter of the WM_QUIT message posted to the application.  
1144  *
1145  * CONFORMANCE
1146  *
1147  *  ECMA-234, Win32
1148  */
1149 void WINAPI PostQuitMessage32( INT32 exitCode )
1150 {
1151     MESSAGEQUEUE *queue;
1152
1153     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return;
1154     queue->wPostQMsg = TRUE;
1155     queue->wExitCode = (WORD)exitCode;
1156     QUEUE_Unlock( queue );
1157 }
1158
1159
1160 /***********************************************************************
1161  *           GetWindowTask16   (USER.224)
1162  */
1163 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
1164 {
1165     WND *wndPtr = WIN_FindWndPtr( hwnd );
1166
1167     if (!wndPtr) return 0;
1168     return QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1169 }
1170
1171 /***********************************************************************
1172  *           GetWindowThreadProcessId   (USER32.313)
1173  */
1174 DWORD WINAPI GetWindowThreadProcessId( HWND32 hwnd, LPDWORD process )
1175 {
1176     HTASK16 htask;
1177     TDB *tdb;
1178
1179     WND *wndPtr = WIN_FindWndPtr( hwnd );
1180
1181     if (!wndPtr) return 0;
1182     htask=QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1183     tdb = (TDB*)GlobalLock16(htask);
1184     if (!tdb || !tdb->thdb) return 0;
1185     if (process) *process = PDB_TO_PROCESS_ID( tdb->thdb->process );
1186     return THDB_TO_THREAD_ID( tdb->thdb );
1187 }
1188
1189
1190 /***********************************************************************
1191  *           SetMessageQueue16   (USER.266)
1192  */
1193 BOOL16 WINAPI SetMessageQueue16( INT16 size )
1194 {
1195     return SetMessageQueue32( size );
1196 }
1197
1198
1199 /***********************************************************************
1200  *           SetMessageQueue32   (USER32.494)
1201  */
1202 BOOL32 WINAPI SetMessageQueue32( INT32 size )
1203 {
1204     /* now obsolete the message queue will be expanded dynamically
1205      as necessary */
1206
1207     /* access the queue to create it if it's not existing */
1208     GetFastQueue();
1209
1210     return TRUE;
1211 }
1212
1213 /***********************************************************************
1214  *           InitThreadInput   (USER.409)
1215  */
1216 HQUEUE16 WINAPI InitThreadInput( WORD unknown, WORD flags )
1217 {
1218     HQUEUE16 hQueue;
1219     MESSAGEQUEUE *queuePtr;
1220
1221     THDB *thdb = THREAD_Current();
1222
1223     if (!thdb)
1224         return 0;
1225
1226     hQueue = thdb->teb.queue;
1227     
1228     if ( !hQueue )
1229     {
1230         /* Create thread message queue */
1231         if( !(hQueue = QUEUE_CreateMsgQueue( TRUE )))
1232         {
1233             WARN(msg, "failed!\n");
1234             return FALSE;
1235     }
1236         
1237         /* Link new queue into list */
1238         queuePtr = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
1239         queuePtr->thdb = THREAD_Current();
1240
1241         SYSTEM_LOCK();
1242         SetThreadQueue( 0, hQueue );
1243         thdb->teb.queue = hQueue;
1244             
1245         queuePtr->next  = hFirstQueue;
1246         hFirstQueue = hQueue;
1247         SYSTEM_UNLOCK();
1248         
1249         QUEUE_Unlock( queuePtr );
1250     }
1251
1252     return hQueue;
1253 }
1254
1255 /***********************************************************************
1256  *           GetQueueStatus16   (USER.334)
1257  */
1258 DWORD WINAPI GetQueueStatus16( UINT16 flags )
1259 {
1260     MESSAGEQUEUE *queue;
1261     DWORD ret;
1262
1263     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return 0;
1264     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1265     queue->changeBits = 0;
1266     QUEUE_Unlock( queue );
1267     
1268     return ret & MAKELONG( flags, flags );
1269 }
1270
1271 /***********************************************************************
1272  *           GetQueueStatus32   (USER32.283)
1273  */
1274 DWORD WINAPI GetQueueStatus32( UINT32 flags )
1275 {
1276     MESSAGEQUEUE *queue;
1277     DWORD ret;
1278
1279     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return 0;
1280     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1281     queue->changeBits = 0;
1282     QUEUE_Unlock( queue );
1283     
1284     return ret & MAKELONG( flags, flags );
1285 }
1286
1287
1288 /***********************************************************************
1289  *           GetInputState16   (USER.335)
1290  */
1291 BOOL16 WINAPI GetInputState16(void)
1292 {
1293     return GetInputState32();
1294 }
1295
1296 /***********************************************************************
1297  *           WaitForInputIdle   (USER32.577)
1298  */
1299 DWORD WINAPI WaitForInputIdle (HANDLE32 hProcess, DWORD dwTimeOut)
1300 {
1301   FIXME (msg, "(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut);
1302
1303   return WAIT_TIMEOUT;
1304 }
1305
1306
1307 /***********************************************************************
1308  *           GetInputState32   (USER32.244)
1309  */
1310 BOOL32 WINAPI GetInputState32(void)
1311 {
1312     MESSAGEQUEUE *queue;
1313     BOOL32 ret;
1314
1315     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() )))
1316         return FALSE;
1317     ret = queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
1318     QUEUE_Unlock( queue );
1319
1320     return ret;
1321 }
1322
1323 /***********************************************************************
1324  *           UserYield  (USER.332)
1325  */
1326 void WINAPI UserYield(void)
1327 {
1328     TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
1329     MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( pCurTask->hQueue );
1330
1331     if ( !THREAD_IsWin16( THREAD_Current() ) )
1332     {
1333         FIXME(task, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel);
1334         QUEUE_Unlock( queue );
1335         return;
1336     }
1337
1338     /* Handle sent messages */
1339     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1340         QUEUE_ReceiveMessage( queue );
1341
1342     QUEUE_Unlock( queue );
1343     
1344     OldYield();
1345
1346     queue = (MESSAGEQUEUE *)QUEUE_Lock( pCurTask->hQueue );
1347     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1348         QUEUE_ReceiveMessage( queue );
1349
1350     QUEUE_Unlock( queue );
1351 }
1352
1353 /***********************************************************************
1354  *           GetMessagePos   (USER.119) (USER32.272)
1355  * 
1356  * The GetMessagePos() function returns a long value representing a
1357  * cursor position, in screen coordinates, when the last message
1358  * retrieved by the GetMessage() function occurs. The x-coordinate is
1359  * in the low-order word of the return value, the y-coordinate is in
1360  * the high-order word. The application can use the MAKEPOINT()
1361  * macro to obtain a POINT structure from the return value. 
1362  *
1363  * For the current cursor position, use GetCursorPos().
1364  *
1365  * RETURNS
1366  *
1367  * Cursor position of last message on success, zero on failure.
1368  *
1369  * CONFORMANCE
1370  *
1371  * ECMA-234, Win32
1372  *
1373  */
1374 DWORD WINAPI GetMessagePos(void)
1375 {
1376     MESSAGEQUEUE *queue;
1377     DWORD ret;
1378
1379     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return 0;
1380     ret = queue->GetMessagePosVal;
1381     QUEUE_Unlock( queue );
1382
1383     return ret;
1384 }
1385
1386
1387 /***********************************************************************
1388  *           GetMessageTime   (USER.120) (USER32.273)
1389  *
1390  * GetMessageTime() returns the message time for the last message
1391  * retrieved by the function. The time is measured in milliseconds with
1392  * the same offset as GetTickCount().
1393  *
1394  * Since the tick count wraps, this is only useful for moderately short
1395  * relative time comparisons.
1396  *
1397  * RETURNS
1398  *
1399  * Time of last message on success, zero on failure.
1400  *
1401  * CONFORMANCE
1402  *
1403  * ECMA-234, Win32
1404  *  
1405  */
1406 LONG WINAPI GetMessageTime(void)
1407 {
1408     MESSAGEQUEUE *queue;
1409     LONG ret;
1410
1411     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return 0;
1412     ret = queue->GetMessageTimeVal;
1413     QUEUE_Unlock( queue );
1414     
1415     return ret;
1416 }
1417
1418
1419 /***********************************************************************
1420  *           GetMessageExtraInfo   (USER.288) (USER32.271)
1421  */
1422 LONG WINAPI GetMessageExtraInfo(void)
1423 {
1424     MESSAGEQUEUE *queue;
1425     LONG ret;
1426
1427     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return 0;
1428     ret = queue->GetMessageExtraInfoVal;
1429     QUEUE_Unlock( queue );
1430
1431     return ret;
1432 }