mirror of
https://github.com/reactos/wine.git
synced 2024-11-25 04:39:45 +00:00
- New implementation of SendMessage, ReceiveMessage, ReplyMessage functions
to support thread-safeness, and nested SendMessage. - Addition of ReplyMessage32.
This commit is contained in:
parent
4aaf65e6b4
commit
2c86dab53a
@ -22,11 +22,43 @@ typedef struct tagQMSG
|
||||
struct tagQMSG *prevMsg;
|
||||
} QMSG;
|
||||
|
||||
typedef struct
|
||||
|
||||
typedef struct tagSMSG
|
||||
{
|
||||
LRESULT lResult;
|
||||
BOOL16 bPending;
|
||||
} QSMCTRL;
|
||||
struct tagSMSG *nextProcessing; /* next SMSG in the processing list */
|
||||
struct tagSMSG *nextPending; /* next SMSG in the pending list */
|
||||
struct tagSMSG *nextWaiting; /* next SMSG in the waiting list */
|
||||
|
||||
HQUEUE16 hSrcQueue; /* sending Queue, (NULL if it didn't wait) */
|
||||
HQUEUE16 hDstQueue; /* destination Queue */
|
||||
|
||||
HWND32 hWnd; /* destinantion window */
|
||||
UINT32 msg; /* message sent */
|
||||
WPARAM32 wParam; /* wParam of the sent message */
|
||||
LPARAM lParam; /* lParam of the sent message */
|
||||
|
||||
LRESULT lResult; /* result of SendMessage */
|
||||
WORD flags; /* see below SMSG_XXXX */
|
||||
} SMSG;
|
||||
|
||||
|
||||
/* SMSG -> flags values */
|
||||
/* set when lResult contains a good value */
|
||||
#define SMSG_HAVE_RESULT 0x0001
|
||||
/* protection for multiple call to ReplyMessage16() */
|
||||
#define SMSG_ALREADY_REPLIED 0x0002
|
||||
/* use with EARLY_REPLY for forcing the receiver to clean SMSG */
|
||||
#define SMSG_RECEIVER_CLEANS 0x0010
|
||||
/* used with EARLY_REPLY to indicate to sender, receiver is done with SMSG */
|
||||
#define SMSG_RECEIVED 0x0020
|
||||
/* set in ReceiveMessage() to indicate it's not an early reply */
|
||||
#define SMSG_SENDING_REPLY 0x0040
|
||||
/* set when ReplyMessage16() is called by the application */
|
||||
#define SMSG_EARLY_REPLY 0x0080
|
||||
/* set when sender is Win32 thread */
|
||||
#define SMSG_WIN32 0x1000
|
||||
/* set when sender is a unnicode thread */
|
||||
#define SMSG_UNICODE 0x2000
|
||||
|
||||
/* Per-queue data for the message queue
|
||||
* Note that we currently only store the current values for
|
||||
@ -55,8 +87,6 @@ typedef struct tagMESSAGEQUEUE
|
||||
|
||||
DWORD magic; /* magic number should be QUEUE_MAGIC */
|
||||
DWORD lockCount; /* reference counter */
|
||||
|
||||
WORD flags; /* Queue flags */
|
||||
WORD wWinVersion; /* Expected Windows version */
|
||||
|
||||
WORD msgCount; /* Number of waiting messages */
|
||||
@ -76,19 +106,9 @@ typedef struct tagMESSAGEQUEUE
|
||||
DWORD GetMessagePosVal; /* Value for GetMessagePos */
|
||||
DWORD GetMessageExtraInfoVal; /* Value for GetMessageExtraInfo */
|
||||
|
||||
HQUEUE16 InSendMessageHandle; /* Queue of task that sent a message */
|
||||
HTASK16 hSendingTask; /* Handle of task that sent a message */
|
||||
HTASK16 hPrevSendingTask; /* Handle of previous sender */
|
||||
|
||||
HWND32 hWnd32; /* Send message arguments */
|
||||
UINT32 msg32;
|
||||
WPARAM32 wParam32;
|
||||
LPARAM lParam;
|
||||
DWORD SendMessageReturn; /* Return value for SendMessage */
|
||||
|
||||
QSMCTRL* smResultInit; /* SendMesage result pointers */
|
||||
QSMCTRL* smResultCurrent;
|
||||
QSMCTRL* smResult;
|
||||
SMSG* smWaiting; /* SendMessage waiting for reply */
|
||||
SMSG* smProcessing; /* SendMessage currently being processed */
|
||||
SMSG* smPending; /* SendMessage waiting to be received */
|
||||
|
||||
HANDLE16 hCurHook; /* Current hook */
|
||||
HANDLE16 hooks[WH_NB_HOOKS]; /* Task hooks list */
|
||||
@ -100,11 +120,11 @@ typedef struct tagMESSAGEQUEUE
|
||||
|
||||
/* Extra (undocumented) queue wake bits - see "Undoc. Windows" */
|
||||
#define QS_SMRESULT 0x8000 /* Queue has a SendMessage() result */
|
||||
#define QS_SMPARAMSFREE 0x4000 /* SendMessage() parameters are available */
|
||||
|
||||
/* Queue flags */
|
||||
#define QUEUE_SM_WIN32 0x0002 /* Currently sent message is Win32 */
|
||||
#define QUEUE_SM_UNICODE 0x0004 /* Currently sent message is Unicode */
|
||||
/* Types of SMSG stack */
|
||||
#define SM_PROCESSING_LIST 1 /* list of SM currently being processed */
|
||||
#define SM_PENDING_LIST 2 /* list of SM wating to be received */
|
||||
#define SM_WAITING_LIST 3 /* list of SM waiting for reply */
|
||||
|
||||
#define QUEUE_MAGIC 0xD46E80AF
|
||||
|
||||
@ -144,7 +164,8 @@ extern BOOL32 QUEUE_AddMsg( HQUEUE16 hQueue, MSG32 * msg, DWORD extraInfo );
|
||||
extern QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND32 hwnd,
|
||||
int first, int last );
|
||||
extern void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg );
|
||||
extern void QUEUE_FlushMessages(HQUEUE16);
|
||||
extern SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg );
|
||||
extern BOOL32 QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg );
|
||||
extern void hardware_event( WORD message, WORD wParam, LONG lParam,
|
||||
int xPos, int yPos, DWORD time, DWORD extraInfo );
|
||||
|
||||
|
@ -445,7 +445,7 @@ init MAIN_UserInit
|
||||
441 stdcall RemoveMenu(long long long) RemoveMenu32
|
||||
442 stdcall RemovePropA(long str) RemoveProp32A
|
||||
443 stdcall RemovePropW(long wstr) RemoveProp32W
|
||||
444 stub ReplyMessage
|
||||
444 stdcall ReplyMessage(long) ReplyMessage32
|
||||
445 stub ResetDisplay
|
||||
446 stdcall ReuseDDElParam(long long long long long) ReuseDDElParam
|
||||
447 stdcall ScreenToClient(long ptr) ScreenToClient32
|
||||
|
@ -43,7 +43,7 @@ extern HQUEUE16 hCursorQueue; /* queue.c */
|
||||
DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
|
||||
|
||||
static UINT32 doubleClickSpeed = 452;
|
||||
static INT32 debugSMRL = 0; /* intertask SendMessage() recursion level */
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* MSG_CheckFilter
|
||||
@ -621,16 +621,20 @@ UINT32 WINAPI GetDoubleClickTime32(void)
|
||||
*
|
||||
* Implementation of an inter-task SendMessage.
|
||||
*/
|
||||
static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND16 hwnd, UINT16 msg,
|
||||
static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND32 hwnd, UINT32 msg,
|
||||
WPARAM32 wParam, LPARAM lParam, WORD flags )
|
||||
{
|
||||
INT32 prevSMRL = debugSMRL;
|
||||
QSMCTRL qCtrl = { 0, 1};
|
||||
MESSAGEQUEUE *queue, *destQ;
|
||||
SMSG *smsg;
|
||||
LRESULT lResult = 0;
|
||||
|
||||
if (IsTaskLocked() || !IsWindow32(hwnd))
|
||||
return 0;
|
||||
|
||||
/* create a SMSG structure to hold SendMessage() parameters */
|
||||
if (! (smsg = (SMSG *) HeapAlloc( SystemHeap, 0, sizeof(SMSG) )) )
|
||||
return 0;
|
||||
|
||||
if (!(queue = (MESSAGEQUEUE*)QUEUE_Lock( GetFastQueue() ))) return 0;
|
||||
|
||||
if (!(destQ = (MESSAGEQUEUE*)QUEUE_Lock( hDestQueue )))
|
||||
@ -639,66 +643,84 @@ static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND16 hwnd, UINT16 msg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
debugSMRL+=4;
|
||||
TRACE(sendmsg,"%*sSM: %s [%04x] (%04x -> %04x)\n",
|
||||
prevSMRL, "", SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
|
||||
TRACE(sendmsg,"SM: %s [%04x] (%04x -> %04x)\n",
|
||||
SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
|
||||
|
||||
if( !(queue->wakeBits & QS_SMPARAMSFREE) )
|
||||
{
|
||||
TRACE(sendmsg,"\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n");
|
||||
QUEUE_WaitBits( QS_SMPARAMSFREE );
|
||||
}
|
||||
/* fill up SMSG structure */
|
||||
smsg->hWnd = hwnd;
|
||||
smsg->msg = msg;
|
||||
smsg->wParam = wParam;
|
||||
smsg->lParam = lParam;
|
||||
|
||||
smsg->lResult = 0;
|
||||
smsg->hSrcQueue = GetFastQueue();
|
||||
smsg->hDstQueue = hDestQueue;
|
||||
smsg->flags = flags;
|
||||
|
||||
/* resume sending */
|
||||
queue->hWnd32 = hwnd;
|
||||
queue->msg32 = msg;
|
||||
queue->wParam32 = wParam;
|
||||
queue->lParam = lParam;
|
||||
queue->hPrevSendingTask = destQ->hSendingTask;
|
||||
destQ->hSendingTask = GetFastQueue();
|
||||
/* add smsg struct in the processing SM list of the source queue */
|
||||
QUEUE_AddSMSG(queue, SM_PROCESSING_LIST, smsg);
|
||||
|
||||
QUEUE_ClearWakeBit( queue, QS_SMPARAMSFREE );
|
||||
queue->flags = (queue->flags & ~(QUEUE_SM_WIN32|QUEUE_SM_UNICODE)) | flags;
|
||||
|
||||
TRACE(sendmsg,"%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl);
|
||||
|
||||
queue->smResultInit = &qCtrl;
|
||||
|
||||
QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
|
||||
/* add smsg struct in the pending list of the destination queue */
|
||||
if (QUEUE_AddSMSG(destQ, SM_PENDING_LIST, smsg) == FALSE)
|
||||
return 0;
|
||||
|
||||
/* perform task switch and wait for the result */
|
||||
|
||||
while( qCtrl.bPending )
|
||||
while( (smsg->flags & SMSG_HAVE_RESULT) == 0 )
|
||||
{
|
||||
if (!(queue->wakeBits & QS_SMRESULT))
|
||||
{
|
||||
if (THREAD_IsWin16( THREAD_Current() ))
|
||||
/* force destination task to run next, if 16 bit threads */
|
||||
if (THREAD_IsWin16(THREAD_Current()) && THREAD_IsWin16(destQ->thdb) )
|
||||
DirectedYield( destQ->thdb->teb.htask16 );
|
||||
|
||||
QUEUE_WaitBits( QS_SMRESULT );
|
||||
TRACE(sendmsg,"\tsm: have result!\n");
|
||||
}
|
||||
/* got something */
|
||||
|
||||
TRACE(sendmsg,"%*ssm: smResult = %08x\n", prevSMRL, "", (unsigned)queue->smResult );
|
||||
|
||||
if (queue->smResult) { /* FIXME, smResult should always be set */
|
||||
queue->smResult->lResult = queue->SendMessageReturn;
|
||||
queue->smResult->bPending = FALSE;
|
||||
if (! (smsg->flags & SMSG_HAVE_RESULT) )
|
||||
{
|
||||
/* not supposed to happen */
|
||||
ERR(sendmsg, "SMSG_HAVE_RESULT not set smsg->flags=%x\n", smsg->flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
lResult = smsg->lResult;
|
||||
TRACE(sendmsg,"smResult = %08x\n", (unsigned)lResult );
|
||||
}
|
||||
|
||||
QUEUE_ClearWakeBit( queue, QS_SMRESULT );
|
||||
|
||||
if( queue->smResult != &qCtrl )
|
||||
ERR(sendmsg, "%*ssm: weird scenes inside the goldmine!\n", prevSMRL, "");
|
||||
}
|
||||
queue->smResultInit = NULL;
|
||||
|
||||
/* remove the smsg from the processingg list of the source queue */
|
||||
QUEUE_RemoveSMSG( queue, SM_PROCESSING_LIST, smsg );
|
||||
|
||||
/* Note: the destination thread is in charge of removing the smsg from
|
||||
the pending list */
|
||||
|
||||
/* sender thread is in charge of releasing smsg if it's not an
|
||||
early reply */
|
||||
if ( !(smsg->flags & SMSG_EARLY_REPLY) )
|
||||
{
|
||||
HeapFree(SystemHeap, 0, smsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In the case of an early reply, sender thread will released the
|
||||
smsg structure if the receiver thread is done (SMSG_RECEIVED set).
|
||||
If the receiver thread isn't done, SMSG_RECEIVER_CLEANS_UP flag
|
||||
is set, and it will be the receiver responsability to released
|
||||
smsg */
|
||||
EnterCriticalSection( &queue->cSection );
|
||||
|
||||
TRACE(sendmsg,"%*sSM: [%04x] returning %08lx\n", prevSMRL, "", msg, qCtrl.lResult);
|
||||
debugSMRL-=4;
|
||||
if (smsg->flags & SMSG_RECEIVED)
|
||||
HeapFree(SystemHeap, 0, smsg);
|
||||
else
|
||||
smsg->flags |= SMSG_RECEIVER_CLEANS;
|
||||
|
||||
LeaveCriticalSection( &queue->cSection );
|
||||
}
|
||||
|
||||
QUEUE_Unlock( queue );
|
||||
QUEUE_Unlock( destQ );
|
||||
|
||||
return qCtrl.lResult;
|
||||
TRACE(sendmsg,"done!\n");
|
||||
return lResult;
|
||||
}
|
||||
|
||||
|
||||
@ -707,52 +729,81 @@ static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND16 hwnd, UINT16 msg,
|
||||
*/
|
||||
void WINAPI ReplyMessage16( LRESULT result )
|
||||
{
|
||||
MESSAGEQUEUE *senderQ;
|
||||
MESSAGEQUEUE *queue;
|
||||
ReplyMessage32( result );
|
||||
}
|
||||
|
||||
if (!(queue = (MESSAGEQUEUE*)QUEUE_Lock( GetFastQueue() ))) return;
|
||||
/***********************************************************************
|
||||
* ReplyMessage (USER.115)
|
||||
*/
|
||||
BOOL32 WINAPI ReplyMessage32( LRESULT result )
|
||||
{
|
||||
MESSAGEQUEUE *senderQ = 0;
|
||||
MESSAGEQUEUE *queue = 0;
|
||||
SMSG *smsg;
|
||||
BOOL32 ret = FALSE;
|
||||
|
||||
TRACE(msg,"ReplyMessage, queue %04x\n", queue->self);
|
||||
if (!(queue = (MESSAGEQUEUE*)QUEUE_Lock( GetFastQueue() ))) return FALSE;
|
||||
|
||||
while( (senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->InSendMessageHandle)))
|
||||
TRACE(sendmsg,"ReplyMessage, queue %04x\n", queue->self);
|
||||
|
||||
while ((smsg = queue->smWaiting) != 0)
|
||||
{
|
||||
TRACE(msg,"\trpm: replying to %08x (%04x -> %04x)\n",
|
||||
queue->msg32, queue->self, senderQ->self);
|
||||
/* if message has already been reply, continue the loop of receving
|
||||
message */
|
||||
if ( smsg->flags & SMSG_ALREADY_REPLIED )
|
||||
goto ReplyMessageDone;
|
||||
|
||||
senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
|
||||
if ( !senderQ )
|
||||
goto ReplyMessageDone;
|
||||
|
||||
/* if send message pending, processed it */
|
||||
if( queue->wakeBits & QS_SENDMESSAGE )
|
||||
{
|
||||
/* Note: QUEUE_ReceiveMessage() and ReplyMessage call each other */
|
||||
QUEUE_ReceiveMessage( queue );
|
||||
QUEUE_Unlock( senderQ );
|
||||
continue; /* ReceiveMessage() already called us */
|
||||
}
|
||||
|
||||
if(!(senderQ->wakeBits & QS_SMRESULT) ) break;
|
||||
if (THREAD_IsWin16(THREAD_Current())) OldYield();
|
||||
|
||||
QUEUE_Unlock( senderQ );
|
||||
}
|
||||
if( !senderQ )
|
||||
{
|
||||
TRACE(msg,"\trpm: done\n");
|
||||
QUEUE_Unlock( queue );
|
||||
return;
|
||||
break; /* message to reply is in smsg */
|
||||
}
|
||||
|
||||
senderQ->SendMessageReturn = result;
|
||||
TRACE(msg,"\trpm: smResult = %08x, result = %08lx\n",
|
||||
(unsigned)queue->smResultCurrent, result );
|
||||
if ( !smsg )
|
||||
goto ReplyMessageDone;
|
||||
|
||||
smsg->lResult = result;
|
||||
smsg->flags |= SMSG_ALREADY_REPLIED | SMSG_HAVE_RESULT;
|
||||
|
||||
senderQ->smResult = queue->smResultCurrent;
|
||||
queue->InSendMessageHandle = 0;
|
||||
/* check if it's an early reply (called by the application) or
|
||||
a regular reply (called by ReceiveMessage) */
|
||||
if ( !(smsg->flags & SMSG_SENDING_REPLY) )
|
||||
smsg->flags |= SMSG_EARLY_REPLY;
|
||||
|
||||
TRACE( sendmsg,"\trpm: smResult = %08lx\n", (long) result );
|
||||
|
||||
/* remove smsg from the waiting list, if it's not an early reply */
|
||||
/* it is important to leave it in the waiting list if it's an early
|
||||
reply, to be protected aginst multiple call to ReplyMessage() */
|
||||
if ( !(smsg->flags & SMSG_EARLY_REPLY) )
|
||||
QUEUE_RemoveSMSG( queue, SM_WAITING_LIST, smsg );
|
||||
|
||||
/* tell the sending task that its reply is ready */
|
||||
QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
|
||||
|
||||
/* switch directly to sending task (16 bit thread only) */
|
||||
if (THREAD_IsWin16( THREAD_Current() ))
|
||||
DirectedYield( senderQ->thdb->teb.htask16 );
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
ReplyMessageDone:
|
||||
if ( senderQ )
|
||||
QUEUE_Unlock( senderQ );
|
||||
if ( queue )
|
||||
QUEUE_Unlock( queue );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MSG_PeekMessage
|
||||
@ -1454,7 +1505,7 @@ LRESULT WINAPI SendMessage32A( HWND32 hwnd, UINT32 msg, WPARAM32 wParam,
|
||||
|
||||
if (wndPtr->hmemTaskQ != GetFastQueue())
|
||||
ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
|
||||
QUEUE_SM_WIN32 );
|
||||
SMSG_WIN32 );
|
||||
else
|
||||
ret = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
|
||||
hwnd, msg, wParam, lParam );
|
||||
@ -1525,7 +1576,7 @@ LRESULT WINAPI SendMessage32W(
|
||||
|
||||
if (wndPtr->hmemTaskQ != GetFastQueue())
|
||||
ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
|
||||
QUEUE_SM_WIN32 | QUEUE_SM_UNICODE );
|
||||
SMSG_WIN32 | SMSG_UNICODE );
|
||||
else
|
||||
ret = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
|
||||
hwnd, msg, wParam, lParam );
|
||||
@ -2115,7 +2166,7 @@ BOOL32 WINAPI InSendMessage32(void)
|
||||
|
||||
if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() )))
|
||||
return 0;
|
||||
ret = (BOOL32)queue->InSendMessageHandle;
|
||||
ret = (BOOL32)queue->smProcessing;
|
||||
|
||||
QUEUE_Unlock( queue );
|
||||
return ret;
|
||||
|
392
windows/queue.c
392
windows/queue.c
@ -19,6 +19,7 @@
|
||||
#include "process.h"
|
||||
#include <assert.h>
|
||||
#include "debug.h"
|
||||
#include "spy.h"
|
||||
|
||||
#define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
|
||||
|
||||
@ -359,23 +360,21 @@ void QUEUE_DumpQueue( HQUEUE16 hQueue )
|
||||
|
||||
DUMP( "next: %12.4x Intertask SendMessage:\n"
|
||||
"thread: %10p ----------------------\n"
|
||||
"hWnd: %12.8x\n"
|
||||
"firstMsg: %8p msg: %11.8x\n"
|
||||
"lastMsg: %8p wParam: %10.8x\n"
|
||||
"msgCount: %8.4x lParam: %10.8x\n"
|
||||
"lockCount: %7.4x lRet: %12.8x\n"
|
||||
"wWinVer: %9.4x ISMH: %10.4x\n"
|
||||
"paints: %10.4x hSendTask: %5.4x\n"
|
||||
"timers: %10.4x hPrevSend: %5.4x\n"
|
||||
"firstMsg: %8p smWaiting: %10p\n"
|
||||
"lastMsg: %8p smPending: %10p\n"
|
||||
"msgCount: %8.4x smProcessing: %10p\n"
|
||||
"lockCount: %7.4x\n"
|
||||
"wWinVer: %9.4x\n"
|
||||
"paints: %10.4x\n"
|
||||
"timers: %10.4x\n"
|
||||
"wakeBits: %8.4x\n"
|
||||
"wakeMask: %8.4x\n"
|
||||
"hCurHook: %8.4x\n",
|
||||
pq->next, pq->thdb, pq->hWnd32, pq->firstMsg, pq->msg32,
|
||||
pq->lastMsg, pq->wParam32, pq->msgCount, (unsigned)pq->lParam,
|
||||
(unsigned)pq->lockCount, (unsigned)pq->SendMessageReturn,
|
||||
pq->wWinVersion, pq->InSendMessageHandle,
|
||||
pq->wPaintCount, pq->hSendingTask, pq->wTimerCount,
|
||||
pq->hPrevSendingTask, pq->wakeBits, pq->wakeMask, pq->hCurHook);
|
||||
pq->next, pq->thdb, pq->firstMsg, pq->smWaiting, pq->lastMsg,
|
||||
pq->smPending, pq->msgCount, pq->smProcessing,
|
||||
(unsigned)pq->lockCount, pq->wWinVersion,
|
||||
pq->wPaintCount, pq->wTimerCount,
|
||||
pq->wakeBits, pq->wakeMask, pq->hCurHook);
|
||||
|
||||
QUEUE_Unlock( pq );
|
||||
}
|
||||
@ -449,7 +448,7 @@ static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
|
||||
return 0;
|
||||
|
||||
msgQueue->self = hQueue;
|
||||
msgQueue->wakeBits = msgQueue->changeBits = QS_SMPARAMSFREE;
|
||||
msgQueue->wakeBits = msgQueue->changeBits = 0;
|
||||
msgQueue->wWinVersion = pTask ? pTask->version : 0;
|
||||
|
||||
InitializeCriticalSection( &msgQueue->cSection );
|
||||
@ -481,6 +480,44 @@ static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* QUEUE_FlushMessage
|
||||
*
|
||||
* Try to reply to all pending sent messages on exit.
|
||||
*/
|
||||
void QUEUE_FlushMessages( MESSAGEQUEUE *queue )
|
||||
{
|
||||
SMSG *smsg;
|
||||
MESSAGEQUEUE *senderQ = 0;
|
||||
|
||||
if( queue )
|
||||
{
|
||||
EnterCriticalSection( &queue->cSection );
|
||||
|
||||
/* empty the list of pending SendMessage waiting to be received */
|
||||
while (queue->smPending)
|
||||
{
|
||||
smsg = QUEUE_RemoveSMSG( queue, SM_PENDING_LIST, 0);
|
||||
|
||||
senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
|
||||
if ( !senderQ )
|
||||
continue;
|
||||
|
||||
/* return 0, to unblock other thread */
|
||||
smsg->lResult = 0;
|
||||
smsg->flags |= SMSG_HAVE_RESULT;
|
||||
QUEUE_SetWakeBit( senderQ, QS_SMRESULT);
|
||||
|
||||
QUEUE_Unlock( senderQ );
|
||||
}
|
||||
|
||||
QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
|
||||
|
||||
LeaveCriticalSection( &queue->cSection );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* QUEUE_DeleteMsgQueue
|
||||
*
|
||||
@ -492,7 +529,6 @@ static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
|
||||
BOOL32 QUEUE_DeleteMsgQueue( HQUEUE16 hQueue )
|
||||
{
|
||||
MESSAGEQUEUE * msgQueue = (MESSAGEQUEUE*)QUEUE_Lock(hQueue);
|
||||
HQUEUE16 senderQ;
|
||||
HQUEUE16 *pPrev;
|
||||
|
||||
TRACE(msg,"(): Deleting message queue %04x\n", hQueue);
|
||||
@ -509,16 +545,7 @@ BOOL32 QUEUE_DeleteMsgQueue( HQUEUE16 hQueue )
|
||||
if( hActiveQueue == hQueue ) hActiveQueue = 0;
|
||||
|
||||
/* flush sent messages */
|
||||
senderQ = msgQueue->hSendingTask;
|
||||
while( senderQ )
|
||||
{
|
||||
MESSAGEQUEUE* sq = (MESSAGEQUEUE*)QUEUE_Lock(senderQ);
|
||||
if( !sq ) break;
|
||||
sq->SendMessageReturn = 0L;
|
||||
QUEUE_SetWakeBit( sq, QS_SMRESULT );
|
||||
senderQ = sq->hPrevSendingTask;
|
||||
QUEUE_Unlock(sq);
|
||||
}
|
||||
QUEUE_FlushMessages( msgQueue );
|
||||
|
||||
SYSTEM_LOCK();
|
||||
|
||||
@ -687,130 +714,265 @@ void QUEUE_WaitBits( WORD bits )
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* QUEUE_ReceiveMessage
|
||||
* QUEUE_AddSMSG
|
||||
*
|
||||
* This routine is called when a SMSG need to be added to one of the three
|
||||
* SM list. (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
|
||||
*/
|
||||
BOOL32 QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
|
||||
{
|
||||
TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
|
||||
smsg, SPY_GetMsgName(smsg->msg));
|
||||
|
||||
switch (list)
|
||||
{
|
||||
case SM_PROCESSING_LIST:
|
||||
/* don't need to be thread safe, only accessed by the
|
||||
thread associated with the sender queue */
|
||||
smsg->nextProcessing = queue->smProcessing;
|
||||
queue->smProcessing = smsg;
|
||||
break;
|
||||
|
||||
case SM_WAITING_LIST:
|
||||
/* don't need to be thread safe, only accessed by the
|
||||
thread associated with the receiver queue */
|
||||
smsg->nextWaiting = queue->smWaiting;
|
||||
queue->smWaiting = smsg;
|
||||
break;
|
||||
|
||||
case SM_PENDING_LIST:
|
||||
/* make it thread safe, could be accessed by the sender and
|
||||
receiver thread */
|
||||
|
||||
EnterCriticalSection( &queue->cSection );
|
||||
smsg->nextPending = queue->smPending;
|
||||
queue->smPending = smsg;
|
||||
QUEUE_SetWakeBit( queue, QS_SENDMESSAGE );
|
||||
LeaveCriticalSection( &queue->cSection );
|
||||
break;
|
||||
|
||||
default:
|
||||
WARN(sendmsg, "Invalid list: %d", list);
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* QUEUE_RemoveSMSG
|
||||
*
|
||||
* This routine is called when a SMSG need to be remove from one of the three
|
||||
* SM list. (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
|
||||
* If smsg == 0, remove the first smsg from the specified list
|
||||
*/
|
||||
SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
|
||||
{
|
||||
|
||||
switch (list)
|
||||
{
|
||||
case SM_PROCESSING_LIST:
|
||||
/* don't need to be thread safe, only accessed by the
|
||||
thread associated with the sender queue */
|
||||
|
||||
/* if smsg is equal to null, it means the first in the list */
|
||||
if (!smsg)
|
||||
smsg = queue->smProcessing;
|
||||
|
||||
TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
|
||||
smsg, SPY_GetMsgName(smsg->msg));
|
||||
/* In fact SM_PROCESSING_LIST is a stack, and smsg
|
||||
should be always at the top of the list */
|
||||
if ( (smsg != queue->smProcessing) || !queue->smProcessing )
|
||||
{
|
||||
ERR( sendmsg, "smsg not at the top of Processing list, smsg=0x%p queue=0x%p", smsg, queue);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
queue->smProcessing = smsg->nextProcessing;
|
||||
smsg->nextProcessing = 0;
|
||||
}
|
||||
return smsg;
|
||||
|
||||
case SM_WAITING_LIST:
|
||||
/* don't need to be thread safe, only accessed by the
|
||||
thread associated with the receiver queue */
|
||||
|
||||
/* if smsg is equal to null, it means the first in the list */
|
||||
if (!smsg)
|
||||
smsg = queue->smWaiting;
|
||||
|
||||
TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
|
||||
smsg, SPY_GetMsgName(smsg->msg));
|
||||
/* In fact SM_WAITING_LIST is a stack, and smsg
|
||||
should be always at the top of the list */
|
||||
if ( (smsg != queue->smWaiting) || !queue->smWaiting )
|
||||
{
|
||||
ERR( sendmsg, "smsg not at the top of Waiting list, smsg=0x%p queue=0x%p", smsg, queue);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
queue->smWaiting = smsg->nextWaiting;
|
||||
smsg->nextWaiting = 0;
|
||||
}
|
||||
return smsg;
|
||||
|
||||
case SM_PENDING_LIST:
|
||||
/* make it thread safe, could be accessed by the sender and
|
||||
receiver thread */
|
||||
EnterCriticalSection( &queue->cSection );
|
||||
|
||||
if (!smsg || !queue->smPending)
|
||||
smsg = queue->smPending;
|
||||
else
|
||||
{
|
||||
ERR( sendmsg, "should always remove the top one in Pending list, smsg=0x%p queue=0x%p", smsg, queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
|
||||
smsg, SPY_GetMsgName(smsg->msg));
|
||||
|
||||
queue->smPending = smsg->nextPending;
|
||||
smsg->nextPending = 0;
|
||||
|
||||
/* if no more SMSG in Pending list, clear QS_SENDMESSAGE flag */
|
||||
if (!queue->smPending)
|
||||
QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
|
||||
|
||||
LeaveCriticalSection( &queue->cSection );
|
||||
return smsg;
|
||||
|
||||
default:
|
||||
WARN(sendmsg, "Invalid list: %d", list);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* QUEUE_ReceiveMessage
|
||||
*
|
||||
* This routine is called when a sent message is waiting for the queue.
|
||||
*/
|
||||
void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
|
||||
{
|
||||
MESSAGEQUEUE *senderQ = NULL;
|
||||
HQUEUE16 prevSender = 0;
|
||||
QSMCTRL* prevCtrlPtr = NULL;
|
||||
LRESULT result = 0;
|
||||
SMSG *smsg;
|
||||
MESSAGEQUEUE *senderQ;
|
||||
|
||||
TRACE(msg, "ReceiveMessage, queue %04x\n", queue->self );
|
||||
if (!(queue->wakeBits & QS_SENDMESSAGE) ||
|
||||
!(senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->hSendingTask)))
|
||||
{ TRACE(msg,"\trcm: nothing to do\n"); return; }
|
||||
TRACE(sendmsg, "queue %04x\n", queue->self );
|
||||
|
||||
if( !senderQ->hPrevSendingTask )
|
||||
QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE ); /* no more sent messages */
|
||||
|
||||
/* Save current state on stack */
|
||||
prevSender = queue->InSendMessageHandle;
|
||||
prevCtrlPtr = queue->smResultCurrent;
|
||||
|
||||
/* Remove sending queue from the list */
|
||||
queue->InSendMessageHandle = queue->hSendingTask;
|
||||
queue->smResultCurrent = senderQ->smResultInit;
|
||||
queue->hSendingTask = senderQ->hPrevSendingTask;
|
||||
|
||||
TRACE(msg, "\trcm: smResultCurrent = %08x, prevCtrl = %08x\n",
|
||||
(unsigned)queue->smResultCurrent, (unsigned)prevCtrlPtr );
|
||||
QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
|
||||
|
||||
TRACE(msg, "\trcm: calling wndproc - %08x %08x %08x %08x\n",
|
||||
senderQ->hWnd32, senderQ->msg32,
|
||||
senderQ->wParam32, (unsigned)senderQ->lParam );
|
||||
|
||||
if (IsWindow32( senderQ->hWnd32 ))
|
||||
if ( !(queue->wakeBits & QS_SENDMESSAGE) && queue->smPending )
|
||||
{
|
||||
WND *wndPtr = WIN_FindWndPtr( senderQ->hWnd32 );
|
||||
DWORD extraInfo = queue->GetMessageExtraInfoVal;
|
||||
queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
|
||||
TRACE(sendmsg,"\trcm: nothing to do\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (senderQ->flags & QUEUE_SM_WIN32)
|
||||
/* remove smsg on the top of the pending list and put it in the processing list */
|
||||
smsg = QUEUE_RemoveSMSG(queue, SM_PENDING_LIST, 0);
|
||||
QUEUE_AddSMSG(queue, SM_WAITING_LIST, smsg);
|
||||
|
||||
TRACE(sendmsg,"RM: %s [%04x] (%04x -> %04x)\n",
|
||||
SPY_GetMsgName(smsg->msg), smsg->msg, smsg->hSrcQueue, smsg->hDstQueue );
|
||||
|
||||
if (IsWindow32( smsg->hWnd ))
|
||||
{
|
||||
WND *wndPtr = WIN_FindWndPtr( smsg->hWnd );
|
||||
DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */
|
||||
|
||||
/* use sender queue extra info value while calling the window proc */
|
||||
senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
|
||||
if (senderQ)
|
||||
{
|
||||
queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
|
||||
QUEUE_Unlock( senderQ );
|
||||
}
|
||||
|
||||
/* call the right version of CallWindowProcXX */
|
||||
if (smsg->flags & SMSG_WIN32)
|
||||
{
|
||||
TRACE(msg, "\trcm: msg is Win32\n" );
|
||||
if (senderQ->flags & QUEUE_SM_UNICODE)
|
||||
TRACE(sendmsg, "\trcm: msg is Win32\n" );
|
||||
if (smsg->flags & SMSG_UNICODE)
|
||||
result = CallWindowProc32W( wndPtr->winproc,
|
||||
senderQ->hWnd32, senderQ->msg32,
|
||||
senderQ->wParam32, senderQ->lParam );
|
||||
smsg->hWnd, smsg->msg,
|
||||
smsg->wParam, smsg->lParam );
|
||||
else
|
||||
result = CallWindowProc32A( wndPtr->winproc,
|
||||
senderQ->hWnd32, senderQ->msg32,
|
||||
senderQ->wParam32, senderQ->lParam );
|
||||
smsg->hWnd, smsg->msg,
|
||||
smsg->wParam, smsg->lParam );
|
||||
}
|
||||
else /* Win16 message */
|
||||
result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
|
||||
(HWND16) senderQ->hWnd32,
|
||||
(UINT16) senderQ->msg32,
|
||||
LOWORD (senderQ->wParam32),
|
||||
senderQ->lParam );
|
||||
(HWND16) smsg->hWnd,
|
||||
(UINT16) smsg->msg,
|
||||
LOWORD (smsg->wParam),
|
||||
smsg->lParam );
|
||||
|
||||
queue->GetMessageExtraInfoVal = extraInfo; /* Restore extra info */
|
||||
TRACE(msg,"\trcm: result = %08x\n", (unsigned)result );
|
||||
TRACE(sendmsg,"result = %08x\n", (unsigned)result );
|
||||
}
|
||||
else WARN(msg, "\trcm: bad hWnd\n");
|
||||
else WARN(sendmsg, "\trcm: bad hWnd\n");
|
||||
|
||||
QUEUE_Unlock( senderQ );
|
||||
|
||||
/* Return the result to the sender task */
|
||||
ReplyMessage16( result );
|
||||
|
||||
queue->InSendMessageHandle = prevSender;
|
||||
queue->smResultCurrent = prevCtrlPtr;
|
||||
|
||||
TRACE(msg,"done!\n");
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* QUEUE_FlushMessage
|
||||
*
|
||||
* Try to reply to all pending sent messages on exit.
|
||||
*/
|
||||
void QUEUE_FlushMessages( HQUEUE16 hQueue )
|
||||
{
|
||||
MESSAGEQUEUE *queue = (MESSAGEQUEUE*)QUEUE_Lock( hQueue );
|
||||
|
||||
if( queue )
|
||||
{
|
||||
MESSAGEQUEUE *senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->hSendingTask );
|
||||
QSMCTRL* CtrlPtr = queue->smResultCurrent;
|
||||
|
||||
TRACE(msg,"Flushing queue %04x:\n", hQueue );
|
||||
|
||||
while( senderQ )
|
||||
/* sometimes when we got early reply, the receiver is in charge of
|
||||
freeing up memory associated with smsg */
|
||||
/* when there is an early reply the sender will not release smsg
|
||||
before SMSG_RECEIVED is set */
|
||||
if ( smsg->flags & SMSG_EARLY_REPLY )
|
||||
{
|
||||
if( !CtrlPtr )
|
||||
CtrlPtr = senderQ->smResultInit;
|
||||
/* remove smsg from the waiting list */
|
||||
QUEUE_RemoveSMSG( queue, SM_WAITING_LIST, smsg );
|
||||
|
||||
TRACE(msg,"\tfrom queue %04x, smResult %08x\n", queue->hSendingTask, (unsigned)CtrlPtr );
|
||||
/* make thread safe when accessing SMSG_SENT_REPLY and
|
||||
SMSG_RECEIVER_CLEANS_UP. Those fleags are used by both thread,
|
||||
the sender and receiver, to find out which thread should released
|
||||
smsg structure. The critical section of the sender queue is used. */
|
||||
|
||||
if( !(queue->hSendingTask = senderQ->hPrevSendingTask) )
|
||||
QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
|
||||
senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
|
||||
|
||||
QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
|
||||
/* synchronize with the sender */
|
||||
if (senderQ)
|
||||
EnterCriticalSection( &senderQ->cSection );
|
||||
|
||||
queue->smResultCurrent = CtrlPtr;
|
||||
while( senderQ->wakeBits & QS_SMRESULT ) OldYield();
|
||||
/* tell the sender we're all done with smsg structure */
|
||||
smsg->flags |= SMSG_RECEIVED;
|
||||
|
||||
senderQ->SendMessageReturn = 0;
|
||||
senderQ->smResult = queue->smResultCurrent;
|
||||
QUEUE_SetWakeBit( senderQ, QS_SMRESULT);
|
||||
/* sender will set SMSG_RECEIVER_CLEANS_UP if it wants the
|
||||
receiver to clean up smsg, it could only happens when there is
|
||||
an early reply */
|
||||
if ( smsg->flags & SMSG_RECEIVER_CLEANS )
|
||||
{
|
||||
TRACE( sendmsg,"Receiver cleans up!\n" );
|
||||
HeapFree( SystemHeap, 0, smsg );
|
||||
}
|
||||
|
||||
/* release lock */
|
||||
if (senderQ)
|
||||
{
|
||||
LeaveCriticalSection( &senderQ->cSection );
|
||||
QUEUE_Unlock( senderQ );
|
||||
|
||||
senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->hSendingTask );
|
||||
CtrlPtr = NULL;
|
||||
}
|
||||
}
|
||||
queue->InSendMessageHandle = 0;
|
||||
else
|
||||
{
|
||||
/* no early reply, so do it now */
|
||||
|
||||
QUEUE_Unlock( queue );
|
||||
/* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not
|
||||
an early reply */
|
||||
smsg->flags |= SMSG_SENDING_REPLY;
|
||||
ReplyMessage32( result );
|
||||
}
|
||||
|
||||
TRACE( sendmsg,"done! \n" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* QUEUE_AddMsg
|
||||
*
|
||||
|
@ -173,7 +173,6 @@ void USER_QueueCleanup( HQUEUE16 hQueue )
|
||||
|
||||
TIMER_RemoveQueueTimers( hQueue );
|
||||
|
||||
QUEUE_FlushMessages( hQueue );
|
||||
HOOK_FreeQueueHooks( hQueue );
|
||||
|
||||
QUEUE_SetExitingQueue( hQueue );
|
||||
|
Loading…
Reference in New Issue
Block a user