- New implementation of SendMessage, ReceiveMessage, ReplyMessage functions

to support thread-safeness, and nested SendMessage.
- Addition of ReplyMessage32.
This commit is contained in:
Stephane Lussier 1999-02-18 17:34:09 +00:00 committed by Alexandre Julliard
parent 4aaf65e6b4
commit 2c86dab53a
5 changed files with 448 additions and 215 deletions

View File

@ -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 );

View File

@ -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

View File

@ -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;

View File

@ -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
*

View File

@ -173,7 +173,6 @@ void USER_QueueCleanup( HQUEUE16 hQueue )
TIMER_RemoveQueueTimers( hQueue );
QUEUE_FlushMessages( hQueue );
HOOK_FreeQueueHooks( hQueue );
QUEUE_SetExitingQueue( hQueue );