first attempt to implement SendMessageTimeout()
authorThomas Bluemel <thomas@reactsoft.com>
Thu, 11 Mar 2004 14:47:44 +0000 (14:47 +0000)
committerThomas Bluemel <thomas@reactsoft.com>
Thu, 11 Mar 2004 14:47:44 +0000 (14:47 +0000)
svn path=/trunk/; revision=8643

reactos/iface/addsys/w32ksvc.db
reactos/include/defines.h
reactos/include/errors.h
reactos/include/win32k/ntuser.h
reactos/lib/user32/windows/message.c
reactos/subsys/win32k/include/msgqueue.h
reactos/subsys/win32k/ntuser/message.c
reactos/subsys/win32k/ntuser/msgqueue.c

index 497f2df..c7d66aa 100644 (file)
@@ -473,6 +473,7 @@ NtUserScrollWindowEx                    8
 NtUserSendInput                         3
 NtUserSendMessage                       5
 NtUserSendMessageCallback               6
+NtUserSendMessageTimeout                8
 NtUserSendNotifyMessage                 4
 NtUserSetActiveWindow                   1
 NtUserSetCapture                        1
index e18e050..447ead7 100644 (file)
@@ -2084,6 +2084,13 @@ extern "C" {
 /* InitializeSecurityDescriptor */
 #define SECURITY_DESCRIPTOR_REVISION   (1)
 
+/* InSendMessageEx */
+#define ISMEX_NOSEND   (0)
+#define ISMEX_SEND     (1)
+#define ISMEX_NOTIFY   (2)
+#define ISMEX_CALLBACK (4)
+#define ISMEX_REPLIED  (8)
+
 /* JournalPlaybackProc, KeyboardProc */
 #define HC_GETNEXT     (1)
 #define HC_SKIP        (2)
index 914746b..78d7c25 100644 (file)
@@ -570,6 +570,8 @@ extern "C" {
 #define ERROR_PAGEFILE_QUOTA             1454L
 #define ERROR_COMMITMENT_LIMIT           1455L
 #define ERROR_MENU_ITEM_NOT_FOUND        1456L
+#define ERROR_TIMEOUT                    1460L
+#define ERROR_INVALID_MONITOR_HANDLE     1461L
 #define ERROR_EVENTLOG_FILE_CORRUPT      1500L
 #define ERROR_EVENTLOG_CANT_START        1501L
 #define ERROR_LOG_FILE_FULL              1502L
index bbf97b8..b73cef8 100644 (file)
@@ -783,10 +783,12 @@ NtUserGetThreadDesktop(
   DWORD dwThreadId,
   DWORD Unknown1);
 
+#define THREADSTATE_FOCUSWINDOW (1)
+#define THREADSTATE_INSENDMESSAGE       (2)
 DWORD
 STDCALL
 NtUserGetThreadState(
-  DWORD Unknown0);
+  DWORD Routine);
 
 DWORD
 STDCALL
@@ -1167,6 +1169,16 @@ NtUserSendMessageCallback(
   SENDASYNCPROC lpCallBack,
   ULONG_PTR dwData);
 
+LRESULT STDCALL
+NtUserSendMessageTimeout(HWND hWnd,
+                        UINT Msg,
+                        WPARAM wParam,
+                        LPARAM lParam,
+                        UINT uFlags,
+                        UINT uTimeout,
+                        ULONG_PTR *uResult,
+                        PNTUSERSENDMESSAGEINFO Info);
+
 BOOL
 STDCALL
 NtUserSendNotifyMessage(
index ac29702..0ce565f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: message.c,v 1.35 2004/01/28 20:54:30 gvg Exp $
+/* $Id: message.c,v 1.36 2004/03/11 14:47:43 weiden Exp $
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS user32.dll
@@ -54,6 +54,8 @@ BOOL
 STDCALL
 InSendMessage(VOID)
 {
+  /* return(NtUserGetThreadState(THREADSTATE_INSENDMESSAGE) != ISMEX_NOSEND); */
+  UNIMPLEMENTED;
   return FALSE;
 }
 
@@ -66,6 +68,7 @@ STDCALL
 InSendMessageEx(
   LPVOID lpReserved)
 {
+  /* return NtUserGetThreadState(THREADSTATE_INSENDMESSAGE); */
   UNIMPLEMENTED;
   return 0;
 }
@@ -834,8 +837,64 @@ SendMessageTimeoutA(
   UINT uTimeout,
   PDWORD_PTR lpdwResult)
 {
-  UNIMPLEMENTED;
-  return (LRESULT)0;
+  MSG AnsiMsg;
+  MSG UcMsg;
+  LRESULT Result;
+  NTUSERSENDMESSAGEINFO Info;
+
+  AnsiMsg.hwnd = hWnd;
+  AnsiMsg.message = Msg;
+  AnsiMsg.wParam = wParam;
+  AnsiMsg.lParam = lParam;
+  if (! MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg))
+    {
+      return FALSE;
+    }
+
+  Info.Ansi = TRUE;
+  Result = NtUserSendMessageTimeout(UcMsg.hwnd, UcMsg.message,
+                                    UcMsg.wParam, UcMsg.lParam,
+                                    fuFlags, uTimeout, (ULONG_PTR*)lpdwResult, &Info);
+  if(!Result)
+  {
+      return FALSE;
+  }
+  if (! Info.HandledByKernel)
+    {
+      /* We need to send the message ourselves */
+      if (Info.Ansi)
+        {
+          /* Ansi message and Ansi window proc, that's easy. Clean up
+             the Unicode message though */
+          MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
+          Result = IntCallWindowProcA(Info.Ansi, Info.Proc, hWnd, Msg, wParam, lParam);
+        }
+      else
+        {
+          /* Unicode winproc. Although we started out with an Ansi message we
+             already converted it to Unicode for the kernel call. Reuse that
+             message to avoid another conversion */
+          Result = IntCallWindowProcW(Info.Ansi, Info.Proc, UcMsg.hwnd,
+                                      UcMsg.message, UcMsg.wParam, UcMsg.lParam);
+          if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
+            {
+              return FALSE;
+            }
+        }
+      if(lpdwResult)
+        *lpdwResult = Result;
+      Result = TRUE;
+    }
+  else
+    {
+      /* Message sent by kernel. Convert back to Ansi */
+      if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
+        {
+          return FALSE;
+        }
+    }
+
+  return Result;
 }
 
 
@@ -853,8 +912,22 @@ SendMessageTimeoutW(
   UINT uTimeout,
   PDWORD_PTR lpdwResult)
 {
-  UNIMPLEMENTED;
-  return (LRESULT)0;
+  NTUSERSENDMESSAGEINFO Info;
+  LRESULT Result;
+
+  Info.Ansi = FALSE;
+  Result = NtUserSendMessageTimeout(hWnd, Msg, wParam, lParam, fuFlags, uTimeout, 
+                                    lpdwResult, &Info);
+  if (! Info.HandledByKernel)
+    {
+      /* We need to send the message ourselves */
+      Result = IntCallWindowProcW(Info.Ansi, Info.Proc, hWnd, Msg, wParam, lParam);
+      if(lpdwResult)
+        *lpdwResult = Result;
+      return TRUE;
+    }
+
+  return Result;
 }
 
 
index 8b35484..c0c78d4 100644 (file)
@@ -6,6 +6,8 @@
 #include "caret.h"
 #include "hook.h"
 
+#define MSQ_HUNG        5000
+
 typedef struct _USER_MESSAGE
 {
   LIST_ENTRY ListEntry;
@@ -59,8 +61,8 @@ typedef struct _USER_MESSAGE_QUEUE
   ULONG QuitExitCode;
   /* Set if there are new messages in any of the queues. */
   KEVENT NewMessages;  
-  /* FIXME: Unknown. */
-  ULONG QueueStatus;
+  /* Last time PeekMessage() was called. */
+  ULONG LastMsgRead;
   /* Current window with focus (ie. receives keyboard input) for this queue. */
   HWND FocusWindow;
   /* True if a window needs painting. */
@@ -94,9 +96,12 @@ typedef struct _USER_MESSAGE_QUEUE
 
 } USER_MESSAGE_QUEUE, *PUSER_MESSAGE_QUEUE;
 
-LRESULT FASTCALL
+BOOL FASTCALL
+MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue);
+NTSTATUS FASTCALL
 MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
-              HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+              HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
+               UINT uTimeout, BOOL Block, ULONG_PTR *uResult);
 VOID FASTCALL
 MsqInitializeMessage(PUSER_MESSAGE Message,
                     LPMSG Msg);
@@ -147,6 +152,14 @@ IntSendMessage(HWND hWnd,
                UINT Msg,
                WPARAM wParam,
                LPARAM lParam);
+LRESULT STDCALL
+IntSendMessageTimeout(HWND hWnd,
+                      UINT Msg,
+                      WPARAM wParam,
+                      LPARAM lParam,
+                      UINT uFlags,
+                      UINT uTimeout,
+                      ULONG_PTR *uResult);
 LRESULT FASTCALL
 IntDispatchMessage(MSG* Msg);
 BOOL FASTCALL
index 3e41db7..f41ec4a 100644 (file)
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: message.c,v 1.52 2004/02/24 13:27:03 weiden Exp $
+/* $Id: message.c,v 1.53 2004/03/11 14:47:44 weiden Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
 #define NDEBUG
 #include <debug.h>
 
+typedef struct
+{
+  UINT uFlags;
+  UINT uTimeout;
+  ULONG_PTR uResult;
+} DOSENDMESSAGE, *PDOSENDMESSAGE;
+
 /* FUNCTIONS *****************************************************************/
 
 NTSTATUS FASTCALL
@@ -235,6 +242,7 @@ IntPeekMessage(LPMSG Msg,
                 UINT MsgFilterMax,
                 UINT RemoveMsg)
 {
+  LARGE_INTEGER LargeTickCount;
   PUSER_MESSAGE_QUEUE ThreadQueue;
   BOOLEAN Present;
   PUSER_MESSAGE Message;
@@ -244,6 +252,9 @@ IntPeekMessage(LPMSG Msg,
      article on GetMessage() */
 
   ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
+  
+  KeQueryTickCount(&LargeTickCount);
+  ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
 
   /* Inspect RemoveMsg flags */
   /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
@@ -706,11 +717,29 @@ UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
 
 LRESULT STDCALL
 IntSendMessage(HWND hWnd,
-               UINT Msg,
-               WPARAM wParam,
-               LPARAM lParam)
+               UINT Msg,
+               WPARAM wParam,
+               LPARAM lParam)
+{
+  LRESULT Result = 0;
+  if(IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
+  {
+    return Result;
+  }
+  return 0;
+}
+
+LRESULT STDCALL
+IntSendMessageTimeout(HWND hWnd,
+                      UINT Msg,
+                      WPARAM wParam,
+                      LPARAM lParam,
+                      UINT uFlags,
+                      UINT uTimeout,
+                      ULONG_PTR *uResult)
 {
   LRESULT Result;
+  NTSTATUS Status;
   PWINDOW_OBJECT Window;
   PMSGMEMORY MsgMemoryEntry;
   INT lParamBufferSize;
@@ -724,7 +753,7 @@ IntSendMessage(HWND hWnd,
   if (!Window)
     {
       SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-      return 0;
+      return FALSE;
     }
 
   Win32Thread = PsGetWin32Thread();
@@ -736,7 +765,7 @@ IntSendMessage(HWND hWnd,
         {
           /* Never send messages to exiting threads */
           IntReleaseWindowObject(Window);
-          return 0;
+          return FALSE;
         }
 
       /* See if this message type is present in the table */
@@ -754,7 +783,7 @@ IntSendMessage(HWND hWnd,
         {
           IntReleaseWindowObject(Window);
           DPRINT1("Failed to pack message parameters\n");
-          return -1;
+          return FALSE;
         }
       if (0xFFFF0000 != ((DWORD) Window->WndProcW & 0xFFFF0000))
         {
@@ -770,17 +799,37 @@ IntSendMessage(HWND hWnd,
         {
           IntReleaseWindowObject(Window);
           DPRINT1("Failed to unpack message parameters\n");
-          return Result;
+          if(uResult)
+            *uResult = Result;
+          return TRUE;
         }
 
       IntReleaseWindowObject(Window);
-      return Result;
+      if(uResult)
+        *uResult = Result;
+      return TRUE;
     }
   
-  Result = MsqSendMessage(Window->MessageQueue, hWnd, Msg, wParam, lParam);
+  if(uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->MessageQueue))
+  {
+    IntReleaseWindowObject(Window);
+    /* FIXME - Set a LastError? */
+    return FALSE;
+  }
+  
+  Status = MsqSendMessage(Window->MessageQueue, hWnd, Msg, wParam, lParam, 
+                          (uFlags & SMTO_BLOCK), uTimeout, &Result);
+  if(Status == STATUS_TIMEOUT)
+  {
+    IntReleaseWindowObject(Window);
+    SetLastWin32Error(ERROR_TIMEOUT);
+    return FALSE;
+  }
 
   IntReleaseWindowObject(Window);
-  return Result;
+  if(uResult)
+    *uResult = Result;
+  return TRUE;
 }
 
 static NTSTATUS FASTCALL
@@ -878,12 +927,13 @@ CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
   return STATUS_SUCCESS;
 }
 
-LRESULT STDCALL
-NtUserSendMessage(HWND Wnd,
-                 UINT Msg,
-                 WPARAM wParam,
-                 LPARAM lParam,
-                  PNTUSERSENDMESSAGEINFO UnsafeInfo)
+LRESULT FASTCALL
+IntDoSendMessage(HWND Wnd,
+                UINT Msg,
+                WPARAM wParam,
+                LPARAM lParam,
+                PDOSENDMESSAGE dsm,
+                PNTUSERSENDMESSAGEINFO UnsafeInfo)
 {
   LRESULT Result;
   NTSTATUS Status;
@@ -957,16 +1007,25 @@ NtUserSendMessage(HWND Wnd,
         {
           MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
           SetLastWin32Error(ERROR_INVALID_PARAMETER);
-          return -1;
+          return (dsm ? 0 : -1);
         }
-      Result = IntSendMessage(KernelModeMsg.hwnd, KernelModeMsg.message,
-                              KernelModeMsg.wParam, KernelModeMsg.lParam);
+      if(!dsm)
+      {
+        Result = IntSendMessage(KernelModeMsg.hwnd, KernelModeMsg.message,
+                                KernelModeMsg.wParam, KernelModeMsg.lParam);
+      }
+      else
+      {
+        Result = IntSendMessageTimeout(KernelModeMsg.hwnd, KernelModeMsg.message,
+                                       KernelModeMsg.wParam, KernelModeMsg.lParam,
+                                       dsm->uFlags, dsm->uTimeout, &dsm->uResult);
+      }
       Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
       if (! NT_SUCCESS(Status))
         {
           MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
           SetLastWin32Error(ERROR_INVALID_PARAMETER);
-          return -1;
+          return(dsm ? 0 : -1);
         }
     }
 
@@ -979,6 +1038,46 @@ NtUserSendMessage(HWND Wnd,
   return Result;
 }
 
+LRESULT STDCALL
+NtUserSendMessageTimeout(HWND hWnd,
+                        UINT Msg,
+                        WPARAM wParam,
+                        LPARAM lParam,
+                        UINT uFlags,
+                        UINT uTimeout,
+                        ULONG_PTR *uResult,
+                        PNTUSERSENDMESSAGEINFO UnsafeInfo)
+{
+  DOSENDMESSAGE dsm;
+  LRESULT Result;
+  
+  dsm.uFlags = uFlags;
+  dsm.uTimeout = uTimeout;
+  Result = IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
+  if(uResult)
+  {
+    NTSTATUS Status;
+    
+    Status = MmCopyToCaller(uResult, &dsm.uResult, sizeof(ULONG_PTR));
+    if(!NT_SUCCESS(Status))
+    {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      return FALSE;
+    }
+  }
+  return Result;
+}
+
+LRESULT STDCALL
+NtUserSendMessage(HWND Wnd,
+                 UINT Msg,
+                 WPARAM wParam,
+                 LPARAM lParam,
+                  PNTUSERSENDMESSAGEINFO UnsafeInfo)
+{
+  return IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo);
+}
+
 BOOL STDCALL
 NtUserSendMessageCallback(HWND hWnd,
                          UINT Msg,
index cbc38e4..608c4bf 100644 (file)
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: msgqueue.c,v 1.74 2004/02/28 00:44:28 weiden Exp $
+/* $Id: msgqueue.c,v 1.75 2004/03/11 14:47:44 weiden Exp $
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
@@ -889,16 +889,17 @@ MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue,
   IntUnLockMessageQueue(MessageQueue);
 }
 
-LRESULT FASTCALL
+NTSTATUS FASTCALL
 MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
-              HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+              HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
+               UINT uTimeout, BOOL Block, ULONG_PTR *uResult)
 {
   PUSER_SENT_MESSAGE Message;
   KEVENT CompletionEvent;
-  PVOID WaitObjects[2];
   NTSTATUS WaitStatus;
   LRESULT Result;
   PUSER_MESSAGE_QUEUE ThreadQueue;
+  LARGE_INTEGER Timeout;
 
   KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE);
 
@@ -914,24 +915,44 @@ MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
 
   IntLockMessageQueue(MessageQueue);
   InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry);
-  KeSetEvent(&MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
   IntUnLockMessageQueue(MessageQueue);
-
+  KeSetEvent(&MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
+  
+  Timeout.QuadPart = uTimeout * -10000;
+  
   ThreadQueue = PsGetWin32Thread()->MessageQueue;
-  WaitObjects[1] = &ThreadQueue->NewMessages;
-  WaitObjects[0] = &CompletionEvent;
-  do
-    {
-      WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
-                                            UserMode, TRUE, NULL, NULL);
-      while (MsqDispatchOneSentMessage(ThreadQueue))
-        {
-          ;
-        }
-    }
-  while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
-
-  return (STATUS_WAIT_0 == WaitStatus ? Result : -1);
+  if(Block)
+  {
+    /* don't process messages sent to the thread */
+    WaitStatus = KeWaitForSingleObject(&CompletionEvent, UserRequest, UserMode, 
+                                       FALSE, (uTimeout ? &Timeout : NULL));
+  }
+  else
+  {
+    PVOID WaitObjects[2];
+    
+    WaitObjects[0] = &CompletionEvent;
+    WaitObjects[1] = &ThreadQueue->NewMessages;
+    do
+      {
+        WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
+                                              UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL);
+        if(WaitStatus == STATUS_TIMEOUT)
+          {DbgPrint("MsqSendMessage timed out\n");
+            break;
+          }
+        while (MsqDispatchOneSentMessage(ThreadQueue))
+          {
+            ;
+          }
+      }
+    while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
+  }
+  
+  if(WaitStatus != STATUS_TIMEOUT)
+    *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1);
+  
+  return WaitStatus;
 }
 
 VOID FASTCALL
@@ -1014,9 +1035,20 @@ MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue)
                                  NULL));
 }
 
+BOOL FASTCALL
+MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue)
+{
+  LARGE_INTEGER LargeTickCount;
+  
+  KeQueryTickCount(&LargeTickCount);
+  return ((LargeTickCount.u.LowPart - MessageQueue->LastMsgRead) > MSQ_HUNG);
+}
+
 VOID FASTCALL
 MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQueue)
 {
+  LARGE_INTEGER LargeTickCount;
+  
   MessageQueue->Thread = Thread;
   MessageQueue->CaretInfo = (PTHRDCARETINFO)(MessageQueue + 1);
   InitializeListHead(&MessageQueue->PostedMessagesListHead);
@@ -1027,7 +1059,8 @@ MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQu
   MessageQueue->QuitPosted = FALSE;
   MessageQueue->QuitExitCode = 0;
   KeInitializeEvent(&MessageQueue->NewMessages, SynchronizationEvent, FALSE);
-  MessageQueue->QueueStatus = 0;
+  KeQueryTickCount(&LargeTickCount);
+  MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
   MessageQueue->FocusWindow = NULL;
   MessageQueue->PaintPosted = FALSE;
   MessageQueue->PaintCount = 0;