- NtUserWaitForInputIdle: Call EngGetTickCount, removing duplicated code
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / message.c
index d32339f..2f23df4 100644 (file)
@@ -16,8 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id$
- *
+/*
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * PURPOSE:          Messages
@@ -115,7 +114,7 @@ MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
    PUNICODE_STRING ClassName;
    UINT Size = 0;
 
-   _SEH_TRY
+   _SEH2_TRY
    {
       if (MMS_SIZE_WPARAM == MsgMemoryEntry->Size)
       {
@@ -168,12 +167,12 @@ MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
          Size = MsgMemoryEntry->Size;
       }
    }
-   _SEH_HANDLE
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
-      DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH_GetExceptionCode());
+      DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
       Size = 0;
    }
-   _SEH_END;
+   _SEH2_END;
    return Size;
 }
 
@@ -296,20 +295,108 @@ UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
    return STATUS_INVALID_PARAMETER;
 }
 
+static
+VOID
+FASTCALL
+IntCallWndProc
+( PWINDOW_OBJECT Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+   BOOL SameThread = FALSE;
+
+   if (Window->ti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->ThreadInfo)
+      SameThread = TRUE;
+
+   if ((!SameThread && (Window->ti->Hooks & HOOKID_TO_FLAG(WH_CALLWNDPROC))) ||
+        (SameThread && ISITHOOKED(WH_CALLWNDPROC)) )
+   {
+      CWPSTRUCT CWP;
+      CWP.hwnd    = hWnd;
+      CWP.message = Msg;
+      CWP.wParam  = wParam;
+      CWP.lParam  = lParam;
+      co_HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, SameThread, (LPARAM)&CWP );
+   }
+}
+static
+VOID
+FASTCALL
+IntCallWndProcRet
+( PWINDOW_OBJECT Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *uResult)
+{
+   BOOL SameThread = FALSE;
+
+   if (Window->ti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->ThreadInfo)
+      SameThread = TRUE;
+
+   if ((!SameThread && (Window->ti->Hooks & HOOKID_TO_FLAG(WH_CALLWNDPROCRET))) ||
+        (SameThread && ISITHOOKED(WH_CALLWNDPROCRET)) )
+   {
+      CWPRETSTRUCT CWPR;
+      CWPR.hwnd    = hWnd;
+      CWPR.message = Msg;
+      CWPR.wParam  = wParam;
+      CWPR.lParam  = lParam;
+      CWPR.lResult = *uResult;
+      co_HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, SameThread, (LPARAM)&CWPR );
+   }
+}
+
+
 BOOL
-STDCALL
+APIENTRY
 NtUserCallMsgFilter(
-   LPMSG msg,
+   LPMSG lpmsg,
    INT code)
 {
+   BOOL BadChk = FALSE, Ret = TRUE;
+   MSG Msg;
    DECLARE_RETURN(BOOL);
 
    DPRINT("Enter NtUserCallMsgFilter\n");
    UserEnterExclusive();
+   if (lpmsg)
+   {
+      _SEH2_TRY
+      {
+         ProbeForRead((PVOID)lpmsg,
+                       sizeof(MSG),
+                                1);
+         RtlCopyMemory( &Msg,
+                (PVOID)lpmsg,
+                 sizeof(MSG));
+      }
+      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+      {
+         BadChk = TRUE;
+      }
+      _SEH2_END;
+   }
+   else
+     RETURN( FALSE);
 
-   if (co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)msg))
-      RETURN( TRUE);
-   RETURN( co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)msg));
+   if (BadChk) RETURN( FALSE);
+
+   if (!co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
+   {
+      Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
+   }
+
+   _SEH2_TRY
+   {
+      ProbeForWrite((PVOID)lpmsg,
+                     sizeof(MSG),
+                               1);
+      RtlCopyMemory((PVOID)lpmsg,
+                            &Msg,
+                     sizeof(MSG));
+   }
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+   {
+      BadChk = TRUE;
+   }
+   _SEH2_END;
+   if (BadChk) RETURN( FALSE);
+   RETURN( Ret)
 
 CLEANUP:
    DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_);
@@ -317,7 +404,7 @@ CLEANUP:
    END_CLEANUP;
 }
 
-LRESULT STDCALL
+LRESULT APIENTRY
 NtUserDispatchMessage(PNTUSERDISPATCHMESSAGEINFO UnsafeMsgInfo)
 {
    NTSTATUS Status;
@@ -407,7 +494,7 @@ CLEANUP:
 }
 
 
-BOOL STDCALL
+BOOL APIENTRY
 NtUserTranslateMessage(LPMSG lpMsg,
                        HKL dwhkl)
 {
@@ -510,10 +597,11 @@ co_IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, PWINDOW_OB
    }
 
    Parent = IntGetParent(MsgWindow);//fixme: deref retval?
-   /* fixme: abort if no parent ? */
+
+   /* If no parent window, pass MsgWindows HWND as wParam. Fixes bug #3111 */
    Result = co_IntSendMessage(MsgWindow->hSelf,
                               WM_MOUSEACTIVATE,
-                              (WPARAM) (Parent ? Parent->hSelf : NULL),
+                              (WPARAM) (Parent ? Parent->hSelf : MsgWindow->hSelf),
                               (LPARAM)MAKELONG(*HitTest, Msg->message)
                              );
 
@@ -653,17 +741,20 @@ co_IntPeekMessage(PUSER_MESSAGE Msg,
                   UINT MsgFilterMax,
                   UINT RemoveMsg)
 {
+   PTHREADINFO pti;
    LARGE_INTEGER LargeTickCount;
    PUSER_MESSAGE_QUEUE ThreadQueue;
    PUSER_MESSAGE Message;
    BOOL Present, RemoveMessages;
    USER_REFERENCE_ENTRY Ref;
    USHORT HitTest;
+   MOUSEHOOKSTRUCT MHook;
 
    /* The queues and order in which they are checked are documented in the MSDN
       article on GetMessage() */
 
-   ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetCurrentThreadWin32Thread()->MessageQueue;
+   pti = PsGetCurrentThreadWin32Thread();
+   ThreadQueue = pti->MessageQueue;
 
    /* Inspect RemoveMsg flags */
    /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
@@ -695,7 +786,7 @@ CheckMessages:
       {
          ThreadQueue->QuitPosted = FALSE;
       }
-      return TRUE;
+      goto MsgExit;
    }
 
    /* Now check for normal messages. */
@@ -739,10 +830,10 @@ CheckMessages:
       ;
 
    /* Check for paint messages. */
-   if (IntGetPaintMessage(hWnd, MsgFilterMin, MsgFilterMax, PsGetCurrentThreadWin32Thread(), &Msg->Msg, RemoveMessages))
+   if (IntGetPaintMessage(hWnd, MsgFilterMin, MsgFilterMax, pti, &Msg->Msg, RemoveMessages))
    {
       Msg->FreeLParam = FALSE;
-      return TRUE;
+      goto MsgExit;
    }
 
    /* Check for WM_(SYS)TIMER messages */
@@ -803,7 +894,7 @@ MessageFound:
 //            UserDereferenceObject(MsgWindow);
 //         }
 
-         return TRUE;
+         goto MsgExit;
       }
 
       if((Msg->Msg.hwnd && Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST) &&
@@ -814,14 +905,63 @@ MessageFound:
          /* eat the message, search again */
          goto CheckMessages;
       }
-
+MsgExit:
+      if ( ISITHOOKED(WH_MOUSE) &&
+           Msg->Msg.message >= WM_MOUSEFIRST &&
+           Msg->Msg.message <= WM_MOUSELAST )
+      {
+         MHook.pt           = Msg->Msg.pt;
+         MHook.hwnd         = Msg->Msg.hwnd;
+         MHook.wHitTestCode = HitTest;
+         MHook.dwExtraInfo  = 0;
+         if (co_HOOK_CallHooks( WH_MOUSE,
+                                RemoveMsg ? HC_ACTION : HC_NOREMOVE,
+                                Msg->Msg.message,
+                                (LPARAM)&MHook ))
+         {
+            if (ISITHOOKED(WH_CBT))
+            {
+                MHook.pt           = Msg->Msg.pt;
+                MHook.hwnd         = Msg->Msg.hwnd;
+                MHook.wHitTestCode = HitTest;
+                MHook.dwExtraInfo  = 0;
+                co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED,
+                                   Msg->Msg.message, (LPARAM)&MHook);
+            }
+            return FALSE;
+         }
+      }
+      if ( ISITHOOKED(WH_KEYBOARD) &&
+          (Msg->Msg.message == WM_KEYDOWN || Msg->Msg.message == WM_KEYUP) )
+      {
+         if (co_HOOK_CallHooks( WH_KEYBOARD,
+                                RemoveMsg ? HC_ACTION : HC_NOREMOVE,
+                                LOWORD(Msg->Msg.wParam),
+                                Msg->Msg.lParam))
+         {
+            if (ISITHOOKED(WH_CBT))
+            {
+               /* skip this message */
+               co_HOOK_CallHooks( WH_CBT, HCBT_KEYSKIPPED,
+                                  LOWORD(Msg->Msg.wParam), Msg->Msg.lParam );
+            }
+            return FALSE;
+         }
+      }
+      // The WH_GETMESSAGE hook enables an application to monitor messages about to
+      // be returned by the GetMessage or PeekMessage function.
+      if (ISITHOOKED(WH_GETMESSAGE))
+      {
+         //DPRINT1("Peek WH_GETMESSAGE -> %x\n",&Msg);
+         co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)&Msg->Msg);
+      }
       return TRUE;
    }
 
    return Present;
 }
 
-BOOL STDCALL
+BOOL APIENTRY
 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
                   HWND hWnd,
                   UINT MsgFilterMin,
@@ -859,6 +999,7 @@ NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
    Present = co_IntPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg);
    if (Present)
    {
+
       Info.Msg = Msg.Msg;
       /* See if this message type is present in the table */
       MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
@@ -918,11 +1059,13 @@ co_IntWaitMessage(HWND Wnd,
                   UINT MsgFilterMin,
                   UINT MsgFilterMax)
 {
+   PTHREADINFO pti;
    PUSER_MESSAGE_QUEUE ThreadQueue;
    NTSTATUS Status;
    USER_MESSAGE Msg;
 
-   ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetCurrentThreadWin32Thread()->MessageQueue;
+   pti = PsGetCurrentThreadWin32Thread();
+   ThreadQueue = pti->MessageQueue;
 
    do
    {
@@ -941,7 +1084,7 @@ co_IntWaitMessage(HWND Wnd,
    return FALSE;
 }
 
-BOOL STDCALL
+BOOL APIENTRY
 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
                  HWND hWnd,
                  UINT MsgFilterMin,
@@ -960,6 +1103,7 @@ NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
    BOOL GotMessage;
    NTUSERGETMESSAGEINFO Info;
    NTSTATUS Status;
+   /* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */
    PWINDOW_OBJECT Window = NULL;
    PMSGMEMORY MsgMemoryEntry;
    PVOID UserMem;
@@ -1053,20 +1197,6 @@ CLEANUP:
    END_CLEANUP;
 }
 
-LRESULT STDCALL
-NtUserMessageCall(
-   HWND hWnd,
-   UINT Msg,
-   WPARAM wParam,
-   LPARAM lParam,
-   ULONG_PTR ResultInfo,
-   DWORD dwType,
-   BOOL Ansi)
-{
-   UNIMPLEMENTED
-
-   return 0;
-}
 
 static NTSTATUS FASTCALL
 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
@@ -1106,7 +1236,7 @@ CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEnt
          if (! NT_SUCCESS(Status))
          {
             DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
-            ExFreePool(KernelMem);
+            ExFreePoolWithTag(KernelMem, TAG_MSG);
             return Status;
          }
       }
@@ -1168,14 +1298,16 @@ UserPostMessage(HWND Wnd,
                 WPARAM wParam,
                 LPARAM lParam)
 {
+   PTHREADINFO pti;
    MSG UserModeMsg, KernelModeMsg;
    LARGE_INTEGER LargeTickCount;
    NTSTATUS Status;
    PMSGMEMORY MsgMemoryEntry;
 
+   pti = PsGetCurrentThreadWin32Thread();
    if (WM_QUIT == Msg)
    {
-      MsqPostQuitMessage(PsGetCurrentThreadWin32Thread()->MessageQueue, wParam);
+      MsqPostQuitMessage(pti->MessageQueue, wParam);
    }
    else if (Wnd == HWND_BROADCAST)
    {
@@ -1220,7 +1352,7 @@ UserPostMessage(HWND Wnd,
          SetLastWin32Error(ERROR_INVALID_PARAMETER);
          return FALSE;
       }
-      IntGetCursorLocation(PsGetCurrentThreadWin32Thread()->Desktop->WindowStation,
+      IntGetCursorLocation(pti->Desktop->WindowStation,
                            &KernelModeMsg.pt);
       KeQueryTickCount(&LargeTickCount);
       KernelModeMsg.time = MsqCalculateMessageTime(&LargeTickCount);
@@ -1233,7 +1365,7 @@ UserPostMessage(HWND Wnd,
 }
 
 
-BOOL STDCALL
+BOOL APIENTRY
 NtUserPostMessage(HWND hWnd,
                   UINT Msg,
                   WPARAM wParam,
@@ -1254,7 +1386,7 @@ CLEANUP:
 
 
 
-BOOL STDCALL
+BOOL APIENTRY
 NtUserPostThreadMessage(DWORD idThread,
                         UINT Msg,
                         WPARAM wParam,
@@ -1262,7 +1394,7 @@ NtUserPostThreadMessage(DWORD idThread,
 {
    MSG UserModeMsg, KernelModeMsg;
    PETHREAD peThread;
-   PW32THREAD pThread;
+   PTHREADINFO pThread;
    NTSTATUS Status;
    PMSGMEMORY MsgMemoryEntry;
    DECLARE_RETURN(BOOL);
@@ -1274,7 +1406,7 @@ NtUserPostThreadMessage(DWORD idThread,
 
    if( Status == STATUS_SUCCESS )
    {
-      pThread = (PW32THREAD)peThread->Tcb.Win32Thread;
+      pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
       if( !pThread || !pThread->MessageQueue )
       {
          ObDereferenceObject( peThread );
@@ -1311,7 +1443,7 @@ CLEANUP:
    END_CLEANUP;
 }
 
-DWORD STDCALL
+DWORD APIENTRY
 NtUserQuerySendMessage(DWORD Unknown0)
 {
    UNIMPLEMENTED;
@@ -1349,11 +1481,10 @@ co_IntSendMessageTimeoutSingle(HWND hWnd,
    PMSGMEMORY MsgMemoryEntry;
    INT lParamBufferSize;
    LPARAM lParamPacked;
-   PW32THREAD Win32Thread;
+   PTHREADINFO Win32Thread;
    DECLARE_RETURN(LRESULT);
    USER_REFERENCE_ENTRY Ref;
 
-   /* FIXME: Call hooks. */
    if (!(Window = UserGetWindowObject(hWnd)))
    {
        RETURN( FALSE);
@@ -1363,8 +1494,10 @@ co_IntSendMessageTimeoutSingle(HWND hWnd,
 
    Win32Thread = PsGetCurrentThreadWin32Thread();
 
+   IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
+
    if (NULL != Win32Thread &&
-         Window->MessageQueue == Win32Thread->MessageQueue)
+       Window->MessageQueue == Win32Thread->MessageQueue)
    {
       if (Win32Thread->IsExiting)
       {
@@ -1385,7 +1518,7 @@ co_IntSendMessageTimeoutSingle(HWND hWnd,
 
       if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam)))
       {
-         DPRINT1("Failed to pack message parameters\n");
+          DPRINT1("Failed to pack message parameters\n");
           RETURN( FALSE);
       }
 
@@ -1397,42 +1530,65 @@ co_IntSendMessageTimeoutSingle(HWND hWnd,
          *uResult = Result;
       }
 
+      IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
+
       if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam)))
       {
          DPRINT1("Failed to unpack message parameters\n");
-          RETURN( TRUE);
+         RETURN( TRUE);
       }
 
-       RETURN( TRUE);
+      RETURN( TRUE);
    }
 
-   if(uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->MessageQueue))
+   if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->MessageQueue))
    {
       /* FIXME - Set a LastError? */
-       RETURN( FALSE);
+      RETURN( FALSE);
    }
 
-   if(Window->Status & WINDOWSTATUS_DESTROYING)
+   if (Window->Status & WINDOWSTATUS_DESTROYING)
    {
       /* FIXME - last error? */
       DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
-       RETURN( FALSE);
+      RETURN( FALSE);
    }
 
-   Status = co_MsqSendMessage(Window->MessageQueue, hWnd, Msg, wParam, lParam,
-                              uTimeout, (uFlags & SMTO_BLOCK), FALSE, uResult);
+   do
+   {
+      Status = co_MsqSendMessage( Window->MessageQueue,
+                                                  hWnd,
+                                                   Msg,
+                                                wParam,
+                                                lParam,
+                                              uTimeout,
+                                 (uFlags & SMTO_BLOCK),
+                                            MSQ_NORMAL,
+                                               uResult);
+   }
+   while ((STATUS_TIMEOUT == Status) &&
+          (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
+          !MsqIsHung(Window->MessageQueue));
 
+   IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
 
    if (STATUS_TIMEOUT == Status)
    {
-      /* MSDN says GetLastError() should return 0 after timeout */
-      SetLastWin32Error(0);
-       RETURN( FALSE);
+/*
+   MSDN says:
+      Microsoft Windows 2000: If GetLastError returns zero, then the function
+      timed out.
+      XP+ : If the function fails or times out, the return value is zero.
+      To get extended error information, call GetLastError. If GetLastError
+      returns ERROR_TIMEOUT, then the function timed out.
+ */
+      SetLastWin32Error(ERROR_TIMEOUT);
+      RETURN( FALSE);
    }
    else if (! NT_SUCCESS(Status))
    {
       SetLastNtError(Status);
-       RETURN( FALSE);
+      RETURN( FALSE);
    }
 
    RETURN( TRUE);
@@ -1494,6 +1650,7 @@ co_IntPostOrSendMessage(HWND hWnd,
                         LPARAM lParam)
 {
    ULONG_PTR Result;
+   PTHREADINFO pti;
    PWINDOW_OBJECT Window;
 
    if(hWnd == HWND_BROADCAST)
@@ -1506,14 +1663,14 @@ co_IntPostOrSendMessage(HWND hWnd,
       return 0;
    }
 
-   if(Window->MessageQueue != PsGetCurrentThreadWin32Thread()->MessageQueue)
+   pti = PsGetCurrentThreadWin32Thread();
+   if(Window->MessageQueue != pti->MessageQueue)
    {
       Result = UserPostMessage(hWnd, Msg, wParam, lParam);
    }
    else
    {
-      if(!co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
-      {
+      if(!co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))      {
          Result = 0;
       }
    }
@@ -1529,9 +1686,10 @@ co_IntDoSendMessage(HWND hWnd,
                     PDOSENDMESSAGE dsm,
                     PNTUSERSENDMESSAGEINFO UnsafeInfo)
 {
+   PTHREADINFO pti;
    LRESULT Result = TRUE;
    NTSTATUS Status;
-   PWINDOW_OBJECT Window;
+   PWINDOW_OBJECT Window = NULL;
    NTUSERSENDMESSAGEINFO Info;
    MSG UserModeMsg;
    MSG KernelModeMsg;
@@ -1557,8 +1715,9 @@ co_IntDoSendMessage(HWND hWnd,
    /* FIXME: Check for an exiting window. */
 
    /* See if the current thread can handle the message */
-   if (HWND_BROADCAST != hWnd && NULL != PsGetCurrentThreadWin32Thread() &&
-         Window->MessageQueue == PsGetCurrentThreadWin32Thread()->MessageQueue)
+   pti = PsGetCurrentThreadWin32Thread();
+   if (HWND_BROADCAST != hWnd && NULL != pti &&
+         Window->MessageQueue == pti->MessageQueue)
    {
       /* Gather the information usermode needs to call the window proc directly */
       Info.HandledByKernel = FALSE;
@@ -1570,6 +1729,8 @@ co_IntDoSendMessage(HWND hWnd,
          Info.Ansi = ! Window->Wnd->Unicode;
       }
 
+      IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
+
       if (Window->Wnd->IsSystem)
       {
           Info.Proc = (!Info.Ansi ? Window->Wnd->WndProc : Window->Wnd->WndProcExtra);
@@ -1579,6 +1740,9 @@ co_IntDoSendMessage(HWND hWnd,
           Info.Ansi = !Window->Wnd->Unicode;
           Info.Proc = Window->Wnd->WndProc;
       }
+
+      IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, &Result);
+
    }
    else
    {
@@ -1629,7 +1793,7 @@ co_IntDoSendMessage(HWND hWnd,
    return (LRESULT)Result;
 }
 
-LRESULT STDCALL
+LRESULT APIENTRY
 NtUserSendMessageTimeout(HWND hWnd,
                          UINT Msg,
                          WPARAM wParam,
@@ -1668,7 +1832,7 @@ CLEANUP:
    END_CLEANUP;
 }
 
-LRESULT STDCALL
+LRESULT APIENTRY
 NtUserSendMessage(HWND Wnd,
                   UINT Msg,
                   WPARAM wParam,
@@ -1718,6 +1882,7 @@ UserSendNotifyMessage(HWND hWnd,
    else
    {
      ULONG_PTR PResult;
+     PTHREADINFO pti;
      PWINDOW_OBJECT Window;
      NTSTATUS Status;
      MSG UserModeMsg;
@@ -1726,7 +1891,8 @@ UserSendNotifyMessage(HWND hWnd,
 
       if(!(Window = UserGetWindowObject(hWnd))) return FALSE;
 
-      if(Window->MessageQueue != PsGetCurrentThreadWin32Thread()->MessageQueue)
+      pti = PsGetCurrentThreadWin32Thread();
+      if(Window->MessageQueue != pti->MessageQueue)
       { // Send message w/o waiting for it.
          Result = UserPostMessage(hWnd, Msg, wParam, lParam);
       }
@@ -1760,7 +1926,7 @@ UserSendNotifyMessage(HWND hWnd,
 }
 
 
-BOOL STDCALL
+BOOL APIENTRY
 NtUserSendNotifyMessage(HWND hWnd,
                         UINT Msg,
                         WPARAM wParam,
@@ -1781,7 +1947,7 @@ CLEANUP:
 }
 
 
-BOOL STDCALL
+BOOL APIENTRY
 NtUserWaitMessage(VOID)
 {
    DECLARE_RETURN(BOOL);
@@ -1797,16 +1963,18 @@ CLEANUP:
    END_CLEANUP;
 }
 
-DWORD STDCALL
+DWORD APIENTRY
 IntGetQueueStatus(BOOL ClearChanges)
 {
+   PTHREADINFO pti;
    PUSER_MESSAGE_QUEUE Queue;
    DWORD Result;
    DECLARE_RETURN(DWORD);
 
    DPRINT("Enter IntGetQueueStatus\n");
 
-   Queue = PsGetCurrentThreadWin32Thread()->MessageQueue;
+   pti = PsGetCurrentThreadWin32Thread();
+   Queue = pti->MessageQueue;
 
    Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
    if (ClearChanges)
@@ -1821,107 +1989,328 @@ CLEANUP:
    END_CLEANUP;
 }
 
-BOOL STDCALL
+BOOL APIENTRY
 IntInitMessagePumpHook()
 {
-   if (((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo)
+   if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo)
    {
-     ((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook++;
+     ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook++;
      return TRUE;
    }
    return FALSE;
 }
 
-BOOL STDCALL
+BOOL APIENTRY
 IntUninitMessagePumpHook()
 {
-   if (((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo)
+   if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo)
    {
-      if (((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook <= 0)
+      if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook <= 0)
       {
          return FALSE;
       }
-      ((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook--;
+      ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook--;
       return TRUE;
    }
    return FALSE;
 }
 
+
+LRESULT APIENTRY
+NtUserMessageCall(
+   HWND hWnd,
+   UINT Msg,
+   WPARAM wParam,
+   LPARAM lParam,
+   ULONG_PTR ResultInfo,
+   DWORD dwType, // fnID?
+   BOOL Ansi)
+{
+   LRESULT lResult = 0;
+   PWINDOW_OBJECT Window = NULL;
+   USER_REFERENCE_ENTRY Ref;
+
+   UserEnterExclusive();
+
+   /* Validate input */
+   if (hWnd && (hWnd != INVALID_HANDLE_VALUE) && !(Window = UserGetWindowObject(hWnd)))
+   {
+      return 0;
+   }
+   switch(dwType)
+   {
+      case FNID_DEFWINDOWPROC:
+         UserRefObjectCo(Window, &Ref);
+         lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
+         UserDerefObjectCo(Window);
+      break;
+      case FNID_BROADCASTSYSTEMMESSAGE:
+      {
+         PBROADCASTPARM parm;
+         BOOL BadChk = FALSE;
+         DWORD_PTR RetVal = 0;
+         lResult = -1;
+
+         if (ResultInfo)
+         {
+            _SEH2_TRY
+            {
+               ProbeForWrite((PVOID)ResultInfo,
+                         sizeof(BROADCASTPARM),
+                                             1);
+               parm = (PBROADCASTPARM)ResultInfo;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+               BadChk = TRUE;
+            }
+            _SEH2_END;
+            if (BadChk) break;
+         }
+         else
+           break;
+
+         if ( parm->recipients & BSM_ALLDESKTOPS ||
+              parm->recipients == BSM_ALLCOMPONENTS )
+         {
+         }
+         else if (parm->recipients & BSM_APPLICATIONS)
+         {
+            if (parm->flags & BSF_QUERY)
+            {
+               if (parm->flags & BSF_FORCEIFHUNG || parm->flags & BSF_NOHANG)
+               {
+                  co_IntSendMessageTimeout( HWND_BROADCAST,
+                                            Msg,
+                                            wParam,
+                                            lParam,
+                                            SMTO_ABORTIFHUNG,
+                                            2000,
+                                            &RetVal);
+               }
+               else if (parm->flags & BSF_NOTIMEOUTIFNOTHUNG)
+               {
+                  co_IntSendMessageTimeout( HWND_BROADCAST,
+                                            Msg,
+                                            wParam,
+                                            lParam,
+                                            SMTO_NOTIMEOUTIFNOTHUNG,
+                                            2000,
+                                            &RetVal);
+               }
+               else
+               {
+                  co_IntSendMessageTimeout( HWND_BROADCAST,
+                                            Msg,
+                                            wParam,
+                                            lParam,
+                                            SMTO_NORMAL,
+                                            2000,
+                                            &RetVal);
+               }
+            }
+            else if (parm->flags & BSF_POSTMESSAGE)
+            {
+               lResult = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
+            }
+            else if ( parm->flags & BSF_SENDNOTIFYMESSAGE)
+            {
+               lResult = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
+            }
+         }
+      }
+      break;
+      case FNID_SENDMESSAGECALLBACK:
+      break;
+      // CallNextHook bypass.
+      case FNID_CALLWNDPROC:
+      case FNID_CALLWNDPROCRET:
+      {
+         PCLIENTINFO ClientInfo = GetWin32ClientInfo();
+         PHOOK NextObj, Hook = ClientInfo->phkCurrent;
+
+         if (!ClientInfo || !Hook) break;
+
+         UserReferenceObject(Hook);
+
+         if (Hook->Thread && (Hook->Thread != PsGetCurrentThread()))
+         {
+            UserDereferenceObject(Hook);
+            break;
+         }
+
+         NextObj = IntGetNextHook(Hook);
+         ClientInfo->phkCurrent = NextObj;
+
+         if ( Hook->HookId == WH_CALLWNDPROC)
+         {
+            CWPSTRUCT CWP;
+            CWP.hwnd    = hWnd;
+            CWP.message = Msg;
+            CWP.wParam  = wParam;
+            CWP.lParam  = lParam;
+            DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
+
+            lResult = co_IntCallHookProc( Hook->HookId,
+                                          HC_ACTION,
+                                        ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
+                                         (LPARAM)&CWP,
+                                          Hook->Proc,
+                                          Hook->Ansi,
+                                          &Hook->ModuleName);
+         }
+         else
+         {
+            CWPRETSTRUCT CWPR;
+            CWPR.hwnd    = hWnd;
+            CWPR.message = Msg;
+            CWPR.wParam  = wParam;
+            CWPR.lParam  = lParam;
+            CWPR.lResult = ClientInfo->dwHookData;
+
+            lResult = co_IntCallHookProc( Hook->HookId,
+                                          HC_ACTION,
+                                        ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
+                                         (LPARAM)&CWPR,
+                                          Hook->Proc,
+                                          Hook->Ansi,
+                                          &Hook->ModuleName);
+         }
+         UserDereferenceObject(Hook);
+         lResult = (LRESULT) NextObj;
+      }
+      break;
+   }
+   UserLeave();
+   return lResult;
+}
+
+#define INFINITE 0xFFFFFFFF
+#define WAIT_FAILED ((DWORD)0xFFFFFFFF)
+
 DWORD
-NTAPI
+APIENTRY
 NtUserWaitForInputIdle(
    IN HANDLE hProcess,
    IN DWORD dwMilliseconds,
    IN BOOL Unknown2)
 {
-  ULONGLONG start_time, elapsed, run;
-  DWORD ret;
-  LARGE_INTEGER Timeout; 
-  HANDLE handles[2];
+  PEPROCESS Process;
+  PW32PROCESS W32Process;
+  NTSTATUS Status;
+  HANDLE Handles[2];
+  LARGE_INTEGER Timeout;
+  ULONGLONG StartTime, Run, Elapsed = 0;
 
   UserEnterExclusive();
 
-  handles[0] = hProcess;
-  handles[1] = &PsGetCurrentProcessWin32Process()->InputIdleEvent; // Fixme!
+  Status = ObReferenceObjectByHandle(hProcess,
+                                     PROCESS_QUERY_INFORMATION,
+                                     PsProcessType,
+                                     UserMode,
+                                     (PVOID*)&Process,
+                                     NULL);
 
-  if (!handles[1]) return 0;  /* no event to wait on */
+  if (!NT_SUCCESS(Status))
+  {
+     UserLeave();
+     SetLastNtError(Status);
+     return WAIT_FAILED;
+  }
+
+  W32Process = (PW32PROCESS)Process->Win32Process;
+  if (!W32Process)
+  {
+      ObDereferenceObject(Process);
+      UserLeave();
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      return WAIT_FAILED;
+  }
+
+  EngCreateEvent((PEVENT *)&W32Process->InputIdleEvent);
+
+  Handles[0] = Process;
+  Handles[1] = W32Process->InputIdleEvent;
+
+  if (!Handles[1])
+  {
+      ObDereferenceObject(Process);
+      UserLeave();
+      return STATUS_SUCCESS;  /* no event to wait on */
+  }
+
+  StartTime = EngGetTickCount();
 
-  start_time = ((ULONGLONG)SharedUserData->TickCountLowDeprecated *
-                           SharedUserData->TickCountMultiplier / 16777216);
-  elapsed = 0;
-  run = dwMilliseconds;
+  Run = dwMilliseconds;
 
-  DPRINT("waiting for %p\n", handles[1] );
+  DPRINT("WFII: waiting for %p\n", Handles[1] );
   do
   {
-     Timeout.QuadPart = run - elapsed;
+     Timeout.QuadPart = Run - Elapsed;
      UserLeave();
-     ret = KeWaitForMultipleObjects( 2,
-                               handles,
-                               WaitAny,
-                           UserRequest,
-                              UserMode,
-                                 FALSE,
-                              &Timeout,
-                                  NULL);
+     Status = KeWaitForMultipleObjects( 2,
+                                        Handles,
+                                        WaitAny,
+                                        UserRequest,
+                                        UserMode,
+                                        FALSE,
+                             dwMilliseconds == INFINITE ? NULL : &Timeout,
+                                        NULL);
      UserEnterExclusive();
 
-     switch (ret)
+     if (!NT_SUCCESS(Status))
      {
-       case STATUS_WAIT_0:
-         ret = (DWORD)-1;
-         goto WaitExit;
-       case STATUS_WAIT_2:
-       {
-         USER_MESSAGE msg;
-         co_IntPeekMessage( &msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE );
-         break;
-       }
-       case STATUS_USER_APC:
-       case STATUS_ALERTED:
-       case STATUS_TIMEOUT:
-         DPRINT1("timeout\n");
-         ret = STATUS_TIMEOUT;
-         goto WaitExit;
-       default:
-         DPRINT1("finished\n");
-         ret = 0;
-         goto WaitExit;
+        SetLastNtError(Status);
+        Status = WAIT_FAILED;
+        goto WaitExit;
      }
-     if (dwMilliseconds != -1 ) //INFINITE)
+
+     switch (Status)
      {
-        elapsed = ((ULONGLONG)SharedUserData->TickCountLowDeprecated *
-                              SharedUserData->TickCountMultiplier / 16777216) - start_time;
+        case STATUS_WAIT_0:
+           Status = WAIT_FAILED;
+           goto WaitExit;
+
+        case STATUS_WAIT_2:
+        {
+           USER_MESSAGE Msg;
+           co_IntPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE );
+           break;
+        }
+
+        case STATUS_USER_APC:
+        case STATUS_ALERTED:
+        case STATUS_TIMEOUT:
+           DPRINT1("WFII: timeout\n");
+           Status = STATUS_TIMEOUT;
+           goto WaitExit;
+
+        default:
+           DPRINT1("WFII: finished\n");
+           Status = STATUS_SUCCESS;
+           goto WaitExit;
+     }
 
-        if (elapsed > run)
-           ret = STATUS_TIMEOUT;
+     if (dwMilliseconds != INFINITE)
+     {
+        Elapsed = EngGetTickCount() - StartTime;
+
+        if (Elapsed > Run)
+           Status = STATUS_TIMEOUT;
            break;
      }
   }
   while (1);
+
 WaitExit:
+  if (W32Process->InputIdleEvent)
+  {
+     EngDeleteEvent((PEVENT)W32Process->InputIdleEvent);
+     W32Process->InputIdleEvent = NULL;
+  }
+  ObDereferenceObject(Process);
   UserLeave();
-  return ret;
+  return Status;
 }
 
 /* EOF */