Release 990226.
[wine/gsoc-2012-control.git] / windows / queue.c
blobd801e5c2d25420f23c3dbd31663a03f1ed671b93
1 /* * Message queues related functions
3 * Copyright 1993, 1994 Alexandre Julliard
4 */
6 #include <stdlib.h>
7 #include <signal.h>
8 #include "wine/winbase16.h"
9 #include "wine/winuser16.h"
10 #include "miscemu.h"
11 #include "module.h"
12 #include "queue.h"
13 #include "task.h"
14 #include "win.h"
15 #include "clipboard.h"
16 #include "hook.h"
17 #include "heap.h"
18 #include "thread.h"
19 #include "process.h"
20 #include <assert.h>
21 #include "debug.h"
22 #include "spy.h"
24 #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
26 static HQUEUE16 hFirstQueue = 0;
27 static HQUEUE16 hExitingQueue = 0;
28 static HQUEUE16 hmemSysMsgQueue = 0;
29 static MESSAGEQUEUE *sysMsgQueue = NULL;
30 static PERQUEUEDATA *pQDataWin16 = NULL; /* Global perQData for Win16 tasks */
32 static MESSAGEQUEUE *pMouseQueue = NULL; /* Queue for last mouse message */
33 static MESSAGEQUEUE *pKbdQueue = NULL; /* Queue for last kbd message */
35 HQUEUE16 hCursorQueue = 0;
36 HQUEUE16 hActiveQueue = 0;
39 /***********************************************************************
40 * PERQDATA_CreateInstance
42 * Creates an instance of a reference counted PERQUEUEDATA element
43 * for the message queue. perQData is stored globally for 16 bit tasks.
45 * Note: We don't implement perQdata exactly the same way Windows does.
46 * Each perQData element is reference counted since it may be potentially
47 * shared by multiple message Queues (via AttachThreadInput).
48 * We only store the current values for Active, Capture and focus windows
49 * currently.
51 PERQUEUEDATA * PERQDATA_CreateInstance( )
53 PERQUEUEDATA *pQData;
55 BOOL16 bIsWin16 = 0;
57 TRACE(msg,"()\n");
59 /* Share a single instance of perQData for all 16 bit tasks */
60 if ( ( bIsWin16 = THREAD_IsWin16( THREAD_Current() ) ) )
62 /* If previously allocated, just bump up ref count */
63 if ( pQDataWin16 )
65 PERQDATA_Addref( pQDataWin16 );
66 return pQDataWin16;
70 /* Allocate PERQUEUEDATA from the system heap */
71 if (!( pQData = (PERQUEUEDATA *) HeapAlloc( SystemHeap, 0,
72 sizeof(PERQUEUEDATA) ) ))
73 return 0;
75 /* Initialize */
76 pQData->hWndCapture = pQData->hWndFocus = pQData->hWndActive = 0;
77 pQData->ulRefCount = 1;
78 pQData->nCaptureHT = HTCLIENT;
80 /* Note: We have an independent critical section for the per queue data
81 * since this may be shared by different threads. see AttachThreadInput()
83 InitializeCriticalSection( &pQData->cSection );
85 /* Save perQData globally for 16 bit tasks */
86 if ( bIsWin16 )
87 pQDataWin16 = pQData;
89 return pQData;
93 /***********************************************************************
94 * PERQDATA_Addref
96 * Increment reference count for the PERQUEUEDATA instance
97 * Returns reference count for debugging purposes
99 ULONG PERQDATA_Addref( PERQUEUEDATA *pQData )
101 assert(pQData != 0 );
102 TRACE(msg,"(): current refcount %lu ...\n", pQData->ulRefCount);
104 EnterCriticalSection( &pQData->cSection );
105 ++pQData->ulRefCount;
106 LeaveCriticalSection( &pQData->cSection );
108 return pQData->ulRefCount;
112 /***********************************************************************
113 * PERQDATA_Release
115 * Release a reference to a PERQUEUEDATA instance.
116 * Destroy the instance if no more references exist
117 * Returns reference count for debugging purposes
119 ULONG PERQDATA_Release( PERQUEUEDATA *pQData )
121 assert(pQData != 0 );
122 TRACE(msg,"(): current refcount %lu ...\n",
123 (LONG)pQData->ulRefCount );
125 EnterCriticalSection( &pQData->cSection );
126 if ( --pQData->ulRefCount == 0 )
128 LeaveCriticalSection( &pQData->cSection );
129 DeleteCriticalSection( &pQData->cSection );
131 TRACE(msg,"(): deleting PERQUEUEDATA instance ...\n" );
133 /* Deleting our global 16 bit perQData? */
134 if ( pQData == pQDataWin16 )
135 pQDataWin16 = 0;
137 /* Free the PERQUEUEDATA instance */
138 HeapFree( SystemHeap, 0, pQData );
140 return 0;
142 LeaveCriticalSection( &pQData->cSection );
144 return pQData->ulRefCount;
148 /***********************************************************************
149 * PERQDATA_GetFocusWnd
151 * Get the focus hwnd member in a threadsafe manner
153 HWND PERQDATA_GetFocusWnd( PERQUEUEDATA *pQData )
155 HWND hWndFocus;
156 assert(pQData != 0 );
158 EnterCriticalSection( &pQData->cSection );
159 hWndFocus = pQData->hWndFocus;
160 LeaveCriticalSection( &pQData->cSection );
162 return hWndFocus;
166 /***********************************************************************
167 * PERQDATA_SetFocusWnd
169 * Set the focus hwnd member in a threadsafe manner
171 HWND PERQDATA_SetFocusWnd( PERQUEUEDATA *pQData, HWND hWndFocus )
173 HWND hWndFocusPrv;
174 assert(pQData != 0 );
176 EnterCriticalSection( &pQData->cSection );
177 hWndFocusPrv = pQData->hWndFocus;
178 pQData->hWndFocus = hWndFocus;
179 LeaveCriticalSection( &pQData->cSection );
181 return hWndFocusPrv;
185 /***********************************************************************
186 * PERQDATA_GetActiveWnd
188 * Get the active hwnd member in a threadsafe manner
190 HWND PERQDATA_GetActiveWnd( PERQUEUEDATA *pQData )
192 HWND hWndActive;
193 assert(pQData != 0 );
195 EnterCriticalSection( &pQData->cSection );
196 hWndActive = pQData->hWndActive;
197 LeaveCriticalSection( &pQData->cSection );
199 return hWndActive;
203 /***********************************************************************
204 * PERQDATA_SetActiveWnd
206 * Set the active focus hwnd member in a threadsafe manner
208 HWND PERQDATA_SetActiveWnd( PERQUEUEDATA *pQData, HWND hWndActive )
210 HWND hWndActivePrv;
211 assert(pQData != 0 );
213 EnterCriticalSection( &pQData->cSection );
214 hWndActivePrv = pQData->hWndActive;
215 pQData->hWndActive = hWndActive;
216 LeaveCriticalSection( &pQData->cSection );
218 return hWndActivePrv;
222 /***********************************************************************
223 * PERQDATA_GetCaptureWnd
225 * Get the capture hwnd member in a threadsafe manner
227 HWND PERQDATA_GetCaptureWnd( PERQUEUEDATA *pQData )
229 HWND hWndCapture;
230 assert(pQData != 0 );
232 EnterCriticalSection( &pQData->cSection );
233 hWndCapture = pQData->hWndCapture;
234 LeaveCriticalSection( &pQData->cSection );
236 return hWndCapture;
240 /***********************************************************************
241 * PERQDATA_SetCaptureWnd
243 * Set the capture hwnd member in a threadsafe manner
245 HWND PERQDATA_SetCaptureWnd( PERQUEUEDATA *pQData, HWND hWndCapture )
247 HWND hWndCapturePrv;
248 assert(pQData != 0 );
250 EnterCriticalSection( &pQData->cSection );
251 hWndCapturePrv = pQData->hWndCapture;
252 pQData->hWndCapture = hWndCapture;
253 LeaveCriticalSection( &pQData->cSection );
255 return hWndCapturePrv;
259 /***********************************************************************
260 * PERQDATA_GetCaptureInfo
262 * Get the capture info member in a threadsafe manner
264 INT16 PERQDATA_GetCaptureInfo( PERQUEUEDATA *pQData )
266 INT16 nCaptureHT;
267 assert(pQData != 0 );
269 EnterCriticalSection( &pQData->cSection );
270 nCaptureHT = pQData->nCaptureHT;
271 LeaveCriticalSection( &pQData->cSection );
273 return nCaptureHT;
277 /***********************************************************************
278 * PERQDATA_SetCaptureInfo
280 * Set the capture info member in a threadsafe manner
282 INT16 PERQDATA_SetCaptureInfo( PERQUEUEDATA *pQData, INT16 nCaptureHT )
284 INT16 nCaptureHTPrv;
285 assert(pQData != 0 );
287 EnterCriticalSection( &pQData->cSection );
288 nCaptureHTPrv = pQData->nCaptureHT;
289 pQData->nCaptureHT = nCaptureHT;
290 LeaveCriticalSection( &pQData->cSection );
292 return nCaptureHTPrv;
296 /***********************************************************************
297 * QUEUE_Lock
299 * Function for getting a 32 bit pointer on queue strcture. For thread
300 * safeness programmers should use this function instead of GlobalLock to
301 * retrieve a pointer on the structure. QUEUE_Unlock should also be called
302 * when access to the queue structure is not required anymore.
304 MESSAGEQUEUE *QUEUE_Lock( HQUEUE16 hQueue )
306 MESSAGEQUEUE *queue;
308 SYSTEM_LOCK();
309 queue = GlobalLock16( hQueue );
310 if ( !queue || (queue->magic != QUEUE_MAGIC) )
312 SYSTEM_UNLOCK();
313 return NULL;
316 queue->lockCount++;
317 SYSTEM_UNLOCK();
319 return queue;
323 /***********************************************************************
324 * QUEUE_Unlock
326 * Use with QUEUE_Lock to get a thread safe acces to message queue
327 * structure
329 void QUEUE_Unlock( MESSAGEQUEUE *queue )
331 if (queue)
333 SYSTEM_LOCK();
335 if ( --queue->lockCount == 0 )
337 DeleteCriticalSection ( &queue->cSection );
338 if (queue->hEvent)
339 CloseHandle( queue->hEvent );
340 GlobalFree16( queue->self );
343 SYSTEM_UNLOCK();
348 /***********************************************************************
349 * QUEUE_DumpQueue
351 void QUEUE_DumpQueue( HQUEUE16 hQueue )
353 MESSAGEQUEUE *pq;
355 if (!(pq = (MESSAGEQUEUE*) QUEUE_Lock( hQueue )) )
357 WARN(msg, "%04x is not a queue handle\n", hQueue );
358 return;
361 DUMP( "next: %12.4x Intertask SendMessage:\n"
362 "thread: %10p ----------------------\n"
363 "firstMsg: %8p smWaiting: %10p\n"
364 "lastMsg: %8p smPending: %10p\n"
365 "msgCount: %8.4x smProcessing: %10p\n"
366 "lockCount: %7.4x\n"
367 "wWinVer: %9.4x\n"
368 "paints: %10.4x\n"
369 "timers: %10.4x\n"
370 "wakeBits: %8.4x\n"
371 "wakeMask: %8.4x\n"
372 "hCurHook: %8.4x\n",
373 pq->next, pq->thdb, pq->firstMsg, pq->smWaiting, pq->lastMsg,
374 pq->smPending, pq->msgCount, pq->smProcessing,
375 (unsigned)pq->lockCount, pq->wWinVersion,
376 pq->wPaintCount, pq->wTimerCount,
377 pq->wakeBits, pq->wakeMask, pq->hCurHook);
379 QUEUE_Unlock( pq );
383 /***********************************************************************
384 * QUEUE_WalkQueues
386 void QUEUE_WalkQueues(void)
388 char module[10];
389 HQUEUE16 hQueue = hFirstQueue;
391 DUMP( "Queue Msgs Thread Task Module\n" );
392 while (hQueue)
394 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
395 if (!queue)
397 WARN( msg, "Bad queue handle %04x\n", hQueue );
398 return;
400 if (!GetModuleName16( queue->thdb->process->task, module, sizeof(module )))
401 strcpy( module, "???" );
402 DUMP( "%04x %4d %p %04x %s\n", hQueue,queue->msgCount,
403 queue->thdb, queue->thdb->process->task, module );
404 hQueue = queue->next;
405 QUEUE_Unlock( queue );
407 DUMP( "\n" );
411 /***********************************************************************
412 * QUEUE_IsExitingQueue
414 BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue )
416 return (hExitingQueue && (hQueue == hExitingQueue));
420 /***********************************************************************
421 * QUEUE_SetExitingQueue
423 void QUEUE_SetExitingQueue( HQUEUE16 hQueue )
425 hExitingQueue = hQueue;
429 /***********************************************************************
430 * QUEUE_CreateMsgQueue
432 * Creates a message queue. Doesn't link it into queue list!
434 static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
436 HQUEUE16 hQueue;
437 MESSAGEQUEUE * msgQueue;
438 TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
440 TRACE(msg,"(): Creating message queue...\n");
442 if (!(hQueue = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT,
443 sizeof(MESSAGEQUEUE) )))
444 return 0;
446 msgQueue = (MESSAGEQUEUE *) GlobalLock16( hQueue );
447 if ( !msgQueue )
448 return 0;
450 msgQueue->self = hQueue;
451 msgQueue->wakeBits = msgQueue->changeBits = 0;
452 msgQueue->wWinVersion = pTask ? pTask->version : 0;
454 InitializeCriticalSection( &msgQueue->cSection );
455 MakeCriticalSectionGlobal( &msgQueue->cSection );
457 /* Create an Event object for waiting on message, used by win32 thread
458 only */
459 if ( !THREAD_IsWin16( THREAD_Current() ) )
461 msgQueue->hEvent = CreateEventA( NULL, FALSE, FALSE, NULL);
463 if (msgQueue->hEvent == 0)
465 WARN(msg, "CreateEvent32A is not able to create an event object");
466 return 0;
468 msgQueue->hEvent = ConvertToGlobalHandle( msgQueue->hEvent );
470 else
471 msgQueue->hEvent = 0;
473 msgQueue->lockCount = 1;
474 msgQueue->magic = QUEUE_MAGIC;
476 /* Create and initialize our per queue data */
477 msgQueue->pQData = bCreatePerQData ? PERQDATA_CreateInstance() : NULL;
479 return hQueue;
483 /***********************************************************************
484 * QUEUE_FlushMessage
486 * Try to reply to all pending sent messages on exit.
488 void QUEUE_FlushMessages( MESSAGEQUEUE *queue )
490 SMSG *smsg;
491 MESSAGEQUEUE *senderQ = 0;
493 if( queue )
495 EnterCriticalSection( &queue->cSection );
497 /* empty the list of pending SendMessage waiting to be received */
498 while (queue->smPending)
500 smsg = QUEUE_RemoveSMSG( queue, SM_PENDING_LIST, 0);
502 senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
503 if ( !senderQ )
504 continue;
506 /* return 0, to unblock other thread */
507 smsg->lResult = 0;
508 smsg->flags |= SMSG_HAVE_RESULT;
509 QUEUE_SetWakeBit( senderQ, QS_SMRESULT);
511 QUEUE_Unlock( senderQ );
514 QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
516 LeaveCriticalSection( &queue->cSection );
521 /***********************************************************************
522 * QUEUE_DeleteMsgQueue
524 * Unlinks and deletes a message queue.
526 * Note: We need to mask asynchronous events to make sure PostMessage works
527 * even in the signal handler.
529 BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue )
531 MESSAGEQUEUE * msgQueue = (MESSAGEQUEUE*)QUEUE_Lock(hQueue);
532 HQUEUE16 *pPrev;
534 TRACE(msg,"(): Deleting message queue %04x\n", hQueue);
536 if (!hQueue || !msgQueue)
538 WARN(msg, "invalid argument.\n");
539 return 0;
542 msgQueue->magic = 0;
544 if( hCursorQueue == hQueue ) hCursorQueue = 0;
545 if( hActiveQueue == hQueue ) hActiveQueue = 0;
547 /* flush sent messages */
548 QUEUE_FlushMessages( msgQueue );
550 SYSTEM_LOCK();
552 /* Release per queue data if present */
553 if ( msgQueue->pQData )
555 PERQDATA_Release( msgQueue->pQData );
556 msgQueue->pQData = 0;
559 /* remove the message queue from the global link list */
560 pPrev = &hFirstQueue;
561 while (*pPrev && (*pPrev != hQueue))
563 MESSAGEQUEUE *msgQ = (MESSAGEQUEUE*)GlobalLock16(*pPrev);
565 /* sanity check */
566 if ( !msgQ || (msgQ->magic != QUEUE_MAGIC) )
568 /* HQUEUE link list is corrupted, try to exit gracefully */
569 WARN( msg, "HQUEUE link list corrupted!\n");
570 pPrev = 0;
571 break;
573 pPrev = &msgQ->next;
575 if (pPrev && *pPrev) *pPrev = msgQueue->next;
576 msgQueue->self = 0;
578 SYSTEM_UNLOCK();
580 /* free up resource used by MESSAGEQUEUE strcture */
581 msgQueue->lockCount--;
582 QUEUE_Unlock( msgQueue );
584 return 1;
588 /***********************************************************************
589 * QUEUE_CreateSysMsgQueue
591 * Create the system message queue, and set the double-click speed.
592 * Must be called only once.
594 BOOL QUEUE_CreateSysMsgQueue( int size )
596 /* Note: We dont need perQ data for the system message queue */
597 if (!(hmemSysMsgQueue = QUEUE_CreateMsgQueue( FALSE )))
598 return FALSE;
600 sysMsgQueue = (MESSAGEQUEUE *) GlobalLock16( hmemSysMsgQueue );
601 return TRUE;
605 /***********************************************************************
606 * QUEUE_GetSysQueue
608 MESSAGEQUEUE *QUEUE_GetSysQueue(void)
610 return sysMsgQueue;
614 /***********************************************************************
615 * QUEUE_Wait
617 static void QUEUE_Wait( DWORD wait_mask )
619 if ( THREAD_IsWin16( THREAD_Current() ) )
620 WaitEvent16( 0 );
621 else
623 TRACE(msg, "current task is 32-bit, calling SYNC_DoWait\n");
624 MsgWaitForMultipleObjects( 0, NULL, FALSE, INFINITE, wait_mask );
629 /***********************************************************************
630 * QUEUE_SetWakeBit
632 * See "Windows Internals", p.449
634 void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit )
636 TRACE(msg,"queue = %04x (wm=%04x), bit = %04x\n",
637 queue->self, queue->wakeMask, bit );
639 if (bit & QS_MOUSE) pMouseQueue = queue;
640 if (bit & QS_KEY) pKbdQueue = queue;
641 queue->changeBits |= bit;
642 queue->wakeBits |= bit;
643 if (queue->wakeMask & bit)
645 queue->wakeMask = 0;
647 /* Wake up thread waiting for message */
648 if ( THREAD_IsWin16( queue->thdb ) )
649 PostEvent16( queue->thdb->process->task );
650 else
652 SetEvent( queue->hEvent );
658 /***********************************************************************
659 * QUEUE_ClearWakeBit
661 void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
663 queue->changeBits &= ~bit;
664 queue->wakeBits &= ~bit;
668 /***********************************************************************
669 * QUEUE_WaitBits
671 * See "Windows Internals", p.447
673 void QUEUE_WaitBits( WORD bits )
675 MESSAGEQUEUE *queue;
677 TRACE(msg,"q %04x waiting for %04x\n", GetFastQueue16(), bits);
679 for (;;)
681 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return;
683 if (queue->changeBits & bits)
685 /* One of the bits is set; we can return */
686 queue->wakeMask = 0;
687 QUEUE_Unlock( queue );
688 return;
690 if (queue->wakeBits & QS_SENDMESSAGE)
692 /* Process the sent message immediately */
694 queue->wakeMask = 0;
695 QUEUE_ReceiveMessage( queue );
696 QUEUE_Unlock( queue );
697 continue; /* nested sm crux */
700 queue->wakeMask = bits | QS_SENDMESSAGE;
701 if(queue->changeBits & bits)
703 QUEUE_Unlock( queue );
704 continue;
707 TRACE(msg,"%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask);
709 QUEUE_Wait( queue->wakeMask );
711 QUEUE_Unlock( queue );
716 /***********************************************************************
717 * QUEUE_AddSMSG
719 * This routine is called when a SMSG need to be added to one of the three
720 * SM list. (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
722 BOOL QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
724 TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
725 smsg, SPY_GetMsgName(smsg->msg));
727 switch (list)
729 case SM_PROCESSING_LIST:
730 /* don't need to be thread safe, only accessed by the
731 thread associated with the sender queue */
732 smsg->nextProcessing = queue->smProcessing;
733 queue->smProcessing = smsg;
734 break;
736 case SM_WAITING_LIST:
737 /* don't need to be thread safe, only accessed by the
738 thread associated with the receiver queue */
739 smsg->nextWaiting = queue->smWaiting;
740 queue->smWaiting = smsg;
741 break;
743 case SM_PENDING_LIST:
744 /* make it thread safe, could be accessed by the sender and
745 receiver thread */
747 EnterCriticalSection( &queue->cSection );
748 smsg->nextPending = queue->smPending;
749 queue->smPending = smsg;
750 QUEUE_SetWakeBit( queue, QS_SENDMESSAGE );
751 LeaveCriticalSection( &queue->cSection );
752 break;
754 default:
755 WARN(sendmsg, "Invalid list: %d", list);
756 break;
759 return TRUE;
763 /***********************************************************************
764 * QUEUE_RemoveSMSG
766 * This routine is called when a SMSG need to be remove from one of the three
767 * SM list. (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
768 * If smsg == 0, remove the first smsg from the specified list
770 SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
773 switch (list)
775 case SM_PROCESSING_LIST:
776 /* don't need to be thread safe, only accessed by the
777 thread associated with the sender queue */
779 /* if smsg is equal to null, it means the first in the list */
780 if (!smsg)
781 smsg = queue->smProcessing;
783 TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
784 smsg, SPY_GetMsgName(smsg->msg));
785 /* In fact SM_PROCESSING_LIST is a stack, and smsg
786 should be always at the top of the list */
787 if ( (smsg != queue->smProcessing) || !queue->smProcessing )
789 ERR( sendmsg, "smsg not at the top of Processing list, smsg=0x%p queue=0x%p", smsg, queue);
790 return 0;
792 else
794 queue->smProcessing = smsg->nextProcessing;
795 smsg->nextProcessing = 0;
797 return smsg;
799 case SM_WAITING_LIST:
800 /* don't need to be thread safe, only accessed by the
801 thread associated with the receiver queue */
803 /* if smsg is equal to null, it means the first in the list */
804 if (!smsg)
805 smsg = queue->smWaiting;
807 TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
808 smsg, SPY_GetMsgName(smsg->msg));
809 /* In fact SM_WAITING_LIST is a stack, and smsg
810 should be always at the top of the list */
811 if ( (smsg != queue->smWaiting) || !queue->smWaiting )
813 ERR( sendmsg, "smsg not at the top of Waiting list, smsg=0x%p queue=0x%p", smsg, queue);
814 return 0;
816 else
818 queue->smWaiting = smsg->nextWaiting;
819 smsg->nextWaiting = 0;
821 return smsg;
823 case SM_PENDING_LIST:
824 /* make it thread safe, could be accessed by the sender and
825 receiver thread */
826 EnterCriticalSection( &queue->cSection );
828 if (!smsg || !queue->smPending)
829 smsg = queue->smPending;
830 else
832 ERR( sendmsg, "should always remove the top one in Pending list, smsg=0x%p queue=0x%p", smsg, queue);
833 return 0;
836 TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
837 smsg, SPY_GetMsgName(smsg->msg));
839 queue->smPending = smsg->nextPending;
840 smsg->nextPending = 0;
842 /* if no more SMSG in Pending list, clear QS_SENDMESSAGE flag */
843 if (!queue->smPending)
844 QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
846 LeaveCriticalSection( &queue->cSection );
847 return smsg;
849 default:
850 WARN(sendmsg, "Invalid list: %d", list);
851 break;
854 return 0;
858 /***********************************************************************
859 * QUEUE_ReceiveMessage
861 * This routine is called when a sent message is waiting for the queue.
863 void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
865 LRESULT result = 0;
866 SMSG *smsg;
867 MESSAGEQUEUE *senderQ;
869 TRACE(sendmsg, "queue %04x\n", queue->self );
871 if ( !(queue->wakeBits & QS_SENDMESSAGE) && queue->smPending )
873 TRACE(sendmsg,"\trcm: nothing to do\n");
874 return;
877 /* remove smsg on the top of the pending list and put it in the processing list */
878 smsg = QUEUE_RemoveSMSG(queue, SM_PENDING_LIST, 0);
879 QUEUE_AddSMSG(queue, SM_WAITING_LIST, smsg);
881 TRACE(sendmsg,"RM: %s [%04x] (%04x -> %04x)\n",
882 SPY_GetMsgName(smsg->msg), smsg->msg, smsg->hSrcQueue, smsg->hDstQueue );
884 if (IsWindow( smsg->hWnd ))
886 WND *wndPtr = WIN_FindWndPtr( smsg->hWnd );
887 DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */
889 /* use sender queue extra info value while calling the window proc */
890 senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
891 if (senderQ)
893 queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
894 QUEUE_Unlock( senderQ );
897 /* call the right version of CallWindowProcXX */
898 if (smsg->flags & SMSG_WIN32)
900 TRACE(sendmsg, "\trcm: msg is Win32\n" );
901 if (smsg->flags & SMSG_UNICODE)
902 result = CallWindowProcW( wndPtr->winproc,
903 smsg->hWnd, smsg->msg,
904 smsg->wParam, smsg->lParam );
905 else
906 result = CallWindowProcA( wndPtr->winproc,
907 smsg->hWnd, smsg->msg,
908 smsg->wParam, smsg->lParam );
910 else /* Win16 message */
911 result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
912 (HWND16) smsg->hWnd,
913 (UINT16) smsg->msg,
914 LOWORD (smsg->wParam),
915 smsg->lParam );
917 queue->GetMessageExtraInfoVal = extraInfo; /* Restore extra info */
918 TRACE(sendmsg,"result = %08x\n", (unsigned)result );
920 else WARN(sendmsg, "\trcm: bad hWnd\n");
922 /* sometimes when we got early reply, the receiver is in charge of
923 freeing up memory associated with smsg */
924 /* when there is an early reply the sender will not release smsg
925 before SMSG_RECEIVED is set */
926 if ( smsg->flags & SMSG_EARLY_REPLY )
928 /* remove smsg from the waiting list */
929 QUEUE_RemoveSMSG( queue, SM_WAITING_LIST, smsg );
931 /* make thread safe when accessing SMSG_SENT_REPLY and
932 SMSG_RECEIVER_CLEANS_UP. Those fleags are used by both thread,
933 the sender and receiver, to find out which thread should released
934 smsg structure. The critical section of the sender queue is used. */
936 senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
938 /* synchronize with the sender */
939 if (senderQ)
940 EnterCriticalSection( &senderQ->cSection );
942 /* tell the sender we're all done with smsg structure */
943 smsg->flags |= SMSG_RECEIVED;
945 /* sender will set SMSG_RECEIVER_CLEANS_UP if it wants the
946 receiver to clean up smsg, it could only happens when there is
947 an early reply */
948 if ( smsg->flags & SMSG_RECEIVER_CLEANS )
950 TRACE( sendmsg,"Receiver cleans up!\n" );
951 HeapFree( SystemHeap, 0, smsg );
954 /* release lock */
955 if (senderQ)
957 LeaveCriticalSection( &senderQ->cSection );
958 QUEUE_Unlock( senderQ );
961 else
963 /* no early reply, so do it now */
965 /* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not
966 an early reply */
967 smsg->flags |= SMSG_SENDING_REPLY;
968 ReplyMessage( result );
971 TRACE( sendmsg,"done! \n" );
976 /***********************************************************************
977 * QUEUE_AddMsg
979 * Add a message to the queue. Return FALSE if queue is full.
981 BOOL QUEUE_AddMsg( HQUEUE16 hQueue, MSG *msg, DWORD extraInfo )
983 MESSAGEQUEUE *msgQueue;
984 QMSG *qmsg;
987 if (!(msgQueue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return FALSE;
989 /* allocate new message in global heap for now */
990 if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
992 QUEUE_Unlock( msgQueue );
993 return 0;
996 EnterCriticalSection( &msgQueue->cSection );
998 /* Store message */
999 qmsg->msg = *msg;
1000 qmsg->extraInfo = extraInfo;
1002 /* insert the message in the link list */
1003 qmsg->nextMsg = 0;
1004 qmsg->prevMsg = msgQueue->lastMsg;
1006 if (msgQueue->lastMsg)
1007 msgQueue->lastMsg->nextMsg = qmsg;
1009 /* update first and last anchor in message queue */
1010 msgQueue->lastMsg = qmsg;
1011 if (!msgQueue->firstMsg)
1012 msgQueue->firstMsg = qmsg;
1014 msgQueue->msgCount++;
1016 LeaveCriticalSection( &msgQueue->cSection );
1018 QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE );
1019 QUEUE_Unlock( msgQueue );
1021 return TRUE;
1026 /***********************************************************************
1027 * QUEUE_FindMsg
1029 * Find a message matching the given parameters. Return -1 if none available.
1031 QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last )
1033 QMSG* qmsg;
1035 EnterCriticalSection( &msgQueue->cSection );
1037 if (!msgQueue->msgCount)
1038 qmsg = 0;
1039 else if (!hwnd && !first && !last)
1040 qmsg = msgQueue->firstMsg;
1041 else
1043 /* look in linked list for message matching first and last criteria */
1044 for (qmsg = msgQueue->firstMsg; qmsg; qmsg = qmsg->nextMsg)
1046 MSG *msg = &(qmsg->msg);
1048 if (!hwnd || (msg->hwnd == hwnd))
1050 if (!first && !last)
1051 break; /* found it */
1053 if ((msg->message >= first) && (!last || (msg->message <= last)))
1054 break; /* found it */
1059 LeaveCriticalSection( &msgQueue->cSection );
1061 return qmsg;
1066 /***********************************************************************
1067 * QUEUE_RemoveMsg
1069 * Remove a message from the queue (pos must be a valid position).
1071 void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg )
1073 EnterCriticalSection( &msgQueue->cSection );
1075 /* set the linked list */
1076 if (qmsg->prevMsg)
1077 qmsg->prevMsg->nextMsg = qmsg->nextMsg;
1079 if (qmsg->nextMsg)
1080 qmsg->nextMsg->prevMsg = qmsg->prevMsg;
1082 if (msgQueue->firstMsg == qmsg)
1083 msgQueue->firstMsg = qmsg->nextMsg;
1085 if (msgQueue->lastMsg == qmsg)
1086 msgQueue->lastMsg = qmsg->prevMsg;
1088 /* deallocate the memory for the message */
1089 HeapFree( SystemHeap, 0, qmsg );
1091 msgQueue->msgCount--;
1092 if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE;
1094 LeaveCriticalSection( &msgQueue->cSection );
1098 /***********************************************************************
1099 * QUEUE_WakeSomeone
1101 * Wake a queue upon reception of a hardware event.
1103 static void QUEUE_WakeSomeone( UINT message )
1105 WND* wndPtr = NULL;
1106 WORD wakeBit;
1107 HWND hwnd;
1108 HQUEUE16 hQueue = 0;
1109 MESSAGEQUEUE *queue = NULL;
1111 if (hCursorQueue)
1112 hQueue = hCursorQueue;
1114 if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) )
1116 wakeBit = QS_KEY;
1117 if( hActiveQueue )
1118 hQueue = hActiveQueue;
1120 else
1122 wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
1123 if( (hwnd = GetCapture()) )
1124 if( (wndPtr = WIN_FindWndPtr( hwnd )) )
1126 hQueue = wndPtr->hmemTaskQ;
1130 if( (hwnd = GetSysModalWindow16()) )
1132 if( (wndPtr = WIN_FindWndPtr( hwnd )) )
1133 hQueue = wndPtr->hmemTaskQ;
1136 if (hQueue)
1137 queue = QUEUE_Lock( hQueue );
1139 if( !queue )
1141 queue = QUEUE_Lock( hFirstQueue );
1142 while( queue )
1144 if (queue->wakeMask & wakeBit) break;
1146 QUEUE_Unlock(queue);
1147 queue = QUEUE_Lock( queue->next );
1149 if( !queue )
1151 WARN(msg, "couldn't find queue\n");
1152 return;
1156 QUEUE_SetWakeBit( queue, wakeBit );
1158 QUEUE_Unlock( queue );
1162 /***********************************************************************
1163 * hardware_event
1165 * Add an event to the system message queue.
1166 * Note: the position is relative to the desktop window.
1168 void hardware_event( WORD message, WORD wParam, LONG lParam,
1169 int xPos, int yPos, DWORD time, DWORD extraInfo )
1171 MSG *msg;
1172 QMSG *qmsg = sysMsgQueue->lastMsg;
1173 int mergeMsg = 0;
1175 if (!sysMsgQueue) return;
1177 /* Merge with previous event if possible */
1179 if ((message == WM_MOUSEMOVE) && sysMsgQueue->lastMsg)
1181 msg = &(sysMsgQueue->lastMsg->msg);
1183 if ((msg->message == message) && (msg->wParam == wParam))
1185 /* Merge events */
1186 qmsg = sysMsgQueue->lastMsg;
1187 mergeMsg = 1;
1191 if (!mergeMsg)
1193 /* Should I limit the number of message in
1194 the system message queue??? */
1196 /* Don't merge allocate a new msg in the global heap */
1198 if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
1199 return;
1201 /* put message at the end of the linked list */
1202 qmsg->nextMsg = 0;
1203 qmsg->prevMsg = sysMsgQueue->lastMsg;
1205 if (sysMsgQueue->lastMsg)
1206 sysMsgQueue->lastMsg->nextMsg = qmsg;
1208 /* set last and first anchor index in system message queue */
1209 sysMsgQueue->lastMsg = qmsg;
1210 if (!sysMsgQueue->firstMsg)
1211 sysMsgQueue->firstMsg = qmsg;
1213 sysMsgQueue->msgCount++;
1216 /* Store message */
1217 msg = &(qmsg->msg);
1218 msg->hwnd = 0;
1219 msg->message = message;
1220 msg->wParam = wParam;
1221 msg->lParam = lParam;
1222 msg->time = time;
1223 msg->pt.x = xPos;
1224 msg->pt.y = yPos;
1225 qmsg->extraInfo = extraInfo;
1227 QUEUE_WakeSomeone( message );
1231 /***********************************************************************
1232 * QUEUE_GetQueueTask
1234 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
1236 HTASK16 hTask = 0;
1238 MESSAGEQUEUE *queue = QUEUE_Lock( hQueue );
1240 if (queue)
1242 hTask = queue->thdb->process->task;
1243 QUEUE_Unlock( queue );
1246 return hTask;
1251 /***********************************************************************
1252 * QUEUE_IncPaintCount
1254 void QUEUE_IncPaintCount( HQUEUE16 hQueue )
1256 MESSAGEQUEUE *queue;
1258 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1259 queue->wPaintCount++;
1260 QUEUE_SetWakeBit( queue, QS_PAINT );
1261 QUEUE_Unlock( queue );
1265 /***********************************************************************
1266 * QUEUE_DecPaintCount
1268 void QUEUE_DecPaintCount( HQUEUE16 hQueue )
1270 MESSAGEQUEUE *queue;
1272 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1273 queue->wPaintCount--;
1274 if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
1275 QUEUE_Unlock( queue );
1279 /***********************************************************************
1280 * QUEUE_IncTimerCount
1282 void QUEUE_IncTimerCount( HQUEUE16 hQueue )
1284 MESSAGEQUEUE *queue;
1286 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1287 queue->wTimerCount++;
1288 QUEUE_SetWakeBit( queue, QS_TIMER );
1289 QUEUE_Unlock( queue );
1293 /***********************************************************************
1294 * QUEUE_DecTimerCount
1296 void QUEUE_DecTimerCount( HQUEUE16 hQueue )
1298 MESSAGEQUEUE *queue;
1300 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1301 queue->wTimerCount--;
1302 if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
1303 QUEUE_Unlock( queue );
1307 /***********************************************************************
1308 * PostQuitMessage16 (USER.6)
1310 void WINAPI PostQuitMessage16( INT16 exitCode )
1312 PostQuitMessage( exitCode );
1316 /***********************************************************************
1317 * PostQuitMessage32 (USER32.421)
1319 * PostQuitMessage() posts a message to the system requesting an
1320 * application to terminate execution. As a result of this function,
1321 * the WM_QUIT message is posted to the application, and
1322 * PostQuitMessage() returns immediately. The exitCode parameter
1323 * specifies an application-defined exit code, which appears in the
1324 * _wParam_ parameter of the WM_QUIT message posted to the application.
1326 * CONFORMANCE
1328 * ECMA-234, Win32
1330 void WINAPI PostQuitMessage( INT exitCode )
1332 MESSAGEQUEUE *queue;
1334 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return;
1335 queue->wPostQMsg = TRUE;
1336 queue->wExitCode = (WORD)exitCode;
1337 QUEUE_Unlock( queue );
1341 /***********************************************************************
1342 * GetWindowTask16 (USER.224)
1344 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
1346 WND *wndPtr = WIN_FindWndPtr( hwnd );
1348 if (!wndPtr) return 0;
1349 return QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1352 /***********************************************************************
1353 * GetWindowThreadProcessId (USER32.313)
1355 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
1357 HTASK16 htask;
1358 TDB *tdb;
1360 WND *wndPtr = WIN_FindWndPtr( hwnd );
1362 if (!wndPtr) return 0;
1363 htask=QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1364 tdb = (TDB*)GlobalLock16(htask);
1365 if (!tdb || !tdb->thdb) return 0;
1366 if (process) *process = PDB_TO_PROCESS_ID( tdb->thdb->process );
1367 return THDB_TO_THREAD_ID( tdb->thdb );
1371 /***********************************************************************
1372 * SetMessageQueue16 (USER.266)
1374 BOOL16 WINAPI SetMessageQueue16( INT16 size )
1376 return SetMessageQueue( size );
1380 /***********************************************************************
1381 * SetMessageQueue32 (USER32.494)
1383 BOOL WINAPI SetMessageQueue( INT size )
1385 /* now obsolete the message queue will be expanded dynamically
1386 as necessary */
1388 /* access the queue to create it if it's not existing */
1389 GetFastQueue16();
1391 return TRUE;
1394 /***********************************************************************
1395 * InitThreadInput (USER.409)
1397 HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags )
1399 HQUEUE16 hQueue;
1400 MESSAGEQUEUE *queuePtr;
1402 THDB *thdb = THREAD_Current();
1404 if (!thdb)
1405 return 0;
1407 hQueue = thdb->teb.queue;
1409 if ( !hQueue )
1411 /* Create thread message queue */
1412 if( !(hQueue = QUEUE_CreateMsgQueue( TRUE )))
1414 WARN(msg, "failed!\n");
1415 return FALSE;
1418 /* Link new queue into list */
1419 queuePtr = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
1420 queuePtr->thdb = THREAD_Current();
1422 SYSTEM_LOCK();
1423 SetThreadQueue16( 0, hQueue );
1424 thdb->teb.queue = hQueue;
1426 queuePtr->next = hFirstQueue;
1427 hFirstQueue = hQueue;
1428 SYSTEM_UNLOCK();
1430 QUEUE_Unlock( queuePtr );
1433 return hQueue;
1436 /***********************************************************************
1437 * GetQueueStatus16 (USER.334)
1439 DWORD WINAPI GetQueueStatus16( UINT16 flags )
1441 MESSAGEQUEUE *queue;
1442 DWORD ret;
1444 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1445 ret = MAKELONG( queue->changeBits, queue->wakeBits );
1446 queue->changeBits = 0;
1447 QUEUE_Unlock( queue );
1449 return ret & MAKELONG( flags, flags );
1452 /***********************************************************************
1453 * GetQueueStatus32 (USER32.283)
1455 DWORD WINAPI GetQueueStatus( UINT flags )
1457 MESSAGEQUEUE *queue;
1458 DWORD ret;
1460 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1461 ret = MAKELONG( queue->changeBits, queue->wakeBits );
1462 queue->changeBits = 0;
1463 QUEUE_Unlock( queue );
1465 return ret & MAKELONG( flags, flags );
1469 /***********************************************************************
1470 * GetInputState16 (USER.335)
1472 BOOL16 WINAPI GetInputState16(void)
1474 return GetInputState();
1477 /***********************************************************************
1478 * WaitForInputIdle (USER32.577)
1480 DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
1482 FIXME (msg, "(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut);
1484 return WAIT_TIMEOUT;
1488 /***********************************************************************
1489 * GetInputState32 (USER32.244)
1491 BOOL WINAPI GetInputState(void)
1493 MESSAGEQUEUE *queue;
1494 BOOL ret;
1496 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
1497 return FALSE;
1498 ret = queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
1499 QUEUE_Unlock( queue );
1501 return ret;
1504 /***********************************************************************
1505 * UserYield (USER.332)
1507 void WINAPI UserYield16(void)
1509 TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
1510 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( pCurTask->hQueue );
1512 if ( !THREAD_IsWin16( THREAD_Current() ) )
1514 FIXME(task, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel);
1515 QUEUE_Unlock( queue );
1516 return;
1519 /* Handle sent messages */
1520 while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1521 QUEUE_ReceiveMessage( queue );
1523 QUEUE_Unlock( queue );
1525 OldYield16();
1527 queue = (MESSAGEQUEUE *)QUEUE_Lock( pCurTask->hQueue );
1528 while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1529 QUEUE_ReceiveMessage( queue );
1531 QUEUE_Unlock( queue );
1534 /***********************************************************************
1535 * GetMessagePos (USER.119) (USER32.272)
1537 * The GetMessagePos() function returns a long value representing a
1538 * cursor position, in screen coordinates, when the last message
1539 * retrieved by the GetMessage() function occurs. The x-coordinate is
1540 * in the low-order word of the return value, the y-coordinate is in
1541 * the high-order word. The application can use the MAKEPOINT()
1542 * macro to obtain a POINT structure from the return value.
1544 * For the current cursor position, use GetCursorPos().
1546 * RETURNS
1548 * Cursor position of last message on success, zero on failure.
1550 * CONFORMANCE
1552 * ECMA-234, Win32
1555 DWORD WINAPI GetMessagePos(void)
1557 MESSAGEQUEUE *queue;
1558 DWORD ret;
1560 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1561 ret = queue->GetMessagePosVal;
1562 QUEUE_Unlock( queue );
1564 return ret;
1568 /***********************************************************************
1569 * GetMessageTime (USER.120) (USER32.273)
1571 * GetMessageTime() returns the message time for the last message
1572 * retrieved by the function. The time is measured in milliseconds with
1573 * the same offset as GetTickCount().
1575 * Since the tick count wraps, this is only useful for moderately short
1576 * relative time comparisons.
1578 * RETURNS
1580 * Time of last message on success, zero on failure.
1582 * CONFORMANCE
1584 * ECMA-234, Win32
1587 LONG WINAPI GetMessageTime(void)
1589 MESSAGEQUEUE *queue;
1590 LONG ret;
1592 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1593 ret = queue->GetMessageTimeVal;
1594 QUEUE_Unlock( queue );
1596 return ret;
1600 /***********************************************************************
1601 * GetMessageExtraInfo (USER.288) (USER32.271)
1603 LONG WINAPI GetMessageExtraInfo(void)
1605 MESSAGEQUEUE *queue;
1606 LONG ret;
1608 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1609 ret = queue->GetMessageExtraInfoVal;
1610 QUEUE_Unlock( queue );
1612 return ret;