1 /* * Message queues related functions
3 * Copyright 1993, 1994 Alexandre Julliard
8 #include "wine/winbase16.h"
9 #include "wine/winuser16.h"
15 #include "clipboard.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
51 PERQUEUEDATA
* PERQDATA_CreateInstance( )
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 */
65 PERQDATA_Addref( pQDataWin16
);
70 /* Allocate PERQUEUEDATA from the system heap */
71 if (!( pQData
= (PERQUEUEDATA
*) HeapAlloc( SystemHeap
, 0,
72 sizeof(PERQUEUEDATA
) ) ))
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 */
93 /***********************************************************************
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 /***********************************************************************
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
)
137 /* Free the PERQUEUEDATA instance */
138 HeapFree( SystemHeap
, 0, pQData
);
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
)
156 assert(pQData
!= 0 );
158 EnterCriticalSection( &pQData
->cSection
);
159 hWndFocus
= pQData
->hWndFocus
;
160 LeaveCriticalSection( &pQData
->cSection
);
166 /***********************************************************************
167 * PERQDATA_SetFocusWnd
169 * Set the focus hwnd member in a threadsafe manner
171 HWND
PERQDATA_SetFocusWnd( PERQUEUEDATA
*pQData
, HWND hWndFocus
)
174 assert(pQData
!= 0 );
176 EnterCriticalSection( &pQData
->cSection
);
177 hWndFocusPrv
= pQData
->hWndFocus
;
178 pQData
->hWndFocus
= hWndFocus
;
179 LeaveCriticalSection( &pQData
->cSection
);
185 /***********************************************************************
186 * PERQDATA_GetActiveWnd
188 * Get the active hwnd member in a threadsafe manner
190 HWND
PERQDATA_GetActiveWnd( PERQUEUEDATA
*pQData
)
193 assert(pQData
!= 0 );
195 EnterCriticalSection( &pQData
->cSection
);
196 hWndActive
= pQData
->hWndActive
;
197 LeaveCriticalSection( &pQData
->cSection
);
203 /***********************************************************************
204 * PERQDATA_SetActiveWnd
206 * Set the active focus hwnd member in a threadsafe manner
208 HWND
PERQDATA_SetActiveWnd( PERQUEUEDATA
*pQData
, HWND hWndActive
)
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
)
230 assert(pQData
!= 0 );
232 EnterCriticalSection( &pQData
->cSection
);
233 hWndCapture
= pQData
->hWndCapture
;
234 LeaveCriticalSection( &pQData
->cSection
);
240 /***********************************************************************
241 * PERQDATA_SetCaptureWnd
243 * Set the capture hwnd member in a threadsafe manner
245 HWND
PERQDATA_SetCaptureWnd( PERQUEUEDATA
*pQData
, HWND hWndCapture
)
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
)
267 assert(pQData
!= 0 );
269 EnterCriticalSection( &pQData
->cSection
);
270 nCaptureHT
= pQData
->nCaptureHT
;
271 LeaveCriticalSection( &pQData
->cSection
);
277 /***********************************************************************
278 * PERQDATA_SetCaptureInfo
280 * Set the capture info member in a threadsafe manner
282 INT16
PERQDATA_SetCaptureInfo( PERQUEUEDATA
*pQData
, INT16 nCaptureHT
)
285 assert(pQData
!= 0 );
287 EnterCriticalSection( &pQData
->cSection
);
288 nCaptureHTPrv
= pQData
->nCaptureHT
;
289 pQData
->nCaptureHT
= nCaptureHT
;
290 LeaveCriticalSection( &pQData
->cSection
);
292 return nCaptureHTPrv
;
296 /***********************************************************************
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
)
309 queue
= GlobalLock16( hQueue
);
310 if ( !queue
|| (queue
->magic
!= QUEUE_MAGIC
) )
323 /***********************************************************************
326 * Use with QUEUE_Lock to get a thread safe acces to message queue
329 void QUEUE_Unlock( MESSAGEQUEUE
*queue
)
335 if ( --queue
->lockCount
== 0 )
337 DeleteCriticalSection ( &queue
->cSection
);
339 CloseHandle( queue
->hEvent
);
340 GlobalFree16( queue
->self
);
348 /***********************************************************************
351 void QUEUE_DumpQueue( HQUEUE16 hQueue
)
355 if (!(pq
= (MESSAGEQUEUE
*) QUEUE_Lock( hQueue
)) )
357 WARN(msg
, "%04x is not a queue handle\n", hQueue
);
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"
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
);
383 /***********************************************************************
386 void QUEUE_WalkQueues(void)
389 HQUEUE16 hQueue
= hFirstQueue
;
391 DUMP( "Queue Msgs Thread Task Module\n" );
394 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)QUEUE_Lock( hQueue
);
397 WARN( msg
, "Bad queue handle %04x\n", hQueue
);
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
);
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
)
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
) )))
446 msgQueue
= (MESSAGEQUEUE
*) GlobalLock16( hQueue
);
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
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");
468 msgQueue
->hEvent
= ConvertToGlobalHandle( msgQueue
->hEvent
);
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
;
483 /***********************************************************************
486 * Try to reply to all pending sent messages on exit.
488 void QUEUE_FlushMessages( MESSAGEQUEUE
*queue
)
491 MESSAGEQUEUE
*senderQ
= 0;
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
);
506 /* return 0, to unblock other thread */
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
);
534 TRACE(msg
,"(): Deleting message queue %04x\n", hQueue
);
536 if (!hQueue
|| !msgQueue
)
538 WARN(msg
, "invalid argument.\n");
544 if( hCursorQueue
== hQueue
) hCursorQueue
= 0;
545 if( hActiveQueue
== hQueue
) hActiveQueue
= 0;
547 /* flush sent messages */
548 QUEUE_FlushMessages( msgQueue
);
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
);
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");
575 if (pPrev
&& *pPrev
) *pPrev
= msgQueue
->next
;
580 /* free up resource used by MESSAGEQUEUE strcture */
581 msgQueue
->lockCount
--;
582 QUEUE_Unlock( msgQueue
);
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
)))
600 sysMsgQueue
= (MESSAGEQUEUE
*) GlobalLock16( hmemSysMsgQueue
);
605 /***********************************************************************
608 MESSAGEQUEUE
*QUEUE_GetSysQueue(void)
614 /***********************************************************************
617 static void QUEUE_Wait( DWORD wait_mask
)
619 if ( THREAD_IsWin16( THREAD_Current() ) )
623 TRACE(msg
, "current task is 32-bit, calling SYNC_DoWait\n");
624 MsgWaitForMultipleObjects( 0, NULL
, FALSE
, INFINITE
, wait_mask
);
629 /***********************************************************************
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
)
647 /* Wake up thread waiting for message */
648 if ( THREAD_IsWin16( queue
->thdb
) )
649 PostEvent16( queue
->thdb
->process
->task
);
652 SetEvent( queue
->hEvent
);
658 /***********************************************************************
661 void QUEUE_ClearWakeBit( MESSAGEQUEUE
*queue
, WORD bit
)
663 queue
->changeBits
&= ~bit
;
664 queue
->wakeBits
&= ~bit
;
668 /***********************************************************************
671 * See "Windows Internals", p.447
673 void QUEUE_WaitBits( WORD bits
)
677 TRACE(msg
,"q %04x waiting for %04x\n", GetFastQueue16(), bits
);
681 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() ))) return;
683 if (queue
->changeBits
& bits
)
685 /* One of the bits is set; we can return */
687 QUEUE_Unlock( queue
);
690 if (queue
->wakeBits
& QS_SENDMESSAGE
)
692 /* Process the sent message immediately */
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
);
707 TRACE(msg
,"%04x) wakeMask is %04x, waiting\n", queue
->self
, queue
->wakeMask
);
709 QUEUE_Wait( queue
->wakeMask
);
711 QUEUE_Unlock( queue
);
716 /***********************************************************************
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
));
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
;
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
;
743 case SM_PENDING_LIST
:
744 /* make it thread safe, could be accessed by the sender and
747 EnterCriticalSection( &queue
->cSection
);
748 smsg
->nextPending
= queue
->smPending
;
749 queue
->smPending
= smsg
;
750 QUEUE_SetWakeBit( queue
, QS_SENDMESSAGE
);
751 LeaveCriticalSection( &queue
->cSection
);
755 WARN(sendmsg
, "Invalid list: %d", list
);
763 /***********************************************************************
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
)
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 */
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
);
794 queue
->smProcessing
= smsg
->nextProcessing
;
795 smsg
->nextProcessing
= 0;
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 */
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
);
818 queue
->smWaiting
= smsg
->nextWaiting
;
819 smsg
->nextWaiting
= 0;
823 case SM_PENDING_LIST
:
824 /* make it thread safe, could be accessed by the sender and
826 EnterCriticalSection( &queue
->cSection
);
828 if (!smsg
|| !queue
->smPending
)
829 smsg
= queue
->smPending
;
832 ERR( sendmsg
, "should always remove the top one in Pending list, smsg=0x%p queue=0x%p", smsg
, queue
);
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
);
850 WARN(sendmsg
, "Invalid list: %d", list
);
858 /***********************************************************************
859 * QUEUE_ReceiveMessage
861 * This routine is called when a sent message is waiting for the queue.
863 void QUEUE_ReceiveMessage( MESSAGEQUEUE
*queue
)
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");
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
);
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
);
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
,
914 LOWORD (smsg
->wParam
),
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 */
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
948 if ( smsg
->flags
& SMSG_RECEIVER_CLEANS
)
950 TRACE( sendmsg
,"Receiver cleans up!\n" );
951 HeapFree( SystemHeap
, 0, smsg
);
957 LeaveCriticalSection( &senderQ
->cSection
);
958 QUEUE_Unlock( senderQ
);
963 /* no early reply, so do it now */
965 /* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not
967 smsg
->flags
|= SMSG_SENDING_REPLY
;
968 ReplyMessage( result
);
971 TRACE( sendmsg
,"done! \n" );
976 /***********************************************************************
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
;
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
);
996 EnterCriticalSection( &msgQueue
->cSection
);
1000 qmsg
->extraInfo
= extraInfo
;
1002 /* insert the message in the link list */
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
);
1026 /***********************************************************************
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
)
1035 EnterCriticalSection( &msgQueue
->cSection
);
1037 if (!msgQueue
->msgCount
)
1039 else if (!hwnd
&& !first
&& !last
)
1040 qmsg
= msgQueue
->firstMsg
;
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
);
1066 /***********************************************************************
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 */
1077 qmsg
->prevMsg
->nextMsg
= 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 /***********************************************************************
1101 * Wake a queue upon reception of a hardware event.
1103 static void QUEUE_WakeSomeone( UINT message
)
1108 HQUEUE16 hQueue
= 0;
1109 MESSAGEQUEUE
*queue
= NULL
;
1112 hQueue
= hCursorQueue
;
1114 if( (message
>= WM_KEYFIRST
) && (message
<= WM_KEYLAST
) )
1118 hQueue
= hActiveQueue
;
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
;
1137 queue
= QUEUE_Lock( hQueue
);
1141 queue
= QUEUE_Lock( hFirstQueue
);
1144 if (queue
->wakeMask
& wakeBit
) break;
1146 QUEUE_Unlock(queue
);
1147 queue
= QUEUE_Lock( queue
->next
);
1151 WARN(msg
, "couldn't find queue\n");
1156 QUEUE_SetWakeBit( queue
, wakeBit
);
1158 QUEUE_Unlock( queue
);
1162 /***********************************************************************
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
)
1172 QMSG
*qmsg
= sysMsgQueue
->lastMsg
;
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
))
1186 qmsg
= sysMsgQueue
->lastMsg
;
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
) ) ))
1201 /* put message at the end of the linked list */
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
++;
1219 msg
->message
= message
;
1220 msg
->wParam
= wParam
;
1221 msg
->lParam
= lParam
;
1225 qmsg
->extraInfo
= extraInfo
;
1227 QUEUE_WakeSomeone( message
);
1231 /***********************************************************************
1232 * QUEUE_GetQueueTask
1234 HTASK16
QUEUE_GetQueueTask( HQUEUE16 hQueue
)
1238 MESSAGEQUEUE
*queue
= QUEUE_Lock( hQueue
);
1242 hTask
= queue
->thdb
->process
->task
;
1243 QUEUE_Unlock( queue
);
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.
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
)
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
1388 /* access the queue to create it if it's not existing */
1394 /***********************************************************************
1395 * InitThreadInput (USER.409)
1397 HQUEUE16 WINAPI
InitThreadInput16( WORD unknown
, WORD flags
)
1400 MESSAGEQUEUE
*queuePtr
;
1402 THDB
*thdb
= THREAD_Current();
1407 hQueue
= thdb
->teb
.queue
;
1411 /* Create thread message queue */
1412 if( !(hQueue
= QUEUE_CreateMsgQueue( TRUE
)))
1414 WARN(msg
, "failed!\n");
1418 /* Link new queue into list */
1419 queuePtr
= (MESSAGEQUEUE
*)QUEUE_Lock( hQueue
);
1420 queuePtr
->thdb
= THREAD_Current();
1423 SetThreadQueue16( 0, hQueue
);
1424 thdb
->teb
.queue
= hQueue
;
1426 queuePtr
->next
= hFirstQueue
;
1427 hFirstQueue
= hQueue
;
1430 QUEUE_Unlock( queuePtr
);
1436 /***********************************************************************
1437 * GetQueueStatus16 (USER.334)
1439 DWORD WINAPI
GetQueueStatus16( UINT16 flags
)
1441 MESSAGEQUEUE
*queue
;
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
;
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
;
1496 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() )))
1498 ret
= queue
->wakeBits
& (QS_KEY
| QS_MOUSEBUTTON
);
1499 QUEUE_Unlock( queue
);
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
);
1519 /* Handle sent messages */
1520 while (queue
&& (queue
->wakeBits
& QS_SENDMESSAGE
))
1521 QUEUE_ReceiveMessage( queue
);
1523 QUEUE_Unlock( queue
);
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().
1548 * Cursor position of last message on success, zero on failure.
1555 DWORD WINAPI
GetMessagePos(void)
1557 MESSAGEQUEUE
*queue
;
1560 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() ))) return 0;
1561 ret
= queue
->GetMessagePosVal
;
1562 QUEUE_Unlock( queue
);
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.
1580 * Time of last message on success, zero on failure.
1587 LONG WINAPI
GetMessageTime(void)
1589 MESSAGEQUEUE
*queue
;
1592 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() ))) return 0;
1593 ret
= queue
->GetMessageTimeVal
;
1594 QUEUE_Unlock( queue
);
1600 /***********************************************************************
1601 * GetMessageExtraInfo (USER.288) (USER32.271)
1603 LONG WINAPI
GetMessageExtraInfo(void)
1605 MESSAGEQUEUE
*queue
;
1608 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() ))) return 0;
1609 ret
= queue
->GetMessageExtraInfoVal
;
1610 QUEUE_Unlock( queue
);