1 /* * Message queues related functions
3 * Copyright 1993, 1994 Alexandre Julliard
12 #include "wine/winbase16.h"
13 #include "wine/winuser16.h"
20 #include "clipboard.h"
24 #include "debugtools.h"
28 DECLARE_DEBUG_CHANNEL(msg);
29 DECLARE_DEBUG_CHANNEL(sendmsg);
31 #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
33 static HQUEUE16 hFirstQueue = 0;
34 static HQUEUE16 hExitingQueue = 0;
35 static HQUEUE16 hmemSysMsgQueue = 0;
36 static MESSAGEQUEUE *sysMsgQueue = NULL;
37 static PERQUEUEDATA *pQDataWin16 = NULL; /* Global perQData for Win16 tasks */
39 static MESSAGEQUEUE *pMouseQueue = NULL; /* Queue for last mouse message */
40 static MESSAGEQUEUE *pKbdQueue = NULL; /* Queue for last kbd message */
42 HQUEUE16 hCursorQueue = 0;
43 HQUEUE16 hActiveQueue = 0;
46 /***********************************************************************
47 * PERQDATA_CreateInstance
49 * Creates an instance of a reference counted PERQUEUEDATA element
50 * for the message queue. perQData is stored globally for 16 bit tasks.
52 * Note: We don't implement perQdata exactly the same way Windows does.
53 * Each perQData element is reference counted since it may be potentially
54 * shared by multiple message Queues (via AttachThreadInput).
55 * We only store the current values for Active, Capture and focus windows
58 PERQUEUEDATA * PERQDATA_CreateInstance( )
66 /* Share a single instance of perQData for all 16 bit tasks */
67 if ( ( bIsWin16 = THREAD_IsWin16( NtCurrentTeb() ) ) )
69 /* If previously allocated, just bump up ref count */
72 PERQDATA_Addref( pQDataWin16 );
77 /* Allocate PERQUEUEDATA from the system heap */
78 if (!( pQData = (PERQUEUEDATA *) HeapAlloc( SystemHeap, 0,
79 sizeof(PERQUEUEDATA) ) ))
83 pQData->hWndCapture = pQData->hWndFocus = pQData->hWndActive = 0;
84 pQData->ulRefCount = 1;
85 pQData->nCaptureHT = HTCLIENT;
87 /* Note: We have an independent critical section for the per queue data
88 * since this may be shared by different threads. see AttachThreadInput()
90 InitializeCriticalSection( &pQData->cSection );
91 /* FIXME: not all per queue data critical sections should be global */
92 MakeCriticalSectionGlobal( &pQData->cSection );
94 /* Save perQData globally for 16 bit tasks */
102 /***********************************************************************
105 * Increment reference count for the PERQUEUEDATA instance
106 * Returns reference count for debugging purposes
108 ULONG PERQDATA_Addref( PERQUEUEDATA *pQData )
110 assert(pQData != 0 );
111 TRACE_(msg)("(): current refcount %lu ...\n", pQData->ulRefCount);
113 EnterCriticalSection( &pQData->cSection );
114 ++pQData->ulRefCount;
115 LeaveCriticalSection( &pQData->cSection );
117 return pQData->ulRefCount;
121 /***********************************************************************
124 * Release a reference to a PERQUEUEDATA instance.
125 * Destroy the instance if no more references exist
126 * Returns reference count for debugging purposes
128 ULONG PERQDATA_Release( PERQUEUEDATA *pQData )
130 assert(pQData != 0 );
131 TRACE_(msg)("(): current refcount %lu ...\n",
132 (LONG)pQData->ulRefCount );
134 EnterCriticalSection( &pQData->cSection );
135 if ( --pQData->ulRefCount == 0 )
137 LeaveCriticalSection( &pQData->cSection );
138 DeleteCriticalSection( &pQData->cSection );
140 TRACE_(msg)("(): deleting PERQUEUEDATA instance ...\n" );
142 /* Deleting our global 16 bit perQData? */
143 if ( pQData == pQDataWin16 )
146 /* Free the PERQUEUEDATA instance */
147 HeapFree( SystemHeap, 0, pQData );
151 LeaveCriticalSection( &pQData->cSection );
153 return pQData->ulRefCount;
157 /***********************************************************************
158 * PERQDATA_GetFocusWnd
160 * Get the focus hwnd member in a threadsafe manner
162 HWND PERQDATA_GetFocusWnd( PERQUEUEDATA *pQData )
165 assert(pQData != 0 );
167 EnterCriticalSection( &pQData->cSection );
168 hWndFocus = pQData->hWndFocus;
169 LeaveCriticalSection( &pQData->cSection );
175 /***********************************************************************
176 * PERQDATA_SetFocusWnd
178 * Set the focus hwnd member in a threadsafe manner
180 HWND PERQDATA_SetFocusWnd( PERQUEUEDATA *pQData, HWND hWndFocus )
183 assert(pQData != 0 );
185 EnterCriticalSection( &pQData->cSection );
186 hWndFocusPrv = pQData->hWndFocus;
187 pQData->hWndFocus = hWndFocus;
188 LeaveCriticalSection( &pQData->cSection );
194 /***********************************************************************
195 * PERQDATA_GetActiveWnd
197 * Get the active hwnd member in a threadsafe manner
199 HWND PERQDATA_GetActiveWnd( PERQUEUEDATA *pQData )
202 assert(pQData != 0 );
204 EnterCriticalSection( &pQData->cSection );
205 hWndActive = pQData->hWndActive;
206 LeaveCriticalSection( &pQData->cSection );
212 /***********************************************************************
213 * PERQDATA_SetActiveWnd
215 * Set the active focus hwnd member in a threadsafe manner
217 HWND PERQDATA_SetActiveWnd( PERQUEUEDATA *pQData, HWND hWndActive )
220 assert(pQData != 0 );
222 EnterCriticalSection( &pQData->cSection );
223 hWndActivePrv = pQData->hWndActive;
224 pQData->hWndActive = hWndActive;
225 LeaveCriticalSection( &pQData->cSection );
227 return hWndActivePrv;
231 /***********************************************************************
232 * PERQDATA_GetCaptureWnd
234 * Get the capture hwnd member in a threadsafe manner
236 HWND PERQDATA_GetCaptureWnd( PERQUEUEDATA *pQData )
239 assert(pQData != 0 );
241 EnterCriticalSection( &pQData->cSection );
242 hWndCapture = pQData->hWndCapture;
243 LeaveCriticalSection( &pQData->cSection );
249 /***********************************************************************
250 * PERQDATA_SetCaptureWnd
252 * Set the capture hwnd member in a threadsafe manner
254 HWND PERQDATA_SetCaptureWnd( PERQUEUEDATA *pQData, HWND hWndCapture )
257 assert(pQData != 0 );
259 EnterCriticalSection( &pQData->cSection );
260 hWndCapturePrv = pQData->hWndCapture;
261 pQData->hWndCapture = hWndCapture;
262 LeaveCriticalSection( &pQData->cSection );
264 return hWndCapturePrv;
268 /***********************************************************************
269 * PERQDATA_GetCaptureInfo
271 * Get the capture info member in a threadsafe manner
273 INT16 PERQDATA_GetCaptureInfo( PERQUEUEDATA *pQData )
276 assert(pQData != 0 );
278 EnterCriticalSection( &pQData->cSection );
279 nCaptureHT = pQData->nCaptureHT;
280 LeaveCriticalSection( &pQData->cSection );
286 /***********************************************************************
287 * PERQDATA_SetCaptureInfo
289 * Set the capture info member in a threadsafe manner
291 INT16 PERQDATA_SetCaptureInfo( PERQUEUEDATA *pQData, INT16 nCaptureHT )
294 assert(pQData != 0 );
296 EnterCriticalSection( &pQData->cSection );
297 nCaptureHTPrv = pQData->nCaptureHT;
298 pQData->nCaptureHT = nCaptureHT;
299 LeaveCriticalSection( &pQData->cSection );
301 return nCaptureHTPrv;
305 /***********************************************************************
308 * Function for getting a 32 bit pointer on queue strcture. For thread
309 * safeness programmers should use this function instead of GlobalLock to
310 * retrieve a pointer on the structure. QUEUE_Unlock should also be called
311 * when access to the queue structure is not required anymore.
313 MESSAGEQUEUE *QUEUE_Lock( HQUEUE16 hQueue )
317 HeapLock( SystemHeap ); /* FIXME: a bit overkill */
318 queue = GlobalLock16( hQueue );
319 if ( !queue || (queue->magic != QUEUE_MAGIC) )
321 HeapUnlock( SystemHeap );
326 HeapUnlock( SystemHeap );
331 /***********************************************************************
334 * Use with QUEUE_Lock to get a thread safe access to message queue
337 void QUEUE_Unlock( MESSAGEQUEUE *queue )
341 HeapLock( SystemHeap ); /* FIXME: a bit overkill */
343 if ( --queue->lockCount == 0 )
345 DeleteCriticalSection ( &queue->cSection );
346 if (queue->server_queue)
347 CloseHandle( queue->server_queue );
348 GlobalFree16( queue->self );
351 HeapUnlock( SystemHeap );
356 /***********************************************************************
359 void QUEUE_DumpQueue( HQUEUE16 hQueue )
363 if (!(pq = (MESSAGEQUEUE*) QUEUE_Lock( hQueue )) )
365 WARN_(msg)("%04x is not a queue handle\n", hQueue );
369 DPRINTF( "next: %12.4x Intertask SendMessage:\n"
370 "thread: %10p ----------------------\n"
371 "firstMsg: %8p smWaiting: %10p\n"
372 "lastMsg: %8p smPending: %10p\n"
373 "msgCount: %8.4x smProcessing: %10p\n"
381 pq->next, pq->teb, pq->firstMsg, pq->smWaiting, pq->lastMsg,
382 pq->smPending, pq->msgCount, pq->smProcessing,
383 (unsigned)pq->lockCount, pq->wWinVersion,
384 pq->wPaintCount, pq->wTimerCount,
385 pq->wakeBits, pq->wakeMask, pq->hCurHook);
391 /***********************************************************************
394 void QUEUE_WalkQueues(void)
397 HQUEUE16 hQueue = hFirstQueue;
399 DPRINTF( "Queue Msgs Thread Task Module\n" );
402 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
405 WARN_(msg)("Bad queue handle %04x\n", hQueue );
408 if (!GetModuleName16( queue->teb->htask16, module, sizeof(module )))
409 strcpy( module, "???" );
410 DPRINTF( "%04x %4d %p %04x %s\n", hQueue,queue->msgCount,
411 queue->teb, queue->teb->htask16, module );
412 hQueue = queue->next;
413 QUEUE_Unlock( queue );
419 /***********************************************************************
420 * QUEUE_IsExitingQueue
422 BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue )
424 return (hExitingQueue && (hQueue == hExitingQueue));
428 /***********************************************************************
429 * QUEUE_SetExitingQueue
431 void QUEUE_SetExitingQueue( HQUEUE16 hQueue )
433 hExitingQueue = hQueue;
437 /***********************************************************************
438 * QUEUE_CreateMsgQueue
440 * Creates a message queue. Doesn't link it into queue list!
442 static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
445 MESSAGEQUEUE * msgQueue;
446 TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
447 struct get_msg_queue_request *req = get_req_buffer();
449 TRACE_(msg)("(): Creating message queue...\n");
451 if (!(hQueue = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT,
452 sizeof(MESSAGEQUEUE) )))
455 msgQueue = (MESSAGEQUEUE *) GlobalLock16( hQueue );
459 if (server_call( REQ_GET_MSG_QUEUE ))
461 ERR_(msg)("Cannot get thread queue");
462 GlobalFree16( hQueue );
465 msgQueue->server_queue = req->handle;
466 msgQueue->server_queue = ConvertToGlobalHandle( msgQueue->server_queue );
468 msgQueue->self = hQueue;
469 msgQueue->wakeBits = msgQueue->changeBits = 0;
470 msgQueue->wWinVersion = pTask ? pTask->version : 0;
472 InitializeCriticalSection( &msgQueue->cSection );
473 MakeCriticalSectionGlobal( &msgQueue->cSection );
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 static 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->teb ) )
637 int iWndsLock = WIN_SuspendWndsLock();
638 PostEvent16( queue->teb->htask16 );
639 WIN_RestoreWndsLock( iWndsLock );
643 struct wake_queue_request *req = get_req_buffer();
644 req->handle = queue->server_queue;
646 server_call( REQ_WAKE_QUEUE );
652 /***********************************************************************
655 void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
657 queue->changeBits &= ~bit;
658 queue->wakeBits &= ~bit;
662 /***********************************************************************
665 * See "Windows Internals", p.447
668 * 0 if exit with timeout
671 int QUEUE_WaitBits( WORD bits, DWORD timeout )
677 TRACE_(msg)("q %04x waiting for %04x\n", GetFastQueue16(), bits);
679 if ( THREAD_IsWin16( NtCurrentTeb() ) && (timeout != INFINITE) )
680 curTime = GetTickCount();
682 hQueue = GetFastQueue16();
683 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return 0;
687 if (queue->changeBits & bits)
689 /* One of the bits is set; we can return */
691 QUEUE_Unlock( queue );
694 if (queue->wakeBits & QS_SENDMESSAGE)
696 /* Process the sent message immediately */
699 QUEUE_ReceiveMessage( queue );
700 continue; /* nested sm crux */
703 queue->wakeMask = bits | QS_SENDMESSAGE;
704 if(queue->changeBits & bits)
709 TRACE_(msg)("%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask);
711 if ( !THREAD_IsWin16( NtCurrentTeb() ) )
716 if ( (bHasWin16Lock = _ConfirmWin16Lock()) )
718 TRACE_(msg)("bHasWin16Lock=TRUE\n");
719 ReleaseThunkLock( &dwlc );
722 WaitForSingleObject( queue->server_queue, timeout );
726 RestoreThunkLock( dwlc );
731 if ( timeout == INFINITE )
732 WaitEvent16( 0 ); /* win 16 thread, use WaitEvent */
735 /* check for timeout, then give control to other tasks */
736 if (GetTickCount() - curTime > timeout)
739 QUEUE_Unlock( queue );
740 return 0; /* exit with timeout */
749 /***********************************************************************
752 * This routine is called when a SMSG need to be added to one of the three
753 * SM list. (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
755 BOOL QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
757 TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
758 smsg, SPY_GetMsgName(smsg->msg));
762 case SM_PROCESSING_LIST:
763 /* don't need to be thread safe, only accessed by the
764 thread associated with the sender queue */
765 smsg->nextProcessing = queue->smProcessing;
766 queue->smProcessing = smsg;
769 case SM_WAITING_LIST:
770 /* don't need to be thread safe, only accessed by the
771 thread associated with the receiver queue */
772 smsg->nextWaiting = queue->smWaiting;
773 queue->smWaiting = smsg;
776 case SM_PENDING_LIST:
778 /* make it thread safe, could be accessed by the sender and
782 EnterCriticalSection( &queue->cSection );
783 smsg->nextPending = NULL;
784 prev = &queue->smPending;
786 prev = &(*prev)->nextPending;
788 LeaveCriticalSection( &queue->cSection );
790 QUEUE_SetWakeBit( queue, QS_SENDMESSAGE );
795 WARN_(sendmsg)("Invalid list: %d", list);
803 /***********************************************************************
806 * This routine is called when a SMSG need to be remove from one of the three
807 * SM list. (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
808 * If smsg == 0, remove the first smsg from the specified list
810 SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
815 case SM_PROCESSING_LIST:
816 /* don't need to be thread safe, only accessed by the
817 thread associated with the sender queue */
819 /* if smsg is equal to null, it means the first in the list */
821 smsg = queue->smProcessing;
823 TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
824 smsg, SPY_GetMsgName(smsg->msg));
825 /* In fact SM_PROCESSING_LIST is a stack, and smsg
826 should be always at the top of the list */
827 if ( (smsg != queue->smProcessing) || !queue->smProcessing )
829 ERR_(sendmsg)("smsg not at the top of Processing list, smsg=0x%p queue=0x%p", smsg, queue);
834 queue->smProcessing = smsg->nextProcessing;
835 smsg->nextProcessing = 0;
839 case SM_WAITING_LIST:
840 /* don't need to be thread safe, only accessed by the
841 thread associated with the receiver queue */
843 /* if smsg is equal to null, it means the first in the list */
845 smsg = queue->smWaiting;
847 TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
848 smsg, SPY_GetMsgName(smsg->msg));
849 /* In fact SM_WAITING_LIST is a stack, and smsg
850 should be always at the top of the list */
851 if ( (smsg != queue->smWaiting) || !queue->smWaiting )
853 ERR_(sendmsg)("smsg not at the top of Waiting list, smsg=0x%p queue=0x%p", smsg, queue);
858 queue->smWaiting = smsg->nextWaiting;
859 smsg->nextWaiting = 0;
863 case SM_PENDING_LIST:
864 /* make it thread safe, could be accessed by the sender and
866 EnterCriticalSection( &queue->cSection );
868 if (!smsg || !queue->smPending)
869 smsg = queue->smPending;
872 ERR_(sendmsg)("should always remove the top one in Pending list, smsg=0x%p queue=0x%p", smsg, queue);
873 LeaveCriticalSection( &queue->cSection );
877 TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
878 smsg, SPY_GetMsgName(smsg->msg));
880 queue->smPending = smsg->nextPending;
881 smsg->nextPending = 0;
883 /* if no more SMSG in Pending list, clear QS_SENDMESSAGE flag */
884 if (!queue->smPending)
885 QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
887 LeaveCriticalSection( &queue->cSection );
891 WARN_(sendmsg)("Invalid list: %d", list);
899 /***********************************************************************
900 * QUEUE_ReceiveMessage
902 * This routine is called when a sent message is waiting for the queue.
904 void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
908 MESSAGEQUEUE *senderQ;
910 TRACE_(sendmsg)("queue %04x\n", queue->self );
912 if ( !(queue->wakeBits & QS_SENDMESSAGE) && queue->smPending )
914 TRACE_(sendmsg)("\trcm: nothing to do\n");
918 /* remove smsg on the top of the pending list and put it in the processing list */
919 smsg = QUEUE_RemoveSMSG(queue, SM_PENDING_LIST, 0);
920 QUEUE_AddSMSG(queue, SM_WAITING_LIST, smsg);
922 TRACE_(sendmsg)("RM: %s [%04x] (%04x -> %04x)\n",
923 SPY_GetMsgName(smsg->msg), smsg->msg, smsg->hSrcQueue, smsg->hDstQueue );
925 if (IsWindow( smsg->hWnd ))
927 WND *wndPtr = WIN_FindWndPtr( smsg->hWnd );
928 DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */
930 /* use sender queue extra info value while calling the window proc */
931 senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
934 queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
935 QUEUE_Unlock( senderQ );
938 /* call the right version of CallWindowProcXX */
939 if (smsg->flags & SMSG_WIN32)
941 TRACE_(sendmsg)("\trcm: msg is Win32\n" );
942 if (smsg->flags & SMSG_UNICODE)
943 result = CallWindowProcW( wndPtr->winproc,
944 smsg->hWnd, smsg->msg,
945 smsg->wParam, smsg->lParam );
947 result = CallWindowProcA( wndPtr->winproc,
948 smsg->hWnd, smsg->msg,
949 smsg->wParam, smsg->lParam );
951 else /* Win16 message */
952 result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
955 LOWORD (smsg->wParam),
958 queue->GetMessageExtraInfoVal = extraInfo; /* Restore extra info */
959 WIN_ReleaseWndPtr(wndPtr);
960 TRACE_(sendmsg)("result = %08x\n", (unsigned)result );
962 else WARN_(sendmsg)("\trcm: bad hWnd\n");
965 /* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not
967 smsg->flags |= SMSG_SENDING_REPLY;
968 ReplyMessage( result );
970 TRACE_(sendmsg)("done! \n" );
975 /***********************************************************************
978 * Add a message to the queue. Return FALSE if queue is full.
980 BOOL QUEUE_AddMsg( HQUEUE16 hQueue, int type, MSG *msg, DWORD extraInfo )
982 MESSAGEQUEUE *msgQueue;
986 if (!(msgQueue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return FALSE;
988 /* allocate new message in global heap for now */
989 if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
991 QUEUE_Unlock( msgQueue );
995 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;
1127 WIN_ReleaseWndPtr(wndPtr);
1131 if( (hwnd = GetSysModalWindow16()) )
1133 if( (wndPtr = WIN_FindWndPtr( hwnd )) )
1135 hQueue = wndPtr->hmemTaskQ;
1136 WIN_ReleaseWndPtr(wndPtr);
1141 queue = QUEUE_Lock( hQueue );
1145 queue = QUEUE_Lock( hFirstQueue );
1148 if (queue->wakeMask & wakeBit) break;
1150 QUEUE_Unlock(queue);
1151 queue = QUEUE_Lock( queue->next );
1155 WARN_(msg)("couldn't find queue\n");
1160 QUEUE_SetWakeBit( queue, wakeBit );
1162 QUEUE_Unlock( queue );
1166 /***********************************************************************
1169 * Add an event to the system message queue.
1170 * Note: the position is relative to the desktop window.
1172 void hardware_event( UINT message, WPARAM wParam, LPARAM lParam,
1173 int xPos, int yPos, DWORD time, DWORD extraInfo )
1179 if (!sysMsgQueue) return;
1181 EnterCriticalSection( &sysMsgQueue->cSection );
1183 /* Merge with previous event if possible */
1184 qmsg = sysMsgQueue->lastMsg;
1186 if ((message == WM_MOUSEMOVE) && sysMsgQueue->lastMsg)
1188 msg = &(sysMsgQueue->lastMsg->msg);
1190 if ((msg->message == message) && (msg->wParam == wParam))
1193 qmsg = sysMsgQueue->lastMsg;
1200 /* Should I limit the number of message in
1201 the system message queue??? */
1203 /* Don't merge allocate a new msg in the global heap */
1205 if (!(qmsg = (QMSG *) HeapAlloc( SystemHeap, 0, sizeof(QMSG) ) ))
1207 LeaveCriticalSection( &sysMsgQueue->cSection );
1211 /* put message at the end of the linked list */
1213 qmsg->prevMsg = sysMsgQueue->lastMsg;
1215 if (sysMsgQueue->lastMsg)
1216 sysMsgQueue->lastMsg->nextMsg = qmsg;
1218 /* set last and first anchor index in system message queue */
1219 sysMsgQueue->lastMsg = qmsg;
1220 if (!sysMsgQueue->firstMsg)
1221 sysMsgQueue->firstMsg = qmsg;
1223 sysMsgQueue->msgCount++;
1229 msg->message = message;
1230 msg->wParam = wParam;
1231 msg->lParam = lParam;
1235 qmsg->extraInfo = extraInfo;
1236 qmsg->type = QMSG_HARDWARE;
1238 LeaveCriticalSection( &sysMsgQueue->cSection );
1240 QUEUE_WakeSomeone( message );
1244 /***********************************************************************
1245 * QUEUE_GetQueueTask
1247 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
1251 MESSAGEQUEUE *queue = QUEUE_Lock( hQueue );
1255 hTask = queue->teb->htask16;
1256 QUEUE_Unlock( queue );
1264 /***********************************************************************
1265 * QUEUE_IncPaintCount
1267 void QUEUE_IncPaintCount( HQUEUE16 hQueue )
1269 MESSAGEQUEUE *queue;
1271 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1272 queue->wPaintCount++;
1273 QUEUE_SetWakeBit( queue, QS_PAINT );
1274 QUEUE_Unlock( queue );
1278 /***********************************************************************
1279 * QUEUE_DecPaintCount
1281 void QUEUE_DecPaintCount( HQUEUE16 hQueue )
1283 MESSAGEQUEUE *queue;
1285 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1286 queue->wPaintCount--;
1287 if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
1288 QUEUE_Unlock( queue );
1292 /***********************************************************************
1293 * QUEUE_IncTimerCount
1295 void QUEUE_IncTimerCount( HQUEUE16 hQueue )
1297 MESSAGEQUEUE *queue;
1299 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1300 queue->wTimerCount++;
1301 QUEUE_SetWakeBit( queue, QS_TIMER );
1302 QUEUE_Unlock( queue );
1306 /***********************************************************************
1307 * QUEUE_DecTimerCount
1309 void QUEUE_DecTimerCount( HQUEUE16 hQueue )
1311 MESSAGEQUEUE *queue;
1313 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
1314 queue->wTimerCount--;
1315 if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
1316 QUEUE_Unlock( queue );
1320 /***********************************************************************
1321 * PostQuitMessage16 (USER.6)
1323 void WINAPI PostQuitMessage16( INT16 exitCode )
1325 PostQuitMessage( exitCode );
1329 /***********************************************************************
1330 * PostQuitMessage (USER32.421)
1332 * PostQuitMessage() posts a message to the system requesting an
1333 * application to terminate execution. As a result of this function,
1334 * the WM_QUIT message is posted to the application, and
1335 * PostQuitMessage() returns immediately. The exitCode parameter
1336 * specifies an application-defined exit code, which appears in the
1337 * _wParam_ parameter of the WM_QUIT message posted to the application.
1343 void WINAPI PostQuitMessage( INT exitCode )
1345 MESSAGEQUEUE *queue;
1347 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return;
1348 queue->wPostQMsg = TRUE;
1349 queue->wExitCode = (WORD)exitCode;
1350 QUEUE_Unlock( queue );
1354 /***********************************************************************
1355 * GetWindowTask16 (USER.224)
1357 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
1360 WND *wndPtr = WIN_FindWndPtr( hwnd );
1362 if (!wndPtr) return 0;
1363 retvalue = QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1364 WIN_ReleaseWndPtr(wndPtr);
1368 /***********************************************************************
1369 * GetWindowThreadProcessId (USER32.313)
1371 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
1374 MESSAGEQUEUE *queue;
1376 WND *wndPtr = WIN_FindWndPtr( hwnd );
1377 if (!wndPtr) return 0;
1379 queue = QUEUE_Lock( wndPtr->hmemTaskQ );
1380 WIN_ReleaseWndPtr(wndPtr);
1382 if (!queue) return 0;
1384 if ( process ) *process = (DWORD)queue->teb->pid;
1385 retvalue = (DWORD)queue->teb->tid;
1387 QUEUE_Unlock( queue );
1392 /***********************************************************************
1393 * SetMessageQueue16 (USER.266)
1395 BOOL16 WINAPI SetMessageQueue16( INT16 size )
1397 return SetMessageQueue( size );
1401 /***********************************************************************
1402 * SetMessageQueue (USER32.494)
1404 BOOL WINAPI SetMessageQueue( INT size )
1406 /* now obsolete the message queue will be expanded dynamically
1409 /* access the queue to create it if it's not existing */
1415 /***********************************************************************
1416 * InitThreadInput16 (USER.409)
1418 HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags )
1421 MESSAGEQUEUE *queuePtr;
1423 TEB *teb = NtCurrentTeb();
1428 hQueue = teb->queue;
1432 /* Create thread message queue */
1433 if( !(hQueue = QUEUE_CreateMsgQueue( TRUE )))
1435 WARN_(msg)("failed!\n");
1439 /* Link new queue into list */
1440 queuePtr = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
1441 queuePtr->teb = NtCurrentTeb();
1443 HeapLock( SystemHeap ); /* FIXME: a bit overkill */
1444 SetThreadQueue16( 0, hQueue );
1445 teb->queue = hQueue;
1447 queuePtr->next = hFirstQueue;
1448 hFirstQueue = hQueue;
1449 HeapUnlock( SystemHeap );
1451 QUEUE_Unlock( queuePtr );
1457 /***********************************************************************
1458 * GetQueueStatus16 (USER.334)
1460 DWORD WINAPI GetQueueStatus16( UINT16 flags )
1462 MESSAGEQUEUE *queue;
1465 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1466 ret = MAKELONG( queue->changeBits, queue->wakeBits );
1467 queue->changeBits = 0;
1468 QUEUE_Unlock( queue );
1470 return ret & MAKELONG( flags, flags );
1473 /***********************************************************************
1474 * GetQueueStatus (USER32.283)
1476 DWORD WINAPI GetQueueStatus( UINT flags )
1478 MESSAGEQUEUE *queue;
1481 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1482 ret = MAKELONG( queue->changeBits, queue->wakeBits );
1483 queue->changeBits = 0;
1484 QUEUE_Unlock( queue );
1486 return ret & MAKELONG( flags, flags );
1490 /***********************************************************************
1491 * GetInputState16 (USER.335)
1493 BOOL16 WINAPI GetInputState16(void)
1495 return GetInputState();
1498 /***********************************************************************
1499 * WaitForInputIdle (USER32.577)
1501 DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
1503 DWORD cur_time, ret;
1505 struct wait_input_idle_request *req = get_req_buffer();
1507 req->handle = hProcess;
1508 req->timeout = dwTimeOut;
1509 if (server_call( REQ_WAIT_INPUT_IDLE )) return 0xffffffff;
1510 if ((idle_event = req->event) == -1) return 0; /* no event to wait on */
1512 cur_time = GetTickCount();
1514 TRACE_(msg)("waiting for %x\n", idle_event );
1515 while ( dwTimeOut > GetTickCount() - cur_time || dwTimeOut == INFINITE ) {
1517 ret = MsgWaitForMultipleObjects ( 1, &idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE );
1518 if ( ret == ( WAIT_OBJECT_0 + 1 )) {
1519 MESSAGEQUEUE * queue;
1520 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0xFFFFFFFF;
1521 QUEUE_ReceiveMessage ( queue );
1522 QUEUE_Unlock ( queue );
1525 if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF ) {
1526 TRACE_(msg)("timeout or error\n");
1530 TRACE_(msg)("finished\n");
1535 return WAIT_TIMEOUT;
1538 /***********************************************************************
1539 * GetInputState (USER32.244)
1541 BOOL WINAPI GetInputState(void)
1543 MESSAGEQUEUE *queue;
1546 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
1548 ret = queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
1549 QUEUE_Unlock( queue );
1554 /***********************************************************************
1555 * UserYield (USER.332)
1557 void WINAPI UserYield16(void)
1559 MESSAGEQUEUE *queue;
1561 /* Handle sent messages */
1562 queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() );
1564 while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1565 QUEUE_ReceiveMessage( queue );
1567 QUEUE_Unlock( queue );
1570 if ( THREAD_IsWin16( NtCurrentTeb() ) )
1575 /* Handle sent messages again */
1576 queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() );
1578 while (queue && (queue->wakeBits & QS_SENDMESSAGE))
1579 QUEUE_ReceiveMessage( queue );
1581 QUEUE_Unlock( queue );
1584 /***********************************************************************
1585 * GetMessagePos (USER.119) (USER32.272)
1587 * The GetMessagePos() function returns a long value representing a
1588 * cursor position, in screen coordinates, when the last message
1589 * retrieved by the GetMessage() function occurs. The x-coordinate is
1590 * in the low-order word of the return value, the y-coordinate is in
1591 * the high-order word. The application can use the MAKEPOINT()
1592 * macro to obtain a POINT structure from the return value.
1594 * For the current cursor position, use GetCursorPos().
1598 * Cursor position of last message on success, zero on failure.
1605 DWORD WINAPI GetMessagePos(void)
1607 MESSAGEQUEUE *queue;
1610 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1611 ret = queue->GetMessagePosVal;
1612 QUEUE_Unlock( queue );
1618 /***********************************************************************
1619 * GetMessageTime (USER.120) (USER32.273)
1621 * GetMessageTime() returns the message time for the last message
1622 * retrieved by the function. The time is measured in milliseconds with
1623 * the same offset as GetTickCount().
1625 * Since the tick count wraps, this is only useful for moderately short
1626 * relative time comparisons.
1630 * Time of last message on success, zero on failure.
1637 LONG WINAPI GetMessageTime(void)
1639 MESSAGEQUEUE *queue;
1642 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1643 ret = queue->GetMessageTimeVal;
1644 QUEUE_Unlock( queue );
1650 /***********************************************************************
1651 * GetMessageExtraInfo (USER.288) (USER32.271)
1653 LONG WINAPI GetMessageExtraInfo(void)
1655 MESSAGEQUEUE *queue;
1658 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1659 ret = queue->GetMessageExtraInfoVal;
1660 QUEUE_Unlock( queue );
1666 /**********************************************************************
1667 * AttachThreadInput [USER32.8] Attaches input of 1 thread to other
1669 * Attaches the input processing mechanism of one thread to that of
1677 * 1. Reset the Key State (currenly per thread key state is not maintained)
1679 BOOL WINAPI AttachThreadInput(
1680 DWORD idAttach, /* [in] Thread to attach */
1681 DWORD idAttachTo, /* [in] Thread to attach to */
1682 BOOL fAttach) /* [in] Attach or detach */
1684 MESSAGEQUEUE *pSrcMsgQ = 0, *pTgtMsgQ = 0;
1687 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1689 /* A thread cannot attach to itself */
1690 if ( idAttach == idAttachTo )
1693 /* According to the docs this method should fail if a
1694 * "Journal record" hook is installed. (attaches all input queues together)
1696 if ( HOOK_IsHooked( WH_JOURNALRECORD ) )
1699 /* Retrieve message queues corresponding to the thread id's */
1700 pTgtMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetThreadQueue16( idAttach ) );
1701 pSrcMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetThreadQueue16( idAttachTo ) );
1703 /* Ensure we have message queues and that Src and Tgt threads
1704 * are not system threads.
1706 if ( !pSrcMsgQ || !pTgtMsgQ || !pSrcMsgQ->pQData || !pTgtMsgQ->pQData )
1709 if (fAttach) /* Attach threads */
1711 /* Only attach if currently detached */
1712 if ( pTgtMsgQ->pQData != pSrcMsgQ->pQData )
1714 /* First release the target threads perQData */
1715 PERQDATA_Release( pTgtMsgQ->pQData );
1717 /* Share a reference to the source threads perQDATA */
1718 PERQDATA_Addref( pSrcMsgQ->pQData );
1719 pTgtMsgQ->pQData = pSrcMsgQ->pQData;
1722 else /* Detach threads */
1724 /* Only detach if currently attached */
1725 if ( pTgtMsgQ->pQData == pSrcMsgQ->pQData )
1727 /* First release the target threads perQData */
1728 PERQDATA_Release( pTgtMsgQ->pQData );
1730 /* Give the target thread its own private perQDATA once more */
1731 pTgtMsgQ->pQData = PERQDATA_CreateInstance();
1735 /* TODO: Reset the Key State */
1737 bRet = 1; /* Success */
1741 /* Unlock the queues before returning */
1743 QUEUE_Unlock( pSrcMsgQ );
1745 QUEUE_Unlock( pTgtMsgQ );