Implemented SendMessageTimeout() functions.

diff --git a/windows/message.c b/windows/message.c
index b91b4e3..6e38808 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -44,7 +44,6 @@
 
 static UINT doubleClickSpeed = 452;
 
-
 /***********************************************************************
  *           MSG_CheckFilter
  */
@@ -617,16 +616,24 @@
 
 
 /***********************************************************************
- *           MSG_SendMessage
+ *           MSG_SendMessageInterThread
  *
  * 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,
-                                WPARAM wParam, LPARAM lParam, WORD flags )
+static LRESULT MSG_SendMessageInterThread( HQUEUE16 hDestQueue,
+                                           HWND hwnd, UINT msg,
+                                           WPARAM wParam, LPARAM lParam,
+                                           DWORD timeout, WORD flags,
+                                           LRESULT *pRes)
 {
     MESSAGEQUEUE *queue, *destQ;
     SMSG         *smsg;
-    LRESULT      lResult = 0;
+    LRESULT      retVal = 1;
+    
+    *pRes = 0;
 
     if (IsTaskLocked16() || !IsWindow(hwnd))
         return 0;
@@ -634,7 +641,6 @@
     /* create a SMSG structure to hold SendMessage() parameters */
     if (! (smsg = (SMSG *) HeapAlloc( SystemHeap, 0, sizeof(SMSG) )) )
         return 0;
-          
     if (!(queue = (MESSAGEQUEUE*)QUEUE_Lock( GetFastQueue16() ))) return 0;
 
     if (!(destQ = (MESSAGEQUEUE*)QUEUE_Lock( hDestQueue )))
@@ -671,7 +677,13 @@
         if (THREAD_IsWin16(THREAD_Current()) && THREAD_IsWin16(destQ->thdb) )
             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) )
         {
@@ -681,8 +693,8 @@
       }
         else
         {
-            lResult = smsg->lResult;
-            TRACE(sendmsg,"smResult = %08x\n", (unsigned)lResult );
+            *pRes = smsg->lResult;
+            TRACE(sendmsg,"smResult = %08x\n", (unsigned)*pRes );
         }
     }
 
@@ -717,19 +729,11 @@
     /* 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 */
+    /* In the case of an early reply (or a timeout), 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 );
     
         if (smsg->flags & SMSG_RECEIVED)
@@ -738,13 +742,13 @@
             smsg->flags |= SMSG_RECEIVER_CLEANS;
         
         LeaveCriticalSection( &queue->cSection );
-    }
+
 
     QUEUE_Unlock( queue );
     QUEUE_Unlock( destQ );
     
     TRACE(sendmsg,"done!\n");
-    return lResult;
+    return retVal;
 }
 
 
@@ -772,15 +776,15 @@
 
     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
          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 )
       {
@@ -793,7 +797,7 @@
     }
 
     if ( !smsg )
-        goto ReplyMessageDone;
+        goto ReplyMessageEnd;
       
     smsg->lResult = result;
     smsg->flags |= SMSG_ALREADY_REPLIED;
@@ -805,12 +809,6 @@
 
     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);
 
     smsg->flags |= SMSG_HAVE_RESULT;
@@ -827,6 +825,30 @@
     ret = TRUE;
     
 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 )
     QUEUE_Unlock( senderQ );
     if ( queue )
@@ -984,7 +1006,7 @@
             return FALSE;
         }
         msgQueue->wakeMask = mask;
-        QUEUE_WaitBits( mask );
+        QUEUE_WaitBits( mask, INFINITE );
         QUEUE_Unlock( msgQueue );
     }
 
@@ -1352,84 +1374,6 @@
     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
  */
@@ -1451,6 +1395,133 @@
    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)
  *
@@ -1499,49 +1570,13 @@
  */
 LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wParam,
                                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;
-            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;
-    }
+    LRESULT res;
 
-    if (HOOK_IsHooked( WH_CALLWNDPROC ))
-	MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE);
+    MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE,
+                    SMSG_WIN32, &res);
 
-    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 );
-    else
-        ret = CallWindowProcA( (WNDPROC)wndPtr->winproc,
-                                 hwnd, msg, wParam, lParam );
-
-    SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, ret );
-    return ret;
+    return res;
 }
 
 
@@ -1572,47 +1607,12 @@
   WPARAM wParam, /* message parameter */
   LPARAM lParam    /* additional message parameter */
 ) {
-    WND * wndPtr;
-    WND **list, **ppWnd;
-    LRESULT ret;
+    LRESULT res;
 
-    if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST)
-    {
-        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;
-    }
+    MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE,
+                    SMSG_WIN32 | SMSG_UNICODE, &res);
 
-    if (HOOK_IsHooked( WH_CALLWNDPROC ))
-        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;
+    return res;
 }
 
 
@@ -1623,32 +1623,54 @@
 				     LPARAM lParam, UINT16 flags,
 				     UINT16 timeout, LPWORD resultp)
 {
-  FIXME(sendmsg, "(...): semistub\n");
-  return SendMessage16 (hwnd, msg, wParam, lParam);
+    LRESULT ret;
+    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,
 				      LPARAM lParam, UINT flags,
 				      UINT timeout, LPDWORD resultp)
 {
-  FIXME(sendmsg, "(...): semistub\n");
-  return SendMessageA (hwnd, msg, wParam, lParam);
+    LRESULT ret;
+    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,
 				      LPARAM lParam, UINT flags,
 				      UINT timeout, LPDWORD resultp)
 {
-  FIXME(sendmsg, "(...): semistub\n");
-  return SendMessageW (hwnd, msg, wParam, lParam);
+    LRESULT ret;
+    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 @@
  */
 void WINAPI WaitMessage( void )
 {
-    QUEUE_WaitBits( QS_ALLINPUT );
+    QUEUE_WaitBits( QS_ALLINPUT, INFINITE );
 }
 
 /***********************************************************************