[win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / message.c
index df26ff0..5d1cf8e 100644 (file)
@@ -1,21 +1,3 @@
-/*
- *  ReactOS W32 Subsystem
- *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
 /*
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
 
 /* INCLUDES ******************************************************************/
 
-#include <w32k.h>
+#include <win32k.h>
 
 #define NDEBUG
 #include <debug.h>
 
+#define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE)
+
 typedef struct
 {
    UINT uFlags;
@@ -156,8 +140,12 @@ MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
                Size = sizeof(COPYDATASTRUCT) + ((PCOPYDATASTRUCT)lParam)->cbData;
                break;
 
+            case WM_COPYGLOBALDATA:
+               Size = wParam;
+               break;
+
             default:
-               assert(FALSE);
+               ASSERT(FALSE);
                Size = 0;
                break;
          }
@@ -177,41 +165,47 @@ MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
 }
 
 static NTSTATUS
-PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
+PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolNeeded)
 {
    NCCALCSIZE_PARAMS *UnpackedNcCalcsize;
    NCCALCSIZE_PARAMS *PackedNcCalcsize;
    CREATESTRUCTW *UnpackedCs;
    CREATESTRUCTW *PackedCs;
-   PUNICODE_STRING WindowName;
+   PLARGE_STRING WindowName;
    PUNICODE_STRING ClassName;
+   POOL_TYPE PoolType;
    UINT Size;
    PCHAR CsData;
 
    *lParamPacked = lParam;
+
+    if (NonPagedPoolNeeded)
+       PoolType = NonPagedPool;
+    else
+       PoolType = PagedPool;
+
    if (WM_NCCALCSIZE == Msg && wParam)
    {
+
       UnpackedNcCalcsize = (NCCALCSIZE_PARAMS *) lParam;
-      if (UnpackedNcCalcsize->lppos != (PWINDOWPOS) (UnpackedNcCalcsize + 1))
+      PackedNcCalcsize = ExAllocatePoolWithTag(PoolType,
+                         sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS),
+                         TAG_MSG);
+
+      if (NULL == PackedNcCalcsize)
       {
-         PackedNcCalcsize = ExAllocatePoolWithTag(PagedPool,
-                            sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS),
-                            TAG_MSG);
-         if (NULL == PackedNcCalcsize)
-         {
-            DPRINT1("Not enough memory to pack lParam\n");
-            return STATUS_NO_MEMORY;
-         }
-         RtlCopyMemory(PackedNcCalcsize, UnpackedNcCalcsize, sizeof(NCCALCSIZE_PARAMS));
-         PackedNcCalcsize->lppos = (PWINDOWPOS) (PackedNcCalcsize + 1);
-         RtlCopyMemory(PackedNcCalcsize->lppos, UnpackedNcCalcsize->lppos, sizeof(WINDOWPOS));
-         *lParamPacked = (LPARAM) PackedNcCalcsize;
+         DPRINT1("Not enough memory to pack lParam\n");
+         return STATUS_NO_MEMORY;
       }
+      RtlCopyMemory(PackedNcCalcsize, UnpackedNcCalcsize, sizeof(NCCALCSIZE_PARAMS));
+      PackedNcCalcsize->lppos = (PWINDOWPOS) (PackedNcCalcsize + 1);
+      RtlCopyMemory(PackedNcCalcsize->lppos, UnpackedNcCalcsize->lppos, sizeof(WINDOWPOS));
+      *lParamPacked = (LPARAM) PackedNcCalcsize;
    }
    else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
    {
       UnpackedCs = (CREATESTRUCTW *) lParam;
-      WindowName = (PUNICODE_STRING) UnpackedCs->lpszName;
+      WindowName = (PLARGE_STRING) UnpackedCs->lpszName;
       ClassName = (PUNICODE_STRING) UnpackedCs->lpszClass;
       Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
       if (IS_ATOM(ClassName->Buffer))
@@ -222,7 +216,7 @@ PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
       {
          Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
       }
-      PackedCs = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
+      PackedCs = ExAllocatePoolWithTag(PoolType, Size, TAG_MSG);
       if (NULL == PackedCs)
       {
          DPRINT1("Not enough memory to pack lParam\n");
@@ -256,11 +250,28 @@ PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
       *lParamPacked = (LPARAM) PackedCs;
    }
 
+   else if (PoolType == NonPagedPool)
+   {
+      PMSGMEMORY MsgMemoryEntry;
+      PVOID PackedData;
+
+      MsgMemoryEntry = FindMsgMemory(Msg);
+
+      if ((!MsgMemoryEntry) || (MsgMemoryEntry->Size < 0))
+      {
+         /* Keep previous behavior */
+         return STATUS_SUCCESS;
+      }
+      PackedData = ExAllocatePoolWithTag(NonPagedPool, MsgMemorySize(MsgMemoryEntry, wParam, lParam), TAG_MSG);
+      RtlCopyMemory(PackedData, (PVOID)lParam, MsgMemorySize(MsgMemoryEntry, wParam, lParam));
+      *lParamPacked = (LPARAM)PackedData;
+   }
+
    return STATUS_SUCCESS;
 }
 
 static NTSTATUS
-UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
+UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolUsed)
 {
    NCCALCSIZE_PARAMS *UnpackedParams;
    NCCALCSIZE_PARAMS *PackedParams;
@@ -289,6 +300,23 @@ UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
 
       return STATUS_SUCCESS;
    }
+   else if (NonPagedPoolUsed)
+   {
+      PMSGMEMORY MsgMemoryEntry;
+      MsgMemoryEntry = FindMsgMemory(Msg);
+      if (MsgMemoryEntry->Size < 0)
+      {
+         /* Keep previous behavior */
+         return STATUS_INVALID_PARAMETER;
+      }
+
+      if (MsgMemory->Flags == MMS_FLAG_READWRITE)
+      {
+         //RtlCopyMemory((PVOID)lParam, (PVOID)lParamPacked, MsgMemory->Size);
+      }
+      ExFreePool((PVOID) lParamPacked);
+      return STATUS_SUCCESS;
+   }
 
    ASSERT(FALSE);
 
@@ -303,10 +331,10 @@ IntCallWndProc
 {
    BOOL SameThread = FALSE;
 
-   if (Window->ti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->ThreadInfo)
+   if (Window->pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
       SameThread = TRUE;
 
-   if ((!SameThread && (Window->ti->Hooks & HOOKID_TO_FLAG(WH_CALLWNDPROC))) ||
+   if ((!SameThread && (Window->pti->fsHooks & HOOKID_TO_FLAG(WH_CALLWNDPROC))) ||
         (SameThread && ISITHOOKED(WH_CALLWNDPROC)) )
    {
       CWPSTRUCT CWP;
@@ -317,6 +345,7 @@ IntCallWndProc
       co_HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, SameThread, (LPARAM)&CWP );
    }
 }
+
 static
 VOID
 FASTCALL
@@ -325,10 +354,10 @@ IntCallWndProcRet
 {
    BOOL SameThread = FALSE;
 
-   if (Window->ti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->ThreadInfo)
+   if (Window->pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
       SameThread = TRUE;
 
-   if ((!SameThread && (Window->ti->Hooks & HOOKID_TO_FLAG(WH_CALLWNDPROCRET))) ||
+   if ((!SameThread && (Window->pti->fsHooks & HOOKID_TO_FLAG(WH_CALLWNDPROCRET))) ||
         (SameThread && ISITHOOKED(WH_CALLWNDPROCRET)) )
    {
       CWPRETSTRUCT CWPR;
@@ -348,6 +377,9 @@ IntDispatchMessage(PMSG pMsg)
   LARGE_INTEGER TickCount;
   LONG Time;
   LRESULT retval;
+  PMSGMEMORY MsgMemoryEntry;
+  INT lParamBufferSize;
+  LPARAM lParamPacked;
   PWINDOW_OBJECT Window = NULL;
 
   if (pMsg->hwnd)
@@ -389,137 +421,48 @@ IntDispatchMessage(PMSG pMsg)
      }
   }
   // Need a window!
-  if (!Window) return 0;
-
-  retval = co_IntPostOrSendMessage(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam);
+  if ( !Window || !Window->Wnd ) return 0;
 
-  if (pMsg->message == WM_PAINT)
+  /* See if this message type is present in the table */
+  MsgMemoryEntry = FindMsgMemory(pMsg->message);
+  if ( !MsgMemoryEntry )
   {
-  /* 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 );
+     lParamBufferSize = -1;
   }
-  return retval;
-}
-
-
-BOOL
-APIENTRY
-NtUserCallMsgFilter(
-   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 (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_);
-   UserLeave();
-   END_CLEANUP;
-}
-
-LRESULT APIENTRY
-NtUserDispatchMessage(PMSG UnsafeMsgInfo)
-{
-  LRESULT Res = 0;
-  BOOL Hit = FALSE;
-  MSG SafeMsg;
-
-  UserEnterExclusive();  
-  _SEH2_TRY
+  else
   {
-    ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
-    RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
+     lParamBufferSize = MsgMemorySize(MsgMemoryEntry, pMsg->wParam, pMsg->lParam);
   }
-  _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+
+  if (! NT_SUCCESS(PackParam(&lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam, FALSE)))
   {
-    SetLastNtError(_SEH2_GetExceptionCode());
-    Hit = TRUE;
+     DPRINT1("Failed to pack message parameters\n");
+     return 0;
   }
-  _SEH2_END;
-  
-  if (!Hit) Res = IntDispatchMessage(&SafeMsg);
-
-  UserLeave();
-  return Res;
-}
-
-
-BOOL APIENTRY
-NtUserTranslateMessage(LPMSG lpMsg,
-                       HKL dwhkl)
-{
-   NTSTATUS Status;
-   MSG SafeMsg;
-   DECLARE_RETURN(BOOL);
-
-   DPRINT("Enter NtUserTranslateMessage\n");
-   UserEnterExclusive();
 
-   Status = MmCopyFromCaller(&SafeMsg, lpMsg, sizeof(MSG));
-   if(!NT_SUCCESS(Status))
-   {
-      SetLastNtError(Status);
-      RETURN( FALSE);
-   }
+  retval = co_IntCallWindowProc( Window->Wnd->lpfnWndProc,
+                                !Window->Wnd->Unicode,
+                                 pMsg->hwnd,
+                                 pMsg->message,
+                                 pMsg->wParam,
+                                 lParamPacked,
+                                 lParamBufferSize);
 
-   RETURN( IntTranslateKbdMessage(&SafeMsg, dwhkl));
+  if (! NT_SUCCESS(UnpackParam(lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam, FALSE)))
+  {
+     DPRINT1("Failed to unpack message parameters\n");
+  }
 
-CLEANUP:
-   DPRINT("Leave NtUserTranslateMessage: ret=%i\n",_ret_);
-   UserLeave();
-   END_CLEANUP;
+  if (pMsg->message == WM_PAINT)
+  {
+  /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
+     HRGN hrgn = IntSysCreateRectRgn( 0, 0, 0, 0 );
+     co_UserGetUpdateRgn( Window, hrgn, TRUE );
+     REGION_FreeRgnByHandle( hrgn );
+  }
+  return retval;
 }
 
-
 VOID FASTCALL
 co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg)
 {
@@ -551,14 +494,9 @@ co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg)
          {
             WPARAM wParam;
             PSYSTEM_CURSORINFO CurInfo;
+                       CurInfo = IntGetSysCursorInfo();
 
-            if(!IntGetWindowStationObject(InputWindowStation))
-            {
-               break;
-            }
-            CurInfo = IntGetSysCursorInfo(InputWindowStation);
             wParam = (WPARAM)(CurInfo->ButtonsDown);
-            ObDereferenceObject(InputWindowStation);
 
             co_IntSendMessage(Msg->hwnd, WM_MOUSEMOVE, wParam, Msg->lParam);
             co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
@@ -581,8 +519,11 @@ co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg)
 }
 
 BOOL FASTCALL
-co_IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, PWINDOW_OBJECT MsgWindow,
-                          USHORT *HitTest)
+co_IntActivateWindowMouse(
+   PUSER_MESSAGE_QUEUE ThreadQueue,
+   LPMSG Msg,
+   PWINDOW_OBJECT MsgWindow,
+   USHORT *HitTest)
 {
    ULONG Result;
    PWINDOW_OBJECT Parent;
@@ -623,7 +564,11 @@ co_IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, PWINDOW_OB
 }
 
 BOOL FASTCALL
-co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *HitTest, BOOL Remove)
+co_IntTranslateMouseMessage(
+   PUSER_MESSAGE_QUEUE ThreadQueue,
+   LPMSG Msg,
+   USHORT *HitTest,
+   BOOL Remove)
 {
    PWINDOW_OBJECT Window;
    USER_REFERENCE_ENTRY Ref, DesktopRef;
@@ -636,34 +581,34 @@ co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *
 
    UserRefObjectCo(Window, &Ref);
 
-   if(ThreadQueue == Window->MessageQueue &&
-         ThreadQueue->CaptureWindow != Window->hSelf)
+   if ( ThreadQueue == Window->pti->MessageQueue &&
+        ThreadQueue->CaptureWindow != Window->hSelf)
    {
       /* only send WM_NCHITTEST messages if we're not capturing the window! */
       *HitTest = co_IntSendMessage(Window->hSelf, WM_NCHITTEST, 0,
                                    MAKELONG(Msg->pt.x, Msg->pt.y));
 
-      if(*HitTest == (USHORT)HTTRANSPARENT)
+      if (*HitTest == (USHORT)HTTRANSPARENT)
       {
          PWINDOW_OBJECT DesktopWindow;
          HWND hDesktop = IntGetDesktopWindow();
 
-         if((DesktopWindow = UserGetWindowObject(hDesktop)))
+         if ((DesktopWindow = UserGetWindowObject(hDesktop)))
          {
             PWINDOW_OBJECT Wnd;
 
             UserRefObjectCo(DesktopWindow, &DesktopRef);
 
-            co_WinPosWindowFromPoint(DesktopWindow, Window->MessageQueue, &Msg->pt, &Wnd);
-            if(Wnd)
+            co_WinPosWindowFromPoint(DesktopWindow, Window->pti->MessageQueue, &Msg->pt, &Wnd);
+            if (Wnd)
             {
-               if(Wnd != Window)
+               if (Wnd != Window)
                {
                   /* post the message to the other window */
                   Msg->hwnd = Wnd->hSelf;
-                  if(!(Wnd->Status & WINDOWSTATUS_DESTROYING))
+                  if(!(Wnd->state & WINDOWSTATUS_DESTROYING))
                   {
-                     MsqPostMessage(Wnd->MessageQueue, Msg, FALSE,
+                     MsqPostMessage(Wnd->pti->MessageQueue, Msg, FALSE,
                                     Msg->message == WM_MOUSEMOVE ? QS_MOUSEMOVE :
                                     QS_MOUSEBUTTON);
                   }
@@ -686,11 +631,22 @@ co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *
       *HitTest = HTCLIENT;
    }
 
-   if(IS_BTN_MESSAGE(Msg->message, DOWN))
+   if ( gspv.bMouseClickLock && 
+        ( (Msg->message == WM_LBUTTONUP) ||
+          (Msg->message == WM_LBUTTONDOWN) ) )
+   {
+      if (MsqIsClkLck(Msg, Remove))
+      {
+        // FIXME: drop the message, hack: use WM_NULL
+        Msg->message = WM_NULL;
+      }
+   }
+
+   if (IS_BTN_MESSAGE(Msg->message, DOWN))
    {
       /* generate double click messages, if necessary */
       if ((((*HitTest) != HTCLIENT) ||
-            (Window->Wnd->Class->Style & CS_DBLCLKS)) &&
+            (Window->Wnd->pcls->style & CS_DBLCLKS)) &&
             MsqIsDblClk(Msg, Remove))
       {
          Msg->message += WM_LBUTTONDBLCLK - WM_LBUTTONDOWN;
@@ -703,8 +659,8 @@ co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *
       if ((*HitTest) != HTCLIENT)
       {
          Msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
-         if((Msg->message == WM_NCRBUTTONUP) &&
-               (((*HitTest) == HTCAPTION) || ((*HitTest) == HTSYSMENU)))
+         if ( (Msg->message == WM_NCRBUTTONUP) &&
+              (((*HitTest) == HTCAPTION) || ((*HitTest) == HTSYSMENU)) )
          {
             Msg->message = WM_CONTEXTMENU;
             Msg->wParam = (WPARAM)Window->hSelf;
@@ -715,13 +671,13 @@ co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *
          }
          Msg->lParam = MAKELONG(Msg->pt.x, Msg->pt.y);
       }
-      else if(ThreadQueue->MoveSize == NULL &&
-              ThreadQueue->MenuOwner == NULL)
+      else if ( ThreadQueue->MoveSize == NULL &&
+                ThreadQueue->MenuOwner == NULL )
       {
          /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
          Msg->lParam = MAKELONG(
-                          Msg->pt.x - (WORD)Window->Wnd->ClientRect.left,
-                          Msg->pt.y - (WORD)Window->Wnd->ClientRect.top);
+                          Msg->pt.x - (WORD)Window->Wnd->rcClient.left,
+                          Msg->pt.y - (WORD)Window->Wnd->rcClient.top);
       }
    }
 
@@ -729,16 +685,83 @@ co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *
    return FALSE;
 }
 
+BOOL ProcessMouseMessage(MSG* Msg, USHORT HitTest, UINT RemoveMsg)
+{
+    MOUSEHOOKSTRUCT MHook;
+    EVENTMSG Event;
+
+    Event.message = Msg->message;
+    Event.time    = Msg->time;
+    Event.hwnd    = Msg->hwnd;
+    Event.paramL  = Msg->pt.x;
+    Event.paramH  = Msg->pt.y;
+    co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
+
+
+    MHook.pt           = Msg->pt;
+    MHook.hwnd         = Msg->hwnd;
+    MHook.wHitTestCode = HitTest;
+    MHook.dwExtraInfo  = 0;
+    if (co_HOOK_CallHooks( WH_MOUSE,
+                           RemoveMsg ? HC_ACTION : HC_NOREMOVE,
+                           Msg->message,
+                           (LPARAM)&MHook ))
+    {
+        if (ISITHOOKED(WH_CBT))
+        {
+            MHook.pt           = Msg->pt;
+            MHook.hwnd         = Msg->hwnd;
+            MHook.wHitTestCode = HitTest;
+            MHook.dwExtraInfo  = 0;
+            co_HOOK_CallHooks( WH_CBT,
+                               HCBT_CLICKSKIPPED,
+                               Msg->message,
+                               (LPARAM)&MHook);
+        }
+        return FALSE;
+    }
+
+       return TRUE;
+}
 
+BOOL ProcessKeyboardMessage(MSG* Msg, UINT RemoveMsg)
+{
+   EVENTMSG Event;
+
+   Event.message = Msg->message;
+   Event.hwnd    = Msg->hwnd;
+   Event.time    = Msg->time;
+   Event.paramL  = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8);
+   Event.paramH  = Msg->lParam & 0x7FFF;
+   if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
+   co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
+
+    if (co_HOOK_CallHooks( WH_KEYBOARD,
+                           RemoveMsg ? HC_ACTION : HC_NOREMOVE,
+                           LOWORD(Msg->wParam),
+                           Msg->lParam))
+    {
+        if (ISITHOOKED(WH_CBT))
+        {
+            /* skip this message */
+            co_HOOK_CallHooks( WH_CBT,
+                               HCBT_KEYSKIPPED,
+                               LOWORD(Msg->wParam),
+                               Msg->lParam );
+        }
+        return FALSE;
+    }
+       return TRUE;
+}
 /*
  * Internal version of PeekMessage() doing all the work
  */
 BOOL FASTCALL
-co_IntPeekMessage(PUSER_MESSAGE Msg,
-                  HWND hWnd,
-                  UINT MsgFilterMin,
-                  UINT MsgFilterMax,
-                  UINT RemoveMsg)
+co_IntPeekMessage( PUSER_MESSAGE Msg,
+                   PWINDOW_OBJECT Window,
+                   UINT MsgFilterMin,
+                   UINT MsgFilterMax,
+                   UINT RemoveMsg )
 {
    PTHREADINFO pti;
    LARGE_INTEGER LargeTickCount;
@@ -747,7 +770,6 @@ co_IntPeekMessage(PUSER_MESSAGE Msg,
    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() */
@@ -756,9 +778,27 @@ co_IntPeekMessage(PUSER_MESSAGE Msg,
    ThreadQueue = pti->MessageQueue;
 
    /* Inspect RemoveMsg flags */
-   /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
+   /* Note:
+       The only flag we process is PM_REMOVE.
+       Processing (High word) PM_QS_Xx Is needed. This and MsgFilterXxx can result
+       with QS_Xx flags to be used to isolate which message check to test for.
+       ATM, we look at all messages and the filters are sent to co_MsqFindMessage
+       and there, it is cross checked.
+       Example: Wine server/queue.c is_keyboard_msg, check_msg_filter and
+                filter_contains_hw_range.
+    */
    RemoveMessages = RemoveMsg & PM_REMOVE;
 
+/*
+   If no filter is specified, messages are processed in the following order:
+
+    * Sent messages
+    * Posted messages
+    * Input (hardware) messages and system internal events
+    * Sent messages (again)
+    * WM_PAINT messages
+    * WM_TIMER messages
+ */
 CheckMessages:
 
    Present = FALSE;
@@ -789,13 +829,13 @@ CheckMessages:
    }
 
    /* Now check for normal messages. */
-   Present = co_MsqFindMessage(ThreadQueue,
-                               FALSE,
-                               RemoveMessages,
-                               hWnd,
-                               MsgFilterMin,
-                               MsgFilterMax,
-                               &Message);
+   Present = co_MsqFindMessage( ThreadQueue,
+                                FALSE,
+                                RemoveMessages,
+                                Window,
+                                MsgFilterMin,
+                                MsgFilterMax,
+                               &Message );
    if (Present)
    {
       RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
@@ -807,13 +847,13 @@ CheckMessages:
    }
 
    /* Check for hardware events. */
-   Present = co_MsqFindMessage(ThreadQueue,
-                               TRUE,
-                               RemoveMessages,
-                               hWnd,
-                               MsgFilterMin,
-                               MsgFilterMax,
-                               &Message);
+   Present = co_MsqFindMessage( ThreadQueue,
+                                TRUE,
+                                RemoveMessages,
+                                Window,
+                                MsgFilterMin,
+                                MsgFilterMax,
+                               &Message );
    if (Present)
    {
       RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
@@ -829,25 +869,19 @@ CheckMessages:
       ;
 
    /* Check for paint messages. */
-   if (IntGetPaintMessage(hWnd, MsgFilterMin, MsgFilterMax, pti, &Msg->Msg, RemoveMessages))
+   if ( IntGetPaintMessage( Window,
+                            MsgFilterMin,
+                            MsgFilterMax,
+                            pti,
+                            &Msg->Msg,
+                            RemoveMessages))
    {
       Msg->FreeLParam = FALSE;
       goto MsgExit;
    }
 
-   if (ThreadQueue->WakeMask & QS_TIMER)
-      if (PostTimerMessages(hWnd)) // 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,
-                                &Msg->Msg, RemoveMessages);
-   if (Present)
-   {
-      Msg->FreeLParam = FALSE;
-      goto MessageFound;
-   }
+   if (PostTimerMessages(Window))
+      goto CheckMessages;
 
    if(Present)
    {
@@ -857,16 +891,23 @@ MessageFound:
       {
          PWINDOW_OBJECT MsgWindow = NULL;
 
-         if(Msg->Msg.hwnd && (MsgWindow = UserGetWindowObject(Msg->Msg.hwnd)) &&
-               Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST)
+         /* Mouse message process */
+
+         if( Msg->Msg.hwnd &&
+            ( MsgWindow = UserGetWindowObject(Msg->Msg.hwnd) ) &&
+             Msg->Msg.message >= WM_MOUSEFIRST &&
+             Msg->Msg.message <= WM_MOUSELAST )
          {
             USHORT HitTest;
 
             UserRefObjectCo(MsgWindow, &Ref);
 
-            if(co_IntTranslateMouseMessage(ThreadQueue, &Msg->Msg, &HitTest, TRUE))
-               /* FIXME - check message filter again, if the message doesn't match anymore,
-                          search again */
+            if ( co_IntTranslateMouseMessage( ThreadQueue,
+                                              &Msg->Msg,
+                                              &HitTest,
+                                              TRUE))
+         /* FIXME - check message filter again, if the message doesn't match anymore,
+                    search again */
             {
                UserDerefObjectCo(MsgWindow);
                /* eat the message, search again */
@@ -876,9 +917,11 @@ MessageFound:
             if(ThreadQueue->CaptureWindow == NULL)
             {
                co_IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
-               if((Msg->Msg.message != WM_MOUSEMOVE && Msg->Msg.message != WM_NCMOUSEMOVE) &&
+
+               if ( ( Msg->Msg.message != WM_MOUSEMOVE &&
+                      Msg->Msg.message != WM_NCMOUSEMOVE ) &&
                      IS_BTN_MESSAGE(Msg->Msg.message, DOWN) &&
-                     co_IntActivateWindowMouse(ThreadQueue, &Msg->Msg, MsgWindow, &HitTest))
+                     co_IntActivateWindowMouse(ThreadQueue, &Msg->Msg, MsgWindow, &HitTest) )
                {
                   UserDerefObjectCo(MsgWindow);
                   /* eat the message, search again */
@@ -901,56 +944,35 @@ MessageFound:
          goto MsgExit;
       }
 
-      if((Msg->Msg.hwnd && Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST) &&
-            co_IntTranslateMouseMessage(ThreadQueue, &Msg->Msg, &HitTest, FALSE))
-         /* FIXME - check message filter again, if the message doesn't match anymore,
-                    search again */
+      if ( ( Msg->Msg.hwnd &&
+             Msg->Msg.message >= WM_MOUSEFIRST &&
+             Msg->Msg.message <= WM_MOUSELAST ) &&
+           co_IntTranslateMouseMessage( ThreadQueue,
+                                       &Msg->Msg,
+                                       &HitTest,
+                                        FALSE) )
+    /* FIXME - check message filter again, if the message doesn't match anymore,
+               search again */
       {
          /* 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 ( ISITHOOKED(WH_MOUSE) && IS_MOUSE_MESSAGE(Msg->Msg.message))
       {
-         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;
-         }
+          if(!ProcessMouseMessage(&Msg->Msg, HitTest, RemoveMsg))
+                 {
+                         return FALSE;
+                 }
+         }
+
+      if ( ISITHOOKED(WH_KEYBOARD) && IS_KBD_MESSAGE(Msg->Msg.message))
+      {
+          if(!ProcessKeyboardMessage(&Msg->Msg, RemoveMsg))
+          {
+              return FALSE;
+          }
       }
       // The WH_GETMESSAGE hook enables an application to monitor messages about to
       // be returned by the GetMessage or PeekMessage function.
@@ -965,107 +987,108 @@ MsgExit:
    return Present;
 }
 
-BOOL APIENTRY
-NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
-                  HWND hWnd,
-                  UINT MsgFilterMin,
-                  UINT MsgFilterMax,
-                  UINT RemoveMsg)
+static NTSTATUS FASTCALL
+CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
 {
    NTSTATUS Status;
-   BOOL Present;
-   NTUSERGETMESSAGEINFO Info;
-   PWINDOW_OBJECT Window;
-   PMSGMEMORY MsgMemoryEntry;
-   PVOID UserMem;
+
+   PVOID KernelMem;
    UINT Size;
-   USER_MESSAGE Msg;
-   DECLARE_RETURN(BOOL);
 
-   DPRINT("Enter NtUserPeekMessage\n");
-   UserEnterExclusive();
+   *KernelModeMsg = *UserModeMsg;
 
-   /* Validate input */
-   if (hWnd && hWnd != INVALID_HANDLE_VALUE)
+   /* See if this message type is present in the table */
+   if (NULL == MsgMemoryEntry)
    {
-      if (!(Window = UserGetWindowObject(hWnd)))
-      {
-         RETURN(-1);
-      }
+      /* Not present, no copying needed */
+      return STATUS_SUCCESS;
    }
 
-   if (MsgFilterMax < MsgFilterMin)
-   {
-      MsgFilterMin = 0;
-      MsgFilterMax = 0;
-   }
+   /* Determine required size */
+   Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
 
-   Present = co_IntPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg);
-   if (Present)
+   if (0 != Size)
    {
-
-      Info.Msg = Msg.Msg;
-      /* See if this message type is present in the table */
-      MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
-      if (NULL == MsgMemoryEntry)
+      /* Allocate kernel mem */
+      KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
+      if (NULL == KernelMem)
       {
-         /* Not present, no copying needed */
-         Info.LParamSize = 0;
+         DPRINT1("Not enough memory to copy message to kernel mem\n");
+         return STATUS_NO_MEMORY;
       }
-      else
+      KernelModeMsg->lParam = (LPARAM) KernelMem;
+
+      /* Copy data if required */
+      if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
       {
-         /* Determine required size */
-         Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
-                              Info.Msg.lParam);
-         /* Allocate required amount of user-mode memory */
-         Info.LParamSize = Size;
-         UserMem = NULL;
-         Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
-                                          &Info.LParamSize, 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 = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
          if (! NT_SUCCESS(Status))
          {
-            ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
-                                &Info.LParamSize, MEM_RELEASE);
-            SetLastNtError(Status);
-            RETURN( (BOOL) -1);
+            DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
+            ExFreePoolWithTag(KernelMem, TAG_MSG);
+            return Status;
          }
-         Info.Msg.lParam = (LPARAM) UserMem;
       }
-      if (RemoveMsg && Msg.FreeLParam && 0 != Msg.Msg.lParam)
+      else
       {
-         ExFreePool((void *) Msg.Msg.lParam);
+         /* Make sure we don't pass any secrets to usermode */
+         RtlZeroMemory(KernelMem, Size);
       }
-      Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
-      if (! NT_SUCCESS(Status))
+   }
+   else
+   {
+      KernelModeMsg->lParam = 0;
+   }
+
+   return STATUS_SUCCESS;
+}
+
+static NTSTATUS FASTCALL
+CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
+{
+   NTSTATUS Status;
+   PMSGMEMORY MsgMemoryEntry;
+   UINT Size;
+
+   /* See if this message type is present in the table */
+   MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
+   if (NULL == MsgMemoryEntry)
+   {
+      /* Not present, no copying needed */
+      return STATUS_SUCCESS;
+   }
+
+   /* Determine required size */
+   Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
+
+   if (0 != Size)
+   {
+      /* Copy data if required */
+      if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
       {
-         SetLastNtError(Status);
-         RETURN( (BOOL) -1);
+         Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
+         if (! NT_SUCCESS(Status))
+         {
+            DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
+            ExFreePool((PVOID) KernelModeMsg->lParam);
+            return Status;
+         }
       }
-   }
 
-   RETURN( Present);
+      ExFreePool((PVOID) KernelModeMsg->lParam);
+   }
 
-CLEANUP:
-   DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
-   UserLeave();
-   END_CLEANUP;
+   return STATUS_SUCCESS;
 }
 
 static BOOL FASTCALL
-co_IntWaitMessage(HWND Wnd,
-                  UINT MsgFilterMin,
-                  UINT MsgFilterMax)
+co_IntWaitMessage( PWINDOW_OBJECT Window,
+                   UINT MsgFilterMin,
+                   UINT MsgFilterMax )
 {
    PTHREADINFO pti;
    PUSER_MESSAGE_QUEUE ThreadQueue;
-   NTSTATUS Status;
+   NTSTATUS Status = STATUS_SUCCESS;
    USER_MESSAGE Msg;
 
    pti = PsGetCurrentThreadWin32Thread();
@@ -1073,59 +1096,63 @@ co_IntWaitMessage(HWND Wnd,
 
    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);
+   while ( (STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) ||
+           STATUS_TIMEOUT == Status );
 
-   SetLastNtError(Status);
+   if (!NT_SUCCESS(Status))
+   {
+      SetLastNtError(Status);
+      DPRINT1("Exit co_IntWaitMessage on error!\n");
+   }
 
    return FALSE;
 }
 
-BOOL APIENTRY
-NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
-                 HWND hWnd,
-                 UINT MsgFilterMin,
-                 UINT MsgFilterMax)
-/*
- * FUNCTION: Get a message from the calling thread's message queue.
- * ARGUMENTS:
- *      UnsafeMsg - Pointer to the structure which receives the returned message.
- *      Wnd - Window whose messages are to be retrieved.
- *      MsgFilterMin - Integer value of the lowest message value to be
- *                     retrieved.
- *      MsgFilterMax - Integer value of the highest message value to be
- *                     retrieved.
- */
+BOOL FASTCALL
+co_IntGetPeekMessage( PMSG pMsg,
+                      HWND hWnd,
+                      UINT MsgFilterMin,
+                      UINT MsgFilterMax,
+                      UINT RemoveMsg,
+                      BOOL bGMSG )
 {
-   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;
+   BOOL Present;
+   PWINDOW_OBJECT Window;
    USER_MESSAGE Msg;
-   DECLARE_RETURN(BOOL);
-//   USER_REFERENCE_ENTRY Ref;
 
-   DPRINT("Enter NtUserGetMessage\n");
-   UserEnterExclusive();
+   if ( hWnd == HWND_TOPMOST ||
+        hWnd == HWND_BROADCAST )
+      hWnd = HWND_BOTTOM;
 
    /* Validate input */
-   if (hWnd && !(Window = UserGetWindowObject(hWnd)))
+   if (hWnd && hWnd != HWND_BOTTOM)
    {
-      RETURN(-1);
+      if (!(Window = UserGetWindowObject(hWnd)))
+      {
+         if (bGMSG)
+            return -1;
+         else
+            return FALSE;
+      }
+   }
+   else
+   {
+      Window = (PWINDOW_OBJECT)hWnd;
    }
-
-//   if (Window) UserRefObjectCo(Window, &Ref);
 
    if (MsgFilterMax < MsgFilterMin)
    {
@@ -1135,185 +1162,117 @@ NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
 
    do
    {
-      GotMessage = co_IntPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE);
-      if (GotMessage)
+      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);
-         if (NULL == MsgMemoryEntry)
-         {
-            /* Not present, no copying needed */
-            Info.LParamSize = 0;
-         }
+         RtlCopyMemory( pMsg, &Msg.Msg, sizeof(MSG));
+
+         if (bGMSG)
+            return (WM_QUIT != pMsg->message);
          else
-         {
-            /* Determine required size */
-            Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
-                                 Info.Msg.lParam);
-            /* Allocate required amount of user-mode memory */
-            Info.LParamSize = Size;
-            UserMem = NULL;
-            Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
-                                             &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
+            return TRUE;
+      }
 
-            if (! NT_SUCCESS(Status))
-            {
-               SetLastNtError(Status);
-               RETURN( (BOOL) -1);
-            }
-            /* Transfer lParam data to user-mode mem */
-            Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
-            if (! NT_SUCCESS(Status))
-            {
-               ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
-                                   &Info.LParamSize, MEM_DECOMMIT);
-               SetLastNtError(Status);
-               RETURN( (BOOL) -1);
-            }
-            Info.Msg.lParam = (LPARAM) UserMem;
-         }
-         if (Msg.FreeLParam && 0 != Msg.Msg.lParam)
-         {
-            ExFreePool((void *) Msg.Msg.lParam);
-         }
-         Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
-         if (! NT_SUCCESS(Status))
-         {
-            SetLastNtError(Status);
-            RETURN( (BOOL) -1);
-         }
+      if ( bGMSG && !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax) )
+      {
+         return -1;
       }
-      else if (! co_IntWaitMessage(hWnd, MsgFilterMin, MsgFilterMax))
+      else
       {
-         RETURN( (BOOL) -1);
+         if (!(RemoveMsg & PM_NOYIELD))
+         {
+         // Yield this thread!
+            UserLeave();
+            ZwYieldExecution();
+            UserEnterExclusive();
+         // Fall through to fail.
+         }
       }
    }
-   while (! GotMessage);
-
-   RETURN( WM_QUIT != Info.Msg.message);
+   while( bGMSG && !Present );
 
-CLEANUP:
-//   if (Window) UserDerefObjectCo(Window);
-
-   DPRINT("Leave NtUserGetMessage\n");
-   UserLeave();
-   END_CLEANUP;
+   return FALSE;
 }
 
-
-static NTSTATUS FASTCALL
-CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
+BOOL FASTCALL
+UserPostThreadMessage( DWORD idThread,
+                       UINT Msg,
+                       WPARAM wParam,
+                       LPARAM lParam )
 {
+   MSG Message;
+   PETHREAD peThread;
+   PTHREADINFO pThread;
+   LARGE_INTEGER LargeTickCount;
    NTSTATUS Status;
 
-   PVOID KernelMem;
-   UINT Size;
-
-   *KernelModeMsg = *UserModeMsg;
+   DPRINT1("UserPostThreadMessage wParam 0x%x  lParam 0x%x\n", wParam,lParam);
 
-   /* See if this message type is present in the table */
-   if (NULL == MsgMemoryEntry)
+   if (FindMsgMemory(Msg) != 0)
    {
-      /* Not present, no copying needed */
-      return STATUS_SUCCESS;
+      SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+      return FALSE;
    }
 
-   /* Determine required size */
-   Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
+   Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
 
-   if (0 != Size)
+   if( Status == STATUS_SUCCESS )
    {
-      /* Allocate kernel mem */
-      KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
-      if (NULL == KernelMem)
+      pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
+      if( !pThread ||
+          !pThread->MessageQueue ||
+         (pThread->TIF_flags & TIF_INCLEANUP))
       {
-         DPRINT1("Not enough memory to copy message to kernel mem\n");
-         return STATUS_NO_MEMORY;
+         ObDereferenceObject( peThread );
+         return FALSE;
       }
-      KernelModeMsg->lParam = (LPARAM) KernelMem;
 
-      /* Copy data if required */
-      if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
-      {
-         Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
-         if (! NT_SUCCESS(Status))
-         {
-            DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
-            ExFreePoolWithTag(KernelMem, TAG_MSG);
-            return Status;
-         }
-      }
-      else
-      {
-         /* Make sure we don't pass any secrets to usermode */
-         RtlZeroMemory(KernelMem, Size);
-      }
+      Message.hwnd = NULL;
+      Message.message = Msg;
+      Message.wParam = wParam;
+      Message.lParam = lParam;
+      Message.pt = gpsi->ptCursor;
+
+      KeQueryTickCount(&LargeTickCount);
+      pThread->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
+      MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
+      ObDereferenceObject( peThread );
+      return TRUE;
    }
    else
    {
-      KernelModeMsg->lParam = 0;
+      SetLastNtError( Status );
    }
-
-   return STATUS_SUCCESS;
+   return FALSE;
 }
 
-static NTSTATUS FASTCALL
-CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
+BOOL FASTCALL
+UserPostMessage( HWND Wnd,
+                 UINT Msg,
+                 WPARAM wParam,
+                 LPARAM lParam )
 {
-   NTSTATUS Status;
-   PMSGMEMORY MsgMemoryEntry;
-   UINT Size;
+   PTHREADINFO pti;
+   MSG Message;
+   LARGE_INTEGER LargeTickCount;
 
-   /* See if this message type is present in the table */
-   MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
-   if (NULL == MsgMemoryEntry)
+   if (FindMsgMemory(Msg) != 0)
    {
-      /* Not present, no copying needed */
-      return STATUS_SUCCESS;
-   }
-
-   /* Determine required size */
-   Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
-
-   if (0 != Size)
-   {
-      /* Copy data if required */
-      if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
-      {
-         Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
-         if (! NT_SUCCESS(Status))
-         {
-            DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
-            ExFreePool((PVOID) KernelModeMsg->lParam);
-            return Status;
-         }
-      }
-
-      ExFreePool((PVOID) KernelModeMsg->lParam);
+      SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+      return FALSE;
    }
 
-   return STATUS_SUCCESS;
-}
-
-BOOL FASTCALL
-UserPostMessage(HWND Wnd,
-                UINT Msg,
-                WPARAM wParam,
-                LPARAM lParam)
-{
-   PTHREADINFO pti;
-   MSG UserModeMsg, KernelModeMsg;
-   LARGE_INTEGER LargeTickCount;
-   NTSTATUS Status;
-   PMSGMEMORY MsgMemoryEntry;
+   if (!Wnd) 
+      return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
+                                    Msg,
+                                    wParam,
+                                    lParam);
 
-   pti = PsGetCurrentThreadWin32Thread();
-   if (WM_QUIT == Msg)
-   {
-      MsqPostQuitMessage(pti->MessageQueue, wParam);
-   }
-   else if (Wnd == HWND_BROADCAST)
+   if (Wnd == HWND_BROADCAST)
    {
       HWND *List;
       PWINDOW_OBJECT DesktopWindow;
@@ -1334,132 +1293,50 @@ UserPostMessage(HWND Wnd,
       PWINDOW_OBJECT Window;
 
       Window = UserGetWindowObject(Wnd);
-      if (NULL == Window)
+      if ( !Window || !Window->Wnd )
       {
          return FALSE;
       }
-      if(Window->Status & WINDOWSTATUS_DESTROYING)
+
+      pti = Window->Wnd->head.pti;
+      if ( pti->TIF_flags & TIF_INCLEANUP )
       {
-         DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
-         /* FIXME - last error code? */
+         DPRINT1("Attempted to post message to window 0x%x when the thread is in cleanup!\n", 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 ( Window->state & WINDOWSTATUS_DESTROYING )
       {
-         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
+         /* FIXME - last error code? */
          return FALSE;
       }
-      IntGetCursorLocation(pti->Desktop->WindowStation,
-                           &KernelModeMsg.pt);
-      KeQueryTickCount(&LargeTickCount);
-      KernelModeMsg.time = MsqCalculateMessageTime(&LargeTickCount);
-      MsqPostMessage(Window->MessageQueue, &KernelModeMsg,
-                     NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam,
-                     QS_POSTMESSAGE);
-   }
-
-   return TRUE;
-}
-
-
-BOOL APIENTRY
-NtUserPostMessage(HWND hWnd,
-                  UINT Msg,
-                  WPARAM wParam,
-                  LPARAM lParam)
-{
-   DECLARE_RETURN(BOOL);
-
-   DPRINT("Enter NtUserPostMessage\n");
-   UserEnterExclusive();
-
-   RETURN(UserPostMessage(hWnd, Msg, wParam, lParam));
 
-CLEANUP:
-   DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_);
-   UserLeave();
-   END_CLEANUP;
-}
-
-
-
-BOOL APIENTRY
-NtUserPostThreadMessage(DWORD idThread,
-                        UINT Msg,
-                        WPARAM wParam,
-                        LPARAM lParam)
-{
-   MSG UserModeMsg, KernelModeMsg;
-   PETHREAD peThread;
-   PTHREADINFO pThread;
-   NTSTATUS Status;
-   PMSGMEMORY MsgMemoryEntry;
-   DECLARE_RETURN(BOOL);
-
-   DPRINT("Enter NtUserPostThreadMessage\n");
-   UserEnterExclusive();
-
-   Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
-
-   if( Status == STATUS_SUCCESS )
-   {
-      pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
-      if( !pThread || !pThread->MessageQueue )
+      if (WM_QUIT == Msg)
       {
-         ObDereferenceObject( peThread );
-         RETURN( FALSE);
+          MsqPostQuitMessage(Window->pti->MessageQueue, wParam);
       }
-
-      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))
+      else
       {
-         ObDereferenceObject( peThread );
-         SetLastWin32Error(ERROR_INVALID_PARAMETER);
-         RETURN( FALSE);
+         Message.hwnd = Wnd;
+         Message.message = Msg;
+         Message.wParam = wParam;
+         Message.lParam = lParam;
+         Message.pt = gpsi->ptCursor;
+         KeQueryTickCount(&LargeTickCount);
+         pti->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
+         MsqPostMessage(Window->pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
       }
-      MsqPostMessage(pThread->MessageQueue, &KernelModeMsg,
-                     NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam,
-                     QS_POSTMESSAGE);
-      ObDereferenceObject( peThread );
-      RETURN( TRUE);
-   }
-   else
-   {
-      SetLastNtError( Status );
-      RETURN( FALSE);
    }
-
-CLEANUP:
-   DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_);
-   UserLeave();
-   END_CLEANUP;
+   return TRUE;
 }
 
-DWORD APIENTRY
-NtUserQuerySendMessage(DWORD Unknown0)
-{
-   UNIMPLEMENTED;
-
-   return 0;
-}
 
 LRESULT FASTCALL
-co_IntSendMessage(HWND hWnd,
-                  UINT Msg,
-                  WPARAM wParam,
-                  LPARAM lParam)
+co_IntSendMessage( HWND hWnd,
+                   UINT Msg,
+                   WPARAM wParam,
+                   LPARAM lParam )
 {
    ULONG_PTR Result = 0;
    if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
@@ -1471,13 +1348,13 @@ co_IntSendMessage(HWND hWnd,
 
 static
 LRESULT FASTCALL
-co_IntSendMessageTimeoutSingle(HWND hWnd,
-                               UINT Msg,
-                               WPARAM wParam,
-                               LPARAM lParam,
-                               UINT uFlags,
-                               UINT uTimeout,
-                               ULONG_PTR *uResult)
+co_IntSendMessageTimeoutSingle( HWND hWnd,
+                                UINT Msg,
+                                WPARAM wParam,
+                                LPARAM lParam,
+                                UINT uFlags,
+                                UINT uTimeout,
+                                ULONG_PTR *uResult )
 {
    ULONG_PTR Result;
    NTSTATUS Status;
@@ -1500,10 +1377,10 @@ co_IntSendMessageTimeoutSingle(HWND hWnd,
 
    IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
 
-   if (NULL != Win32Thread &&
-       Window->MessageQueue == Win32Thread->MessageQueue)
+   if ( NULL != Win32Thread &&
+        Window->pti->MessageQueue == Win32Thread->MessageQueue)
    {
-      if (Win32Thread->IsExiting)
+      if (Win32Thread->TIF_flags & TIF_INCLEANUP)
       {
          /* Never send messages to exiting threads */
           RETURN( FALSE);
@@ -1520,15 +1397,19 @@ co_IntSendMessageTimeoutSingle(HWND hWnd,
          lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
       }
 
-      if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam)))
+      if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE)))
       {
           DPRINT1("Failed to pack message parameters\n");
           RETURN( FALSE);
       }
 
-      Result = (ULONG_PTR)co_IntCallWindowProc(Window->Wnd->WndProc, !Window->Wnd->Unicode, hWnd, Msg, wParam,
-               lParamPacked,lParamBufferSize);
-
+      Result = (ULONG_PTR)co_IntCallWindowProc( Window->Wnd->lpfnWndProc,
+                                               !Window->Wnd->Unicode,
+                                                hWnd,
+                                                Msg,
+                                                wParam,
+                                                lParamPacked,
+                                                lParamBufferSize );
       if(uResult)
       {
          *uResult = Result;
@@ -1536,7 +1417,7 @@ co_IntSendMessageTimeoutSingle(HWND hWnd,
 
       IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
 
-      if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam)))
+      if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
       {
          DPRINT1("Failed to unpack message parameters\n");
          RETURN( TRUE);
@@ -1545,13 +1426,13 @@ co_IntSendMessageTimeoutSingle(HWND hWnd,
       RETURN( TRUE);
    }
 
-   if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->MessageQueue))
+   if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->pti->MessageQueue))
    {
       /* FIXME - Set a LastError? */
       RETURN( FALSE);
    }
 
-   if (Window->Status & WINDOWSTATUS_DESTROYING)
+   if (Window->state & WINDOWSTATUS_DESTROYING)
    {
       /* FIXME - last error? */
       DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
@@ -1560,19 +1441,19 @@ co_IntSendMessageTimeoutSingle(HWND hWnd,
 
    do
    {
-      Status = co_MsqSendMessage( Window->MessageQueue,
-                                                  hWnd,
-                                                   Msg,
-                                                wParam,
-                                                lParam,
-                                              uTimeout,
-                                 (uFlags & SMTO_BLOCK),
-                                            MSQ_NORMAL,
-                                               uResult);
+      Status = co_MsqSendMessage( Window->pti->MessageQueue,
+                                                       hWnd,
+                                                        Msg,
+                                                     wParam,
+                                                     lParam,
+                                                   uTimeout,
+                                      (uFlags & SMTO_BLOCK),
+                                                 MSQ_NORMAL,
+                                                    uResult );
    }
    while ((STATUS_TIMEOUT == Status) &&
           (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
-          !MsqIsHung(Window->MessageQueue));
+          !MsqIsHung(Window->pti->MessageQueue));
 
    IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
 
@@ -1603,13 +1484,13 @@ CLEANUP:
 }
 
 LRESULT FASTCALL
-co_IntSendMessageTimeout(HWND hWnd,
-                         UINT Msg,
-                         WPARAM wParam,
-                         LPARAM lParam,
-                         UINT uFlags,
-                         UINT uTimeout,
-                         ULONG_PTR *uResult)
+co_IntSendMessageTimeout( HWND hWnd,
+                          UINT Msg,
+                          WPARAM wParam,
+                          LPARAM lParam,
+                          UINT uFlags,
+                          UINT uTimeout,
+                          ULONG_PTR *uResult )
 {
    PWINDOW_OBJECT DesktopWindow;
    HWND *Children;
@@ -1643,21 +1524,160 @@ co_IntSendMessageTimeout(HWND hWnd,
    return (LRESULT) TRUE;
 }
 
+LRESULT FASTCALL co_IntSendMessageNoWait(HWND hWnd,
+                                         UINT Msg,
+                                         WPARAM wParam,
+                                         LPARAM lParam)
+{
+   ULONG_PTR Result = 0;
+   co_IntSendMessageWithCallBack(hWnd,
+                                 Msg,
+                                 wParam,
+                                 lParam,
+                                 NULL,
+                                 0,
+                                 &Result);
+   return Result;
+}
+
+LRESULT FASTCALL
+co_IntSendMessageWithCallBack( HWND hWnd,
+                               UINT Msg,
+                               WPARAM wParam,
+                               LPARAM lParam,
+                               SENDASYNCPROC CompletionCallback,
+                               ULONG_PTR CompletionCallbackContext,
+                               ULONG_PTR *uResult)
+{
+   ULONG_PTR Result;
+   PWINDOW_OBJECT Window = NULL;
+   PMSGMEMORY MsgMemoryEntry;
+   INT lParamBufferSize;
+   LPARAM lParamPacked;
+   PTHREADINFO Win32Thread;
+   DECLARE_RETURN(LRESULT);
+   USER_REFERENCE_ENTRY Ref;
+   PUSER_SENT_MESSAGE Message;
+
+   if (!(Window = UserGetWindowObject(hWnd)))
+   {
+       RETURN(FALSE);
+   }
+
+   UserRefObjectCo(Window, &Ref);
+
+   if (Window->state & WINDOWSTATUS_DESTROYING)
+   {
+      /* FIXME - last error? */
+      DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
+      RETURN(FALSE);
+   }
+
+   Win32Thread = PsGetCurrentThreadWin32Thread();
+
+   IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
+
+   if (Win32Thread == NULL)
+   {
+     ASSERT(FALSE);
+     RETURN(FALSE);
+   }
+
+   if (Win32Thread->TIF_flags & TIF_INCLEANUP)
+   {
+      /* Never send messages to exiting threads */
+       RETURN(FALSE);
+   }
+
+   /* See if this message type is present in the table */
+   MsgMemoryEntry = FindMsgMemory(Msg);
+   if (NULL == MsgMemoryEntry)
+   {
+      lParamBufferSize = -1;
+   }
+   else
+   {
+      lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
+   }
+
+   if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, Window->pti->MessageQueue != Win32Thread->MessageQueue)))
+   {
+       DPRINT1("Failed to pack message parameters\n");
+       RETURN( FALSE);
+   }
+
+   /* If this is not a callback and it can be sent now, then send it. */
+   if ((Window->pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
+   {
+
+      Result = (ULONG_PTR)co_IntCallWindowProc( Window->Wnd->lpfnWndProc,
+                                               !Window->Wnd->Unicode,
+                                                hWnd,
+                                                Msg,
+                                                wParam,
+                                                lParamPacked,
+                                                lParamBufferSize );
+      if(uResult)
+      {
+         *uResult = Result;
+      }
+   }
+
+   IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
+
+   if ((Window->pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
+   {
+      if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
+      {
+         DPRINT1("Failed to unpack message parameters\n");
+      }
+      RETURN(TRUE);
+   }
+
+   if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
+   {
+      DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
+      return STATUS_INSUFFICIENT_RESOURCES;
+   }
+
+   Message->Msg.hwnd = hWnd;
+   Message->Msg.message = Msg;
+   Message->Msg.wParam = wParam;
+   Message->Msg.lParam = lParamPacked;
+   Message->CompletionEvent = NULL;
+   Message->Result = 0;
+   Message->SenderQueue = NULL; //Win32Thread->MessageQueue;
+
+   IntReferenceMessageQueue(Window->pti->MessageQueue);
+   Message->CompletionCallback = CompletionCallback;
+   Message->CompletionCallbackContext = CompletionCallbackContext;
+   Message->HookMessage = MSQ_NORMAL | MSQ_SENTNOWAIT;
+   Message->HasPackedLParam = (lParamBufferSize > 0);
+
+   InsertTailList(&Window->pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
+   IntDereferenceMessageQueue(Window->pti->MessageQueue);
+
+   RETURN(TRUE);
+
+CLEANUP:
+   if (Window) UserDerefObjectCo(Window);
+   END_CLEANUP;
+}
 
 /* This function posts a message if the destination's message queue belongs to
    another thread, otherwise it sends the message. It does not support broadcast
    messages! */
 LRESULT FASTCALL
-co_IntPostOrSendMessage(HWND hWnd,
-                        UINT Msg,
-                        WPARAM wParam,
-                        LPARAM lParam)
+co_IntPostOrSendMessage( HWND hWnd,
+                         UINT Msg,
+                         WPARAM wParam,
+                         LPARAM lParam )
 {
    ULONG_PTR Result;
    PTHREADINFO pti;
    PWINDOW_OBJECT Window;
 
-   if(hWnd == HWND_BROADCAST)
+   if ( hWnd == HWND_BROADCAST )
    {
       return 0;
    }
@@ -1668,13 +1688,16 @@ co_IntPostOrSendMessage(HWND hWnd,
    }
 
    pti = PsGetCurrentThreadWin32Thread();
-   if(Window->MessageQueue != pti->MessageQueue)
+
+   if ( Window->pti->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;
       }
    }
@@ -1683,12 +1706,12 @@ co_IntPostOrSendMessage(HWND hWnd,
 }
 
 LRESULT FASTCALL
-co_IntDoSendMessage(HWND hWnd,
-                    UINT Msg,
-                    WPARAM wParam,
-                    LPARAM lParam,
-                    PDOSENDMESSAGE dsm,
-                    PNTUSERSENDMESSAGEINFO UnsafeInfo)
+co_IntDoSendMessage( HWND hWnd,
+                     UINT Msg,
+                     WPARAM wParam,
+                     LPARAM lParam,
+                     PDOSENDMESSAGE dsm,
+                     PNTUSERSENDMESSAGEINFO UnsafeInfo )
 {
    PTHREADINFO pti;
    LRESULT Result = TRUE;
@@ -1705,23 +1728,31 @@ co_IntDoSendMessage(HWND hWnd,
    if (HWND_BROADCAST != hWnd)
    {
       Window = UserGetWindowObject(hWnd);
-      if (NULL == Window)
+      if ( !Window || !Window->Wnd )
       {
          /* Tell usermode to not touch this one */
          Info.HandledByKernel = TRUE;
          MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
          return 0;
       }
-      if (!Window->Wnd)
-         return 0;
    }
 
-   /* FIXME: Check for an exiting window. */
+   /* Check for an exiting window. */
+   if (Window && Window->state & WINDOWSTATUS_DESTROYING)
+   {
+      DPRINT1("co_IntDoSendMessage Window Exiting!\n");
+   }
 
    /* See if the current thread can handle the message */
    pti = PsGetCurrentThreadWin32Thread();
-   if (HWND_BROADCAST != hWnd && NULL != pti &&
-         Window->MessageQueue == pti->MessageQueue)
+
+   // This is checked in user mode!!!!!!!
+   if ( HWND_BROADCAST != hWnd &&
+        NULL != pti &&
+        Window->pti->MessageQueue == pti->MessageQueue &&
+       !ISITHOOKED(WH_CALLWNDPROC) &&
+       !ISITHOOKED(WH_CALLWNDPROCRET) &&
+        ( Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST ) )
    {
       /* Gather the information usermode needs to call the window proc directly */
       Info.HandledByKernel = FALSE;
@@ -1733,20 +1764,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);
-      }
-      else
-      {
-          Info.Ansi = !Window->Wnd->Unicode;
-          Info.Proc = Window->Wnd->WndProc;
-      }
-
-      IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, &Result);
-
+      Info.Ansi = !Window->Wnd->Unicode;
+      Info.Proc = Window->Wnd->lpfnWndProc;
    }
    else
    {
@@ -1761,6 +1780,7 @@ co_IntDoSendMessage(HWND hWnd,
       UserModeMsg.wParam = wParam;
       UserModeMsg.lParam = lParam;
       MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
+
       Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
       if (! NT_SUCCESS(Status))
       {
@@ -1768,17 +1788,25 @@ co_IntDoSendMessage(HWND hWnd,
          SetLastWin32Error(ERROR_INVALID_PARAMETER);
          return (dsm ? 0 : -1);
       }
+
       if(!dsm)
       {
-         Result = co_IntSendMessage(KernelModeMsg.hwnd, KernelModeMsg.message,
-                                    KernelModeMsg.wParam, KernelModeMsg.lParam);
+         Result = co_IntSendMessage( KernelModeMsg.hwnd,
+                                     KernelModeMsg.message,
+                                     KernelModeMsg.wParam,
+                                     KernelModeMsg.lParam );
       }
       else
       {
-         Result = co_IntSendMessageTimeout(KernelModeMsg.hwnd, KernelModeMsg.message,
-                                           KernelModeMsg.wParam, KernelModeMsg.lParam,
-                                           dsm->uFlags, dsm->uTimeout, &dsm->Result);
+         Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
+                                            KernelModeMsg.message,
+                                            KernelModeMsg.wParam,
+                                            KernelModeMsg.lParam,
+                                            dsm->uFlags,
+                                            dsm->uTimeout,
+                                           &dsm->Result );
       }
+
       Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
       if (! NT_SUCCESS(Status))
       {
@@ -1797,27 +1825,201 @@ co_IntDoSendMessage(HWND hWnd,
    return (LRESULT)Result;
 }
 
-LRESULT APIENTRY
-NtUserSendMessageTimeout(HWND hWnd,
-                         UINT Msg,
-                         WPARAM wParam,
-                         LPARAM lParam,
-                         UINT uFlags,
-                         UINT uTimeout,
-                         ULONG_PTR *uResult,
-                         PNTUSERSENDMESSAGEINFO UnsafeInfo)
-{
-   DOSENDMESSAGE dsm;
-   LRESULT Result;
-   DECLARE_RETURN(BOOL);
 
-   DPRINT("Enter NtUserSendMessageTimeout\n");
-   UserEnterExclusive();
+BOOL FASTCALL
+UserSendNotifyMessage( HWND hWnd,
+                       UINT Msg,
+                       WPARAM wParam,
+                       LPARAM lParam )
+{
+   BOOL Result = TRUE;
 
-   dsm.uFlags = uFlags;
-   dsm.uTimeout = uTimeout;
-   Result = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
-   if(uResult != NULL && Result != 0)
+   if (FindMsgMemory(Msg) != 0)
+   {
+      SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+      return FALSE;
+   }
+
+   // Basicly the same as IntPostOrSendMessage
+   if (hWnd == HWND_BROADCAST) //Handle Broadcast
+   {
+      HWND *List;
+      PWINDOW_OBJECT DesktopWindow;
+      ULONG i;
+
+      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->pti->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;
+}
+
+
+DWORD APIENTRY
+IntGetQueueStatus(BOOL ClearChanges)
+{
+   PTHREADINFO pti;
+   PUSER_MESSAGE_QUEUE Queue;
+   DWORD Result;
+   DECLARE_RETURN(DWORD);
+
+   DPRINT("Enter IntGetQueueStatus\n");
+
+   pti = PsGetCurrentThreadWin32Thread();
+   Queue = pti->MessageQueue;
+
+   Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
+   if (ClearChanges)
+   {
+      Queue->ChangedBits = 0;
+   }
+
+   RETURN(Result);
+
+CLEANUP:
+   DPRINT("Leave IntGetQueueStatus, ret=%i\n",_ret_);
+   END_CLEANUP;
+}
+
+BOOL APIENTRY
+IntInitMessagePumpHook()
+{
+   if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti)
+   {
+     ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook++;
+     return TRUE;
+   }
+   return FALSE;
+}
+
+BOOL APIENTRY
+IntUninitMessagePumpHook()
+{
+   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;
+}
+
+/** Functions ******************************************************************/
+
+BOOL APIENTRY
+NtUserPostMessage(HWND hWnd,
+                  UINT Msg,
+                  WPARAM wParam,
+                  LPARAM lParam)
+{
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserPostMessage\n");
+   UserEnterExclusive();
+
+   RETURN( UserPostMessage(hWnd, Msg, wParam, lParam));
+
+CLEANUP:
+   DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
+BOOL APIENTRY
+NtUserPostThreadMessage(DWORD idThread,
+                        UINT Msg,
+                        WPARAM wParam,
+                        LPARAM lParam)
+{
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserPostThreadMessage\n");
+   UserEnterExclusive();
+
+   RETURN( UserPostThreadMessage( idThread,
+                                  Msg,
+                                  wParam,
+                                  lParam));
+
+CLEANUP:
+   DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
+DWORD APIENTRY
+NtUserQuerySendMessage(DWORD Unknown0)
+{
+   UNIMPLEMENTED;
+
+   return 0;
+}
+
+
+////////// API on the way out!
+LRESULT APIENTRY
+NtUserSendMessageTimeout( HWND hWnd,
+                          UINT Msg,
+                          WPARAM wParam,
+                          LPARAM lParam,
+                          UINT uFlags,
+                          UINT uTimeout,
+                          ULONG_PTR *uResult,
+                          PNTUSERSENDMESSAGEINFO UnsafeInfo )
+{
+   DOSENDMESSAGE dsm;
+   LRESULT Result;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserSendMessageTimeout\n");
+   UserEnterExclusive();
+
+   dsm.uFlags = uFlags;
+   dsm.uTimeout = uTimeout;
+   Result = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
+   if(uResult != NULL && Result != 0)
    {
       NTSTATUS Status;
 
@@ -1837,11 +2039,11 @@ CLEANUP:
 }
 
 LRESULT APIENTRY
-NtUserSendMessage(HWND Wnd,
-                  UINT Msg,
-                  WPARAM wParam,
-                  LPARAM lParam,
-                  PNTUSERSENDMESSAGEINFO UnsafeInfo)
+NtUserSendMessage( HWND Wnd,
+                   UINT Msg,
+                   WPARAM wParam,
+                   LPARAM lParam,
+                   PNTUSERSENDMESSAGEINFO UnsafeInfo )
 {
    DECLARE_RETURN(BOOL);
 
@@ -1855,172 +2057,458 @@ CLEANUP:
    UserLeave();
    END_CLEANUP;
 }
+//////////
 
+BOOL APIENTRY
+NtUserWaitMessage(VOID)
+{
+   DECLARE_RETURN(BOOL);
 
-BOOL FASTCALL
-UserSendNotifyMessage(HWND hWnd,
-                      UINT Msg,
-                      WPARAM wParam,
-                      LPARAM lParam)
+   DPRINT("EnterNtUserWaitMessage\n");
+   UserEnterExclusive();
+
+   RETURN(co_IntWaitMessage(NULL, 0, 0));
+
+CLEANUP:
+   DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
+
+BOOL APIENTRY
+NtUserGetMessage( PNTUSERGETMESSAGEINFO UnsafeInfo,
+                  HWND hWnd,
+                  UINT MsgFilterMin,
+                  UINT MsgFilterMax )
+/*
+ * FUNCTION: Get a message from the calling thread's message queue.
+ * ARGUMENTS:
+ *      UnsafeMsg - Pointer to the structure which receives the returned message.
+ *      Wnd - Window whose messages are to be retrieved.
+ *      MsgFilterMin - Integer value of the lowest message value to be
+ *                     retrieved.
+ *      MsgFilterMax - Integer value of the highest message value to be
+ *                     retrieved.
+ */
 {
-   BOOL Result = TRUE;
-   // Basicly the same as IntPostOrSendMessage
-   if (hWnd == HWND_BROADCAST) //Handle Broadcast
+   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;
+   USER_MESSAGE Msg;
+   DECLARE_RETURN(BOOL);
+//   USER_REFERENCE_ENTRY Ref;
+
+   DPRINT("Enter NtUserGetMessage\n");
+   UserEnterExclusive();
+
+   /* Validate input */
+   if (hWnd && !(Window = UserGetWindowObject(hWnd)))
    {
-      HWND *List;
-      PWINDOW_OBJECT DesktopWindow;
-      ULONG i;
+      RETURN(-1);
+   }
 
-      DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
-      List = IntWinListChildren(DesktopWindow);
+//   if (Window) UserRefObjectCo(Window, &Ref);
 
-      if (List != NULL)
+   if (MsgFilterMax < MsgFilterMin)
+   {
+      MsgFilterMin = 0;
+      MsgFilterMax = 0;
+   }
+
+   do
+   {
+      GotMessage = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, PM_REMOVE);
+      if (GotMessage)
+      {
+         Info.Msg = Msg.Msg;
+         /* See if this message type is present in the table */
+         MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
+         if (NULL == MsgMemoryEntry)
+         {
+            /* Not present, no copying needed */
+            Info.LParamSize = 0;
+         }
+         else
+         {
+            /* Determine required size */
+            Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
+                                 Info.Msg.lParam);
+            /* Allocate required amount of user-mode memory */
+            Info.LParamSize = Size;
+            UserMem = NULL;
+            Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
+                                             &Info.LParamSize, 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);
+            if (! NT_SUCCESS(Status))
+            {
+               ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
+                                   &Info.LParamSize, MEM_DECOMMIT);
+               SetLastNtError(Status);
+               RETURN( (BOOL) -1);
+            }
+            Info.Msg.lParam = (LPARAM) UserMem;
+         }
+         if (Msg.FreeLParam && 0 != Msg.Msg.lParam)
+         {
+            ExFreePool((void *) Msg.Msg.lParam);
+         }
+         Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
+         if (! NT_SUCCESS(Status))
+         {
+            SetLastNtError(Status);
+            RETURN( (BOOL) -1);
+         }
+      }
+      else if (! co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax))
+      {
+         RETURN( (BOOL) -1);
+      }
+   }
+   while (! GotMessage);
+
+   RETURN( WM_QUIT != Info.Msg.message);
+
+CLEANUP:
+//   if (Window) UserDerefObjectCo(Window);
+
+   DPRINT("Leave NtUserGetMessage\n");
+   UserLeave();
+   END_CLEANUP;
+}
+
+
+BOOL
+APIENTRY
+NtUserGetMessageX(
+   PMSG pMsg,
+   HWND hWnd,
+   UINT MsgFilterMin,
+   UINT MsgFilterMax)
+{
+   MSG Msg;
+   BOOL Ret = FALSE;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserGetMessage\n");
+   UserEnterExclusive();
+
+   if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
+   {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      RETURN( Ret);
+   }
+
+   RtlZeroMemory(&Msg, sizeof(MSG));
+
+   Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
+
+   if (Ret)
+   {
+      _SEH2_TRY
+      {
+         ProbeForWrite(pMsg, sizeof(MSG), 1);
+         RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
+      }
+      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+      {
+         SetLastNtError(_SEH2_GetExceptionCode());
+         Ret = FALSE;
+      }
+      _SEH2_END;
+   }
+   RETURN( Ret);
+
+CLEANUP:
+   DPRINT("Leave NtUserGetMessage\n");
+   UserLeave();
+   END_CLEANUP;
+}
+
+BOOL APIENTRY
+NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
+                  HWND hWnd,
+                  UINT MsgFilterMin,
+                  UINT MsgFilterMax,
+                  UINT RemoveMsg)
+{
+   NTSTATUS Status;
+   BOOL Present;
+   NTUSERGETMESSAGEINFO Info;
+   PWINDOW_OBJECT Window;
+   PMSGMEMORY MsgMemoryEntry;
+   PVOID UserMem;
+   UINT 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 != (HWND)1)
+   {
+      if (!(Window = UserGetWindowObject(hWnd)))
       {
-         for (i = 0; List[i]; i++)
-         {
-            UserSendNotifyMessage(List[i], Msg, wParam, lParam);
-         }
-         ExFreePool(List);
+         RETURN(-1);
       }
    }
    else
    {
-     ULONG_PTR PResult;
-     PTHREADINFO pti;
-     PWINDOW_OBJECT Window;
-     NTSTATUS Status;
-     MSG UserModeMsg;
-     MSG KernelModeMsg;
-     PMSGMEMORY MsgMemoryEntry;
+      Window = (PWINDOW_OBJECT)hWnd;
+   }
+
+   if (MsgFilterMax < MsgFilterMin)
+   {
+      MsgFilterMin = 0;
+      MsgFilterMax = 0;
+   }
 
-      if(!(Window = UserGetWindowObject(hWnd))) return FALSE;
+   Present = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, RemoveMsg);
+   if (Present)
+   {
 
-      pti = PsGetCurrentThreadWin32Thread();
-      if(Window->MessageQueue != pti->MessageQueue)
-      { // Send message w/o waiting for it.
-         Result = UserPostMessage(hWnd, Msg, wParam, lParam);
+      Info.Msg = Msg.Msg;
+      /* See if this message type is present in the table */
+      MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
+      if (NULL == MsgMemoryEntry)
+      {
+         /* Not present, no copying needed */
+         Info.LParamSize = 0;
       }
       else
-      { // Handle message and callback.
-         UserModeMsg.hwnd = hWnd;
-         UserModeMsg.message = Msg;
-         UserModeMsg.wParam = wParam;
-         UserModeMsg.lParam = lParam;
-         MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
-         Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
+      {
+         /* Determine required size */
+         Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
+                              Info.Msg.lParam);
+         /* Allocate required amount of user-mode memory */
+         Info.LParamSize = Size;
+         UserMem = NULL;
+         Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
+                                          &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
          if (! NT_SUCCESS(Status))
          {
-            SetLastWin32Error(ERROR_INVALID_PARAMETER);
-            return FALSE;
+            SetLastNtError(Status);
+            RETURN( (BOOL) -1);
          }
-         Result = co_IntSendMessageTimeoutSingle(
-                                   KernelModeMsg.hwnd, KernelModeMsg.message,
-                                   KernelModeMsg.wParam, KernelModeMsg.lParam,
-                                   SMTO_NORMAL, 0, &PResult);
-
-         Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
+         /* Transfer lParam data to user-mode mem */
+         Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
          if (! NT_SUCCESS(Status))
          {
-            SetLastWin32Error(ERROR_INVALID_PARAMETER);
-            return FALSE;
+            ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
+                                &Info.LParamSize, MEM_RELEASE);
+            SetLastNtError(Status);
+            RETURN( (BOOL) -1);
          }
+         Info.Msg.lParam = (LPARAM) UserMem;
+      }
+      if (RemoveMsg && Msg.FreeLParam && 0 != Msg.Msg.lParam)
+      {
+         ExFreePool((void *) Msg.Msg.lParam);
+      }
+      Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
+      if (! NT_SUCCESS(Status))
+      {
+         SetLastNtError(Status);
+         RETURN( (BOOL) -1);
       }
    }
-   return Result;
-}
 
-
-BOOL APIENTRY
-NtUserSendNotifyMessage(HWND hWnd,
-                        UINT Msg,
-                        WPARAM wParam,
-                        LPARAM lParam)
-{
-   DECLARE_RETURN(BOOL);
-
-   DPRINT("EnterNtUserSendNotifyMessage\n");
-   UserEnterExclusive();
-
-   RETURN(UserSendNotifyMessage(hWnd, Msg, wParam, lParam));
+   RETURN( Present);
 
 CLEANUP:
-   DPRINT("Leave NtUserSendNotifyMessage, ret=%i\n",_ret_);
+   DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
    UserLeave();
    END_CLEANUP;
-
 }
 
-
-BOOL APIENTRY
-NtUserWaitMessage(VOID)
+BOOL
+APIENTRY
+NtUserPeekMessageX(
+   PMSG pMsg,
+   HWND hWnd,
+   UINT MsgFilterMin,
+   UINT MsgFilterMax,
+   UINT RemoveMsg)
 {
+   MSG Msg;
+   BOOL Ret = FALSE;
    DECLARE_RETURN(BOOL);
 
-   DPRINT("EnterNtUserWaitMessage\n");
+   DPRINT("Enter NtUserPeekMessage\n");
    UserEnterExclusive();
 
-   RETURN(co_IntWaitMessage(NULL, 0, 0));
+   if ( RemoveMsg & PM_BADMSGFLAGS )
+   {
+      SetLastWin32Error(ERROR_INVALID_FLAGS);
+      RETURN( Ret);
+   }
+
+   RtlZeroMemory(&Msg, sizeof(MSG));
+
+   Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
+
+   if (Ret)
+   {
+      _SEH2_TRY
+      {
+         ProbeForWrite(pMsg, sizeof(MSG), 1);
+         RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
+      }
+      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+      {
+         SetLastNtError(_SEH2_GetExceptionCode());
+         Ret = FALSE;
+      }
+      _SEH2_END;
+   }
+   RETURN( Ret);
 
 CLEANUP:
-   DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_);
+   DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
    UserLeave();
    END_CLEANUP;
 }
 
-DWORD APIENTRY
-IntGetQueueStatus(BOOL ClearChanges)
+BOOL
+APIENTRY
+NtUserCallMsgFilter(
+   LPMSG lpmsg,
+   INT code)
 {
-   PTHREADINFO pti;
-   PUSER_MESSAGE_QUEUE Queue;
-   DWORD Result;
-   DECLARE_RETURN(DWORD);
+   BOOL BadChk = FALSE, Ret = FALSE;
+   MSG Msg;
+   DECLARE_RETURN(BOOL);
 
-   DPRINT("Enter IntGetQueueStatus\n");
+   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);
 
-   pti = PsGetCurrentThreadWin32Thread();
-   Queue = pti->MessageQueue;
+   if (BadChk) RETURN( FALSE);
 
-   Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
-   if (ClearChanges)
+   if ( ISITHOOKED(WH_SYSMSGFILTER) &&
+        co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
    {
-      Queue->ChangedBits = 0;
+      Ret = TRUE;
+   }
+   else
+   {
+      if ( ISITHOOKED(WH_MSGFILTER) )
+      {
+         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 IntGetQueueStatus, ret=%i\n",_ret_);
+   DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_);
+   UserLeave();
    END_CLEANUP;
 }
 
-BOOL APIENTRY
-IntInitMessagePumpHook()
+LRESULT APIENTRY
+NtUserDispatchMessage(PMSG UnsafeMsgInfo)
 {
-   if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo)
-   {
-     ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook++;
-     return TRUE;
-   }
-   return FALSE;
+  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 APIENTRY
-IntUninitMessagePumpHook()
+NtUserTranslateMessage(LPMSG lpMsg,
+                       UINT flags)
 {
-   if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo)
+   NTSTATUS Status;
+   MSG SafeMsg;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserTranslateMessage\n");
+   UserEnterExclusive();
+
+   Status = MmCopyFromCaller(&SafeMsg, lpMsg, sizeof(MSG));
+   if(!NT_SUCCESS(Status))
    {
-      if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook <= 0)
-      {
-         return FALSE;
-      }
-      ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook--;
-      return TRUE;
+      SetLastNtError(Status);
+      RETURN( FALSE);
    }
-   return FALSE;
-}
 
+   RETURN( IntTranslateKbdMessage(&SafeMsg, flags));
 
-LRESULT APIENTRY
+CLEANUP:
+   DPRINT("Leave NtUserTranslateMessage: ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
+BOOL APIENTRY
 NtUserMessageCall(
    HWND hWnd,
    UINT Msg,
@@ -2031,6 +2519,8 @@ NtUserMessageCall(
    BOOL Ansi)
 {
    LRESULT lResult = 0;
+   BOOL Ret = FALSE;
+   BOOL BadChk = FALSE;
    PWINDOW_OBJECT Window = NULL;
    USER_REFERENCE_ENTRY Ref;
 
@@ -2039,21 +2529,24 @@ NtUserMessageCall(
    /* Validate input */
    if (hWnd && (hWnd != INVALID_HANDLE_VALUE) && !(Window = UserGetWindowObject(hWnd)))
    {
-      return 0;
+      UserLeave();
+      return FALSE;
    }
    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:
       {
-         PBROADCASTPARM parm;
-         BOOL BadChk = FALSE;
+         BROADCASTPARM parm;
          DWORD_PTR RetVal = 0;
-         lResult = -1;
 
          if (ResultInfo)
          {
@@ -2062,7 +2555,7 @@ NtUserMessageCall(
                ProbeForWrite((PVOID)ResultInfo,
                          sizeof(BROADCASTPARM),
                                              1);
-               parm = (PBROADCASTPARM)ResultInfo;
+               RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
             }
             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
@@ -2074,15 +2567,15 @@ NtUserMessageCall(
          else
            break;
 
-         if ( parm->recipients & BSM_ALLDESKTOPS ||
-              parm->recipients == BSM_ALLCOMPONENTS )
+         if ( parm.recipients & BSM_ALLDESKTOPS ||
+              parm.recipients == BSM_ALLCOMPONENTS )
          {
          }
-         else if (parm->recipients & BSM_APPLICATIONS)
+         else if (parm.recipients & BSM_APPLICATIONS)
          {
-            if (parm->flags & BSF_QUERY)
+            if (parm.flags & BSF_QUERY)
             {
-               if (parm->flags & BSF_FORCEIFHUNG || parm->flags & BSF_NOHANG)
+               if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
                {
                   co_IntSendMessageTimeout( HWND_BROADCAST,
                                             Msg,
@@ -2092,7 +2585,7 @@ NtUserMessageCall(
                                             2000,
                                             &RetVal);
                }
-               else if (parm->flags & BSF_NOTIMEOUTIFNOTHUNG)
+               else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
                {
                   co_IntSendMessageTimeout( HWND_BROADCAST,
                                             Msg,
@@ -2113,18 +2606,30 @@ NtUserMessageCall(
                                             &RetVal);
                }
             }
-            else if (parm->flags & BSF_POSTMESSAGE)
+            else if (parm.flags & BSF_POSTMESSAGE)
             {
-               lResult = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
+               Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
             }
-            else if ( parm->flags & BSF_SENDNOTIFYMESSAGE)
+            else if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
             {
-               lResult = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
+               Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
             }
          }
       }
       break;
       case FNID_SENDMESSAGECALLBACK:
+      {
+         PCALL_BACK_INFO CallBackInfo = (PCALL_BACK_INFO)ResultInfo;
+
+         if (!CallBackInfo)
+            break;
+
+         if (!co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
+             CallBackInfo->CallBack, CallBackInfo->Context, NULL))
+         {
+            DPRINT1("Callback failure!\n");
+         }
+      }
       break;
       // CallNextHook bypass.
       case FNID_CALLWNDPROC:
@@ -2185,8 +2690,33 @@ NtUserMessageCall(
       }
       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 lResult;
+
+   return BadChk ? FALSE : Ret;
 }
 
 #define INFINITE 0xFFFFFFFF
@@ -2200,7 +2730,7 @@ NtUserWaitForInputIdle(
    IN BOOL Unknown2)
 {
   PEPROCESS Process;
-  PW32PROCESS W32Process;
+  PPROCESSINFO W32Process;
   NTSTATUS Status;
   HANDLE Handles[2];
   LARGE_INTEGER Timeout;
@@ -2222,7 +2752,7 @@ NtUserWaitForInputIdle(
      return WAIT_FAILED;
   }
 
-  W32Process = (PW32PROCESS)Process->Win32Process;
+  W32Process = (PPROCESSINFO)Process->Win32Process;
   if (!W32Process)
   {
       ObDereferenceObject(Process);
@@ -2309,7 +2839,7 @@ NtUserWaitForInputIdle(
 WaitExit:
   if (W32Process->InputIdleEvent)
   {
-     EngDeleteEvent((PEVENT)W32Process->InputIdleEvent);
+     EngFreeMem((PVOID)W32Process->InputIdleEvent);
      W32Process->InputIdleEvent = NULL;
   }
   ObDereferenceObject(Process);