Added management and allocation of the PERQUEUEDATA structure.
[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         pPrev = &msgQ->next;
516     }
517     if (*pPrev) *pPrev = msgQueue->next;
518     msgQueue->self = 0;
519
520     SYSTEM_UNLOCK();
521
522     /* free up resource used by MESSAGEQUEUE strcture */
523     msgQueue->lockCount--;
524     QUEUE_Unlock( msgQueue );
525     
526     return 1;
527 }
528
529
530 /***********************************************************************
531  *           QUEUE_CreateSysMsgQueue
532  *
533  * Create the system message queue, and set the double-click speed.
534  * Must be called only once.
535  */
536 BOOL32 QUEUE_CreateSysMsgQueue( int size )
537 {
538     /* Note: We dont need perQ data for the system message queue */
539     if (!(hmemSysMsgQueue = QUEUE_CreateMsgQueue( FALSE )))
540         return FALSE;
541     
542     sysMsgQueue = (MESSAGEQUEUE *) GlobalLock16( hmemSysMsgQueue );
543     return TRUE;
544 }
545
546
547 /***********************************************************************
548  *           QUEUE_GetSysQueue
549  */
550 MESSAGEQUEUE *QUEUE_GetSysQueue(void)
551 {
552     return sysMsgQueue;
553 }
554
555 /***********************************************************************
556  *           QUEUE_Signal
557  */
558 void QUEUE_Signal( THDB *thdb  )
559 {
560     /* Wake up thread waiting for message */
561     SetEvent( thdb->event );
562
563     PostEvent( thdb->process->task );
564 }
565
566 /***********************************************************************
567  *           QUEUE_Wait
568  */
569 static void QUEUE_Wait( DWORD wait_mask )
570 {
571     if ( THREAD_IsWin16( THREAD_Current() ) )
572         WaitEvent( 0 );
573     else
574     {
575         TRACE(msg, "current task is 32-bit, calling SYNC_DoWait\n");
576         MsgWaitForMultipleObjects( 0, NULL, FALSE, INFINITE32, wait_mask );
577     }
578 }
579
580
581 /***********************************************************************
582  *           QUEUE_SetWakeBit               `
583  *
584  * See "Windows Internals", p.449
585  */
586 void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit )
587 {
588     TRACE(msg,"queue = %04x (wm=%04x), bit = %04x\n", 
589                         queue->self, queue->wakeMask, bit );
590
591     if (bit & QS_MOUSE) pMouseQueue = queue;
592     if (bit & QS_KEY) pKbdQueue = queue;
593     queue->changeBits |= bit;
594     queue->wakeBits   |= bit;
595     if (queue->wakeMask & bit)
596     {
597         queue->wakeMask = 0;
598         QUEUE_Signal( queue->thdb );
599     }
600 }
601
602
603 /***********************************************************************
604  *           QUEUE_ClearWakeBit
605  */
606 void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
607 {
608     queue->changeBits &= ~bit;
609     queue->wakeBits   &= ~bit;
610 }
611
612
613 /***********************************************************************
614  *           QUEUE_WaitBits
615  *
616  * See "Windows Internals", p.447
617  */
618 void QUEUE_WaitBits( WORD bits )
619 {
620     MESSAGEQUEUE *queue;
621
622     TRACE(msg,"q %04x waiting for %04x\n", GetFastQueue(), bits);
623
624     for (;;)
625     {
626         if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return;
627
628         if (queue->changeBits & bits)
629         {
630             /* One of the bits is set; we can return */
631             queue->wakeMask = 0;
632             QUEUE_Unlock( queue );
633             return;
634         }
635         if (queue->wakeBits & QS_SENDMESSAGE)
636         {
637             /* Process the sent message immediately */
638
639             queue->wakeMask = 0;
640             QUEUE_ReceiveMessage( queue );
641             QUEUE_Unlock( queue );
642             continue;                           /* nested sm crux */
643         }
644
645         queue->wakeMask = bits | QS_SENDMESSAGE;
646         if(queue->changeBits & bits)
647         {
648             QUEUE_Unlock( queue );
649             continue;
650         }
651         
652         TRACE(msg,"%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask);
653
654         QUEUE_Wait( queue->wakeMask );
655
656         QUEUE_Unlock( queue );
657     }
658 }
659
660
661 /***********************************************************************
662  *           QUEUE_ReceiveMessage
663  *
664  * This routine is called when a sent message is waiting for the queue.
665  */
666 void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
667 {
668     MESSAGEQUEUE *senderQ = NULL;
669     HQUEUE16      prevSender = 0;
670     QSMCTRL*      prevCtrlPtr = NULL;
671     LRESULT       result = 0;
672
673     TRACE(msg, "ReceiveMessage, queue %04x\n", queue->self );
674     if (!(queue->wakeBits & QS_SENDMESSAGE) ||
675         !(senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->hSendingTask)))
676         { TRACE(msg,"\trcm: nothing to do\n"); return; }
677
678     if( !senderQ->hPrevSendingTask )
679         QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );   /* no more sent messages */
680
681     /* Save current state on stack */
682     prevSender                 = queue->InSendMessageHandle;
683     prevCtrlPtr                = queue->smResultCurrent;
684
685     /* Remove sending queue from the list */
686     queue->InSendMessageHandle = queue->hSendingTask;
687     queue->smResultCurrent     = senderQ->smResultInit;
688     queue->hSendingTask        = senderQ->hPrevSendingTask;
689
690     TRACE(msg, "\trcm: smResultCurrent = %08x, prevCtrl = %08x\n", 
691                                 (unsigned)queue->smResultCurrent, (unsigned)prevCtrlPtr );
692     QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
693
694     TRACE(msg, "\trcm: calling wndproc - %08x %08x %08x %08x\n",
695                 senderQ->hWnd32, senderQ->msg32,
696                 senderQ->wParam32, (unsigned)senderQ->lParam );
697
698     if (IsWindow32( senderQ->hWnd32 ))
699     {
700         WND *wndPtr = WIN_FindWndPtr( senderQ->hWnd32 );
701         DWORD extraInfo = queue->GetMessageExtraInfoVal;
702         queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
703
704         if (senderQ->flags & QUEUE_SM_WIN32)
705         {
706             TRACE(msg, "\trcm: msg is Win32\n" );
707             if (senderQ->flags & QUEUE_SM_UNICODE)
708                 result = CallWindowProc32W( wndPtr->winproc,
709                                             senderQ->hWnd32, senderQ->msg32,
710                                             senderQ->wParam32, senderQ->lParam );
711             else
712                 result = CallWindowProc32A( wndPtr->winproc,
713                                             senderQ->hWnd32, senderQ->msg32,
714                                             senderQ->wParam32, senderQ->lParam );
715         }
716         else  /* Win16 message */
717             result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
718                                        (HWND16) senderQ->hWnd32,
719                                        (UINT16) senderQ->msg32,
720                                        LOWORD (senderQ->wParam32),
721                                        senderQ->lParam );
722
723         queue->GetMessageExtraInfoVal = extraInfo;  /* Restore extra info */
724         TRACE(msg,"\trcm: result =  %08x\n", (unsigned)result );
725     }
726     else WARN(msg, "\trcm: bad hWnd\n");
727
728     QUEUE_Unlock( senderQ );
729     
730     /* Return the result to the sender task */
731     ReplyMessage16( result );
732
733     queue->InSendMessageHandle = prevSender;
734     queue->smResultCurrent     = prevCtrlPtr;
735
736     TRACE(msg,"done!\n");
737 }
738
739 /***********************************************************************
740  *           QUEUE_FlushMessage
741  * 
742  * Try to reply to all pending sent messages on exit.
743  */
744 void QUEUE_FlushMessages( HQUEUE16 hQueue )
745 {
746   MESSAGEQUEUE *queue = (MESSAGEQUEUE*)QUEUE_Lock( hQueue );
747
748   if( queue )
749   {
750     MESSAGEQUEUE *senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->hSendingTask );
751     QSMCTRL*      CtrlPtr = queue->smResultCurrent;
752
753     TRACE(msg,"Flushing queue %04x:\n", hQueue );
754
755     while( senderQ )
756     {
757       if( !CtrlPtr )
758            CtrlPtr = senderQ->smResultInit;
759
760       TRACE(msg,"\tfrom queue %04x, smResult %08x\n", queue->hSendingTask, (unsigned)CtrlPtr );
761
762       if( !(queue->hSendingTask = senderQ->hPrevSendingTask) )
763         QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
764
765       QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
766       
767       queue->smResultCurrent = CtrlPtr;
768       while( senderQ->wakeBits & QS_SMRESULT ) OldYield();
769
770       senderQ->SendMessageReturn = 0;
771       senderQ->smResult = queue->smResultCurrent;
772       QUEUE_SetWakeBit( senderQ, QS_SMRESULT);
773
774       QUEUE_Unlock( senderQ );
775
776       senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->hSendingTask );
777       CtrlPtr = NULL;
778     }
779     queue->InSendMessageHandle = 0;
780     
781     QUEUE_Unlock( queue );
782   }  
783
784 }
785
786 /***********************************************************************
787  *           QUEUE_AddMsg
788  *
789  * Add a message to the queue. Return FALSE if queue is full.
790  */
791 BOOL32 QUEUE_AddMsg( HQUEUE16 hQueue, MSG32 *msg, DWORD extraInfo )
792 {
793     MESSAGEQUEUE *msgQueue;
794     QMSG         *qmsg;
795
796
797     if (!(msgQueue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return FALSE;
798
799     /* allocate new message in global heap for now */
800     if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
801     {
802         QUEUE_Unlock( msgQueue );
803         return 0;
804     }
805
806     EnterCriticalSection( &msgQueue->cSection );
807
808       /* Store message */
809     qmsg->msg = *msg;
810     qmsg->extraInfo = extraInfo;
811
812     /* insert the message in the link list */
813     qmsg->nextMsg = 0;
814     qmsg->prevMsg = msgQueue->lastMsg;
815
816     if (msgQueue->lastMsg)
817         msgQueue->lastMsg->nextMsg = qmsg;
818
819     /* update first and last anchor in message queue */
820     msgQueue->lastMsg = qmsg;
821     if (!msgQueue->firstMsg)
822         msgQueue->firstMsg = qmsg;
823     
824     msgQueue->msgCount++;
825
826     LeaveCriticalSection( &msgQueue->cSection );
827
828     QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE );
829     QUEUE_Unlock( msgQueue );
830     
831     return TRUE;
832 }
833
834
835
836 /***********************************************************************
837  *           QUEUE_FindMsg
838  *
839  * Find a message matching the given parameters. Return -1 if none available.
840  */
841 QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND32 hwnd, int first, int last )
842 {
843     QMSG* qmsg;
844
845     EnterCriticalSection( &msgQueue->cSection );
846
847     if (!msgQueue->msgCount)
848         qmsg = 0;
849     else if (!hwnd && !first && !last)
850         qmsg = msgQueue->firstMsg;
851     else
852     {
853         /* look in linked list for message matching first and last criteria */
854         for (qmsg = msgQueue->firstMsg; qmsg; qmsg = qmsg->nextMsg)
855     {
856             MSG32 *msg = &(qmsg->msg);
857
858         if (!hwnd || (msg->hwnd == hwnd))
859         {
860                 if (!first && !last)
861                     break;   /* found it */
862                 
863                 if ((msg->message >= first) && (msg->message <= last))
864                     break;   /* found it */
865             }
866         }
867     }
868     
869     LeaveCriticalSection( &msgQueue->cSection );
870
871     return qmsg;
872 }
873
874
875
876 /***********************************************************************
877  *           QUEUE_RemoveMsg
878  *
879  * Remove a message from the queue (pos must be a valid position).
880  */
881 void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg )
882 {
883     EnterCriticalSection( &msgQueue->cSection );
884
885     /* set the linked list */
886     if (qmsg->prevMsg)
887         qmsg->prevMsg->nextMsg = qmsg->nextMsg;
888
889     if (qmsg->nextMsg)
890         qmsg->nextMsg->prevMsg = qmsg->prevMsg;
891
892     if (msgQueue->firstMsg == qmsg)
893         msgQueue->firstMsg = qmsg->nextMsg;
894
895     if (msgQueue->lastMsg == qmsg)
896         msgQueue->lastMsg = qmsg->prevMsg;
897
898     /* deallocate the memory for the message */
899     HeapFree( SystemHeap, 0, qmsg );
900     
901     msgQueue->msgCount--;
902     if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE;
903
904     LeaveCriticalSection( &msgQueue->cSection );
905 }
906
907
908 /***********************************************************************
909  *           QUEUE_WakeSomeone
910  *
911  * Wake a queue upon reception of a hardware event.
912  */
913 static void QUEUE_WakeSomeone( UINT32 message )
914 {
915     WND*          wndPtr = NULL;
916     WORD          wakeBit;
917     HWND32 hwnd;
918     HQUEUE16     hQueue = 0;
919     MESSAGEQUEUE *queue = NULL;
920
921     if (hCursorQueue)
922         hQueue = hCursorQueue;
923
924     if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) )
925     {
926        wakeBit = QS_KEY;
927        if( hActiveQueue )
928            hQueue = hActiveQueue;
929     }
930     else 
931     {
932        wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
933        if( (hwnd = GetCapture32()) )
934          if( (wndPtr = WIN_FindWndPtr( hwnd )) ) 
935            {
936                hQueue = wndPtr->hmemTaskQ;
937            }
938     }
939
940     if( (hwnd = GetSysModalWindow16()) )
941     {
942       if( (wndPtr = WIN_FindWndPtr( hwnd )) )
943             hQueue = wndPtr->hmemTaskQ;
944     }
945
946     if (hQueue)
947         queue = QUEUE_Lock( hQueue );
948     
949     if( !queue ) 
950     {
951         queue = QUEUE_Lock( hFirstQueue );
952       while( queue )
953       {
954         if (queue->wakeMask & wakeBit) break;
955           
956             QUEUE_Unlock(queue);
957             queue = QUEUE_Lock( queue->next );
958       }
959       if( !queue )
960       { 
961         WARN(msg, "couldn't find queue\n"); 
962         return; 
963       }
964     }
965
966     QUEUE_SetWakeBit( queue, wakeBit );
967
968     QUEUE_Unlock( queue );
969 }
970
971
972 /***********************************************************************
973  *           hardware_event
974  *
975  * Add an event to the system message queue.
976  * Note: the position is relative to the desktop window.
977  */
978 void hardware_event( WORD message, WORD wParam, LONG lParam,
979                      int xPos, int yPos, DWORD time, DWORD extraInfo )
980 {
981     MSG32 *msg;
982     QMSG  *qmsg = sysMsgQueue->lastMsg;
983     int  mergeMsg = 0;
984
985     if (!sysMsgQueue) return;
986
987       /* Merge with previous event if possible */
988
989     if ((message == WM_MOUSEMOVE) && sysMsgQueue->lastMsg)
990     {
991         msg = &(sysMsgQueue->lastMsg->msg);
992         
993         if ((msg->message == message) && (msg->wParam == wParam))
994         {
995             /* Merge events */
996             qmsg = sysMsgQueue->lastMsg;
997             mergeMsg = 1;
998     }
999     }
1000
1001     if (!mergeMsg)
1002     {
1003         /* Should I limit the number of message in
1004           the system message queue??? */
1005
1006         /* Don't merge allocate a new msg in the global heap */
1007         
1008         if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
1009         return;
1010         
1011         /* put message at the end of the linked list */
1012         qmsg->nextMsg = 0;
1013         qmsg->prevMsg = sysMsgQueue->lastMsg;
1014
1015         if (sysMsgQueue->lastMsg)
1016             sysMsgQueue->lastMsg->nextMsg = qmsg;
1017
1018         /* set last and first anchor index in system message queue */
1019         sysMsgQueue->lastMsg = qmsg;
1020         if (!sysMsgQueue->firstMsg)
1021             sysMsgQueue->firstMsg = qmsg;
1022         
1023         sysMsgQueue->msgCount++;
1024     }
1025
1026       /* Store message */
1027     msg = &(qmsg->msg);
1028     msg->hwnd    = 0;
1029     msg->message = message;
1030     msg->wParam  = wParam;
1031     msg->lParam  = lParam;
1032     msg->time    = time;
1033     msg->pt.x    = xPos;
1034     msg->pt.y    = yPos;
1035     qmsg->extraInfo = extraInfo;
1036
1037     QUEUE_WakeSomeone( message );
1038 }
1039
1040                     
1041 /***********************************************************************
1042  *           QUEUE_GetQueueTask
1043  */
1044 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
1045 {
1046     HTASK16 hTask = 0;
1047     
1048     MESSAGEQUEUE *queue = QUEUE_Lock( hQueue );
1049
1050     if (queue)
1051 {
1052         hTask = queue->thdb->process->task;
1053         QUEUE_Unlock( queue );
1054 }
1055
1056     return hTask;
1057 }
1058
1059
1060
1061 /***********************************************************************
1062  *           QUEUE_IncPaintCount
1063  */
1064 void QUEUE_IncPaintCount( HQUEUE16 hQueue )
1065 {
1066     MESSAGEQUEUE *queue;
1067
1068     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1069     queue->wPaintCount++;
1070     QUEUE_SetWakeBit( queue, QS_PAINT );
1071     QUEUE_Unlock( queue );
1072 }
1073
1074
1075 /***********************************************************************
1076  *           QUEUE_DecPaintCount
1077  */
1078 void QUEUE_DecPaintCount( HQUEUE16 hQueue )
1079 {
1080     MESSAGEQUEUE *queue;
1081
1082     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1083     queue->wPaintCount--;
1084     if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
1085     QUEUE_Unlock( queue );
1086 }
1087
1088
1089 /***********************************************************************
1090  *           QUEUE_IncTimerCount
1091  */
1092 void QUEUE_IncTimerCount( HQUEUE16 hQueue )
1093 {
1094     MESSAGEQUEUE *queue;
1095
1096     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1097     queue->wTimerCount++;
1098     QUEUE_SetWakeBit( queue, QS_TIMER );
1099     QUEUE_Unlock( queue );
1100 }
1101
1102
1103 /***********************************************************************
1104  *           QUEUE_DecTimerCount
1105  */
1106 void QUEUE_DecTimerCount( HQUEUE16 hQueue )
1107 {
1108     MESSAGEQUEUE *queue;
1109
1110     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1111     queue->wTimerCount--;
1112     if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
1113     QUEUE_Unlock( queue );
1114 }
1115
1116
1117 /***********************************************************************
1118  *           PostQuitMessage16   (USER.6)
1119  */
1120 void WINAPI PostQuitMessage16( INT16 exitCode )
1121 {
1122     PostQuitMessage32( exitCode );
1123 }
1124
1125
1126 /***********************************************************************
1127  *           PostQuitMessage32   (USER32.421)
1128  *
1129  * PostQuitMessage() posts a message to the system requesting an
1130  * application to terminate execution. As a result of this function,
1131  * the WM_QUIT message is posted to the application, and
1132  * PostQuitMessage() returns immediately.  The exitCode parameter
1133  * specifies an application-defined exit code, which appears in the
1134  * _wParam_ parameter of the WM_QUIT message posted to the application.  
1135  *
1136  * CONFORMANCE
1137  *
1138  *  ECMA-234, Win32
1139  */
1140 void WINAPI PostQuitMessage32( INT32 exitCode )
1141 {
1142     MESSAGEQUEUE *queue;
1143
1144     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return;
1145     queue->wPostQMsg = TRUE;
1146     queue->wExitCode = (WORD)exitCode;
1147     QUEUE_Unlock( queue );
1148 }
1149
1150
1151 /***********************************************************************
1152  *           GetWindowTask16   (USER.224)
1153  */
1154 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
1155 {
1156     WND *wndPtr = WIN_FindWndPtr( hwnd );
1157
1158     if (!wndPtr) return 0;
1159     return QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1160 }
1161
1162 /***********************************************************************
1163  *           GetWindowThreadProcessId   (USER32.313)
1164  */
1165 DWORD WINAPI GetWindowThreadProcessId( HWND32 hwnd, LPDWORD process )
1166 {
1167     HTASK16 htask;
1168     TDB *tdb;
1169
1170     WND *wndPtr = WIN_FindWndPtr( hwnd );
1171
1172     if (!wndPtr) return 0;
1173     htask=QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1174     tdb = (TDB*)GlobalLock16(htask);
1175     if (!tdb || !tdb->thdb) return 0;
1176     if (process) *process = PDB_TO_PROCESS_ID( tdb->thdb->process );
1177     return THDB_TO_THREAD_ID( tdb->thdb );
1178 }
1179
1180
1181 /***********************************************************************
1182  *           SetMessageQueue16   (USER.266)
1183  */
1184 BOOL16 WINAPI SetMessageQueue16( INT16 size )
1185 {
1186     return SetMessageQueue32( size );
1187 }
1188
1189
1190 /***********************************************************************
1191  *           SetMessageQueue32   (USER32.494)
1192  */
1193 BOOL32 WINAPI SetMessageQueue32( INT32 size )
1194 {
1195     /* now obsolete the message queue will be expanded dynamically
1196      as necessary */
1197
1198     /* access the queue to create it if it's not existing */
1199     GetFastQueue();
1200
1201     return TRUE;
1202 }
1203
1204 /***********************************************************************
1205  *           InitThreadInput   (USER.409)
1206  */
1207 HQUEUE16 WINAPI InitThreadInput( WORD unknown, WORD flags )
1208 {
1209     HQUEUE16 hQueue;
1210     MESSAGEQUEUE *queuePtr;
1211
1212     THDB *thdb = THREAD_Current();
1213
1214     if (!thdb)
1215         return 0;
1216
1217     hQueue = thdb->teb.queue;
1218     
1219     if ( !hQueue )
1220     {
1221         /* Create thread message queue */
1222         if( !(hQueue = QUEUE_CreateMsgQueue( TRUE )))
1223         {
1224             WARN(msg, "failed!\n");
1225             return FALSE;
1226     }
1227         
1228         /* Link new queue into list */
1229         queuePtr = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
1230         queuePtr->thdb = THREAD_Current();
1231
1232         SYSTEM_LOCK();
1233         SetThreadQueue( 0, hQueue );
1234         thdb->teb.queue = hQueue;
1235             
1236         queuePtr->next  = hFirstQueue;
1237         hFirstQueue = hQueue;
1238         SYSTEM_UNLOCK();
1239         
1240         QUEUE_Unlock( queuePtr );
1241     }
1242
1243     return hQueue;
1244 }
1245
1246 /***********************************************************************
1247  *           GetQueueStatus16   (USER.334)
1248  */
1249 DWORD WINAPI GetQueueStatus16( UINT16 flags )
1250 {
1251     MESSAGEQUEUE *queue;
1252     DWORD ret;
1253
1254     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return 0;
1255     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1256     queue->changeBits = 0;
1257     QUEUE_Unlock( queue );
1258     
1259     return ret & MAKELONG( flags, flags );
1260 }
1261
1262 /***********************************************************************
1263  *           GetQueueStatus32   (USER32.283)
1264  */
1265 DWORD WINAPI GetQueueStatus32( UINT32 flags )
1266 {
1267     MESSAGEQUEUE *queue;
1268     DWORD ret;
1269
1270     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return 0;
1271     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1272     queue->changeBits = 0;
1273     QUEUE_Unlock( queue );
1274     
1275     return ret & MAKELONG( flags, flags );
1276 }
1277
1278
1279 /***********************************************************************
1280  *           GetInputState16   (USER.335)
1281  */
1282 BOOL16 WINAPI GetInputState16(void)
1283 {
1284     return GetInputState32();
1285 }
1286
1287 /***********************************************************************
1288  *           WaitForInputIdle   (USER32.577)
1289  */
1290 DWORD WINAPI WaitForInputIdle (HANDLE32 hProcess, DWORD dwTimeOut)
1291 {
1292   FIXME (msg, "(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut);
1293
1294   return WAIT_TIMEOUT;
1295 }
1296
1297
1298 /***********************************************************************
1299  *           GetInputState32   (USER32.244)
1300  */
1301 BOOL32 WINAPI GetInputState32(void)
1302 {
1303     MESSAGEQUEUE *queue;
1304     BOOL32 ret;
1305
1306     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() )))
1307         return FALSE;
1308     ret = queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
1309     QUEUE_Unlock( queue );
1310
1311     return ret;
1312 }
1313
1314 /***********************************************************************
1315  *           UserYield  (USER.332)
1316  */
1317 void WINAPI UserYield(void)
1318 {
1319     TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
1320     MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( pCurTask->hQueue );
1321
1322     if ( !THREAD_IsWin16( THREAD_Current() ) )
1323     {
1324         FIXME(task, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel);
1325         QUEUE_Unlock( queue );
1326         return;
1327     }
1328
1329     /* Handle sent messages */
1330     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1331         QUEUE_ReceiveMessage( queue );
1332
1333     QUEUE_Unlock( queue );
1334     
1335     OldYield();
1336
1337     queue = (MESSAGEQUEUE *)QUEUE_Lock( pCurTask->hQueue );
1338     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1339         QUEUE_ReceiveMessage( queue );
1340
1341     QUEUE_Unlock( queue );
1342 }
1343
1344 /***********************************************************************
1345  *           GetMessagePos   (USER.119) (USER32.272)
1346  * 
1347  * The GetMessagePos() function returns a long value representing a
1348  * cursor position, in screen coordinates, when the last message
1349  * retrieved by the GetMessage() function occurs. The x-coordinate is
1350  * in the low-order word of the return value, the y-coordinate is in
1351  * the high-order word. The application can use the MAKEPOINT()
1352  * macro to obtain a POINT structure from the return value. 
1353  *
1354  * For the current cursor position, use GetCursorPos().
1355  *
1356  * RETURNS
1357  *
1358  * Cursor position of last message on success, zero on failure.
1359  *
1360  * CONFORMANCE
1361  *
1362  * ECMA-234, Win32
1363  *
1364  */
1365 DWORD WINAPI GetMessagePos(void)
1366 {
1367     MESSAGEQUEUE *queue;
1368     DWORD ret;
1369
1370     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return 0;
1371     ret = queue->GetMessagePosVal;
1372     QUEUE_Unlock( queue );
1373
1374     return ret;
1375 }
1376
1377
1378 /***********************************************************************
1379  *           GetMessageTime   (USER.120) (USER32.273)
1380  *
1381  * GetMessageTime() returns the message time for the last message
1382  * retrieved by the function. The time is measured in milliseconds with
1383  * the same offset as GetTickCount().
1384  *
1385  * Since the tick count wraps, this is only useful for moderately short
1386  * relative time comparisons.
1387  *
1388  * RETURNS
1389  *
1390  * Time of last message on success, zero on failure.
1391  *
1392  * CONFORMANCE
1393  *
1394  * ECMA-234, Win32
1395  *  
1396  */
1397 LONG WINAPI GetMessageTime(void)
1398 {
1399     MESSAGEQUEUE *queue;
1400     LONG ret;
1401
1402     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return 0;
1403     ret = queue->GetMessageTimeVal;
1404     QUEUE_Unlock( queue );
1405     
1406     return ret;
1407 }
1408
1409
1410 /***********************************************************************
1411  *           GetMessageExtraInfo   (USER.288) (USER32.271)
1412  */
1413 LONG WINAPI GetMessageExtraInfo(void)
1414 {
1415     MESSAGEQUEUE *queue;
1416     LONG ret;
1417
1418     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return 0;
1419     ret = queue->GetMessageExtraInfoVal;
1420     QUEUE_Unlock( queue );
1421
1422     return ret;
1423 }