Implemented SendMessageTimeout() functions.

This commit is contained in:
Stephane Lussier 1999-03-10 16:21:12 +00:00 committed by Alexandre Julliard
parent ebe76b73a9
commit bae5552a14
3 changed files with 256 additions and 268 deletions

View File

@ -152,7 +152,7 @@ extern MESSAGEQUEUE *QUEUE_GetSysQueue(void);
extern void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit ); extern void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit );
extern void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit ); extern void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit );
extern void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue ); extern void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue );
extern void QUEUE_WaitBits( WORD bits ); extern int QUEUE_WaitBits( WORD bits, DWORD timeout );
extern void QUEUE_IncPaintCount( HQUEUE16 hQueue ); extern void QUEUE_IncPaintCount( HQUEUE16 hQueue );
extern void QUEUE_DecPaintCount( HQUEUE16 hQueue ); extern void QUEUE_DecPaintCount( HQUEUE16 hQueue );
extern void QUEUE_IncTimerCount( HQUEUE16 hQueue ); extern void QUEUE_IncTimerCount( HQUEUE16 hQueue );

View File

@ -44,7 +44,6 @@ DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
static UINT doubleClickSpeed = 452; static UINT doubleClickSpeed = 452;
/*********************************************************************** /***********************************************************************
* MSG_CheckFilter * MSG_CheckFilter
*/ */
@ -617,16 +616,24 @@ UINT WINAPI GetDoubleClickTime(void)
/*********************************************************************** /***********************************************************************
* MSG_SendMessage * MSG_SendMessageInterThread
* *
* Implementation of an inter-task SendMessage. * Implementation of an inter-task SendMessage.
* Return values:
* 0 if error or timeout
* 1 if successflul
*/ */
static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND hwnd, UINT msg, static LRESULT MSG_SendMessageInterThread( HQUEUE16 hDestQueue,
WPARAM wParam, LPARAM lParam, WORD flags ) HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam,
DWORD timeout, WORD flags,
LRESULT *pRes)
{ {
MESSAGEQUEUE *queue, *destQ; MESSAGEQUEUE *queue, *destQ;
SMSG *smsg; SMSG *smsg;
LRESULT lResult = 0; LRESULT retVal = 1;
*pRes = 0;
if (IsTaskLocked16() || !IsWindow(hwnd)) if (IsTaskLocked16() || !IsWindow(hwnd))
return 0; return 0;
@ -634,7 +641,6 @@ static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND hwnd, UINT msg,
/* create a SMSG structure to hold SendMessage() parameters */ /* create a SMSG structure to hold SendMessage() parameters */
if (! (smsg = (SMSG *) HeapAlloc( SystemHeap, 0, sizeof(SMSG) )) ) if (! (smsg = (SMSG *) HeapAlloc( SystemHeap, 0, sizeof(SMSG) )) )
return 0; return 0;
if (!(queue = (MESSAGEQUEUE*)QUEUE_Lock( GetFastQueue16() ))) return 0; if (!(queue = (MESSAGEQUEUE*)QUEUE_Lock( GetFastQueue16() ))) return 0;
if (!(destQ = (MESSAGEQUEUE*)QUEUE_Lock( hDestQueue ))) if (!(destQ = (MESSAGEQUEUE*)QUEUE_Lock( hDestQueue )))
@ -671,7 +677,13 @@ static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND hwnd, UINT msg,
if (THREAD_IsWin16(THREAD_Current()) && THREAD_IsWin16(destQ->thdb) ) if (THREAD_IsWin16(THREAD_Current()) && THREAD_IsWin16(destQ->thdb) )
DirectedYield16( destQ->thdb->teb.htask16 ); DirectedYield16( destQ->thdb->teb.htask16 );
QUEUE_WaitBits( QS_SMRESULT ); if (QUEUE_WaitBits( QS_SMRESULT, timeout ) == 0)
{
/* return with timeout */
SetLastError( 0 );
retVal = 0;
break;
}
if (! (smsg->flags & SMSG_HAVE_RESULT) ) if (! (smsg->flags & SMSG_HAVE_RESULT) )
{ {
@ -681,8 +693,8 @@ static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND hwnd, UINT msg,
} }
else else
{ {
lResult = smsg->lResult; *pRes = smsg->lResult;
TRACE(sendmsg,"smResult = %08x\n", (unsigned)lResult ); TRACE(sendmsg,"smResult = %08x\n", (unsigned)*pRes );
} }
} }
@ -717,19 +729,11 @@ static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND hwnd, UINT msg,
/* Note: the destination thread is in charge of removing the smsg from /* Note: the destination thread is in charge of removing the smsg from
the pending list */ the pending list */
/* sender thread is in charge of releasing smsg if it's not an /* In the case of an early reply (or a timeout), sender thread will
early reply */ released the smsg structure if the receiver thread is done
if ( !(smsg->flags & SMSG_EARLY_REPLY) ) (SMSG_RECEIVED set). If the receiver thread isn't done,
{ SMSG_RECEIVER_CLEANS_UP flag is set, and it will be the receiver
HeapFree(SystemHeap, 0, smsg); responsability to released 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 ); EnterCriticalSection( &queue->cSection );
if (smsg->flags & SMSG_RECEIVED) if (smsg->flags & SMSG_RECEIVED)
@ -738,13 +742,13 @@ static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND hwnd, UINT msg,
smsg->flags |= SMSG_RECEIVER_CLEANS; smsg->flags |= SMSG_RECEIVER_CLEANS;
LeaveCriticalSection( &queue->cSection ); LeaveCriticalSection( &queue->cSection );
}
QUEUE_Unlock( queue ); QUEUE_Unlock( queue );
QUEUE_Unlock( destQ ); QUEUE_Unlock( destQ );
TRACE(sendmsg,"done!\n"); TRACE(sendmsg,"done!\n");
return lResult; return retVal;
} }
@ -772,15 +776,15 @@ BOOL WINAPI ReplyMessage( LRESULT result )
while ((smsg = queue->smWaiting) != 0) while ((smsg = queue->smWaiting) != 0)
{ {
senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
if ( !senderQ )
goto ReplyMessageEnd;
/* if message has already been reply, continue the loop of receving /* if message has already been reply, continue the loop of receving
message */ message */
if ( smsg->flags & SMSG_ALREADY_REPLIED ) if ( smsg->flags & SMSG_ALREADY_REPLIED )
goto ReplyMessageDone; goto ReplyMessageDone;
senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
if ( !senderQ )
goto ReplyMessageDone;
/* if send message pending, processed it */ /* if send message pending, processed it */
if( queue->wakeBits & QS_SENDMESSAGE ) if( queue->wakeBits & QS_SENDMESSAGE )
{ {
@ -793,7 +797,7 @@ BOOL WINAPI ReplyMessage( LRESULT result )
} }
if ( !smsg ) if ( !smsg )
goto ReplyMessageDone; goto ReplyMessageEnd;
smsg->lResult = result; smsg->lResult = result;
smsg->flags |= SMSG_ALREADY_REPLIED; smsg->flags |= SMSG_ALREADY_REPLIED;
@ -805,12 +809,6 @@ BOOL WINAPI ReplyMessage( LRESULT result )
TRACE( sendmsg,"\trpm: smResult = %08lx\n", (long) result ); 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 );
EnterCriticalSection(&senderQ->cSection); EnterCriticalSection(&senderQ->cSection);
smsg->flags |= SMSG_HAVE_RESULT; smsg->flags |= SMSG_HAVE_RESULT;
@ -827,6 +825,30 @@ BOOL WINAPI ReplyMessage( LRESULT result )
ret = TRUE; ret = TRUE;
ReplyMessageDone: ReplyMessageDone:
if (smsg->flags & SMSG_SENDING_REPLY)
{
/* remove msg from the waiting list, since this is the last
ReplyMessage */
QUEUE_RemoveSMSG( queue, SM_WAITING_LIST, smsg );
EnterCriticalSection(&senderQ->cSection);
/* tell the sender we're all done with smsg structure */
smsg->flags |= SMSG_RECEIVED;
/* 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 or a timeout */
if ( smsg->flags & SMSG_RECEIVER_CLEANS )
{
TRACE( sendmsg,"Receiver cleans up!\n" );
HeapFree( SystemHeap, 0, smsg );
}
LeaveCriticalSection(&senderQ->cSection);
}
ReplyMessageEnd:
if ( senderQ ) if ( senderQ )
QUEUE_Unlock( senderQ ); QUEUE_Unlock( senderQ );
if ( queue ) if ( queue )
@ -984,7 +1006,7 @@ static BOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, DWORD first, DWORD last,
return FALSE; return FALSE;
} }
msgQueue->wakeMask = mask; msgQueue->wakeMask = mask;
QUEUE_WaitBits( mask ); QUEUE_WaitBits( mask, INFINITE );
QUEUE_Unlock( msgQueue ); QUEUE_Unlock( msgQueue );
} }
@ -1352,84 +1374,6 @@ BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 message, WPARAM16 wParam,
return QUEUE_AddMsg( GetTaskQueue16(hTask), &msg, 0 ); return QUEUE_AddMsg( GetTaskQueue16(hTask), &msg, 0 );
} }
/***********************************************************************
* SendMessage16 (USER.111)
*/
LRESULT WINAPI SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
LPARAM lParam)
{
WND * wndPtr;
WND **list, **ppWnd;
LRESULT ret;
#ifdef CONFIG_IPC
MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
if (DDE_SendMessage(&DDE_msg)) return TRUE;
#endif /* CONFIG_IPC */
if (hwnd == HWND_BROADCAST)
{
if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
return TRUE;
TRACE(msg,"HWND_BROADCAST !\n");
for (ppWnd = list; *ppWnd; ppWnd++)
{
wndPtr = *ppWnd;
if (!IsWindow(wndPtr->hwndSelf)) continue;
if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
{
TRACE(msg,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
SendMessage16( wndPtr->hwndSelf, msg, wParam, lParam );
}
}
HeapFree( SystemHeap, 0, list );
TRACE(msg,"End of HWND_BROADCAST !\n");
return TRUE;
}
if (HOOK_IsHooked( WH_CALLWNDPROC ))
{
LPCWPSTRUCT16 pmsg;
if ((pmsg = SEGPTR_NEW(CWPSTRUCT16)))
{
pmsg->hwnd = hwnd;
pmsg->message= msg;
pmsg->wParam = wParam;
pmsg->lParam = lParam;
HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
(LPARAM)SEGPTR_GET(pmsg) );
hwnd = pmsg->hwnd;
msg = pmsg->message;
wParam = pmsg->wParam;
lParam = pmsg->lParam;
SEGPTR_FREE( pmsg );
}
}
if (!(wndPtr = WIN_FindWndPtr( hwnd )))
{
WARN(msg, "invalid hwnd %04x\n", hwnd );
return 0;
}
if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
return 0; /* Don't send anything if the task is dying */
SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
if (wndPtr->hmemTaskQ != GetFastQueue16())
ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg,
wParam, lParam, 0 );
else
ret = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
hwnd, msg, wParam, lParam );
SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
return ret;
}
/************************************************************************ /************************************************************************
* MSG_CallWndProcHook32 * MSG_CallWndProcHook32
*/ */
@ -1451,6 +1395,133 @@ static void MSG_CallWndProcHook( LPMSG pmsg, BOOL bUnicode )
pmsg->hwnd = cwp.hwnd; pmsg->hwnd = cwp.hwnd;
} }
/***********************************************************************
* MSG_SendMessage
*
* return values: 0 if timeout occurs
* 1 otherwise
*/
LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam, DWORD timeout, WORD flags,
LRESULT *pRes)
{
WND * wndPtr;
WND **list, **ppWnd;
LRESULT ret = 1;
*pRes = 0;
if (hwnd == HWND_BROADCAST)
{
*pRes = 1;
if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
return 1;
TRACE(msg,"HWND_BROADCAST !\n");
for (ppWnd = list; *ppWnd; ppWnd++)
{
wndPtr = *ppWnd;
if (!IsWindow(wndPtr->hwndSelf)) continue;
if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
{
TRACE(msg,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
MSG_SendMessage( wndPtr->hwndSelf, msg, wParam, lParam,
timeout, flags, pRes);
}
}
HeapFree( SystemHeap, 0, list );
TRACE(msg,"End of HWND_BROADCAST !\n");
return 1;
}
if (HOOK_IsHooked( WH_CALLWNDPROC ))
{
if (flags & SMSG_UNICODE)
MSG_CallWndProcHook( (LPMSG)&hwnd, TRUE);
else if (flags & SMSG_WIN32)
MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE);
else
{
LPCWPSTRUCT16 pmsg;
if ((pmsg = SEGPTR_NEW(CWPSTRUCT16)))
{
pmsg->hwnd = hwnd & 0xffff;
pmsg->message= msg & 0xffff;
pmsg->wParam = wParam & 0xffff;
pmsg->lParam = lParam;
HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
(LPARAM)SEGPTR_GET(pmsg) );
hwnd = pmsg->hwnd;
msg = pmsg->message;
wParam = pmsg->wParam;
lParam = pmsg->lParam;
SEGPTR_FREE( pmsg );
}
}
}
if (!(wndPtr = WIN_FindWndPtr( hwnd )))
{
WARN(msg, "invalid hwnd %04x\n", hwnd );
return 0;
}
if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
return 0; /* Don't send anything if the task is dying */
if (flags & SMSG_WIN32)
SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam );
else
SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
if (wndPtr->hmemTaskQ != GetFastQueue16())
ret = MSG_SendMessageInterThread( wndPtr->hmemTaskQ, hwnd, msg,
wParam, lParam, timeout, flags, pRes );
else
{
/* Call the right CallWindowProc flavor */
if (flags & SMSG_UNICODE)
*pRes = CallWindowProcW( (WNDPROC)wndPtr->winproc,
hwnd, msg, wParam, lParam );
else if (flags & SMSG_WIN32)
*pRes = CallWindowProcA( (WNDPROC)wndPtr->winproc,
hwnd, msg, wParam, lParam );
else
*pRes = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
(HWND16) hwnd, (UINT16) msg,
(WPARAM16) wParam, lParam );
}
if (flags & SMSG_WIN32)
SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, ret );
else
SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
return ret;
}
/***********************************************************************
* SendMessage16 (USER.111)
*/
LRESULT WINAPI SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
LPARAM lParam)
{
LRESULT res;
#ifdef CONFIG_IPC
MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
if (DDE_SendMessage(&DDE_msg)) return TRUE;
#endif /* CONFIG_IPC */
MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, 0, &res);
return res;
}
/********************************************************************** /**********************************************************************
* PostThreadMessage32A (USER32.422) * PostThreadMessage32A (USER32.422)
* *
@ -1499,49 +1570,13 @@ BOOL WINAPI PostThreadMessageW(DWORD idThread , UINT message,
*/ */
LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wParam, LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam ) LPARAM lParam )
{
WND * wndPtr;
WND **list, **ppWnd;
LRESULT ret;
if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST)
{
if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
return TRUE;
for (ppWnd = list; *ppWnd; ppWnd++)
{ {
wndPtr = *ppWnd; LRESULT res;
if (!IsWindow(wndPtr->hwndSelf)) continue;
if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
SendMessageA( wndPtr->hwndSelf, msg, wParam, lParam );
}
HeapFree( SystemHeap, 0, list );
return TRUE;
}
if (HOOK_IsHooked( WH_CALLWNDPROC )) MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE,
MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE); SMSG_WIN32, &res);
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return res;
{
WARN(msg, "invalid hwnd %08x\n", hwnd );
return 0;
}
if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
return 0; /* Don't send anything if the task is dying */
SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam );
if (wndPtr->hmemTaskQ != GetFastQueue16())
ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
SMSG_WIN32 );
else
ret = CallWindowProcA( (WNDPROC)wndPtr->winproc,
hwnd, msg, wParam, lParam );
SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, ret );
return ret;
} }
@ -1572,47 +1607,12 @@ LRESULT WINAPI SendMessageW(
WPARAM wParam, /* message parameter */ WPARAM wParam, /* message parameter */
LPARAM lParam /* additional message parameter */ LPARAM lParam /* additional message parameter */
) { ) {
WND * wndPtr; LRESULT res;
WND **list, **ppWnd;
LRESULT ret;
if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST) MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE,
{ SMSG_WIN32 | SMSG_UNICODE, &res);
if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
return TRUE;
for (ppWnd = list; *ppWnd; ppWnd++)
{
wndPtr = *ppWnd;
if (!IsWindow(wndPtr->hwndSelf)) continue;
if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
SendMessageW( wndPtr->hwndSelf, msg, wParam, lParam );
}
HeapFree( SystemHeap, 0, list );
return TRUE;
}
if (HOOK_IsHooked( WH_CALLWNDPROC )) return res;
MSG_CallWndProcHook( (LPMSG)&hwnd, TRUE);
if (!(wndPtr = WIN_FindWndPtr( hwnd )))
{
WARN(msg, "invalid hwnd %08x\n", hwnd );
return 0;
}
if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
return 0; /* Don't send anything if the task is dying */
SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam );
if (wndPtr->hmemTaskQ != GetFastQueue16())
ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
SMSG_WIN32 | SMSG_UNICODE );
else
ret = CallWindowProcW( (WNDPROC)wndPtr->winproc,
hwnd, msg, wParam, lParam );
SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, ret );
return ret;
} }
@ -1623,32 +1623,54 @@ LRESULT WINAPI SendMessageTimeout16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
LPARAM lParam, UINT16 flags, LPARAM lParam, UINT16 flags,
UINT16 timeout, LPWORD resultp) UINT16 timeout, LPWORD resultp)
{ {
FIXME(sendmsg, "(...): semistub\n"); LRESULT ret;
return SendMessage16 (hwnd, msg, wParam, lParam); LRESULT msgRet;
/* FIXME: need support for SMTO_BLOCK */
ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, 0, &msgRet);
*resultp = (WORD) msgRet;
return ret;
} }
/*********************************************************************** /***********************************************************************
* SendMessageTimeout32A (USER32.457) * SendMessageTimeoutA (USER32.457)
*/ */
LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wParam, LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam, UINT flags, LPARAM lParam, UINT flags,
UINT timeout, LPDWORD resultp) UINT timeout, LPDWORD resultp)
{ {
FIXME(sendmsg, "(...): semistub\n"); LRESULT ret;
return SendMessageA (hwnd, msg, wParam, lParam); LRESULT msgRet;
/* FIXME: need support for SMTO_BLOCK */
ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, SMSG_WIN32,
&msgRet);
*resultp = (DWORD) msgRet;
return ret;
} }
/*********************************************************************** /***********************************************************************
* SendMessageTimeout32W (USER32.458) * SendMessageTimeoutW (USER32.458)
*/ */
LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam, LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam, UINT flags, LPARAM lParam, UINT flags,
UINT timeout, LPDWORD resultp) UINT timeout, LPDWORD resultp)
{ {
FIXME(sendmsg, "(...): semistub\n"); LRESULT ret;
return SendMessageW (hwnd, msg, wParam, lParam); LRESULT msgRet;
/* FIXME: need support for SMTO_BLOCK */
ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout,
SMSG_WIN32 | SMSG_UNICODE, &msgRet);
*resultp = (DWORD) msgRet;
return ret;
} }
@ -1671,7 +1693,7 @@ LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam,
*/ */
void WINAPI WaitMessage( void ) void WINAPI WaitMessage( void )
{ {
QUEUE_WaitBits( QS_ALLINPUT ); QUEUE_WaitBits( QS_ALLINPUT, INFINITE );
} }
/*********************************************************************** /***********************************************************************

View File

@ -611,21 +611,6 @@ MESSAGEQUEUE *QUEUE_GetSysQueue(void)
} }
/***********************************************************************
* QUEUE_Wait
*/
static void QUEUE_Wait( DWORD wait_mask )
{
if ( THREAD_IsWin16( THREAD_Current() ) )
WaitEvent16( 0 );
else
{
TRACE(msg, "current task is 32-bit, calling SYNC_DoWait\n");
MsgWaitForMultipleObjects( 0, NULL, FALSE, INFINITE, wait_mask );
}
}
/*********************************************************************** /***********************************************************************
* QUEUE_SetWakeBit * QUEUE_SetWakeBit
* *
@ -669,23 +654,31 @@ void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
* QUEUE_WaitBits * QUEUE_WaitBits
* *
* See "Windows Internals", p.447 * See "Windows Internals", p.447
*
* return values:
* 0 if exit with timeout
* 1 otherwise
*/ */
void QUEUE_WaitBits( WORD bits ) int QUEUE_WaitBits( WORD bits, DWORD timeout )
{ {
MESSAGEQUEUE *queue; MESSAGEQUEUE *queue;
DWORD curTime = 0;
TRACE(msg,"q %04x waiting for %04x\n", GetFastQueue16(), bits); TRACE(msg,"q %04x waiting for %04x\n", GetFastQueue16(), bits);
if ( THREAD_IsWin16( THREAD_Current() ) && (timeout != INFINITE) )
curTime = GetTickCount();
if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
for (;;) for (;;)
{ {
if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return;
if (queue->changeBits & bits) if (queue->changeBits & bits)
{ {
/* One of the bits is set; we can return */ /* One of the bits is set; we can return */
queue->wakeMask = 0; queue->wakeMask = 0;
QUEUE_Unlock( queue ); QUEUE_Unlock( queue );
return; return 1;
} }
if (queue->wakeBits & QS_SENDMESSAGE) if (queue->wakeBits & QS_SENDMESSAGE)
{ {
@ -693,24 +686,40 @@ void QUEUE_WaitBits( WORD bits )
queue->wakeMask = 0; queue->wakeMask = 0;
QUEUE_ReceiveMessage( queue ); QUEUE_ReceiveMessage( queue );
QUEUE_Unlock( queue );
continue; /* nested sm crux */ continue; /* nested sm crux */
} }
queue->wakeMask = bits | QS_SENDMESSAGE; queue->wakeMask = bits | QS_SENDMESSAGE;
if(queue->changeBits & bits) if(queue->changeBits & bits)
{ {
QUEUE_Unlock( queue );
continue; continue;
} }
TRACE(msg,"%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask); TRACE(msg,"%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask);
QUEUE_Wait( queue->wakeMask ); if ( !THREAD_IsWin16( THREAD_Current() ) )
{
/* win32 thread, use WaitForMultipleObjects */
MsgWaitForMultipleObjects( 0, NULL, FALSE, timeout, queue->wakeMask );
}
else
{
if ( timeout == INFINITE )
WaitEvent16( 0 ); /* win 16 thread, use WaitEvent */
else
{
/* check for timeout, then give control to other tasks */
if (GetTickCount() - curTime > timeout)
{
QUEUE_Unlock( queue ); QUEUE_Unlock( queue );
return 0; /* exit with timeout */
}
Yield16();
}
} }
} }
}
/*********************************************************************** /***********************************************************************
@ -919,54 +928,11 @@ void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
} }
else WARN(sendmsg, "\trcm: bad hWnd\n"); else WARN(sendmsg, "\trcm: bad hWnd\n");
/* 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 )
{
/* remove smsg from the waiting list */
QUEUE_RemoveSMSG( queue, SM_WAITING_LIST, smsg );
/* 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. */
senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue );
/* synchronize with the sender */
if (senderQ)
EnterCriticalSection( &senderQ->cSection );
/* tell the sender we're all done with smsg structure */
smsg->flags |= SMSG_RECEIVED;
/* 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 );
}
}
else
{
/* no early reply, so do it now */
/* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not /* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not
an early reply */ an early reply */
smsg->flags |= SMSG_SENDING_REPLY; smsg->flags |= SMSG_SENDING_REPLY;
ReplyMessage( result ); ReplyMessage( result );
}
TRACE( sendmsg,"done! \n" ); TRACE( sendmsg,"done! \n" );
} }