[win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / message.c
index bef05ad..5d1cf8e 100644 (file)
@@ -10,7 +10,7 @@
 
 /* INCLUDES ******************************************************************/
 
-#include <w32k.h>
+#include <win32k.h>
 
 #define NDEBUG
 #include <debug.h>
@@ -145,7 +145,7 @@ MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
                break;
 
             default:
-               assert(FALSE);
+               ASSERT(FALSE);
                Size = 0;
                break;
          }
@@ -165,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))
@@ -210,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");
@@ -244,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;
@@ -277,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);
 
@@ -394,7 +434,7 @@ IntDispatchMessage(PMSG pMsg)
      lParamBufferSize = MsgMemorySize(MsgMemoryEntry, pMsg->wParam, pMsg->lParam);
   }
 
-  if (! NT_SUCCESS(PackParam(&lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam)))
+  if (! NT_SUCCESS(PackParam(&lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam, FALSE)))
   {
      DPRINT1("Failed to pack message parameters\n");
      return 0;
@@ -408,7 +448,7 @@ IntDispatchMessage(PMSG pMsg)
                                  lParamPacked,
                                  lParamBufferSize);
 
-  if (! NT_SUCCESS(UnpackParam(lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam)))
+  if (! NT_SUCCESS(UnpackParam(lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam, FALSE)))
   {
      DPRINT1("Failed to unpack message parameters\n");
   }
@@ -416,9 +456,9 @@ IntDispatchMessage(PMSG pMsg)
   if (pMsg->message == WM_PAINT)
   {
   /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
-     HRGN hrgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
+     HRGN hrgn = IntSysCreateRectRgn( 0, 0, 0, 0 );
      co_UserGetUpdateRgn( Window, hrgn, TRUE );
-     GreDeleteObject( hrgn );
+     REGION_FreeRgnByHandle( hrgn );
   }
   return retval;
 }
@@ -541,7 +581,7 @@ co_IntTranslateMouseMessage(
 
    UserRefObjectCo(Window, &Ref);
 
-   if ( ThreadQueue == Window->MessageQueue &&
+   if ( ThreadQueue == Window->pti->MessageQueue &&
         ThreadQueue->CaptureWindow != Window->hSelf)
    {
       /* only send WM_NCHITTEST messages if we're not capturing the window! */
@@ -559,7 +599,7 @@ co_IntTranslateMouseMessage(
 
             UserRefObjectCo(DesktopWindow, &DesktopRef);
 
-            co_WinPosWindowFromPoint(DesktopWindow, Window->MessageQueue, &Msg->pt, &Wnd);
+            co_WinPosWindowFromPoint(DesktopWindow, Window->pti->MessageQueue, &Msg->pt, &Wnd);
             if (Wnd)
             {
                if (Wnd != Window)
@@ -568,7 +608,7 @@ co_IntTranslateMouseMessage(
                   Msg->hwnd = Wnd->hSelf;
                   if(!(Wnd->state & WINDOWSTATUS_DESTROYING))
                   {
-                     MsqPostMessage(Wnd->MessageQueue, Msg, FALSE,
+                     MsqPostMessage(Wnd->pti->MessageQueue, Msg, FALSE,
                                     Msg->message == WM_MOUSEMOVE ? QS_MOUSEMOVE :
                                     QS_MOUSEBUTTON);
                   }
@@ -645,6 +685,74 @@ co_IntTranslateMouseMessage(
    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
  */
@@ -662,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() */
@@ -671,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;
@@ -755,23 +880,8 @@ CheckMessages:
       goto MsgExit;
    }
 
-   if (ThreadQueue->WakeMask & QS_TIMER)
-      if (PostTimerMessages(Window)) // If there are timers ready,
-         goto CheckMessages;       // go back and process them.
-
-   // LOL! Polling Timer Queue? How much time is spent doing this?
-   /* Check for WM_(SYS)TIMER messages */
-   Present = MsqGetTimerMessage( ThreadQueue,
-                                 Window,
-                                 MsgFilterMin,
-                                 MsgFilterMax,
-                                &Msg->Msg,
-                                 RemoveMessages);
-   if (Present)
-   {
-      Msg->FreeLParam = FALSE;
-      goto MessageFound;
-   }
+   if (PostTimerMessages(Window))
+      goto CheckMessages;
 
    if(Present)
    {
@@ -834,7 +944,8 @@ MessageFound:
          goto MsgExit;
       }
 
-      if ( ( Msg->Msg.hwnd && Msg->Msg.message >= WM_MOUSEFIRST &&
+      if ( ( Msg->Msg.hwnd &&
+             Msg->Msg.message >= WM_MOUSEFIRST &&
              Msg->Msg.message <= WM_MOUSELAST ) &&
            co_IntTranslateMouseMessage( ThreadQueue,
                                        &Msg->Msg,
@@ -848,52 +959,20 @@ MessageFound:
       }
 
 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_MOUSE) && IS_MOUSE_MESSAGE(Msg->Msg.message))
+      {
+          if(!ProcessMouseMessage(&Msg->Msg, HitTest, RemoveMsg))
+                 {
+                         return FALSE;
+                 }
+         }
 
-      if ( ISITHOOKED(WH_KEYBOARD) &&
-          (Msg->Msg.message == WM_KEYDOWN || Msg->Msg.message == WM_KEYUP) )
+      if ( ISITHOOKED(WH_KEYBOARD) && IS_KBD_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(!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.
@@ -908,58 +987,6 @@ MsgExit:
    return Present;
 }
 
-BOOL FASTCALL
-co_IntGetPeekMessage( PMSG pMsg,
-                      HWND hWnd,
-                      UINT MsgFilterMin,
-                      UINT MsgFilterMax,
-                      UINT RemoveMsg,
-                      BOOL bGMSG )
-{
-   return FALSE;
-}
-
-
-static BOOL FASTCALL
-co_IntWaitMessage( PWINDOW_OBJECT Window,
-                   UINT MsgFilterMin,
-                   UINT MsgFilterMax )
-{
-   PTHREADINFO pti;
-   PUSER_MESSAGE_QUEUE ThreadQueue;
-   NTSTATUS Status = STATUS_SUCCESS;
-   USER_MESSAGE Msg;
-
-   pti = PsGetCurrentThreadWin32Thread();
-   ThreadQueue = pti->MessageQueue;
-
-   do
-   {
-      if ( co_IntPeekMessage( &Msg,
-                               Window,
-                               MsgFilterMin,
-                               MsgFilterMax,
-                               PM_NOREMOVE))
-      {
-         return TRUE;
-      }
-      /* Nothing found. Wait for new messages. */
-      Status = co_MsqWaitForNewMessages( ThreadQueue,
-                                         Window,
-                                         MsgFilterMin,
-                                         MsgFilterMax);
-   }
-   while ( (STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) ||
-           STATUS_TIMEOUT == Status );
-
-   SetLastNtError(Status);
-
-   DPRINT1("Exit co_IntWaitMessage on error!\n");
-
-   return FALSE;
-}
-
-
 static NTSTATUS FASTCALL
 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
 {
@@ -1054,6 +1081,123 @@ CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
    return STATUS_SUCCESS;
 }
 
+static BOOL FASTCALL
+co_IntWaitMessage( PWINDOW_OBJECT Window,
+                   UINT MsgFilterMin,
+                   UINT MsgFilterMax )
+{
+   PTHREADINFO pti;
+   PUSER_MESSAGE_QUEUE ThreadQueue;
+   NTSTATUS Status = STATUS_SUCCESS;
+   USER_MESSAGE Msg;
+
+   pti = PsGetCurrentThreadWin32Thread();
+   ThreadQueue = pti->MessageQueue;
+
+   do
+   {
+      if ( co_IntPeekMessage( &Msg,
+                               Window,
+                               MsgFilterMin,
+                               MsgFilterMax,
+                               PM_NOREMOVE))
+      {
+         return TRUE;
+      }
+      /* Nothing found. Wait for new messages. */
+      Status = co_MsqWaitForNewMessages( ThreadQueue,
+                                         Window,
+                                         MsgFilterMin,
+                                         MsgFilterMax);
+   }
+   while ( (STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) ||
+           STATUS_TIMEOUT == Status );
+
+   if (!NT_SUCCESS(Status))
+   {
+      SetLastNtError(Status);
+      DPRINT1("Exit co_IntWaitMessage on error!\n");
+   }
+
+   return FALSE;
+}
+
+BOOL FASTCALL
+co_IntGetPeekMessage( PMSG pMsg,
+                      HWND hWnd,
+                      UINT MsgFilterMin,
+                      UINT MsgFilterMax,
+                      UINT RemoveMsg,
+                      BOOL bGMSG )
+{
+   BOOL Present;
+   PWINDOW_OBJECT Window;
+   USER_MESSAGE Msg;
+
+   if ( hWnd == HWND_TOPMOST ||
+        hWnd == HWND_BROADCAST )
+      hWnd = HWND_BOTTOM;
+
+   /* Validate input */
+   if (hWnd && hWnd != HWND_BOTTOM)
+   {
+      if (!(Window = UserGetWindowObject(hWnd)))
+      {
+         if (bGMSG)
+            return -1;
+         else
+            return FALSE;
+      }
+   }
+   else
+   {
+      Window = (PWINDOW_OBJECT)hWnd;
+   }
+
+   if (MsgFilterMax < MsgFilterMin)
+   {
+      MsgFilterMin = 0;
+      MsgFilterMax = 0;
+   }
+
+   do
+   {
+      Present = co_IntPeekMessage( &Msg,
+                                    Window,
+                                    MsgFilterMin,
+                                    MsgFilterMax,
+                                    RemoveMsg );
+      if (Present)
+      {
+         RtlCopyMemory( pMsg, &Msg.Msg, sizeof(MSG));
+
+         if (bGMSG)
+            return (WM_QUIT != pMsg->message);
+         else
+            return TRUE;
+      }
+
+      if ( bGMSG && !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax) )
+      {
+         return -1;
+      }
+      else
+      {
+         if (!(RemoveMsg & PM_NOYIELD))
+         {
+         // Yield this thread!
+            UserLeave();
+            ZwYieldExecution();
+            UserEnterExclusive();
+         // Fall through to fail.
+         }
+      }
+   }
+   while( bGMSG && !Present );
+
+   return FALSE;
+}
+
 BOOL FASTCALL
 UserPostThreadMessage( DWORD idThread,
                        UINT Msg,
@@ -1079,7 +1223,9 @@ UserPostThreadMessage( DWORD idThread,
    if( Status == STATUS_SUCCESS )
    {
       pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
-      if( !pThread || !pThread->MessageQueue || (pThread->TIF_flags & TIF_INCLEANUP))
+      if( !pThread ||
+          !pThread->MessageQueue ||
+         (pThread->TIF_flags & TIF_INCLEANUP))
       {
          ObDereferenceObject( peThread );
          return FALSE;
@@ -1168,7 +1314,7 @@ UserPostMessage( HWND Wnd,
 
       if (WM_QUIT == Msg)
       {
-          MsqPostQuitMessage(Window->MessageQueue, wParam);
+          MsqPostQuitMessage(Window->pti->MessageQueue, wParam);
       }
       else
       {
@@ -1179,7 +1325,7 @@ UserPostMessage( HWND Wnd,
          Message.pt = gpsi->ptCursor;
          KeQueryTickCount(&LargeTickCount);
          pti->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
-         MsqPostMessage(Window->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
+         MsqPostMessage(Window->pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
       }
    }
    return TRUE;
@@ -1232,7 +1378,7 @@ co_IntSendMessageTimeoutSingle( HWND hWnd,
    IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
 
    if ( NULL != Win32Thread &&
-        Window->MessageQueue == Win32Thread->MessageQueue)
+        Window->pti->MessageQueue == Win32Thread->MessageQueue)
    {
       if (Win32Thread->TIF_flags & TIF_INCLEANUP)
       {
@@ -1251,7 +1397,7 @@ 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);
@@ -1271,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);
@@ -1280,7 +1426,7 @@ 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);
@@ -1295,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);
 
@@ -1378,6 +1524,145 @@ 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
@@ -1404,7 +1689,7 @@ 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);
@@ -1464,7 +1749,7 @@ co_IntDoSendMessage( HWND hWnd,
    // This is checked in user mode!!!!!!!
    if ( HWND_BROADCAST != hWnd &&
         NULL != pti &&
-        Window->MessageQueue == pti->MessageQueue &&
+        Window->pti->MessageQueue == pti->MessageQueue &&
        !ISITHOOKED(WH_CALLWNDPROC) &&
        !ISITHOOKED(WH_CALLWNDPROCRET) &&
         ( Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST ) )
@@ -1585,7 +1870,7 @@ UserSendNotifyMessage( HWND hWnd,
 
       pti = PsGetCurrentThreadWin32Thread();
 
-      if (Window->MessageQueue != pti->MessageQueue)
+      if (Window->pti->MessageQueue != pti->MessageQueue)
       { // Send message w/o waiting for it.
          Result = UserPostMessage(hWnd, Msg, wParam, lParam);
       }
@@ -1926,6 +2211,8 @@ NtUserGetMessageX(
       RETURN( Ret);
    }
 
+   RtlZeroMemory(&Msg, sizeof(MSG));
+
    Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
 
    if (Ret)
@@ -2072,6 +2359,8 @@ NtUserPeekMessageX(
       RETURN( Ret);
    }
 
+   RtlZeroMemory(&Msg, sizeof(MSG));
+
    Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
 
    if (Ret)
@@ -2329,6 +2618,18 @@ NtUserMessageCall(
       }
       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:
@@ -2538,7 +2839,7 @@ NtUserWaitForInputIdle(
 WaitExit:
   if (W32Process->InputIdleEvent)
   {
-     EngDeleteEvent((PEVENT)W32Process->InputIdleEvent);
+     EngFreeMem((PVOID)W32Process->InputIdleEvent);
      W32Process->InputIdleEvent = NULL;
   }
   ObDereferenceObject(Process);