Sync to trunk head (r42241)
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / message.c
index b6005ca..a96d05d 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)
       {
@@ -157,6 +156,10 @@ MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
                Size = sizeof(COPYDATASTRUCT) + ((PCOPYDATASTRUCT)lParam)->cbData;
                break;
 
+            case WM_COPYGLOBALDATA:
+               Size = wParam;
+               break;
+
             default:
                assert(FALSE);
                Size = 0;
@@ -167,13 +170,13 @@ 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,114 +299,205 @@ UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
    return STATUS_INVALID_PARAMETER;
 }
 
-BOOL
-STDCALL
-NtUserCallMsgFilter(
-   LPMSG msg,
-   INT code)
+static
+VOID
+FASTCALL
+IntCallWndProc
+( PWINDOW_OBJECT Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
 {
-   DECLARE_RETURN(BOOL);
-
-   DPRINT("Enter NtUserCallMsgFilter\n");
-   UserEnterExclusive();
+   BOOL SameThread = FALSE;
 
-   if (co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)msg))
-      RETURN( TRUE);
-   RETURN( co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)msg));
+   if (Window->ti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->ThreadInfo)
+      SameThread = TRUE;
 
-CLEANUP:
-   DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_);
-   UserLeave();
-   END_CLEANUP;
+   if ((!SameThread && (Window->ti->fsHooks & 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 );
+   }
 }
-
-LRESULT STDCALL
-NtUserDispatchMessage(PNTUSERDISPATCHMESSAGEINFO UnsafeMsgInfo)
+static
+VOID
+FASTCALL
+IntCallWndProcRet
+( PWINDOW_OBJECT Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *uResult)
 {
-   NTSTATUS Status;
-   NTUSERDISPATCHMESSAGEINFO MsgInfo;
-   LRESULT Result = TRUE;
-   DECLARE_RETURN(LRESULT);
+   BOOL SameThread = FALSE;
 
-   DPRINT("Enter NtUserDispatchMessage\n");
-   UserEnterExclusive();
+   if (Window->ti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->ThreadInfo)
+      SameThread = TRUE;
 
-   Status = MmCopyFromCaller(&MsgInfo, UnsafeMsgInfo, sizeof(NTUSERDISPATCHMESSAGEINFO));
-   if (! NT_SUCCESS(Status))
+   if ((!SameThread && (Window->ti->fsHooks & HOOKID_TO_FLAG(WH_CALLWNDPROCRET))) ||
+        (SameThread && ISITHOOKED(WH_CALLWNDPROCRET)) )
    {
-      SetLastNtError(Status);
-      RETURN( 0);
+      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 );
    }
+}
 
-   /* Process timer messages. */
-   if (WM_TIMER == MsgInfo.Msg.message && 0 != MsgInfo.Msg.lParam)
-   {
-      LARGE_INTEGER LargeTickCount;
-      /* FIXME: Call hooks. */
+LRESULT
+FASTCALL
+IntDispatchMessage(PMSG pMsg)
+{
+  LARGE_INTEGER TickCount;
+  LONG Time;
+  LRESULT retval;
+  PWINDOW_OBJECT Window = NULL;
+
+  if (pMsg->hwnd)
+  {
+     Window = UserGetWindowObject(pMsg->hwnd);
+     if (!Window || !Window->Wnd) return 0;
+  }
+
+  if (((pMsg->message == WM_SYSTIMER) ||
+       (pMsg->message == WM_TIMER)) &&
+      (pMsg->lParam) )
+  {
+     if (pMsg->message == WM_TIMER)
+     {
+        if (ValidateTimerCallback(PsGetCurrentThreadWin32Thread(),Window,pMsg->wParam,pMsg->lParam))
+        {
+           KeQueryTickCount(&TickCount);
+           Time = MsqCalculateMessageTime(&TickCount);
+           return co_IntCallWindowProc((WNDPROC)pMsg->lParam,
+                                        TRUE,
+                                        pMsg->hwnd,
+                                        WM_TIMER,
+                                        pMsg->wParam,
+                                        (LPARAM)Time,
+                                        sizeof(LPARAM));
+        }
+        return 0;        
+     }
+     else
+     {
+        PTIMER pTimer = FindSystemTimer(pMsg);
+        if (pTimer && pTimer->pfn)
+        {
+           KeQueryTickCount(&TickCount);
+           Time = MsqCalculateMessageTime(&TickCount);
+           pTimer->pfn(pMsg->hwnd, WM_SYSTIMER, (UINT)pMsg->wParam, Time);
+        }
+        return 0;
+     }
+  }
+  // Need a window!
+  if (!Window) return 0;
+
+  retval = co_IntPostOrSendMessage(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam);
+
+  if (pMsg->message == WM_PAINT)
+  {
+  /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
+     HRGN hrgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
+     co_UserGetUpdateRgn( Window, hrgn, TRUE );
+     GreDeleteObject( hrgn );
+  }
+  return retval;
+}
 
-      /* FIXME: Check for continuing validity of timer. */
 
-      MsgInfo.HandledByKernel = FALSE;
-      KeQueryTickCount(&LargeTickCount);
-      MsgInfo.Proc = (WNDPROC) MsgInfo.Msg.lParam;
-      MsgInfo.Msg.lParam = (LPARAM)LargeTickCount.u.LowPart;
-   }
-   else if (NULL == MsgInfo.Msg.hwnd)
-   {
-      MsgInfo.HandledByKernel = TRUE;
-      Result = 0;
-   }
-   else
+BOOL
+APIENTRY
+NtUserCallMsgFilter(
+   LPMSG lpmsg,
+   INT code)
+{
+   BOOL BadChk = FALSE, Ret = TRUE;
+   MSG Msg;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserCallMsgFilter\n");
+   UserEnterExclusive();
+   if (lpmsg)
    {
-      PWINDOW_OBJECT Window;
-      
-      /* Get the window object. */
-      Window = UserGetWindowObject(MsgInfo.Msg.hwnd);
-      if (NULL == Window)
+      _SEH2_TRY
       {
-         MsgInfo.HandledByKernel = TRUE;
-         Result = 0;
+         ProbeForRead((PVOID)lpmsg,
+                       sizeof(MSG),
+                                1);
+         RtlCopyMemory( &Msg,
+                (PVOID)lpmsg,
+                 sizeof(MSG));
       }
-      else
+      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
       {
-         if (Window->OwnerThread != PsGetCurrentThread())
-         {
-            DPRINT1("Window doesn't belong to the calling thread!\n");
-            MsgInfo.HandledByKernel = TRUE;
-            Result = 0;
-         }
-         else
-         {
-            /* FIXME: Call hook procedures. */
-
-            MsgInfo.HandledByKernel = FALSE;
-            Result = 0;
-
-            MsgInfo.Ansi = !Window->Unicode;
-            if (Window->IsSystem)
-                MsgInfo.Proc = (Window->Unicode ? Window->WndProc : Window->WndProcExtra);
-            else
-                MsgInfo.Proc = Window->WndProc;
-         }
+         BadChk = TRUE;
       }
+      _SEH2_END;
    }
-   Status = MmCopyToCaller(UnsafeMsgInfo, &MsgInfo, sizeof(NTUSERDISPATCHMESSAGEINFO));
-   if (! NT_SUCCESS(Status))
+   else
+     RETURN( FALSE);
+
+   if (BadChk) RETURN( FALSE);
+
+   if (!co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
    {
-      SetLastNtError(Status);
-      RETURN( 0);
+      Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
    }
 
-   RETURN( Result);
+   _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 NtUserDispatchMessage. ret=%i\n", _ret_);
+   DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_);
    UserLeave();
    END_CLEANUP;
 }
 
+LRESULT APIENTRY
+NtUserDispatchMessage(PMSG UnsafeMsgInfo)
+{
+  LRESULT Res = 0;
+  BOOL Hit = FALSE;
+  MSG SafeMsg;
+
+  UserEnterExclusive();  
+  _SEH2_TRY
+  {
+    ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
+    RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
+  }
+  _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+  {
+    SetLastNtError(_SEH2_GetExceptionCode());
+    Hit = TRUE;
+  }
+  _SEH2_END;
+  
+  if (!Hit) Res = IntDispatchMessage(&SafeMsg);
+
+  UserLeave();
+  return Res;
+}
+
 
-BOOL STDCALL
+BOOL APIENTRY
 NtUserTranslateMessage(LPMSG lpMsg,
                        HKL dwhkl)
 {
@@ -506,10 +600,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)
                              );
 
@@ -560,9 +655,9 @@ co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *
          if((DesktopWindow = UserGetWindowObject(hDesktop)))
          {
             PWINDOW_OBJECT Wnd;
-            
+
             UserRefObjectCo(DesktopWindow, &DesktopRef);
-            
+
             co_WinPosWindowFromPoint(DesktopWindow, Window->MessageQueue, &Msg->pt, &Wnd);
             if(Wnd)
             {
@@ -578,12 +673,12 @@ co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *
                   }
 
                   /* eat the message */
-                  UserDerefObject(Wnd);
+                  UserDereferenceObject(Wnd);
                   UserDerefObjectCo(DesktopWindow);
                   UserDerefObjectCo(Window);
                   return TRUE;
                }
-               UserDerefObject(Wnd);
+               UserDereferenceObject(Wnd);
             }
 
             UserDerefObjectCo(DesktopWindow);
@@ -599,7 +694,7 @@ co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *
    {
       /* generate double click messages, if necessary */
       if ((((*HitTest) != HTCLIENT) ||
-            (Window->Class->Style & CS_DBLCLKS)) &&
+            (Window->Wnd->pcls->style & CS_DBLCLKS)) &&
             MsqIsDblClk(Msg, Remove))
       {
          Msg->message += WM_LBUTTONDBLCLK - WM_LBUTTONDOWN;
@@ -629,8 +724,8 @@ co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *
       {
          /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
          Msg->lParam = MAKELONG(
-                          Msg->pt.x - (WORD)Window->ClientRect.left,
-                          Msg->pt.y - (WORD)Window->ClientRect.top);
+                          Msg->pt.x - (WORD)Window->Wnd->rcClient.left,
+                          Msg->pt.y - (WORD)Window->Wnd->rcClient.top);
       }
    }
 
@@ -644,22 +739,25 @@ co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *
  */
 BOOL FASTCALL
 co_IntPeekMessage(PUSER_MESSAGE Msg,
-                  HWND hWnd,
+                  PWINDOW_OBJECT Window,
                   UINT MsgFilterMin,
                   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)PsGetWin32Thread()->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 */
@@ -691,14 +789,14 @@ CheckMessages:
       {
          ThreadQueue->QuitPosted = FALSE;
       }
-      return TRUE;
+      goto MsgExit;
    }
 
    /* Now check for normal messages. */
    Present = co_MsqFindMessage(ThreadQueue,
                                FALSE,
                                RemoveMessages,
-                               hWnd,
+                               Window,
                                MsgFilterMin,
                                MsgFilterMax,
                                &Message);
@@ -716,7 +814,7 @@ CheckMessages:
    Present = co_MsqFindMessage(ThreadQueue,
                                TRUE,
                                RemoveMessages,
-                               hWnd,
+                               Window,
                                MsgFilterMin,
                                MsgFilterMax,
                                &Message);
@@ -735,14 +833,19 @@ CheckMessages:
       ;
 
    /* Check for paint messages. */
-   if (IntGetPaintMessage(hWnd, MsgFilterMin, MsgFilterMax, PsGetWin32Thread(), &Msg->Msg, RemoveMessages))
+   if (IntGetPaintMessage(Window, MsgFilterMin, MsgFilterMax, pti, &Msg->Msg, RemoveMessages))
    {
       Msg->FreeLParam = FALSE;
-      return TRUE;
+      goto MsgExit;
    }
 
+   if (ThreadQueue->WakeMask & QS_TIMER)
+      if (PostTimerMessages(Window)) // If there are timers ready,
+         goto CheckMessages;       // go back and process them.
+
+   // LOL! Polling Timer Queue? How much time is spent doing this?
    /* Check for WM_(SYS)TIMER messages */
-   Present = MsqGetTimerMessage(ThreadQueue, hWnd, MsgFilterMin, MsgFilterMax,
+   Present = MsqGetTimerMessage(ThreadQueue, Window, MsgFilterMin, MsgFilterMax,
                                 &Msg->Msg, RemoveMessages);
    if (Present)
    {
@@ -786,7 +889,7 @@ MessageFound:
                   goto CheckMessages;
                }
             }
-            
+
             UserDerefObjectCo(MsgWindow);
          }
          else
@@ -796,10 +899,10 @@ MessageFound:
 
 //         if(MsgWindow)
 //         {
-//            UserDerefObject(MsgWindow);
+//            UserDereferenceObject(MsgWindow);
 //         }
 
-         return TRUE;
+         goto MsgExit;
       }
 
       if((Msg->Msg.hwnd && Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST) &&
@@ -810,14 +913,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,
@@ -830,21 +982,28 @@ NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
    PWINDOW_OBJECT Window;
    PMSGMEMORY MsgMemoryEntry;
    PVOID UserMem;
-   UINT Size;
+   SIZE_T Size;
    USER_MESSAGE Msg;
    DECLARE_RETURN(BOOL);
 
    DPRINT("Enter NtUserPeekMessage\n");
    UserEnterExclusive();
 
+   if (hWnd == (HWND)-1 || hWnd == (HWND)0x0000FFFF || hWnd == (HWND)0xFFFFFFFF)
+      hWnd = (HWND)1;
+
    /* Validate input */
-   if (hWnd && hWnd != INVALID_HANDLE_VALUE)
+   if (hWnd && hWnd != (HWND)1)
    {
       if (!(Window = UserGetWindowObject(hWnd)))
       {
          RETURN(-1);
       }
    }
+   else
+   {
+      Window = (PWINDOW_OBJECT)hWnd;
+   }
 
    if (MsgFilterMax < MsgFilterMin)
    {
@@ -852,9 +1011,10 @@ NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
       MsgFilterMax = 0;
    }
 
-   Present = co_IntPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg);
+   Present = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, RemoveMsg);
    if (Present)
    {
+
       Info.Msg = Msg.Msg;
       /* See if this message type is present in the table */
       MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
@@ -872,18 +1032,18 @@ NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
          Info.LParamSize = Size;
          UserMem = NULL;
          Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
-                                          &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
+                                          &Size, MEM_COMMIT, PAGE_READWRITE);
          if (! NT_SUCCESS(Status))
          {
             SetLastNtError(Status);
             RETURN( (BOOL) -1);
          }
          /* Transfer lParam data to user-mode mem */
-         Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
+         Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Info.LParamSize);
          if (! NT_SUCCESS(Status))
          {
             ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
-                                &Info.LParamSize, MEM_DECOMMIT);
+                                &Size, MEM_RELEASE);
             SetLastNtError(Status);
             RETURN( (BOOL) -1);
          }
@@ -910,25 +1070,27 @@ CLEANUP:
 }
 
 static BOOL FASTCALL
-co_IntWaitMessage(HWND Wnd,
+co_IntWaitMessage(PWINDOW_OBJECT Window,
                   UINT MsgFilterMin,
                   UINT MsgFilterMax)
 {
+   PTHREADINFO pti;
    PUSER_MESSAGE_QUEUE ThreadQueue;
    NTSTATUS Status;
    USER_MESSAGE Msg;
 
-   ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
+   pti = PsGetCurrentThreadWin32Thread();
+   ThreadQueue = pti->MessageQueue;
 
    do
    {
-      if (co_IntPeekMessage(&Msg, Wnd, MsgFilterMin, MsgFilterMax, PM_NOREMOVE))
+      if (co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, PM_NOREMOVE))
       {
          return TRUE;
       }
 
       /* Nothing found. Wait for new messages. */
-      Status = co_MsqWaitForNewMessages(ThreadQueue, Wnd, MsgFilterMin, MsgFilterMax);
+      Status = co_MsqWaitForNewMessages(ThreadQueue, Window, MsgFilterMin, MsgFilterMax);
    }
    while ((STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) || STATUS_TIMEOUT == Status);
 
@@ -937,7 +1099,7 @@ co_IntWaitMessage(HWND Wnd,
    return FALSE;
 }
 
-BOOL STDCALL
+BOOL APIENTRY
 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
                  HWND hWnd,
                  UINT MsgFilterMin,
@@ -956,10 +1118,11 @@ 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;
-   UINT Size;
+   SIZE_T Size;
    USER_MESSAGE Msg;
    DECLARE_RETURN(BOOL);
 //   USER_REFERENCE_ENTRY Ref;
@@ -972,9 +1135,9 @@ NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
    {
       RETURN(-1);
    }
-   
+
 //   if (Window) UserRefObjectCo(Window, &Ref);
-   
+
    if (MsgFilterMax < MsgFilterMin)
    {
       MsgFilterMin = 0;
@@ -983,7 +1146,7 @@ NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
 
    do
    {
-      GotMessage = co_IntPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE);
+      GotMessage = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, PM_REMOVE);
       if (GotMessage)
       {
          Info.Msg = Msg.Msg;
@@ -1003,7 +1166,7 @@ NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
             Info.LParamSize = Size;
             UserMem = NULL;
             Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
-                                             &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
+                                             &Size, MEM_COMMIT, PAGE_READWRITE);
 
             if (! NT_SUCCESS(Status))
             {
@@ -1011,11 +1174,11 @@ NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
                RETURN( (BOOL) -1);
             }
             /* Transfer lParam data to user-mode mem */
-            Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
+            Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Info.LParamSize);
             if (! NT_SUCCESS(Status))
             {
                ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
-                                   &Info.LParamSize, MEM_DECOMMIT);
+                                   &Size, MEM_DECOMMIT);
                SetLastNtError(Status);
                RETURN( (BOOL) -1);
             }
@@ -1032,7 +1195,7 @@ NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
             RETURN( (BOOL) -1);
          }
       }
-      else if (! co_IntWaitMessage(hWnd, MsgFilterMin, MsgFilterMax))
+      else if (! co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax))
       {
          RETURN( (BOOL) -1);
       }
@@ -1049,21 +1212,6 @@ CLEANUP:
    END_CLEANUP;
 }
 
-DWORD
-STDCALL
-NtUserMessageCall(
-   DWORD Unknown0,
-   DWORD Unknown1,
-   DWORD Unknown2,
-   DWORD Unknown3,
-   DWORD Unknown4,
-   DWORD Unknown5,
-   DWORD Unknown6)
-{
-   UNIMPLEMENTED
-
-   return 0;
-}
 
 static NTSTATUS FASTCALL
 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
@@ -1103,7 +1251,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;
          }
       }
@@ -1159,22 +1307,79 @@ CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
    return STATUS_SUCCESS;
 }
 
+BOOL FASTCALL
+UserPostThreadMessage( DWORD idThread,
+                       UINT Msg,
+                       WPARAM wParam,
+                       LPARAM lParam)
+{
+   MSG Message;
+   PETHREAD peThread;
+   PTHREADINFO pThread;
+   LARGE_INTEGER LargeTickCount;
+   NTSTATUS Status;
+
+   DPRINT1("UserPostThreadMessage wParam 0x%x  lParam 0x%x\n", wParam,lParam);
+
+   if (FindMsgMemory(Msg) != 0)
+   {
+      SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+      return FALSE;
+   }
+
+   Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
+
+   if( Status == STATUS_SUCCESS )
+   {
+      pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
+      if( !pThread || !pThread->MessageQueue )
+      {
+         ObDereferenceObject( peThread );
+         return FALSE;
+      }
+
+      Message.hwnd = NULL;
+      Message.message = Msg;
+      Message.wParam = wParam;
+      Message.lParam = lParam;
+      IntGetCursorLocation(pThread->Desktop->WindowStation, &Message.pt);
+      KeQueryTickCount(&LargeTickCount);
+      pThread->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
+      MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
+      ObDereferenceObject( peThread );
+      return TRUE;
+   }
+   else
+   {
+      SetLastNtError( Status );
+   }
+   return FALSE;
+}
+
 BOOL FASTCALL
 UserPostMessage(HWND Wnd,
                 UINT Msg,
                 WPARAM wParam,
                 LPARAM lParam)
 {
-   MSG UserModeMsg, KernelModeMsg;
+   PTHREADINFO pti;
+   MSG Message;
    LARGE_INTEGER LargeTickCount;
-   NTSTATUS Status;
-   PMSGMEMORY MsgMemoryEntry;
 
-   if (WM_QUIT == Msg)
+   if (FindMsgMemory(Msg) != 0)
    {
-      MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue, wParam);
+      SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+      return FALSE;
    }
-   else if (Wnd == HWND_BROADCAST)
+
+   if (!Wnd) 
+      return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
+                                    Msg,
+                                    wParam,
+                                    lParam);
+
+   pti = PsGetCurrentThreadWin32Thread();
+   if (Wnd == HWND_BROADCAST)
    {
       HWND *List;
       PWINDOW_OBJECT DesktopWindow;
@@ -1182,7 +1387,7 @@ UserPostMessage(HWND Wnd,
 
       DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
       List = IntWinListChildren(DesktopWindow);
-      
+
       if (List != NULL)
       {
          for (i = 0; List[i]; i++)
@@ -1193,7 +1398,7 @@ UserPostMessage(HWND Wnd,
    else
    {
       PWINDOW_OBJECT Window;
-      
+
       Window = UserGetWindowObject(Wnd);
       if (NULL == Window)
       {
@@ -1206,31 +1411,27 @@ UserPostMessage(HWND Wnd,
          return FALSE;
       }
 
-      UserModeMsg.hwnd = Wnd;
-      UserModeMsg.message = Msg;
-      UserModeMsg.wParam = wParam;
-      UserModeMsg.lParam = lParam;
-      MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
-      Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
-      if (! NT_SUCCESS(Status))
+      if (WM_QUIT == Msg)
       {
-         SetLastWin32Error(ERROR_INVALID_PARAMETER);
-         return FALSE;
+          MsqPostQuitMessage(Window->MessageQueue, wParam);
+      }
+      else
+      {
+         Message.hwnd = Wnd;
+         Message.message = Msg;
+         Message.wParam = wParam;
+         Message.lParam = lParam;
+         IntGetCursorLocation(pti->Desktop->WindowStation, &Message.pt);
+         KeQueryTickCount(&LargeTickCount);
+         pti->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
+         MsqPostMessage(Window->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
       }
-      IntGetCursorLocation(PsGetWin32Thread()->Desktop->WindowStation,
-                           &KernelModeMsg.pt);
-      KeQueryTickCount(&LargeTickCount);
-      KernelModeMsg.time = LargeTickCount.u.LowPart;
-      MsqPostMessage(Window->MessageQueue, &KernelModeMsg,
-                     NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam,
-                     QS_POSTMESSAGE);
    }
-
    return TRUE;
 }
 
 
-BOOL STDCALL
+BOOL APIENTRY
 NtUserPostMessage(HWND hWnd,
                   UINT Msg,
                   WPARAM wParam,
@@ -1241,7 +1442,7 @@ NtUserPostMessage(HWND hWnd,
    DPRINT("Enter NtUserPostMessage\n");
    UserEnterExclusive();
 
-   RETURN(UserPostMessage(hWnd, Msg, wParam, lParam));
+   RETURN( UserPostMessage(hWnd, Msg, wParam, lParam));
 
 CLEANUP:
    DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_);
@@ -1251,56 +1452,21 @@ CLEANUP:
 
 
 
-BOOL STDCALL
+BOOL APIENTRY
 NtUserPostThreadMessage(DWORD idThread,
                         UINT Msg,
                         WPARAM wParam,
                         LPARAM lParam)
 {
-   MSG UserModeMsg, KernelModeMsg;
-   PETHREAD peThread;
-   PW32THREAD pThread;
-   NTSTATUS Status;
-   PMSGMEMORY MsgMemoryEntry;
    DECLARE_RETURN(BOOL);
 
    DPRINT("Enter NtUserPostThreadMessage\n");
    UserEnterExclusive();
 
-   Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
-
-   if( Status == STATUS_SUCCESS )
-   {
-      pThread = (PW32THREAD)peThread->Tcb.Win32Thread;
-      if( !pThread || !pThread->MessageQueue )
-      {
-         ObDereferenceObject( peThread );
-         RETURN( FALSE);
-      }
-
-      UserModeMsg.hwnd = NULL;
-      UserModeMsg.message = Msg;
-      UserModeMsg.wParam = wParam;
-      UserModeMsg.lParam = lParam;
-      MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
-      Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
-      if (! NT_SUCCESS(Status))
-      {
-         ObDereferenceObject( peThread );
-         SetLastWin32Error(ERROR_INVALID_PARAMETER);
-         RETURN( FALSE);
-      }
-      MsqPostMessage(pThread->MessageQueue, &KernelModeMsg,
-                     NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam,
-                     QS_POSTMESSAGE);
-      ObDereferenceObject( peThread );
-      RETURN( TRUE);
-   }
-   else
-   {
-      SetLastNtError( Status );
-      RETURN( FALSE);
-   }
+   RETURN( UserPostThreadMessage( idThread,
+                                  Msg,
+                                  wParam,
+                                  lParam));
 
 CLEANUP:
    DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_);
@@ -1308,7 +1474,7 @@ CLEANUP:
    END_CLEANUP;
 }
 
-DWORD STDCALL
+DWORD APIENTRY
 NtUserQuerySendMessage(DWORD Unknown0)
 {
    UNIMPLEMENTED;
@@ -1330,7 +1496,7 @@ co_IntSendMessage(HWND hWnd,
    return 0;
 }
 
-static 
+static
 LRESULT FASTCALL
 co_IntSendMessageTimeoutSingle(HWND hWnd,
                                UINT Msg,
@@ -1346,22 +1512,23 @@ 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);
    }
-   
+
    UserRefObjectCo(Window, &Ref);
 
-   Win32Thread = PsGetWin32Thread();
+   Win32Thread = PsGetCurrentThreadWin32Thread();
+
+   IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
 
    if (NULL != Win32Thread &&
-         Window->MessageQueue == Win32Thread->MessageQueue)
+       Window->MessageQueue == Win32Thread->MessageQueue)
    {
       if (Win32Thread->IsExiting)
       {
@@ -1382,11 +1549,11 @@ 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);
       }
 
-      Result = (ULONG_PTR)co_IntCallWindowProc(Window->WndProc, !Window->Unicode, hWnd, Msg, wParam,
+      Result = (ULONG_PTR)co_IntCallWindowProc(Window->Wnd->lpfnWndProc, !Window->Wnd->Unicode, hWnd, Msg, wParam,
                lParamPacked,lParamBufferSize);
 
       if(uResult)
@@ -1394,46 +1561,69 @@ 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);
-   
+
 CLEANUP:
    if (Window) UserDerefObjectCo(Window);
    END_CLEANUP;
@@ -1491,6 +1681,7 @@ co_IntPostOrSendMessage(HWND hWnd,
                         LPARAM lParam)
 {
    ULONG_PTR Result;
+   PTHREADINFO pti;
    PWINDOW_OBJECT Window;
 
    if(hWnd == HWND_BROADCAST)
@@ -1503,14 +1694,14 @@ co_IntPostOrSendMessage(HWND hWnd,
       return 0;
    }
 
-   if(Window->MessageQueue != PsGetWin32Thread()->MessageQueue)
+   pti = PsGetCurrentThreadWin32Thread();
+   if(Window->MessageQueue != pti->MessageQueue && FindMsgMemory(Msg) ==0)
    {
       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;
       }
    }
@@ -1526,9 +1717,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;
@@ -1547,13 +1739,16 @@ co_IntDoSendMessage(HWND hWnd,
          MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
          return 0;
       }
+      if (!Window->Wnd)
+         return 0;
    }
 
    /* FIXME: Check for an exiting window. */
 
    /* See if the current thread can handle the message */
-   if (HWND_BROADCAST != hWnd && NULL != PsGetWin32Thread() &&
-         Window->MessageQueue == PsGetWin32Thread()->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;
@@ -1562,21 +1757,30 @@ co_IntDoSendMessage(HWND hWnd,
                                 sizeof(BOOL));
       if (! NT_SUCCESS(Status))
       {
-         Info.Ansi = ! Window->Unicode;
+         Info.Ansi = ! Window->Wnd->Unicode;
       }
 
-      Info.Ansi = !Window->Unicode;
-      if (Window->IsSystem)
-          Info.Proc = (Window->Unicode ? Window->WndProc : Window->WndProcExtra);
+      IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
+
+      if (Window->Wnd->IsSystem)
+      {
+          Info.Proc = (!Info.Ansi ? Window->Wnd->lpfnWndProc : Window->Wnd->WndProcExtra);
+      }
       else
-          Info.Proc = Window->WndProc;
+      {
+          Info.Ansi = !Window->Wnd->Unicode;
+          Info.Proc = Window->Wnd->lpfnWndProc;
+      }
+
+      IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, &Result);
+
    }
    else
    {
       /* Must be handled by other thread */
 //      if (HWND_BROADCAST != hWnd)
 //      {
-//         UserDerefObject(Window);
+//         UserDereferenceObject(Window);
 //      }
       Info.HandledByKernel = TRUE;
       UserModeMsg.hwnd = hWnd;
@@ -1620,7 +1824,7 @@ co_IntDoSendMessage(HWND hWnd,
    return (LRESULT)Result;
 }
 
-LRESULT STDCALL
+LRESULT APIENTRY
 NtUserSendMessageTimeout(HWND hWnd,
                          UINT Msg,
                          WPARAM wParam,
@@ -1659,7 +1863,7 @@ CLEANUP:
    END_CLEANUP;
 }
 
-LRESULT STDCALL
+LRESULT APIENTRY
 NtUserSendMessage(HWND Wnd,
                   UINT Msg,
                   WPARAM wParam,
@@ -1679,31 +1883,69 @@ CLEANUP:
    END_CLEANUP;
 }
 
-BOOL STDCALL
-NtUserSendMessageCallback(HWND hWnd,
-                          UINT Msg,
-                          WPARAM wParam,
-                          LPARAM lParam,
-                          SENDASYNCPROC lpCallBack,
-                          ULONG_PTR dwData)
+
+BOOL FASTCALL
+UserSendNotifyMessage(HWND hWnd,
+                      UINT Msg,
+                      WPARAM wParam,
+                      LPARAM lParam)
 {
-   UNIMPLEMENTED;
+   BOOL Result = TRUE;
 
-   return 0;
-}
+   if (FindMsgMemory(Msg) != 0)
+   {
+      SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+      return FALSE;
+   }
 
-BOOL STDCALL
-NtUserSendNotifyMessage(HWND hWnd,
-                        UINT Msg,
-                        WPARAM wParam,
-                        LPARAM lParam)
-{
-   UNIMPLEMENTED;
+   // Basicly the same as IntPostOrSendMessage
+   if (hWnd == HWND_BROADCAST) //Handle Broadcast
+   {
+      HWND *List;
+      PWINDOW_OBJECT DesktopWindow;
+      ULONG i;
 
-   return 0;
+      DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
+      List = IntWinListChildren(DesktopWindow);
+
+      if (List != NULL)
+      {
+         for (i = 0; List[i]; i++)
+         {
+            UserSendNotifyMessage(List[i], Msg, wParam, lParam);
+         }
+         ExFreePool(List);
+      }
+   }
+   else
+   {
+     ULONG_PTR PResult;
+     PTHREADINFO pti;
+     PWINDOW_OBJECT Window;
+     MSG Message;
+
+      if(!(Window = UserGetWindowObject(hWnd))) return FALSE;
+
+      pti = PsGetCurrentThreadWin32Thread();
+      if(Window->MessageQueue != pti->MessageQueue)
+      { // Send message w/o waiting for it.
+         Result = UserPostMessage(hWnd, Msg, wParam, lParam);
+      }
+      else
+      { // Handle message and callback.
+         Message.hwnd = hWnd;
+         Message.message = Msg;
+         Message.wParam = wParam;
+         Message.lParam = lParam;
+
+         Result = co_IntSendMessageTimeoutSingle( hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &PResult);
+      }
+   }
+   return Result;
 }
 
-BOOL STDCALL
+
+BOOL APIENTRY
 NtUserWaitMessage(VOID)
 {
    DECLARE_RETURN(BOOL);
@@ -1719,17 +1961,18 @@ CLEANUP:
    END_CLEANUP;
 }
 
-DWORD STDCALL
-NtUserGetQueueStatus(BOOL ClearChanges)
+DWORD APIENTRY
+IntGetQueueStatus(BOOL ClearChanges)
 {
+   PTHREADINFO pti;
    PUSER_MESSAGE_QUEUE Queue;
    DWORD Result;
    DECLARE_RETURN(DWORD);
 
-   DPRINT("Enter NtUserGetQueueStatus\n");
-   UserEnterExclusive();
+   DPRINT("Enter IntGetQueueStatus\n");
 
-   Queue = PsGetWin32Thread()->MessageQueue;
+   pti = PsGetCurrentThreadWin32Thread();
+   Queue = pti->MessageQueue;
 
    Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
    if (ClearChanges)
@@ -1737,30 +1980,365 @@ NtUserGetQueueStatus(BOOL ClearChanges)
       Queue->ChangedBits = 0;
    }
 
-   RETURN( Result);
+   RETURN(Result);
 
 CLEANUP:
-   DPRINT("Leave NtUserGetQueueStatus, ret=%i\n",_ret_);
-   UserLeave();
+   DPRINT("Leave IntGetQueueStatus, ret=%i\n",_ret_);
    END_CLEANUP;
 }
 
-BOOL STDCALL
+BOOL APIENTRY
 IntInitMessagePumpHook()
 {
-   ((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->MessagePumpHookValue++;
-   return TRUE;
+   if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti)
+   {
+     ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook++;
+     return TRUE;
+   }
+   return FALSE;
 }
 
-BOOL STDCALL
+BOOL APIENTRY
 IntUninitMessagePumpHook()
 {
-   if (((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->MessagePumpHookValue <= 0)
+   if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti)
+   {
+      if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook <= 0)
+      {
+         return FALSE;
+      }
+      ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook--;
+      return TRUE;
+   }
+   return FALSE;
+}
+
+
+BOOL APIENTRY
+NtUserMessageCall(
+   HWND hWnd,
+   UINT Msg,
+   WPARAM wParam,
+   LPARAM lParam,
+   ULONG_PTR ResultInfo,
+   DWORD dwType, // fnID?
+   BOOL Ansi)
+{
+   LRESULT lResult = 0;
+   BOOL Ret = FALSE;
+   BOOL BadChk = FALSE;
+   PWINDOW_OBJECT Window = NULL;
+   USER_REFERENCE_ENTRY Ref;
+
+   UserEnterExclusive();
+
+   /* Validate input */
+   if (hWnd && (hWnd != INVALID_HANDLE_VALUE) && !(Window = UserGetWindowObject(hWnd)))
    {
+      UserLeave();
       return FALSE;
    }
-   ((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->MessagePumpHookValue--;
-   return TRUE;
+   switch(dwType)
+   {
+      case FNID_DEFWINDOWPROC:
+         UserRefObjectCo(Window, &Ref);
+         lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
+         Ret = TRUE;
+         UserDerefObjectCo(Window);
+      break;
+      case FNID_SENDNOTIFYMESSAGE:
+         Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
+      break;
+      case FNID_BROADCASTSYSTEMMESSAGE:
+      {
+         BROADCASTPARM parm;
+         DWORD_PTR RetVal = 0;
+
+         if (ResultInfo)
+         {
+            _SEH2_TRY
+            {
+               ProbeForWrite((PVOID)ResultInfo,
+                         sizeof(BROADCASTPARM),
+                                             1);
+               RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
+            }
+            _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)
+            {
+               Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
+            }
+            else if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
+            {
+               Ret = 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;
+   }
+
+   switch(dwType)
+   {
+      case FNID_DEFWINDOWPROC:
+      case FNID_CALLWNDPROC:
+      case FNID_CALLWNDPROCRET:
+         if (ResultInfo)
+         {
+            _SEH2_TRY
+            {
+                ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
+                RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                BadChk = TRUE;
+            }
+            _SEH2_END;      
+         }
+         break;
+      default:
+         break;   
+   }
+
+   UserLeave();
+
+   return BadChk ? FALSE : Ret;
+}
+
+#define INFINITE 0xFFFFFFFF
+#define WAIT_FAILED ((DWORD)0xFFFFFFFF)
+
+DWORD
+APIENTRY
+NtUserWaitForInputIdle(
+   IN HANDLE hProcess,
+   IN DWORD dwMilliseconds,
+   IN BOOL Unknown2)
+{
+  PEPROCESS Process;
+  PPROCESSINFO W32Process;
+  NTSTATUS Status;
+  HANDLE Handles[2];
+  LARGE_INTEGER Timeout;
+  ULONGLONG StartTime, Run, Elapsed = 0;
+
+  UserEnterExclusive();
+
+  Status = ObReferenceObjectByHandle(hProcess,
+                                     PROCESS_QUERY_INFORMATION,
+                                     PsProcessType,
+                                     UserMode,
+                                     (PVOID*)&Process,
+                                     NULL);
+
+  if (!NT_SUCCESS(Status))
+  {
+     UserLeave();
+     SetLastNtError(Status);
+     return WAIT_FAILED;
+  }
+
+  W32Process = (PPROCESSINFO)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();
+
+  Run = dwMilliseconds;
+
+  DPRINT("WFII: waiting for %p\n", Handles[1] );
+  do
+  {
+     Timeout.QuadPart = Run - Elapsed;
+     UserLeave();
+     Status = KeWaitForMultipleObjects( 2,
+                                        Handles,
+                                        WaitAny,
+                                        UserRequest,
+                                        UserMode,
+                                        FALSE,
+                             dwMilliseconds == INFINITE ? NULL : &Timeout,
+                                        NULL);
+     UserEnterExclusive();
+
+     if (!NT_SUCCESS(Status))
+     {
+        SetLastNtError(Status);
+        Status = WAIT_FAILED;
+        goto WaitExit;
+     }
+
+     switch (Status)
+     {
+        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 (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 Status;
 }
 
 /* EOF */