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 DECLARE_DEBUG_CHANNEL(msg
)
25 DECLARE_DEBUG_CHANNEL(sendmsg
)
27 #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
29 static HQUEUE16 hFirstQueue
= 0;
30 static HQUEUE16 hExitingQueue
= 0;
31 static HQUEUE16 hmemSysMsgQueue
= 0;
32 static MESSAGEQUEUE
*sysMsgQueue
= NULL
;
33 static PERQUEUEDATA
*pQDataWin16
= NULL
; /* Global perQData for Win16 tasks */
35 static MESSAGEQUEUE
*pMouseQueue
= NULL
; /* Queue for last mouse message */
36 static MESSAGEQUEUE
*pKbdQueue
= NULL
; /* Queue for last kbd message */
38 HQUEUE16 hCursorQueue
= 0;
39 HQUEUE16 hActiveQueue
= 0;
42 /***********************************************************************
43 * PERQDATA_CreateInstance
45 * Creates an instance of a reference counted PERQUEUEDATA element
46 * for the message queue. perQData is stored globally for 16 bit tasks.
48 * Note: We don't implement perQdata exactly the same way Windows does.
49 * Each perQData element is reference counted since it may be potentially
50 * shared by multiple message Queues (via AttachThreadInput).
51 * We only store the current values for Active, Capture and focus windows
54 PERQUEUEDATA
* PERQDATA_CreateInstance( )
62 /* Share a single instance of perQData for all 16 bit tasks */
63 if ( ( bIsWin16
= THREAD_IsWin16( THREAD_Current() ) ) )
65 /* If previously allocated, just bump up ref count */
68 PERQDATA_Addref( pQDataWin16
);
73 /* Allocate PERQUEUEDATA from the system heap */
74 if (!( pQData
= (PERQUEUEDATA
*) HeapAlloc( SystemHeap
, 0,
75 sizeof(PERQUEUEDATA
) ) ))
79 pQData
->hWndCapture
= pQData
->hWndFocus
= pQData
->hWndActive
= 0;
80 pQData
->ulRefCount
= 1;
81 pQData
->nCaptureHT
= HTCLIENT
;
83 /* Note: We have an independent critical section for the per queue data
84 * since this may be shared by different threads. see AttachThreadInput()
86 InitializeCriticalSection( &pQData
->cSection
);
88 /* Save perQData globally for 16 bit tasks */
96 /***********************************************************************
99 * Increment reference count for the PERQUEUEDATA instance
100 * Returns reference count for debugging purposes
102 ULONG
PERQDATA_Addref( PERQUEUEDATA
*pQData
)
104 assert(pQData
!= 0 );
105 TRACE(msg
,"(): current refcount %lu ...\n", pQData
->ulRefCount
);
107 EnterCriticalSection( &pQData
->cSection
);
108 ++pQData
->ulRefCount
;
109 LeaveCriticalSection( &pQData
->cSection
);
111 return pQData
->ulRefCount
;
115 /***********************************************************************
118 * Release a reference to a PERQUEUEDATA instance.
119 * Destroy the instance if no more references exist
120 * Returns reference count for debugging purposes
122 ULONG
PERQDATA_Release( PERQUEUEDATA
*pQData
)
124 assert(pQData
!= 0 );
125 TRACE(msg
,"(): current refcount %lu ...\n",
126 (LONG
)pQData
->ulRefCount
);
128 EnterCriticalSection( &pQData
->cSection
);
129 if ( --pQData
->ulRefCount
== 0 )
131 LeaveCriticalSection( &pQData
->cSection
);
132 DeleteCriticalSection( &pQData
->cSection
);
134 TRACE(msg
,"(): deleting PERQUEUEDATA instance ...\n" );
136 /* Deleting our global 16 bit perQData? */
137 if ( pQData
== pQDataWin16
)
140 /* Free the PERQUEUEDATA instance */
141 HeapFree( SystemHeap
, 0, pQData
);
145 LeaveCriticalSection( &pQData
->cSection
);
147 return pQData
->ulRefCount
;
151 /***********************************************************************
152 * PERQDATA_GetFocusWnd
154 * Get the focus hwnd member in a threadsafe manner
156 HWND
PERQDATA_GetFocusWnd( PERQUEUEDATA
*pQData
)
159 assert(pQData
!= 0 );
161 EnterCriticalSection( &pQData
->cSection
);
162 hWndFocus
= pQData
->hWndFocus
;
163 LeaveCriticalSection( &pQData
->cSection
);
169 /***********************************************************************
170 * PERQDATA_SetFocusWnd
172 * Set the focus hwnd member in a threadsafe manner
174 HWND
PERQDATA_SetFocusWnd( PERQUEUEDATA
*pQData
, HWND hWndFocus
)
177 assert(pQData
!= 0 );
179 EnterCriticalSection( &pQData
->cSection
);
180 hWndFocusPrv
= pQData
->hWndFocus
;
181 pQData
->hWndFocus
= hWndFocus
;
182 LeaveCriticalSection( &pQData
->cSection
);
188 /***********************************************************************
189 * PERQDATA_GetActiveWnd
191 * Get the active hwnd member in a threadsafe manner
193 HWND
PERQDATA_GetActiveWnd( PERQUEUEDATA
*pQData
)
196 assert(pQData
!= 0 );
198 EnterCriticalSection( &pQData
->cSection
);
199 hWndActive
= pQData
->hWndActive
;
200 LeaveCriticalSection( &pQData
->cSection
);
206 /***********************************************************************
207 * PERQDATA_SetActiveWnd
209 * Set the active focus hwnd member in a threadsafe manner
211 HWND
PERQDATA_SetActiveWnd( PERQUEUEDATA
*pQData
, HWND hWndActive
)
214 assert(pQData
!= 0 );
216 EnterCriticalSection( &pQData
->cSection
);
217 hWndActivePrv
= pQData
->hWndActive
;
218 pQData
->hWndActive
= hWndActive
;
219 LeaveCriticalSection( &pQData
->cSection
);
221 return hWndActivePrv
;
225 /***********************************************************************
226 * PERQDATA_GetCaptureWnd
228 * Get the capture hwnd member in a threadsafe manner
230 HWND
PERQDATA_GetCaptureWnd( PERQUEUEDATA
*pQData
)
233 assert(pQData
!= 0 );
235 EnterCriticalSection( &pQData
->cSection
);
236 hWndCapture
= pQData
->hWndCapture
;
237 LeaveCriticalSection( &pQData
->cSection
);
243 /***********************************************************************
244 * PERQDATA_SetCaptureWnd
246 * Set the capture hwnd member in a threadsafe manner
248 HWND
PERQDATA_SetCaptureWnd( PERQUEUEDATA
*pQData
, HWND hWndCapture
)
251 assert(pQData
!= 0 );
253 EnterCriticalSection( &pQData
->cSection
);
254 hWndCapturePrv
= pQData
->hWndCapture
;
255 pQData
->hWndCapture
= hWndCapture
;
256 LeaveCriticalSection( &pQData
->cSection
);
258 return hWndCapturePrv
;
262 /***********************************************************************
263 * PERQDATA_GetCaptureInfo
265 * Get the capture info member in a threadsafe manner
267 INT16
PERQDATA_GetCaptureInfo( PERQUEUEDATA
*pQData
)
270 assert(pQData
!= 0 );
272 EnterCriticalSection( &pQData
->cSection
);
273 nCaptureHT
= pQData
->nCaptureHT
;
274 LeaveCriticalSection( &pQData
->cSection
);
280 /***********************************************************************
281 * PERQDATA_SetCaptureInfo
283 * Set the capture info member in a threadsafe manner
285 INT16
PERQDATA_SetCaptureInfo( PERQUEUEDATA
*pQData
, INT16 nCaptureHT
)
288 assert(pQData
!= 0 );
290 EnterCriticalSection( &pQData
->cSection
);
291 nCaptureHTPrv
= pQData
->nCaptureHT
;
292 pQData
->nCaptureHT
= nCaptureHT
;
293 LeaveCriticalSection( &pQData
->cSection
);
295 return nCaptureHTPrv
;
299 /***********************************************************************
302 * Function for getting a 32 bit pointer on queue strcture. For thread
303 * safeness programmers should use this function instead of GlobalLock to
304 * retrieve a pointer on the structure. QUEUE_Unlock should also be called
305 * when access to the queue structure is not required anymore.
307 MESSAGEQUEUE
*QUEUE_Lock( HQUEUE16 hQueue
)
311 HeapLock( SystemHeap
); /* FIXME: a bit overkill */
312 queue
= GlobalLock16( hQueue
);
313 if ( !queue
|| (queue
->magic
!= QUEUE_MAGIC
) )
315 HeapUnlock( SystemHeap
);
320 HeapUnlock( SystemHeap
);
325 /***********************************************************************
328 * Use with QUEUE_Lock to get a thread safe acces to message queue
331 void QUEUE_Unlock( MESSAGEQUEUE
*queue
)
335 HeapLock( SystemHeap
); /* FIXME: a bit overkill */
337 if ( --queue
->lockCount
== 0 )
339 DeleteCriticalSection ( &queue
->cSection
);
341 CloseHandle( queue
->hEvent
);
342 GlobalFree16( queue
->self
);
345 HeapUnlock( SystemHeap
);
350 /***********************************************************************
353 void QUEUE_DumpQueue( HQUEUE16 hQueue
)
357 if (!(pq
= (MESSAGEQUEUE
*) QUEUE_Lock( hQueue
)) )
359 WARN(msg
, "%04x is not a queue handle\n", hQueue
);
363 DUMP( "next: %12.4x Intertask SendMessage:\n"
364 "thread: %10p ----------------------\n"
365 "firstMsg: %8p smWaiting: %10p\n"
366 "lastMsg: %8p smPending: %10p\n"
367 "msgCount: %8.4x smProcessing: %10p\n"
375 pq
->next
, pq
->thdb
, pq
->firstMsg
, pq
->smWaiting
, pq
->lastMsg
,
376 pq
->smPending
, pq
->msgCount
, pq
->smProcessing
,
377 (unsigned)pq
->lockCount
, pq
->wWinVersion
,
378 pq
->wPaintCount
, pq
->wTimerCount
,
379 pq
->wakeBits
, pq
->wakeMask
, pq
->hCurHook
);
385 /***********************************************************************
388 void QUEUE_WalkQueues(void)
391 HQUEUE16 hQueue
= hFirstQueue
;
393 DUMP( "Queue Msgs Thread Task Module\n" );
396 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)QUEUE_Lock( hQueue
);
399 WARN( msg
, "Bad queue handle %04x\n", hQueue
);
402 if (!GetModuleName16( queue
->thdb
->process
->task
, module
, sizeof(module
)))
403 strcpy( module
, "???" );
404 DUMP( "%04x %4d %p %04x %s\n", hQueue
,queue
->msgCount
,
405 queue
->thdb
, queue
->thdb
->process
->task
, module
);
406 hQueue
= queue
->next
;
407 QUEUE_Unlock( queue
);
413 /***********************************************************************
414 * QUEUE_IsExitingQueue
416 BOOL
QUEUE_IsExitingQueue( HQUEUE16 hQueue
)
418 return (hExitingQueue
&& (hQueue
== hExitingQueue
));
422 /***********************************************************************
423 * QUEUE_SetExitingQueue
425 void QUEUE_SetExitingQueue( HQUEUE16 hQueue
)
427 hExitingQueue
= hQueue
;
431 /***********************************************************************
432 * QUEUE_CreateMsgQueue
434 * Creates a message queue. Doesn't link it into queue list!
436 static HQUEUE16
QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData
)
439 MESSAGEQUEUE
* msgQueue
;
440 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
442 TRACE(msg
,"(): Creating message queue...\n");
444 if (!(hQueue
= GlobalAlloc16( GMEM_FIXED
| GMEM_ZEROINIT
,
445 sizeof(MESSAGEQUEUE
) )))
448 msgQueue
= (MESSAGEQUEUE
*) GlobalLock16( hQueue
);
452 msgQueue
->self
= hQueue
;
453 msgQueue
->wakeBits
= msgQueue
->changeBits
= 0;
454 msgQueue
->wWinVersion
= pTask
? pTask
->version
: 0;
456 InitializeCriticalSection( &msgQueue
->cSection
);
457 MakeCriticalSectionGlobal( &msgQueue
->cSection
);
459 /* Create an Event object for waiting on message, used by win32 thread
461 if ( !THREAD_IsWin16( THREAD_Current() ) )
463 msgQueue
->hEvent
= CreateEventA( NULL
, FALSE
, FALSE
, NULL
);
465 if (msgQueue
->hEvent
== 0)
467 WARN(msg
, "CreateEvent32A is not able to create an event object");
470 msgQueue
->hEvent
= ConvertToGlobalHandle( msgQueue
->hEvent
);
473 msgQueue
->hEvent
= 0;
475 msgQueue
->lockCount
= 1;
476 msgQueue
->magic
= QUEUE_MAGIC
;
478 /* Create and initialize our per queue data */
479 msgQueue
->pQData
= bCreatePerQData
? PERQDATA_CreateInstance() : NULL
;
485 /***********************************************************************
488 * Try to reply to all pending sent messages on exit.
490 void QUEUE_FlushMessages( MESSAGEQUEUE
*queue
)
493 MESSAGEQUEUE
*senderQ
= 0;
497 EnterCriticalSection( &queue
->cSection
);
499 /* empty the list of pending SendMessage waiting to be received */
500 while (queue
->smPending
)
502 smsg
= QUEUE_RemoveSMSG( queue
, SM_PENDING_LIST
, 0);
504 senderQ
= (MESSAGEQUEUE
*)QUEUE_Lock( smsg
->hSrcQueue
);
508 /* return 0, to unblock other thread */
510 smsg
->flags
|= SMSG_HAVE_RESULT
;
511 QUEUE_SetWakeBit( senderQ
, QS_SMRESULT
);
513 QUEUE_Unlock( senderQ
);
516 QUEUE_ClearWakeBit( queue
, QS_SENDMESSAGE
);
518 LeaveCriticalSection( &queue
->cSection
);
523 /***********************************************************************
524 * QUEUE_DeleteMsgQueue
526 * Unlinks and deletes a message queue.
528 * Note: We need to mask asynchronous events to make sure PostMessage works
529 * even in the signal handler.
531 BOOL
QUEUE_DeleteMsgQueue( HQUEUE16 hQueue
)
533 MESSAGEQUEUE
* msgQueue
= (MESSAGEQUEUE
*)QUEUE_Lock(hQueue
);
536 TRACE(msg
,"(): Deleting message queue %04x\n", hQueue
);
538 if (!hQueue
|| !msgQueue
)
540 WARN(msg
, "invalid argument.\n");
546 if( hCursorQueue
== hQueue
) hCursorQueue
= 0;
547 if( hActiveQueue
== hQueue
) hActiveQueue
= 0;
549 /* flush sent messages */
550 QUEUE_FlushMessages( msgQueue
);
552 HeapLock( SystemHeap
); /* FIXME: a bit overkill */
554 /* Release per queue data if present */
555 if ( msgQueue
->pQData
)
557 PERQDATA_Release( msgQueue
->pQData
);
558 msgQueue
->pQData
= 0;
561 /* remove the message queue from the global link list */
562 pPrev
= &hFirstQueue
;
563 while (*pPrev
&& (*pPrev
!= hQueue
))
565 MESSAGEQUEUE
*msgQ
= (MESSAGEQUEUE
*)GlobalLock16(*pPrev
);
568 if ( !msgQ
|| (msgQ
->magic
!= QUEUE_MAGIC
) )
570 /* HQUEUE link list is corrupted, try to exit gracefully */
571 WARN( msg
, "HQUEUE link list corrupted!\n");
577 if (pPrev
&& *pPrev
) *pPrev
= msgQueue
->next
;
580 HeapUnlock( SystemHeap
);
582 /* free up resource used by MESSAGEQUEUE strcture */
583 msgQueue
->lockCount
--;
584 QUEUE_Unlock( msgQueue
);
590 /***********************************************************************
591 * QUEUE_CreateSysMsgQueue
593 * Create the system message queue, and set the double-click speed.
594 * Must be called only once.
596 BOOL
QUEUE_CreateSysMsgQueue( int size
)
598 /* Note: We dont need perQ data for the system message queue */
599 if (!(hmemSysMsgQueue
= QUEUE_CreateMsgQueue( FALSE
)))
602 sysMsgQueue
= (MESSAGEQUEUE
*) GlobalLock16( hmemSysMsgQueue
);
607 /***********************************************************************
610 MESSAGEQUEUE
*QUEUE_GetSysQueue(void)
616 /***********************************************************************
619 * See "Windows Internals", p.449
621 void QUEUE_SetWakeBit( MESSAGEQUEUE
*queue
, WORD bit
)
623 TRACE(msg
,"queue = %04x (wm=%04x), bit = %04x\n",
624 queue
->self
, queue
->wakeMask
, bit
);
626 if (bit
& QS_MOUSE
) pMouseQueue
= queue
;
627 if (bit
& QS_KEY
) pKbdQueue
= queue
;
628 queue
->changeBits
|= bit
;
629 queue
->wakeBits
|= bit
;
630 if (queue
->wakeMask
& bit
)
634 /* Wake up thread waiting for message */
635 if ( THREAD_IsWin16( queue
->thdb
) )
636 PostEvent16( queue
->thdb
->process
->task
);
639 SetEvent( queue
->hEvent
);
645 /***********************************************************************
648 void QUEUE_ClearWakeBit( MESSAGEQUEUE
*queue
, WORD bit
)
650 queue
->changeBits
&= ~bit
;
651 queue
->wakeBits
&= ~bit
;
655 /***********************************************************************
658 * See "Windows Internals", p.447
661 * 0 if exit with timeout
664 int QUEUE_WaitBits( WORD bits
, DWORD timeout
)
669 TRACE(msg
,"q %04x waiting for %04x\n", GetFastQueue16(), bits
);
671 if ( THREAD_IsWin16( THREAD_Current() ) && (timeout
!= INFINITE
) )
672 curTime
= GetTickCount();
674 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() ))) return 0;
678 if (queue
->changeBits
& bits
)
680 /* One of the bits is set; we can return */
682 QUEUE_Unlock( queue
);
685 if (queue
->wakeBits
& QS_SENDMESSAGE
)
687 /* Process the sent message immediately */
690 QUEUE_ReceiveMessage( queue
);
691 continue; /* nested sm crux */
694 queue
->wakeMask
= bits
| QS_SENDMESSAGE
;
695 if(queue
->changeBits
& bits
)
700 TRACE(msg
,"%04x) wakeMask is %04x, waiting\n", queue
->self
, queue
->wakeMask
);
702 if ( !THREAD_IsWin16( THREAD_Current() ) )
704 /* win32 thread, use WaitForMultipleObjects */
705 MsgWaitForMultipleObjects( 0, NULL
, FALSE
, timeout
, queue
->wakeMask
);
709 if ( timeout
== INFINITE
)
710 WaitEvent16( 0 ); /* win 16 thread, use WaitEvent */
713 /* check for timeout, then give control to other tasks */
714 if (GetTickCount() - curTime
> timeout
)
717 QUEUE_Unlock( queue
);
718 return 0; /* exit with timeout */
727 /***********************************************************************
730 * This routine is called when a SMSG need to be added to one of the three
731 * SM list. (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
733 BOOL
QUEUE_AddSMSG( MESSAGEQUEUE
*queue
, int list
, SMSG
*smsg
)
735 TRACE(sendmsg
,"queue=%x, list=%d, smsg=%p msg=%s\n", queue
->self
, list
,
736 smsg
, SPY_GetMsgName(smsg
->msg
));
740 case SM_PROCESSING_LIST
:
741 /* don't need to be thread safe, only accessed by the
742 thread associated with the sender queue */
743 smsg
->nextProcessing
= queue
->smProcessing
;
744 queue
->smProcessing
= smsg
;
747 case SM_WAITING_LIST
:
748 /* don't need to be thread safe, only accessed by the
749 thread associated with the receiver queue */
750 smsg
->nextWaiting
= queue
->smWaiting
;
751 queue
->smWaiting
= smsg
;
754 case SM_PENDING_LIST
:
756 /* make it thread safe, could be accessed by the sender and
760 EnterCriticalSection( &queue
->cSection
);
761 smsg
->nextPending
= NULL
;
762 prev
= &queue
->smPending
;
764 prev
= &(*prev
)->nextPending
;
766 LeaveCriticalSection( &queue
->cSection
);
768 QUEUE_SetWakeBit( queue
, QS_SENDMESSAGE
);
773 WARN(sendmsg
, "Invalid list: %d", list
);
781 /***********************************************************************
784 * This routine is called when a SMSG need to be remove from one of the three
785 * SM list. (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
786 * If smsg == 0, remove the first smsg from the specified list
788 SMSG
*QUEUE_RemoveSMSG( MESSAGEQUEUE
*queue
, int list
, SMSG
*smsg
)
793 case SM_PROCESSING_LIST
:
794 /* don't need to be thread safe, only accessed by the
795 thread associated with the sender queue */
797 /* if smsg is equal to null, it means the first in the list */
799 smsg
= queue
->smProcessing
;
801 TRACE(sendmsg
,"queue=%x, list=%d, smsg=%p msg=%s\n", queue
->self
, list
,
802 smsg
, SPY_GetMsgName(smsg
->msg
));
803 /* In fact SM_PROCESSING_LIST is a stack, and smsg
804 should be always at the top of the list */
805 if ( (smsg
!= queue
->smProcessing
) || !queue
->smProcessing
)
807 ERR( sendmsg
, "smsg not at the top of Processing list, smsg=0x%p queue=0x%p", smsg
, queue
);
812 queue
->smProcessing
= smsg
->nextProcessing
;
813 smsg
->nextProcessing
= 0;
817 case SM_WAITING_LIST
:
818 /* don't need to be thread safe, only accessed by the
819 thread associated with the receiver queue */
821 /* if smsg is equal to null, it means the first in the list */
823 smsg
= queue
->smWaiting
;
825 TRACE(sendmsg
,"queue=%x, list=%d, smsg=%p msg=%s\n", queue
->self
, list
,
826 smsg
, SPY_GetMsgName(smsg
->msg
));
827 /* In fact SM_WAITING_LIST is a stack, and smsg
828 should be always at the top of the list */
829 if ( (smsg
!= queue
->smWaiting
) || !queue
->smWaiting
)
831 ERR( sendmsg
, "smsg not at the top of Waiting list, smsg=0x%p queue=0x%p", smsg
, queue
);
836 queue
->smWaiting
= smsg
->nextWaiting
;
837 smsg
->nextWaiting
= 0;
841 case SM_PENDING_LIST
:
842 /* make it thread safe, could be accessed by the sender and
844 EnterCriticalSection( &queue
->cSection
);
846 if (!smsg
|| !queue
->smPending
)
847 smsg
= queue
->smPending
;
850 ERR( sendmsg
, "should always remove the top one in Pending list, smsg=0x%p queue=0x%p", smsg
, queue
);
854 TRACE(sendmsg
,"queue=%x, list=%d, smsg=%p msg=%s\n", queue
->self
, list
,
855 smsg
, SPY_GetMsgName(smsg
->msg
));
857 queue
->smPending
= smsg
->nextPending
;
858 smsg
->nextPending
= 0;
860 /* if no more SMSG in Pending list, clear QS_SENDMESSAGE flag */
861 if (!queue
->smPending
)
862 QUEUE_ClearWakeBit( queue
, QS_SENDMESSAGE
);
864 LeaveCriticalSection( &queue
->cSection
);
868 WARN(sendmsg
, "Invalid list: %d", list
);
876 /***********************************************************************
877 * QUEUE_ReceiveMessage
879 * This routine is called when a sent message is waiting for the queue.
881 void QUEUE_ReceiveMessage( MESSAGEQUEUE
*queue
)
885 MESSAGEQUEUE
*senderQ
;
887 TRACE(sendmsg
, "queue %04x\n", queue
->self
);
889 if ( !(queue
->wakeBits
& QS_SENDMESSAGE
) && queue
->smPending
)
891 TRACE(sendmsg
,"\trcm: nothing to do\n");
895 /* remove smsg on the top of the pending list and put it in the processing list */
896 smsg
= QUEUE_RemoveSMSG(queue
, SM_PENDING_LIST
, 0);
897 QUEUE_AddSMSG(queue
, SM_WAITING_LIST
, smsg
);
899 TRACE(sendmsg
,"RM: %s [%04x] (%04x -> %04x)\n",
900 SPY_GetMsgName(smsg
->msg
), smsg
->msg
, smsg
->hSrcQueue
, smsg
->hDstQueue
);
902 if (IsWindow( smsg
->hWnd
))
904 WND
*wndPtr
= WIN_FindWndPtr( smsg
->hWnd
);
905 DWORD extraInfo
= queue
->GetMessageExtraInfoVal
; /* save ExtraInfo */
907 /* use sender queue extra info value while calling the window proc */
908 senderQ
= (MESSAGEQUEUE
*)QUEUE_Lock( smsg
->hSrcQueue
);
911 queue
->GetMessageExtraInfoVal
= senderQ
->GetMessageExtraInfoVal
;
912 QUEUE_Unlock( senderQ
);
915 /* call the right version of CallWindowProcXX */
916 if (smsg
->flags
& SMSG_WIN32
)
918 TRACE(sendmsg
, "\trcm: msg is Win32\n" );
919 if (smsg
->flags
& SMSG_UNICODE
)
920 result
= CallWindowProcW( wndPtr
->winproc
,
921 smsg
->hWnd
, smsg
->msg
,
922 smsg
->wParam
, smsg
->lParam
);
924 result
= CallWindowProcA( wndPtr
->winproc
,
925 smsg
->hWnd
, smsg
->msg
,
926 smsg
->wParam
, smsg
->lParam
);
928 else /* Win16 message */
929 result
= CallWindowProc16( (WNDPROC16
)wndPtr
->winproc
,
932 LOWORD (smsg
->wParam
),
935 queue
->GetMessageExtraInfoVal
= extraInfo
; /* Restore extra info */
936 WIN_ReleaseWndPtr(wndPtr
);
937 TRACE(sendmsg
,"result = %08x\n", (unsigned)result
);
939 else WARN(sendmsg
, "\trcm: bad hWnd\n");
942 /* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not
944 smsg
->flags
|= SMSG_SENDING_REPLY
;
945 ReplyMessage( result
);
947 TRACE( sendmsg
,"done! \n" );
952 /***********************************************************************
955 * Add a message to the queue. Return FALSE if queue is full.
957 BOOL
QUEUE_AddMsg( HQUEUE16 hQueue
, MSG
*msg
, DWORD extraInfo
)
959 MESSAGEQUEUE
*msgQueue
;
963 if (!(msgQueue
= (MESSAGEQUEUE
*)QUEUE_Lock( hQueue
))) return FALSE
;
965 /* allocate new message in global heap for now */
966 if (!(qmsg
= (QMSG
*) HeapAlloc( SystemHeap
, 0, sizeof(QMSG
) ) ))
968 QUEUE_Unlock( msgQueue
);
972 EnterCriticalSection( &msgQueue
->cSection
);
976 qmsg
->extraInfo
= extraInfo
;
978 /* insert the message in the link list */
980 qmsg
->prevMsg
= msgQueue
->lastMsg
;
982 if (msgQueue
->lastMsg
)
983 msgQueue
->lastMsg
->nextMsg
= qmsg
;
985 /* update first and last anchor in message queue */
986 msgQueue
->lastMsg
= qmsg
;
987 if (!msgQueue
->firstMsg
)
988 msgQueue
->firstMsg
= qmsg
;
990 msgQueue
->msgCount
++;
992 LeaveCriticalSection( &msgQueue
->cSection
);
994 QUEUE_SetWakeBit( msgQueue
, QS_POSTMESSAGE
);
995 QUEUE_Unlock( msgQueue
);
1002 /***********************************************************************
1005 * Find a message matching the given parameters. Return -1 if none available.
1007 QMSG
* QUEUE_FindMsg( MESSAGEQUEUE
* msgQueue
, HWND hwnd
, int first
, int last
)
1011 EnterCriticalSection( &msgQueue
->cSection
);
1013 if (!msgQueue
->msgCount
)
1015 else if (!hwnd
&& !first
&& !last
)
1016 qmsg
= msgQueue
->firstMsg
;
1019 /* look in linked list for message matching first and last criteria */
1020 for (qmsg
= msgQueue
->firstMsg
; qmsg
; qmsg
= qmsg
->nextMsg
)
1022 MSG
*msg
= &(qmsg
->msg
);
1024 if (!hwnd
|| (msg
->hwnd
== hwnd
))
1026 if (!first
&& !last
)
1027 break; /* found it */
1029 if ((msg
->message
>= first
) && (!last
|| (msg
->message
<= last
)))
1030 break; /* found it */
1035 LeaveCriticalSection( &msgQueue
->cSection
);
1042 /***********************************************************************
1045 * Remove a message from the queue (pos must be a valid position).
1047 void QUEUE_RemoveMsg( MESSAGEQUEUE
* msgQueue
, QMSG
*qmsg
)
1049 EnterCriticalSection( &msgQueue
->cSection
);
1051 /* set the linked list */
1053 qmsg
->prevMsg
->nextMsg
= qmsg
->nextMsg
;
1056 qmsg
->nextMsg
->prevMsg
= qmsg
->prevMsg
;
1058 if (msgQueue
->firstMsg
== qmsg
)
1059 msgQueue
->firstMsg
= qmsg
->nextMsg
;
1061 if (msgQueue
->lastMsg
== qmsg
)
1062 msgQueue
->lastMsg
= qmsg
->prevMsg
;
1064 /* deallocate the memory for the message */
1065 HeapFree( SystemHeap
, 0, qmsg
);
1067 msgQueue
->msgCount
--;
1068 if (!msgQueue
->msgCount
) msgQueue
->wakeBits
&= ~QS_POSTMESSAGE
;
1070 LeaveCriticalSection( &msgQueue
->cSection
);
1074 /***********************************************************************
1077 * Wake a queue upon reception of a hardware event.
1079 static void QUEUE_WakeSomeone( UINT message
)
1084 HQUEUE16 hQueue
= 0;
1085 MESSAGEQUEUE
*queue
= NULL
;
1088 hQueue
= hCursorQueue
;
1090 if( (message
>= WM_KEYFIRST
) && (message
<= WM_KEYLAST
) )
1094 hQueue
= hActiveQueue
;
1098 wakeBit
= (message
== WM_MOUSEMOVE
) ? QS_MOUSEMOVE
: QS_MOUSEBUTTON
;
1099 if( (hwnd
= GetCapture()) )
1100 if( (wndPtr
= WIN_FindWndPtr( hwnd
)) )
1102 hQueue
= wndPtr
->hmemTaskQ
;
1103 WIN_ReleaseWndPtr(wndPtr
);
1107 if( (hwnd
= GetSysModalWindow16()) )
1109 if( (wndPtr
= WIN_FindWndPtr( hwnd
)) )
1111 hQueue
= wndPtr
->hmemTaskQ
;
1112 WIN_ReleaseWndPtr(wndPtr
);
1117 queue
= QUEUE_Lock( hQueue
);
1121 queue
= QUEUE_Lock( hFirstQueue
);
1124 if (queue
->wakeMask
& wakeBit
) break;
1126 QUEUE_Unlock(queue
);
1127 queue
= QUEUE_Lock( queue
->next
);
1131 WARN(msg
, "couldn't find queue\n");
1136 QUEUE_SetWakeBit( queue
, wakeBit
);
1138 QUEUE_Unlock( queue
);
1142 /***********************************************************************
1145 * Add an event to the system message queue.
1146 * Note: the position is relative to the desktop window.
1148 void hardware_event( WORD message
, WORD wParam
, LONG lParam
,
1149 int xPos
, int yPos
, DWORD time
, DWORD extraInfo
)
1155 if (!sysMsgQueue
) return;
1157 EnterCriticalSection( &sysMsgQueue
->cSection
);
1159 /* Merge with previous event if possible */
1160 qmsg
= sysMsgQueue
->lastMsg
;
1162 if ((message
== WM_MOUSEMOVE
) && sysMsgQueue
->lastMsg
)
1164 msg
= &(sysMsgQueue
->lastMsg
->msg
);
1166 if ((msg
->message
== message
) && (msg
->wParam
== wParam
))
1169 qmsg
= sysMsgQueue
->lastMsg
;
1176 /* Should I limit the number of message in
1177 the system message queue??? */
1179 /* Don't merge allocate a new msg in the global heap */
1181 if (!(qmsg
= (QMSG
*) HeapAlloc( SystemHeap
, 0, sizeof(QMSG
) ) ))
1183 LeaveCriticalSection( &sysMsgQueue
->cSection
);
1187 /* put message at the end of the linked list */
1189 qmsg
->prevMsg
= sysMsgQueue
->lastMsg
;
1191 if (sysMsgQueue
->lastMsg
)
1192 sysMsgQueue
->lastMsg
->nextMsg
= qmsg
;
1194 /* set last and first anchor index in system message queue */
1195 sysMsgQueue
->lastMsg
= qmsg
;
1196 if (!sysMsgQueue
->firstMsg
)
1197 sysMsgQueue
->firstMsg
= qmsg
;
1199 sysMsgQueue
->msgCount
++;
1205 msg
->message
= message
;
1206 msg
->wParam
= wParam
;
1207 msg
->lParam
= lParam
;
1211 qmsg
->extraInfo
= extraInfo
;
1213 LeaveCriticalSection( &sysMsgQueue
->cSection
);
1215 QUEUE_WakeSomeone( message
);
1219 /***********************************************************************
1220 * QUEUE_GetQueueTask
1222 HTASK16
QUEUE_GetQueueTask( HQUEUE16 hQueue
)
1226 MESSAGEQUEUE
*queue
= QUEUE_Lock( hQueue
);
1230 hTask
= queue
->thdb
->process
->task
;
1231 QUEUE_Unlock( queue
);
1239 /***********************************************************************
1240 * QUEUE_IncPaintCount
1242 void QUEUE_IncPaintCount( HQUEUE16 hQueue
)
1244 MESSAGEQUEUE
*queue
;
1246 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( hQueue
))) return;
1247 queue
->wPaintCount
++;
1248 QUEUE_SetWakeBit( queue
, QS_PAINT
);
1249 QUEUE_Unlock( queue
);
1253 /***********************************************************************
1254 * QUEUE_DecPaintCount
1256 void QUEUE_DecPaintCount( HQUEUE16 hQueue
)
1258 MESSAGEQUEUE
*queue
;
1260 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( hQueue
))) return;
1261 queue
->wPaintCount
--;
1262 if (!queue
->wPaintCount
) queue
->wakeBits
&= ~QS_PAINT
;
1263 QUEUE_Unlock( queue
);
1267 /***********************************************************************
1268 * QUEUE_IncTimerCount
1270 void QUEUE_IncTimerCount( HQUEUE16 hQueue
)
1272 MESSAGEQUEUE
*queue
;
1274 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( hQueue
))) return;
1275 queue
->wTimerCount
++;
1276 QUEUE_SetWakeBit( queue
, QS_TIMER
);
1277 QUEUE_Unlock( queue
);
1281 /***********************************************************************
1282 * QUEUE_DecTimerCount
1284 void QUEUE_DecTimerCount( HQUEUE16 hQueue
)
1286 MESSAGEQUEUE
*queue
;
1288 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( hQueue
))) return;
1289 queue
->wTimerCount
--;
1290 if (!queue
->wTimerCount
) queue
->wakeBits
&= ~QS_TIMER
;
1291 QUEUE_Unlock( queue
);
1295 /***********************************************************************
1296 * PostQuitMessage16 (USER.6)
1298 void WINAPI
PostQuitMessage16( INT16 exitCode
)
1300 PostQuitMessage( exitCode
);
1304 /***********************************************************************
1305 * PostQuitMessage32 (USER32.421)
1307 * PostQuitMessage() posts a message to the system requesting an
1308 * application to terminate execution. As a result of this function,
1309 * the WM_QUIT message is posted to the application, and
1310 * PostQuitMessage() returns immediately. The exitCode parameter
1311 * specifies an application-defined exit code, which appears in the
1312 * _wParam_ parameter of the WM_QUIT message posted to the application.
1318 void WINAPI
PostQuitMessage( INT exitCode
)
1320 MESSAGEQUEUE
*queue
;
1322 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() ))) return;
1323 queue
->wPostQMsg
= TRUE
;
1324 queue
->wExitCode
= (WORD
)exitCode
;
1325 QUEUE_Unlock( queue
);
1329 /***********************************************************************
1330 * GetWindowTask16 (USER.224)
1332 HTASK16 WINAPI
GetWindowTask16( HWND16 hwnd
)
1335 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1337 if (!wndPtr
) return 0;
1338 retvalue
= QUEUE_GetQueueTask( wndPtr
->hmemTaskQ
);
1339 WIN_ReleaseWndPtr(wndPtr
);
1343 /***********************************************************************
1344 * GetWindowThreadProcessId (USER32.313)
1346 DWORD WINAPI
GetWindowThreadProcessId( HWND hwnd
, LPDWORD process
)
1351 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1353 if (!wndPtr
) return 0;
1354 htask
=QUEUE_GetQueueTask( wndPtr
->hmemTaskQ
);
1355 WIN_ReleaseWndPtr(wndPtr
);
1356 tdb
= (TDB
*)GlobalLock16(htask
);
1357 if (!tdb
|| !tdb
->thdb
) return 0;
1358 if (process
) *process
= (DWORD
)tdb
->thdb
->process
->server_pid
;
1359 return (DWORD
)tdb
->thdb
->server_tid
;
1363 /***********************************************************************
1364 * SetMessageQueue16 (USER.266)
1366 BOOL16 WINAPI
SetMessageQueue16( INT16 size
)
1368 return SetMessageQueue( size
);
1372 /***********************************************************************
1373 * SetMessageQueue32 (USER32.494)
1375 BOOL WINAPI
SetMessageQueue( INT size
)
1377 /* now obsolete the message queue will be expanded dynamically
1380 /* access the queue to create it if it's not existing */
1386 /***********************************************************************
1387 * InitThreadInput (USER.409)
1389 HQUEUE16 WINAPI
InitThreadInput16( WORD unknown
, WORD flags
)
1392 MESSAGEQUEUE
*queuePtr
;
1394 THDB
*thdb
= THREAD_Current();
1399 hQueue
= thdb
->teb
.queue
;
1403 /* Create thread message queue */
1404 if( !(hQueue
= QUEUE_CreateMsgQueue( TRUE
)))
1406 WARN(msg
, "failed!\n");
1410 /* Link new queue into list */
1411 queuePtr
= (MESSAGEQUEUE
*)QUEUE_Lock( hQueue
);
1412 queuePtr
->thdb
= THREAD_Current();
1414 HeapLock( SystemHeap
); /* FIXME: a bit overkill */
1415 SetThreadQueue16( 0, hQueue
);
1416 thdb
->teb
.queue
= hQueue
;
1418 queuePtr
->next
= hFirstQueue
;
1419 hFirstQueue
= hQueue
;
1420 HeapUnlock( SystemHeap
);
1422 QUEUE_Unlock( queuePtr
);
1428 /***********************************************************************
1429 * GetQueueStatus16 (USER.334)
1431 DWORD WINAPI
GetQueueStatus16( UINT16 flags
)
1433 MESSAGEQUEUE
*queue
;
1436 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() ))) return 0;
1437 ret
= MAKELONG( queue
->changeBits
, queue
->wakeBits
);
1438 queue
->changeBits
= 0;
1439 QUEUE_Unlock( queue
);
1441 return ret
& MAKELONG( flags
, flags
);
1444 /***********************************************************************
1445 * GetQueueStatus32 (USER32.283)
1447 DWORD WINAPI
GetQueueStatus( UINT flags
)
1449 MESSAGEQUEUE
*queue
;
1452 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() ))) return 0;
1453 ret
= MAKELONG( queue
->changeBits
, queue
->wakeBits
);
1454 queue
->changeBits
= 0;
1455 QUEUE_Unlock( queue
);
1457 return ret
& MAKELONG( flags
, flags
);
1461 /***********************************************************************
1462 * GetInputState16 (USER.335)
1464 BOOL16 WINAPI
GetInputState16(void)
1466 return GetInputState();
1469 /***********************************************************************
1470 * WaitForInputIdle (USER32.577)
1472 DWORD WINAPI
WaitForInputIdle (HANDLE hProcess
, DWORD dwTimeOut
)
1474 FIXME (msg
, "(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess
, dwTimeOut
);
1476 return WAIT_TIMEOUT
;
1480 /***********************************************************************
1481 * GetInputState32 (USER32.244)
1483 BOOL WINAPI
GetInputState(void)
1485 MESSAGEQUEUE
*queue
;
1488 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() )))
1490 ret
= queue
->wakeBits
& (QS_KEY
| QS_MOUSEBUTTON
);
1491 QUEUE_Unlock( queue
);
1496 /***********************************************************************
1497 * UserYield (USER.332)
1499 void WINAPI
UserYield16(void)
1501 MESSAGEQUEUE
*queue
;
1503 /* Handle sent messages */
1504 queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() );
1506 while (queue
&& (queue
->wakeBits
& QS_SENDMESSAGE
))
1507 QUEUE_ReceiveMessage( queue
);
1509 QUEUE_Unlock( queue
);
1512 if ( THREAD_IsWin16( THREAD_Current() ) )
1518 ReleaseThunkLock(&count
);
1519 RestoreThunkLock(count
);
1522 /* Handle sent messages again */
1523 queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() );
1525 while (queue
&& (queue
->wakeBits
& QS_SENDMESSAGE
))
1526 QUEUE_ReceiveMessage( queue
);
1528 QUEUE_Unlock( queue
);
1531 /***********************************************************************
1532 * GetMessagePos (USER.119) (USER32.272)
1534 * The GetMessagePos() function returns a long value representing a
1535 * cursor position, in screen coordinates, when the last message
1536 * retrieved by the GetMessage() function occurs. The x-coordinate is
1537 * in the low-order word of the return value, the y-coordinate is in
1538 * the high-order word. The application can use the MAKEPOINT()
1539 * macro to obtain a POINT structure from the return value.
1541 * For the current cursor position, use GetCursorPos().
1545 * Cursor position of last message on success, zero on failure.
1552 DWORD WINAPI
GetMessagePos(void)
1554 MESSAGEQUEUE
*queue
;
1557 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() ))) return 0;
1558 ret
= queue
->GetMessagePosVal
;
1559 QUEUE_Unlock( queue
);
1565 /***********************************************************************
1566 * GetMessageTime (USER.120) (USER32.273)
1568 * GetMessageTime() returns the message time for the last message
1569 * retrieved by the function. The time is measured in milliseconds with
1570 * the same offset as GetTickCount().
1572 * Since the tick count wraps, this is only useful for moderately short
1573 * relative time comparisons.
1577 * Time of last message on success, zero on failure.
1584 LONG WINAPI
GetMessageTime(void)
1586 MESSAGEQUEUE
*queue
;
1589 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() ))) return 0;
1590 ret
= queue
->GetMessageTimeVal
;
1591 QUEUE_Unlock( queue
);
1597 /***********************************************************************
1598 * GetMessageExtraInfo (USER.288) (USER32.271)
1600 LONG WINAPI
GetMessageExtraInfo(void)
1602 MESSAGEQUEUE
*queue
;
1605 if (!(queue
= (MESSAGEQUEUE
*)QUEUE_Lock( GetFastQueue16() ))) return 0;
1606 ret
= queue
->GetMessageExtraInfoVal
;
1607 QUEUE_Unlock( queue
);