[User32|Win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / message.c
index 8cabf9f..030b1c9 100644 (file)
@@ -2,7 +2,7 @@
 * COPYRIGHT:        See COPYING in the top level directory
 * PROJECT:          ReactOS kernel
 * PURPOSE:          Messages
-* FILE:             subsys/win32k/ntuser/message.c
+* FILE:             subsystems/win32/win32k/ntuser/message.c
 * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
 * REVISION HISTORY:
 *       06-06-2001  CSH  Created
@@ -19,14 +19,6 @@ BOOLEAN NTAPI PsGetProcessExitProcessCalled(PEPROCESS Process);
 
 #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;
-    UINT uTimeout;
-    ULONG_PTR Result;
-}
-DOSENDMESSAGE, *PDOSENDMESSAGE;
-
 /* FUNCTIONS *****************************************************************/
 
 NTSTATUS FASTCALL
@@ -41,6 +33,81 @@ IntCleanupMessageImpl(VOID)
     return STATUS_SUCCESS;
 }
 
+/* From wine: */
+/* flag for messages that contain pointers */
+/* 32 messages per entry, messages 0..31 map to bits 0..31 */
+
+#define SET(msg) (1 << ((msg) & 31))
+
+static const unsigned int message_pointer_flags[] =
+{
+    /* 0x00 - 0x1f */
+    SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) |
+    SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
+    /* 0x20 - 0x3f */
+    SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) |
+    SET(WM_COMPAREITEM),
+    /* 0x40 - 0x5f */
+    SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) |
+    SET(WM_COPYGLOBALDATA) | SET(WM_NOTIFY) | SET(WM_HELP),
+    /* 0x60 - 0x7f */
+    SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
+    /* 0x80 - 0x9f */
+    SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
+    /* 0xa0 - 0xbf */
+    SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
+    /* 0xc0 - 0xdf */
+    SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
+    /* 0xe0 - 0xff */
+    SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO) | SET(SBM_GETSCROLLBARINFO),
+    /* 0x100 - 0x11f */
+    0,
+    /* 0x120 - 0x13f */
+    0,
+    /* 0x140 - 0x15f */
+    SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) |
+    SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) |
+    SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
+    /* 0x160 - 0x17f */
+    0,
+    /* 0x180 - 0x19f */
+    SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
+    SET(LB_DIR) | SET(LB_FINDSTRING) |
+    SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
+    /* 0x1a0 - 0x1bf */
+    SET(LB_FINDSTRINGEXACT),
+    /* 0x1c0 - 0x1df */
+    0,
+    /* 0x1e0 - 0x1ff */
+    0,
+    /* 0x200 - 0x21f */
+    SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE),
+    /* 0x220 - 0x23f */
+    SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
+    SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE),
+    /* 0x240 - 0x25f */
+    0,
+    /* 0x260 - 0x27f */
+    0,
+    /* 0x280 - 0x29f */
+    0,
+    /* 0x2a0 - 0x2bf */
+    0,
+    /* 0x2c0 - 0x2df */
+    0,
+    /* 0x2e0 - 0x2ff */
+    0,
+    /* 0x300 - 0x31f */
+    SET(WM_ASKCBFORMATNAME)
+};
+
+/* check whether a given message type includes pointers */
+static inline int is_pointer_message( UINT message )
+{
+    if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
+        return (message_pointer_flags[message / 32] & SET(message)) != 0;
+}
+
 #define MMS_SIZE_WPARAM      -1
 #define MMS_SIZE_WPARAMWCHAR -2
 #define MMS_SIZE_LPARAMSZ    -3
@@ -69,6 +136,7 @@ static MSGMEMORY MsgMemory[] =
     { WM_STYLECHANGED, sizeof(STYLESTRUCT), MMS_FLAG_READ },
     { WM_STYLECHANGING, sizeof(STYLESTRUCT), MMS_FLAG_READWRITE },
     { WM_COPYDATA, MMS_SIZE_SPECIAL, MMS_FLAG_READ },
+    { WM_COPYGLOBALDATA, MMS_SIZE_WPARAM, MMS_FLAG_READ },
     { WM_WINDOWPOSCHANGED, sizeof(WINDOWPOS), MMS_FLAG_READ },
     { WM_WINDOWPOSCHANGING, sizeof(WINDOWPOS), MMS_FLAG_READWRITE },
 };
@@ -142,10 +210,6 @@ MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
                 Size = sizeof(COPYDATASTRUCT) + ((PCOPYDATASTRUCT)lParam)->cbData;
                 break;
 
-            case WM_COPYGLOBALDATA:
-                Size = wParam;
-                break;
-
             default:
                 ASSERT(FALSE);
                 Size = 0;
@@ -251,11 +315,11 @@ PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL Non
         ASSERT(CsData == (PCHAR) PackedCs + Size);
         *lParamPacked = (LPARAM) PackedCs;
     }
-
     else if (PoolType == NonPagedPool)
     {
         PMSGMEMORY MsgMemoryEntry;
         PVOID PackedData;
+        SIZE_T size;
 
         MsgMemoryEntry = FindMsgMemory(Msg);
 
@@ -264,7 +328,13 @@ PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL Non
             /* Keep previous behavior */
             return STATUS_SUCCESS;
         }
-        PackedData = ExAllocatePoolWithTag(NonPagedPool, MsgMemorySize(MsgMemoryEntry, wParam, lParam), TAG_MSG);
+        size = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
+        if (!size)
+        {
+           DPRINT1("No size for lParamPacked\n");
+           return STATUS_SUCCESS;
+        }
+        PackedData = ExAllocatePoolWithTag(NonPagedPool, size, TAG_MSG);
         RtlCopyMemory(PackedData, (PVOID)lParam, MsgMemorySize(MsgMemoryEntry, wParam, lParam));
         *lParamPacked = (LPARAM)PackedData;
     }
@@ -325,6 +395,100 @@ UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL No
     return STATUS_INVALID_PARAMETER;
 }
 
+static NTSTATUS FASTCALL
+CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
+{
+    NTSTATUS Status;
+
+    PVOID KernelMem;
+    UINT Size;
+
+    *KernelModeMsg = *UserModeMsg;
+
+    /* See if this message type is present in the table */
+    if (NULL == MsgMemoryEntry)
+    {
+        /* Not present, no copying needed */
+        return STATUS_SUCCESS;
+    }
+
+    /* Determine required size */
+    Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
+
+    if (0 != Size)
+    {
+        /* Allocate kernel mem */
+        KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
+        if (NULL == KernelMem)
+        {
+            DPRINT1("Not enough memory to copy message to kernel mem\n");
+            return STATUS_NO_MEMORY;
+        }
+        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);
+        }
+    }
+    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))
+        {
+            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);
+    }
+
+    return STATUS_SUCCESS;
+}
+
 //
 // Wakeup any thread/process waiting on idle input.
 //
@@ -339,15 +503,20 @@ IdlePing(VOID)
 
    if (ForegroundQueue)
       ptiForeground = ForegroundQueue->Thread->Tcb.Win32Thread;
-     
+
    pti = PsGetCurrentThreadWin32Thread();
 
-   if ( pti && pti->pDeskInfo && pti == ptiForeground )
+   if ( pti )
    {
-      if ( pti->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) ||
-           pti->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) )
+      pti->pClientInfo->cSpins = 0; // Reset spins.
+
+      if ( pti->pDeskInfo && pti == ptiForeground )
       {
-         co_HOOK_CallHooks(WH_FOREGROUNDIDLE,HC_ACTION,0,0);
+         if ( pti->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) ||
+              pti->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) )
+         {
+            co_HOOK_CallHooks(WH_FOREGROUNDIDLE,HC_ACTION,0,0);
+         }
       }
    }
 
@@ -371,6 +540,25 @@ IdlePong(VOID)
    }
 }
 
+UINT FASTCALL
+GetWakeMask(UINT first, UINT last )
+{
+    UINT mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
+
+    if (first || last)
+    {
+        if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
+        if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
+             ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
+        if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
+        if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
+        if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
+    }
+    else mask = QS_ALLINPUT;
+
+    return mask;
+}
+
 static VOID FASTCALL
 IntCallWndProc( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
 {
@@ -410,10 +598,7 @@ IntDispatchMessage(PMSG pMsg)
     LARGE_INTEGER TickCount;
     LONG Time;
     LRESULT retval = 0;
-    PMSGMEMORY MsgMemoryEntry;
-    INT lParamBufferSize;
     PTHREADINFO pti;
-    LPARAM lParamPacked;
     PWND Window = NULL;
 
     if (pMsg->hwnd)
@@ -424,13 +609,18 @@ IntDispatchMessage(PMSG pMsg)
 
     pti = PsGetCurrentThreadWin32Thread();
 
+    if ( Window->head.pti != pti)
+    {
+       EngSetLastError( ERROR_MESSAGE_SYNC_ONLY );
+       return 0;
+    }
+
     if (((pMsg->message == WM_SYSTIMER) ||
          (pMsg->message == WM_TIMER)) &&
          (pMsg->lParam) )
     {
         if (pMsg->message == WM_TIMER)
         {
-            ObReferenceObject(pti->pEThread);
             if (ValidateTimerCallback(pti,pMsg->lParam))
             {
                 KeQueryTickCount(&TickCount);
@@ -441,10 +631,9 @@ IntDispatchMessage(PMSG pMsg)
                                               WM_TIMER,
                                               pMsg->wParam,
                                               (LPARAM)Time,
-                                              sizeof(LPARAM));
+                                              0);
             }
-            ObDereferenceObject(pti->pEThread);
-            return retval;        
+            return retval;
         }
         else
         {
@@ -461,35 +650,17 @@ IntDispatchMessage(PMSG pMsg)
     // Need a window!
     if ( !Window ) return 0;
 
-    /* See if this message type is present in the table */
-    MsgMemoryEntry = FindMsgMemory(pMsg->message);
-    if ( !MsgMemoryEntry )
-    {
-        lParamBufferSize = -1;
-    }
-    else
-    {
-        lParamBufferSize = MsgMemorySize(MsgMemoryEntry, pMsg->wParam, pMsg->lParam);
-    }
+    /* Since we are doing a callback on the same thread right away, there is
+       no need to copy the lparam to kernel mode and then back to usermode.
+       We just pretend it isn't a pointer */
 
-    if (! NT_SUCCESS(PackParam(&lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam, FALSE)))
-    {
-        DPRINT1("Failed to pack message parameters\n");
-        return 0;
-    }
-    ObReferenceObject(pti->pEThread);
     retval = co_IntCallWindowProc( Window->lpfnWndProc,
                                    !Window->Unicode,
                                    pMsg->hwnd,
                                    pMsg->message,
                                    pMsg->wParam,
-                                   lParamPacked,
-                                   lParamBufferSize);
-
-    if (! NT_SUCCESS(UnpackParam(lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam, FALSE)))
-    {
-        DPRINT1("Failed to unpack message parameters\n");
-    }
+                                   pMsg->lParam,
+                                   0);
 
     if (pMsg->message == WM_PAINT)
     {
@@ -498,410 +669,39 @@ IntDispatchMessage(PMSG pMsg)
         co_UserGetUpdateRgn( Window, hrgn, TRUE );
         REGION_FreeRgnByHandle( hrgn );
     }
-    ObDereferenceObject(pti->pEThread);
-    return retval;
-}
 
-VOID FASTCALL
-co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg)
-{
-    if(!Msg->hwnd || ThreadQueue->CaptureWindow)
-    {
-        return;
-    }
-
-    switch(Msg->message)
-    {
-    case WM_MOUSEMOVE:
-        {
-            co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
-            break;
-        }
-    case WM_NCMOUSEMOVE:
-        {
-            co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
-            break;
-        }
-    case WM_LBUTTONDOWN:
-    case WM_MBUTTONDOWN:
-    case WM_RBUTTONDOWN:
-    case WM_XBUTTONDOWN:
-    case WM_LBUTTONDBLCLK:
-    case WM_MBUTTONDBLCLK:
-    case WM_RBUTTONDBLCLK:
-    case WM_XBUTTONDBLCLK:
-        {
-            WPARAM wParam;
-            PSYSTEM_CURSORINFO CurInfo;
-            CurInfo = IntGetSysCursorInfo();
-
-            wParam = (WPARAM)(CurInfo->ButtonsDown);
-
-            co_IntSendMessage(Msg->hwnd, WM_MOUSEMOVE, wParam, Msg->lParam);
-            co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
-            break;
-        }
-    case WM_NCLBUTTONDOWN:
-    case WM_NCMBUTTONDOWN:
-    case WM_NCRBUTTONDOWN:
-    case WM_NCXBUTTONDOWN:
-    case WM_NCLBUTTONDBLCLK:
-    case WM_NCMBUTTONDBLCLK:
-    case WM_NCRBUTTONDBLCLK:
-    case WM_NCXBUTTONDBLCLK:
-        {
-            co_IntSendMessage(Msg->hwnd, WM_NCMOUSEMOVE, (WPARAM)Msg->wParam, Msg->lParam);
-            co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
-            break;
-        }
-    }
-}
-
-BOOL FASTCALL
-co_IntActivateWindowMouse( PUSER_MESSAGE_QUEUE ThreadQueue,
-                           LPMSG Msg,
-                           PWND MsgWindow,
-                           USHORT *HitTest)
-{
-    ULONG Result;
-    PWND Parent;
-
-    ASSERT_REFS_CO(MsgWindow);
-
-    if(*HitTest == (USHORT)HTTRANSPARENT)
-    {
-        /* eat the message, search again! */
-        return TRUE;
-    }
-
-    Parent = IntGetParent(MsgWindow);//fixme: deref retval?
-
-    /* If no parent window, pass MsgWindows HWND as wParam. Fixes bug #3111 */
-    Result = co_IntSendMessage(MsgWindow->head.h,
-                               WM_MOUSEACTIVATE,
-                              (WPARAM) (Parent ? Parent->head.h : MsgWindow->head.h),
-                              (LPARAM)MAKELONG(*HitTest, Msg->message)
-    );
-
-    switch (Result)
-    {
-    case MA_NOACTIVATEANDEAT:
-        return TRUE;
-    case MA_NOACTIVATE:
-        break;
-    case MA_ACTIVATEANDEAT:
-        co_IntMouseActivateWindow(MsgWindow);
-        return TRUE;
-    default:
-        /* MA_ACTIVATE */
-        co_IntMouseActivateWindow(MsgWindow);
-        break;
-    }
-
-    return FALSE;
-}
-
-BOOL FASTCALL
-co_IntTranslateMouseMessage( PUSER_MESSAGE_QUEUE ThreadQueue,
-                             LPMSG Msg,
-                             USHORT *HitTest,
-                             BOOL Remove)
-{
-    PWND Window;
-    USER_REFERENCE_ENTRY Ref, DesktopRef;
-
-    if(!(Window = UserGetWindowObject(Msg->hwnd)))
-    {
-        /* let's just eat the message?! */
-        return TRUE;
-    }
-
-    *HitTest = HTCLIENT;
-
-    UserRefObjectCo(Window, &Ref);
-
-    if ( ThreadQueue == Window->head.pti->MessageQueue &&
-         ThreadQueue->CaptureWindow != Window->head.h)
-    {
-        /* only send WM_NCHITTEST messages if we're not capturing the window! */
-        if (Remove ) 
-        {
-            *HitTest = co_IntSendMessage(Window->head.h, WM_NCHITTEST, 0,
-                                         MAKELONG(Msg->pt.x, Msg->pt.y));
-        } 
-        /* else we are going to see this message again, but then with Remove == TRUE */
-
-        if (*HitTest == (USHORT)HTTRANSPARENT)
-        {
-            PWND DesktopWindow;
-            HWND hDesktop = IntGetDesktopWindow();
-
-            if ((DesktopWindow = UserGetWindowObject(hDesktop)))
-            {
-                PWND Wnd;
-
-                UserRefObjectCo(DesktopWindow, &DesktopRef);
-
-                co_WinPosWindowFromPoint(DesktopWindow, Window->head.pti->MessageQueue, &Msg->pt, &Wnd);
-                if (Wnd)
-                {
-                    if (Wnd != Window)
-                    {
-                        /* post the message to the other window */
-                        Msg->hwnd = Wnd->head.h;
-                        if(!(Wnd->state & WNDS_DESTROYED))
-                        {
-                            MsqPostMessage(Wnd->head.pti->MessageQueue, Msg, FALSE,
-                                           Msg->message == WM_MOUSEMOVE ? QS_MOUSEMOVE :
-                            QS_MOUSEBUTTON);
-                        }
-
-                        /* eat the message */
-                        UserDereferenceObject(Wnd);
-                        UserDerefObjectCo(DesktopWindow);
-                        UserDerefObjectCo(Window);
-                        return TRUE;
-                    }
-                    UserDereferenceObject(Wnd);
-                }
-
-                UserDerefObjectCo(DesktopWindow);
-            }
-        }
-    }
-
-    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->pcls->style & CS_DBLCLKS)) &&
-            MsqIsDblClk(Msg, Remove))
-        {
-            Msg->message += WM_LBUTTONDBLCLK - WM_LBUTTONDOWN;
-        }
-    }
-
-    if(Msg->message != WM_MOUSEWHEEL)
-    {
-
-        if ((*HitTest) != HTCLIENT)
-        {
-            Msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
-            if ( (Msg->message == WM_NCRBUTTONUP) &&
-                 (((*HitTest) == HTCAPTION) || ((*HitTest) == HTSYSMENU)) )
-            {
-                Msg->message = WM_CONTEXTMENU;
-                Msg->wParam = (WPARAM)Window->head.h;
-            }
-            else
-            {
-                Msg->wParam = *HitTest;
-            }
-            Msg->lParam = MAKELONG(Msg->pt.x, Msg->pt.y);
-        }
-        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->rcClient.left,
-                     Msg->pt.y - (WORD)Window->rcClient.top);
-        }
-    }
-
-    UserDerefObjectCo(Window);
-    return FALSE;
-}
-
-BOOL ProcessMouseMessage(MSG* Msg, BOOLEAN RemoveMessages)
-{
-    MOUSEHOOKSTRUCT MHook;
-    EVENTMSG Event;
-    PTHREADINFO pti;
-    PUSER_MESSAGE_QUEUE ThreadQueue;
-    USER_REFERENCE_ENTRY Ref;
-    USHORT HitTest = HTNOWHERE;
-
-    pti = PsGetCurrentThreadWin32Thread();
-    ThreadQueue = pti->MessageQueue;
-
-    if(RemoveMessages)
-    {
-        PWND MsgWindow = NULL;
-
-        /* Mouse message process */
-
-        if( Msg->hwnd &&
-            ( MsgWindow = UserGetWindowObject(Msg->hwnd) ) &&
-            Msg->message >= WM_MOUSEFIRST &&
-            Msg->message <= WM_MOUSELAST )
-        {
-            USHORT HitTest;
-
-            UserRefObjectCo(MsgWindow, &Ref);
-
-            if ( co_IntTranslateMouseMessage( ThreadQueue,
-                                              Msg,
-                                             &HitTest,
-                                              TRUE))
-            /* FIXME - check message filter again, if the message doesn't match anymore,
-                    search again */
-            {
-                UserDerefObjectCo(MsgWindow);
-                /* eat the message, search again */
-                return FALSE;
-            }
-
-            if(ThreadQueue->CaptureWindow == NULL)
-            {
-                co_IntSendHitTestMessages(ThreadQueue, Msg);
-
-                if ( ( Msg->message != WM_MOUSEMOVE &&
-                       Msg->message != WM_NCMOUSEMOVE ) &&
-                       IS_BTN_MESSAGE(Msg->message, DOWN) &&
-                       co_IntActivateWindowMouse(ThreadQueue, Msg, MsgWindow, &HitTest) )
-                {
-                    UserDerefObjectCo(MsgWindow);
-                    /* eat the message, search again */
-                    return FALSE;
-                }
-            }
-
-            UserDerefObjectCo(MsgWindow);
-        }
-        else
-        {
-            co_IntSendHitTestMessages(ThreadQueue, Msg);
-        }
-
-        return TRUE;
-    }
-
-    if ( ( Msg->hwnd &&
-           Msg->message >= WM_MOUSEFIRST &&
-           Msg->message <= WM_MOUSELAST ) &&
-           co_IntTranslateMouseMessage( ThreadQueue,
-                                        Msg,
-                                       &HitTest,
-                                        FALSE) )
-    /* FIXME - check message filter again, if the message doesn't match anymore,
-            search again */
-    {
-        /* eat the message, search again */
-        return FALSE;
-    }
-
-    pti->rpdesk->htEx = HitTest; /* Now set the capture hit. */
-
-    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,
-                           RemoveMessages ? HC_ACTION : HC_NOREMOVE,
-                           Msg->message,
-                           (LPARAM)&MHook ))
-    {
-        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);
-        DPRINT1("MouseMessage WH_CBT Call Hook return!\n");
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-BOOL ProcessKeyboardMessage(MSG* Msg, BOOLEAN RemoveMessages)
-{
-    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,
-                           RemoveMessages ? HC_ACTION : HC_NOREMOVE,
-                           LOWORD(Msg->wParam),
-                           Msg->lParam))
-    {
-        /* skip this message */
-        co_HOOK_CallHooks( WH_CBT,
-                           HCBT_KEYSKIPPED,
-                           LOWORD(Msg->wParam),
-                           Msg->lParam );
-        DPRINT1("KeyboardMessage WH_CBT Call Hook return!\n");
-        return FALSE;
-    }
-    return TRUE;
+    return retval;
 }
 
-BOOL ProcessHardwareMessage(MSG* Msg, BOOLEAN RemoveMessages)
-{
-    if ( IS_MOUSE_MESSAGE(Msg->message))
-    {
-        if (!ProcessMouseMessage(Msg, RemoveMessages))
-        {
-            return FALSE;
-        }
-    }
-    else if ( IS_KBD_MESSAGE(Msg->message))
-    {
-        if(!ProcessKeyboardMessage(Msg, RemoveMessages))
-        {
-            return FALSE;
-        }
-    }
-
-    return TRUE;
-}
 /*
-* Internal version of PeekMessage() doing all the work
-*/
+ * Internal version of PeekMessage() doing all the work
+ */
 BOOL FASTCALL
 co_IntPeekMessage( PMSG Msg,
                    PWND Window,
                    UINT MsgFilterMin,
                    UINT MsgFilterMax,
-                   UINT RemoveMsg )
+                   UINT RemoveMsg,
+                   BOOL bGMSG )
 {
     PTHREADINFO pti;
+    PCLIENTINFO pci;
     LARGE_INTEGER LargeTickCount;
     PUSER_MESSAGE_QUEUE ThreadQueue;
     BOOL RemoveMessages;
+    UINT ProcessMask;
+    BOOL Hit = FALSE;
 
     pti = PsGetCurrentThreadWin32Thread();
     ThreadQueue = pti->MessageQueue;
+    pci = pti->pClientInfo;
 
     RemoveMessages = RemoveMsg & PM_REMOVE;
+    ProcessMask = HIWORD(RemoveMsg);
+
+ /* Hint, "If wMsgFilterMin and wMsgFilterMax are both zero, PeekMessage returns
+    all available messages (that is, no range filtering is performed)".        */
+    if (!ProcessMask) ProcessMask = (QS_ALLPOSTMESSAGE|QS_ALLINPUT);
 
     IdlePong();
 
@@ -909,173 +709,122 @@ co_IntPeekMessage( PMSG Msg,
     {
         KeQueryTickCount(&LargeTickCount);
         ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
+        pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart;
 
         /* Dispatch sent messages here. */
-        while (co_MsqDispatchOneSentMessage(ThreadQueue)) ;
-
-        /* Now look for a quit message. */
-
-        if (ThreadQueue->QuitPosted)
+        while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
         {
-            /* According to the PSDK, WM_QUIT messages are always returned, regardless
-        of the filter specified */
-            Msg->hwnd = NULL;
-            Msg->message = WM_QUIT;
-            Msg->wParam = ThreadQueue->QuitExitCode;
-            Msg->lParam = 0;
-            if (RemoveMessages)
-            {
-                ThreadQueue->QuitPosted = FALSE;
-            }
-
-            return TRUE;
-        }
-
-        /* Now check for normal messages. */
-        if (MsqPeekMessage( ThreadQueue,
-                            RemoveMessages,
-                            Window,
-                            MsgFilterMin,
-                            MsgFilterMax,
-                            Msg ))
-        {
-            return TRUE;
-        }
-
-        /* Check for hardware events. */
-        if(co_MsqPeekHardwareMessage( ThreadQueue,
-                                     RemoveMessages, 
-                                     Window, 
-                                     MsgFilterMin, 
-                                     MsgFilterMax, 
-                                     Msg))
-        {
-
-            if(!ProcessHardwareMessage(Msg, RemoveMessages))
-                continue;
-
-            return TRUE;
+           /* if some PM_QS* flags were specified, only handle sent messages from now on */
+           if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE; // wine does this; ProcessMask = QS_SENDMESSAGE;
         }
+        if (Hit) return FALSE;
 
-        /* Check for sent messages again. */
-        while (co_MsqDispatchOneSentMessage(ThreadQueue))
-        ;
-
-        /* Check for paint messages. */
-        if( IntGetPaintMessage( Window,
-                                MsgFilterMin,
-                                MsgFilterMax,
-                                pti,
-                                Msg,
-                                RemoveMessages))
+        /* Clear changed bits so we can wait on them if we don't find a message */
+        if (ProcessMask & QS_POSTMESSAGE)
         {
-            return TRUE;
+           pti->pcti->fsChangeBits &= ~(QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER);
+           if (MsgFilterMin == 0 && MsgFilterMax == 0) // wine hack does this; ~0U)
+           {
+              pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
+           }
         }
 
-        if (PostTimerMessages(Window))
+        if (ProcessMask & QS_INPUT)
         {
-            continue;
+           pti->pcti->fsChangeBits &= ~QS_INPUT;
         }
 
-        return FALSE;
-    }
-    while (TRUE);
-
-    return TRUE;
-}
-
-static NTSTATUS FASTCALL
-CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
-{
-    NTSTATUS Status;
-
-    PVOID KernelMem;
-    UINT Size;
-
-    *KernelModeMsg = *UserModeMsg;
-
-    /* See if this message type is present in the table */
-    if (NULL == MsgMemoryEntry)
-    {
-        /* Not present, no copying needed */
-        return STATUS_SUCCESS;
-    }
-
-    /* Determine required size */
-    Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
-
-    if (0 != Size)
-    {
-        /* Allocate kernel mem */
-        KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
-        if (NULL == KernelMem)
+        /* Now check for normal messages. */
+        if (( (ProcessMask & QS_POSTMESSAGE) ||
+              (ProcessMask & QS_HOTKEY) ) &&
+            MsqPeekMessage( ThreadQueue,
+                            RemoveMessages,
+                            Window,
+                            MsgFilterMin,
+                            MsgFilterMax,
+                            ProcessMask,
+                            Msg ))
         {
-            DPRINT1("Not enough memory to copy message to kernel mem\n");
-            return STATUS_NO_MEMORY;
+               return TRUE;
         }
-        KernelModeMsg->lParam = (LPARAM) KernelMem;
 
-        /* Copy data if required */
-        if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
+        /* Now look for a quit message. */
+        if (ThreadQueue->QuitPosted)
         {
-            Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
-            if (! NT_SUCCESS(Status))
+            /* According to the PSDK, WM_QUIT messages are always returned, regardless
+               of the filter specified */
+            Msg->hwnd = NULL;
+            Msg->message = WM_QUIT;
+            Msg->wParam = ThreadQueue->QuitExitCode;
+            Msg->lParam = 0;
+            if (RemoveMessages)
             {
-                DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
-                ExFreePoolWithTag(KernelMem, TAG_MSG);
-                return Status;
+                ThreadQueue->QuitPosted = FALSE;
+                ClearMsgBitsMask(ThreadQueue, QS_POSTMESSAGE);
+                pti->pcti->fsWakeBits &= ~QS_ALLPOSTMESSAGE;
+                pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
             }
+            return TRUE;
         }
-        else
+
+        /* Check for hardware events. */
+        if ((ProcessMask & QS_MOUSE) &&
+            co_MsqPeekMouseMove( ThreadQueue,
+                                 RemoveMessages,
+                                 Window,
+                                 MsgFilterMin,
+                                 MsgFilterMax,
+                                 Msg ))
         {
-            /* Make sure we don't pass any secrets to usermode */
-            RtlZeroMemory(KernelMem, Size);
+            return TRUE;
         }
-    }
-    else
-    {
-        KernelModeMsg->lParam = 0;
-    }
 
-    return STATUS_SUCCESS;
-}
-
-static NTSTATUS FASTCALL
-CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
-{
-    NTSTATUS Status;
-    PMSGMEMORY MsgMemoryEntry;
-    UINT Size;
+        if ((ProcessMask & QS_INPUT) &&
+            co_MsqPeekHardwareMessage( ThreadQueue,
+                                       RemoveMessages,
+                                       Window,
+                                       MsgFilterMin,
+                                       MsgFilterMax,
+                                       ProcessMask,
+                                       Msg))
+        {
+            return TRUE;
+        }
 
-    /* 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;
-    }
+        /* Check for sent messages again. */
+        while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
+        {
+           if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE;
+        }
+        if (Hit) return FALSE;
 
-    /* Determine required size */
-    Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
+        /* Check for paint messages. */
+        if ((ProcessMask & QS_PAINT) &&
+            pti->cPaintsReady &&
+            IntGetPaintMessage( Window,
+                                MsgFilterMin,
+                                MsgFilterMax,
+                                pti,
+                                Msg,
+                                RemoveMessages))
+        {
+            return TRUE;
+        }
 
-    if (0 != Size)
-    {
-        /* Copy data if required */
-        if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
+       /* This is correct, check for the current threads timers waiting to be
+          posted to this threads message queue. If any we loop again.
+        */
+        if ((ProcessMask & QS_TIMER) &&
+            PostTimerMessages(Window))
         {
-            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;
-            }
+            continue;
         }
 
-        ExFreePool((PVOID) KernelModeMsg->lParam);
+        return FALSE;
     }
+    while (TRUE);
 
-    return STATUS_SUCCESS;
+    return TRUE;
 }
 
 static BOOL FASTCALL
@@ -1093,29 +842,33 @@ co_IntWaitMessage( PWND Window,
 
     do
     {
-        if ( co_IntPeekMessage( &Msg,
-                                Window,
-                                MsgFilterMin,
-                                MsgFilterMax,
-                                PM_NOREMOVE))
+        if ( co_IntPeekMessage( &Msg,       // Dont reenter!
+                                 Window,
+                                 MsgFilterMin,
+                                 MsgFilterMax,
+                                 MAKELONG( PM_NOREMOVE, GetWakeMask( MsgFilterMin, MsgFilterMax)),
+                                 TRUE ) )   // act like GetMessage.
         {
             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");
+                                           Window,
+                                           MsgFilterMin,
+                                           MsgFilterMax);
+        if (!NT_SUCCESS(Status))
+        {
+            SetLastNtError(Status);
+            DPRINT1("Exit co_IntWaitMessage on error!\n");
+            return FALSE;
+        }
+        if (Status == STATUS_USER_APC || Status == STATUS_TIMEOUT)
+        {
+           return FALSE;
+        }
     }
+    while ( TRUE );
 
     return FALSE;
 }
@@ -1129,7 +882,9 @@ co_IntGetPeekMessage( PMSG pMsg,
                       BOOL bGMSG )
 {
     PWND Window;
+    PTHREADINFO pti;
     BOOL Present = FALSE;
+    NTSTATUS Status;
 
     if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST )
         hWnd = HWND_BOTTOM;
@@ -1156,28 +911,54 @@ co_IntGetPeekMessage( PMSG pMsg,
         MsgFilterMax = 0;
     }
 
+    if (bGMSG)
+    {
+       RemoveMsg |= ((GetWakeMask( MsgFilterMin, MsgFilterMax ))<< 16);
+    }
+
+    pti = PsGetCurrentThreadWin32Thread();
+    pti->pClientInfo->cSpins++; // Bump up the spin count.
+
     do
     {
         Present = co_IntPeekMessage( pMsg,
                                      Window,
                                      MsgFilterMin,
                                      MsgFilterMax,
-                                     RemoveMsg );
+                                     RemoveMsg,
+                                     bGMSG );
         if (Present)
         {
+           /* GetMessage or PostMessage must never get messages that contain pointers */
+           ASSERT(FindMsgMemory(pMsg->message) == NULL);
+
+           if (pMsg->message != WM_PAINT && pMsg->message != WM_QUIT)
+           {
+              pti->timeLast = pMsg->time;
+              pti->ptLast   = pMsg->pt;
+           }
+
            // The WH_GETMESSAGE hook enables an application to monitor messages about to
            // be returned by the GetMessage or PeekMessage function.
 
            co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg);
 
-           if ( bGMSG )
-              return (WM_QUIT != pMsg->message);
+           if ( bGMSG ) break;
         }
 
         if ( bGMSG )
         {
-           if ( !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax) )
-              return -1;
+            Status = co_MsqWaitForNewMessages( pti->MessageQueue,
+                                               Window,
+                                               MsgFilterMin,
+                                               MsgFilterMax);
+           if ( !NT_SUCCESS(Status) ||
+                Status == STATUS_USER_APC ||
+                Status == STATUS_TIMEOUT )
+           {
+              Present = -1;
+              break;
+           }
         }
         else
         {
@@ -1196,6 +977,13 @@ co_IntGetPeekMessage( PMSG pMsg,
     }
     while( bGMSG && !Present );
 
+    // Been spinning, time to swap vinyl...
+    if (pti->pClientInfo->cSpins >= 100)
+    {
+       // Clear the spin cycle to fix the mix.
+       pti->pClientInfo->cSpins = 0;
+       //if (!(pti->TIF_flags & TIF_SPINNING)) FIXME need to swap vinyl..
+    }
     return Present;
 }
 
@@ -1211,11 +999,9 @@ UserPostThreadMessage( DWORD idThread,
     LARGE_INTEGER LargeTickCount;
     NTSTATUS Status;
 
-    DPRINT1("UserPostThreadMessage wParam 0x%x  lParam 0x%x\n", wParam,lParam);
-
-    if (FindMsgMemory(Msg) != 0)
+    if (is_pointer_message(Msg))
     {
-        SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+        EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
         return FALSE;
     }
 
@@ -1239,7 +1025,7 @@ UserPostThreadMessage( DWORD idThread,
         Message.pt = gpsi->ptCursor;
 
         KeQueryTickCount(&LargeTickCount);
-        pThread->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
+        Message.time = MsqCalculateMessageTime(&LargeTickCount);
         MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
         ObDereferenceObject( peThread );
         return TRUE;
@@ -1258,15 +1044,47 @@ UserPostMessage( HWND Wnd,
                  LPARAM lParam )
 {
     PTHREADINFO pti;
-    MSG Message;
+    MSG Message, KernelModeMsg;
     LARGE_INTEGER LargeTickCount;
 
-    if (FindMsgMemory(Msg) != 0)
+    Message.hwnd = Wnd;
+    Message.message = Msg;
+    Message.wParam = wParam;
+    Message.lParam = lParam;
+    Message.pt = gpsi->ptCursor;
+    KeQueryTickCount(&LargeTickCount);
+    Message.time = MsqCalculateMessageTime(&LargeTickCount);
+
+    if (is_pointer_message(Message.message))
     {
-        SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+        EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
         return FALSE;
     }
 
+    if( Msg >= WM_DDE_FIRST && Msg <= WM_DDE_LAST )
+    {
+        NTSTATUS Status;
+        PMSGMEMORY MsgMemoryEntry;
+
+        MsgMemoryEntry = FindMsgMemory(Message.message);
+
+        Status = CopyMsgToKernelMem(&KernelModeMsg, &Message, MsgMemoryEntry);
+        if (! NT_SUCCESS(Status))
+        {
+            EngSetLastError(ERROR_INVALID_PARAMETER);
+            return FALSE;
+        }
+        co_IntSendMessageNoWait(KernelModeMsg.hwnd,
+                                KernelModeMsg.message,
+                                KernelModeMsg.wParam,
+                                KernelModeMsg.lParam);
+
+        if (MsgMemoryEntry && KernelModeMsg.lParam)
+            ExFreePool((PVOID) KernelModeMsg.lParam);
+
+        return TRUE;
+    }
+
     if (!Wnd)
     {
         return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
@@ -1290,7 +1108,7 @@ UserPostMessage( HWND Wnd,
             {
                 UserPostMessage(List[i], Msg, wParam, lParam);
             }
-            ExFreePool(List);
+            ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
         }
     }
     else
@@ -1323,13 +1141,6 @@ UserPostMessage( HWND Wnd,
         }
         else
         {
-            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->head.pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
         }
     }
@@ -1435,6 +1246,7 @@ co_IntSendMessageTimeoutSingle( HWND hWnd,
 
     if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->head.pti->MessageQueue))
     {
+        // FIXME - Set window hung and add to a list.
         /* FIXME - Set a LastError? */
         RETURN( FALSE);
     }
@@ -1460,21 +1272,21 @@ co_IntSendMessageTimeoutSingle( HWND hWnd,
     }
     while ((STATUS_TIMEOUT == Status) &&
            (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
-           !MsqIsHung(Window->head.pti->MessageQueue));
+           !MsqIsHung(Window->head.pti->MessageQueue)); // FIXME - Set window hung and add to a list.
 
     IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
 
     if (STATUS_TIMEOUT == Status)
     {
-        /*
-MSDN says:
+/*
+    MSDN says:
     Microsoft Windows 2000: If GetLastError returns zero, then the function
     timed out.
     XP+ : If the function fails or times out, the return value is zero.
     To get extended error information, call GetLastError. If GetLastError
     returns ERROR_TIMEOUT, then the function timed out.
 */
-        SetLastWin32Error(ERROR_TIMEOUT);
+        EngSetLastError(ERROR_TIMEOUT);
         RETURN( FALSE);
     }
     else if (! NT_SUCCESS(Status))
@@ -1511,7 +1323,7 @@ co_IntSendMessageTimeout( HWND hWnd,
     DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
     if (NULL == DesktopWindow)
     {
-        SetLastWin32Error(ERROR_INTERNAL_ERROR);
+        EngSetLastError(ERROR_INTERNAL_ERROR);
         return 0;
     }
 
@@ -1534,7 +1346,7 @@ co_IntSendMessageTimeout( HWND hWnd,
     return (LRESULT) TRUE;
 }
 
-LRESULT FASTCALL 
+LRESULT FASTCALL
 co_IntSendMessageNoWait(HWND hWnd,
                         UINT Msg,
                         WPARAM wParam,
@@ -1550,7 +1362,13 @@ co_IntSendMessageNoWait(HWND hWnd,
                                   &Result);
     return Result;
 }
-
+/* MSDN:
+   If you send a message in the range below WM_USER to the asynchronous message
+   functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its
+   message parameters cannot include pointers. Otherwise, the operation will fail.
+   The functions will return before the receiving thread has had a chance to
+   process the message and the sender will free the memory before it is used.
+*/
 LRESULT FASTCALL
 co_IntSendMessageWithCallBack( HWND hWnd,
                               UINT Msg,
@@ -1586,17 +1404,8 @@ co_IntSendMessageWithCallBack( HWND hWnd,
 
     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);
     }
 
@@ -1617,9 +1426,18 @@ co_IntSendMessageWithCallBack( HWND hWnd,
         RETURN( FALSE);
     }
 
-    /* If this is not a callback and it can be sent now, then send it. */
-    if ((Window->head.pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
+    /* If it can be sent now, then send it. */
+    if (Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
     {
+        if (Win32Thread->TIF_flags & TIF_INCLEANUP)
+        {
+            UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE);
+            /* Never send messages to exiting threads */
+            RETURN(FALSE);
+        }
+
+        IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
+
         ObReferenceObject(Win32Thread->pEThread);
         Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
                                                   !Window->Unicode,
@@ -1633,11 +1451,22 @@ co_IntSendMessageWithCallBack( HWND hWnd,
             *uResult = Result;
         }
         ObDereferenceObject(Win32Thread->pEThread);
+
+        IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
+
+        if (CompletionCallback)
+        {
+            co_IntCallSentMessageCallback(CompletionCallback,
+                                          hWnd,
+                                          Msg,
+                                          CompletionCallbackContext,
+                                          Result);
+        }
     }
 
-    IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
 
-    if ((Window->head.pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
+
+    if (Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
     {
         if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
         {
@@ -1649,24 +1478,34 @@ co_IntSendMessageWithCallBack( HWND hWnd,
     if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
     {
         DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
-        return STATUS_INSUFFICIENT_RESOURCES;
+        RETURN( FALSE);
     }
 
+    IntReferenceMessageQueue(Window->head.pti->MessageQueue);
+    /* Take reference on this MessageQueue if its a callback. It will be released 
+       when message is processed or removed from target hwnd MessageQueue */
+    if (CompletionCallback)
+       IntReferenceMessageQueue(Win32Thread->MessageQueue);
+
     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->head.pti->MessageQueue);
+    Message->lResult = 0;
+    Message->QS_Flags = 0;
+    Message->SenderQueue = NULL; // mjmartin, you are right! This is null.
+    Message->CallBackSenderQueue = Win32Thread->MessageQueue;
+    Message->DispatchingListEntry.Flink = NULL;
     Message->CompletionCallback = CompletionCallback;
     Message->CompletionCallbackContext = CompletionCallbackContext;
-    Message->HookMessage = MSQ_NORMAL | MSQ_SENTNOWAIT;
+    Message->HookMessage = MSQ_NORMAL;
     Message->HasPackedLParam = (lParamBufferSize > 0);
+    Message->QS_Flags = QS_SENDMESSAGE;
 
     InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
+    MsqWakeQueue(Window->head.pti->MessageQueue, QS_SENDMESSAGE, TRUE);
     IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
 
     RETURN(TRUE);
@@ -1722,29 +1561,21 @@ co_IntDoSendMessage( HWND hWnd,
                      UINT Msg,
                      WPARAM wParam,
                      LPARAM lParam,
-                     PDOSENDMESSAGE dsm,
-                     PNTUSERSENDMESSAGEINFO UnsafeInfo )
+                     PDOSENDMESSAGE dsm)
 {
     PTHREADINFO pti;
     LRESULT Result = TRUE;
     NTSTATUS Status;
     PWND Window = NULL;
-    NTUSERSENDMESSAGEINFO Info;
     MSG UserModeMsg;
     MSG KernelModeMsg;
     PMSGMEMORY MsgMemoryEntry;
 
-    RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
-
-    /* FIXME: Call hooks. */
     if (HWND_BROADCAST != hWnd)
     {
         Window = UserGetWindowObject(hWnd);
         if ( !Window )
         {
-            /* Tell usermode to not touch this one */
-            Info.HandledByKernel = TRUE;
-            MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
             return 0;
         }
     }
@@ -1758,96 +1589,58 @@ co_IntDoSendMessage( HWND hWnd,
     /* See if the current thread can handle the message */
     pti = PsGetCurrentThreadWin32Thread();
 
-    // This is checked in user mode!!!!!!!
-    if ( HWND_BROADCAST != hWnd &&
-         NULL != pti &&
-         Window->head.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;
+    UserModeMsg.hwnd = hWnd;
+    UserModeMsg.message = Msg;
+    UserModeMsg.wParam = wParam;
+    UserModeMsg.lParam = lParam;
+    MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
 
-        Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi), sizeof(BOOL));
-        if (! NT_SUCCESS(Status))
-        {
-            Info.Ansi = ! Window->Unicode;
-        }
+    Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
+    if (! NT_SUCCESS(Status))
+    {
+       EngSetLastError(ERROR_INVALID_PARAMETER);
+       return (dsm ? 0 : -1);
+    }
 
-        Info.Ansi = !Window->Unicode;
-        Info.Proc = Window->lpfnWndProc;
+    if (!dsm)
+    {
+       Result = co_IntSendMessage( KernelModeMsg.hwnd,
+                                   KernelModeMsg.message,
+                                   KernelModeMsg.wParam,
+                                   KernelModeMsg.lParam );
     }
     else
     {
-        /* Must be handled by other thread */
-        //      if (HWND_BROADCAST != hWnd)
-        //      {
-        //         UserDereferenceObject(Window);
-        //      }
-        Info.HandledByKernel = TRUE;
-        UserModeMsg.hwnd = hWnd;
-        UserModeMsg.message = Msg;
-        UserModeMsg.wParam = wParam;
-        UserModeMsg.lParam = lParam;
-        MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
-
-        Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
-        if (! NT_SUCCESS(Status))
-        {
-            MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
-            SetLastWin32Error(ERROR_INVALID_PARAMETER);
-            return (dsm ? 0 : -1);
-        }
-
-        if(!dsm)
-        {
-            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 );
-        }
-
-        Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
-        if (! NT_SUCCESS(Status))
-        {
-            MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
-            SetLastWin32Error(ERROR_INVALID_PARAMETER);
-            return(dsm ? 0 : -1);
-        }
+       Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
+                                          KernelModeMsg.message,
+                                          KernelModeMsg.wParam,
+                                          KernelModeMsg.lParam,
+                                          dsm->uFlags,
+                                          dsm->uTimeout,
+                                         &dsm->Result );
     }
 
-    Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
+    Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
     if (! NT_SUCCESS(Status))
     {
-        SetLastWin32Error(ERROR_INVALID_PARAMETER);
+       EngSetLastError(ERROR_INVALID_PARAMETER);
+       return(dsm ? 0 : -1);
     }
 
     return (LRESULT)Result;
 }
 
-
 BOOL FASTCALL
 UserSendNotifyMessage( HWND hWnd,
                        UINT Msg,
                        WPARAM wParam,
                        LPARAM lParam )
 {
-    BOOL Result = TRUE;
+    BOOL Ret = TRUE;
 
-    if (FindMsgMemory(Msg) != 0)
+    if (is_pointer_message(Msg))
     {
-        SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+        EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
         return FALSE;
     }
 
@@ -1866,37 +1659,23 @@ UserSendNotifyMessage( HWND hWnd,
             UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
             for (i = 0; List[i]; i++)
             {
-                UserSendNotifyMessage(List[i], Msg, wParam, lParam);
+                Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
             }
             ExFreePool(List);
         }
     }
     else
     {
-        ULONG_PTR PResult;
-        PTHREADINFO pti;
-        PWND Window;
-
-        if ( !(Window = UserGetWindowObject(hWnd)) ) return FALSE;
-
-        pti = PsGetCurrentThreadWin32Thread();
-
-        if (Window->head.pti->MessageQueue != pti->MessageQueue)
-        { // Send message w/o waiting for it.
-            Result = UserPostMessage(hWnd, Msg, wParam, lParam);
-        }
-        else
-        { // Handle message and callback.
-            Result = co_IntSendMessageTimeoutSingle( hWnd,
-                                                     Msg,
-                                                     wParam,
-                                                     lParam,
-                                                     SMTO_NORMAL,
-                                                     0,
-                                                     &PResult );
-        }
+        ULONG_PTR lResult = 0;
+        Ret = co_IntSendMessageWithCallBack( hWnd,
+                                             Msg,
+                                             wParam,
+                                             lParam,
+                                             NULL,
+                                             0,
+                                            &lResult);
     }
-    return Result;
+    return Ret;
 }
 
 
@@ -1912,278 +1691,179 @@ IntGetQueueStatus(DWORD Changes)
 // wine:
     Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
 
-    Result = MAKELONG(Queue->ChangedBits & Changes, Queue->QueueBits & Changes);
-
-    if (pti->pcti)
-    {
-       pti->pcti->fsChangeBits = Queue->ChangedBits;
-       pti->pcti->fsChangeBits &= ~Changes;
-    }
+    /* High word, types of messages currently in the queue.
+       Low  word, types of messages that have been added to the queue and that
+                  are still in the queue
+     */
+    Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
 
-    Queue->ChangedBits &= ~Changes;
+    pti->pcti->fsChangeBits &= ~Changes;
 
     return Result;
 }
 
 BOOL APIENTRY
-IntInitMessagePumpHook()
-{
-    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
-
-    if (pti->pcti)
-    {
-        pti->pcti->dwcPumpHook++;
-        return TRUE;
-    }
-    return FALSE;
-}
-
-BOOL APIENTRY
-IntUninitMessagePumpHook()
-{
-    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
-
-    if (pti->pcti)
-    {
-        if (pti->pcti->dwcPumpHook <= 0)
-        {
-            return FALSE;
-        }
-        pti->pcti->dwcPumpHook--;
-        return TRUE;
-    }
-    return FALSE;
-}
-
-/** Functions ******************************************************************/
-
-BOOL APIENTRY
-NtUserPostMessage(HWND hWnd,
-                  UINT Msg,
-                  WPARAM wParam,
-                  LPARAM lParam)
-{
-    BOOL ret;
-
-    UserEnterExclusive();
-
-    ret = UserPostMessage(hWnd, Msg, wParam, lParam);
-
-    UserLeave();
-
-    return ret;
-}
-
-BOOL APIENTRY
-NtUserPostThreadMessage(DWORD idThread,
-                        UINT Msg,
-                        WPARAM wParam,
-                        LPARAM lParam)
-{
-    BOOL ret;
-
-    UserEnterExclusive();
-
-    ret = UserPostThreadMessage( idThread, Msg, wParam, lParam);
+IntInitMessagePumpHook()
+{
+    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
 
-    UserLeave();
-    
-    return ret;
+    if (pti->pcti)
+    {
+        pti->pcti->dwcPumpHook++;
+        return TRUE;
+    }
+    return FALSE;
 }
 
-DWORD APIENTRY
-NtUserQuerySendMessage(DWORD Unknown0)
+BOOL APIENTRY
+IntUninitMessagePumpHook()
 {
-    UNIMPLEMENTED;
+    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
 
-    return 0;
+    if (pti->pcti)
+    {
+        if (pti->pcti->dwcPumpHook <= 0)
+        {
+            return FALSE;
+        }
+        pti->pcti->dwcPumpHook--;
+        return TRUE;
+    }
+    return FALSE;
 }
 
+/** Functions ******************************************************************/
 
-////////// 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 )
+BOOL
+APIENTRY
+NtUserDragDetect(
+   HWND hWnd,
+   POINT pt) // Just like the User call.
 {
-    DOSENDMESSAGE dsm;
-    LRESULT Result;
+    MSG msg;
+    RECT rect;
+    WORD wDragWidth, wDragHeight;
+    DECLARE_RETURN(BOOL);
 
-    DPRINT("Enter NtUserSendMessageTimeout\n");
+    DPRINT("Enter NtUserDragDetect(%x)\n", hWnd);
+    UserEnterExclusive();
 
-    dsm.uFlags = uFlags;
-    dsm.uTimeout = uTimeout;
+    wDragWidth = UserGetSystemMetrics(SM_CXDRAG);
+    wDragHeight= UserGetSystemMetrics(SM_CYDRAG);
 
-    UserEnterExclusive();
+    rect.left = pt.x - wDragWidth;
+    rect.right = pt.x + wDragWidth;
 
-    Result = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
+    rect.top = pt.y - wDragHeight;
+    rect.bottom = pt.y + wDragHeight;
 
-    UserLeave();
+    co_UserSetCapture(hWnd);
 
-    if(uResult != NULL && Result != 0)
+    for (;;)
     {
-        _SEH2_TRY
-        {
-            ProbeForWrite(uResult, sizeof(ULONG_PTR), 1);
-            RtlCopyMemory(uResult, &dsm.Result, sizeof(ULONG_PTR));
-        }
-        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        while (co_IntGetPeekMessage( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, FALSE ) ||
+               co_IntGetPeekMessage( &msg, 0, WM_QUEUESYNC,  WM_QUEUESYNC, PM_REMOVE, FALSE ) ||
+               co_IntGetPeekMessage( &msg, 0, WM_KEYFIRST,   WM_KEYLAST,   PM_REMOVE, FALSE ) )
         {
-            SetLastWin32Error(ERROR_INVALID_PARAMETER);;
-            Result = FALSE;
+            if ( msg.message == WM_LBUTTONUP )
+            {
+                co_UserSetCapture(NULL);
+                RETURN( FALSE);
+            }
+            if ( msg.message == WM_MOUSEMOVE )
+            {
+                POINT tmp;
+                tmp.x = (short)LOWORD(msg.lParam);
+                tmp.y = (short)HIWORD(msg.lParam);
+                if( !IntPtInRect( &rect, tmp ) )
+                {
+                    co_UserSetCapture(NULL);
+                    RETURN( TRUE);
+                }
+            }
+            if ( msg.message == WM_KEYDOWN )
+            {
+                if ( msg.wParam == VK_ESCAPE )
+                {
+                   co_UserSetCapture(NULL);
+                   RETURN( TRUE);
+                }
+            }
+            if ( msg.message == WM_QUEUESYNC )
+            {
+                co_HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0 );
+            }
         }
-        _SEH2_END;
+        co_IntWaitMessage(NULL, 0, 0);
     }
+    RETURN( FALSE);
 
-    return Result;
+CLEANUP:
+   DPRINT("Leave NtUserDragDetect, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
-LRESULT APIENTRY
-NtUserSendMessage( HWND Wnd,
-                   UINT Msg,
-                   WPARAM wParam,
-                   LPARAM lParam,
-                   PNTUSERSENDMESSAGEINFO UnsafeInfo )
+BOOL APIENTRY
+NtUserPostMessage(HWND hWnd,
+                  UINT Msg,
+                  WPARAM wParam,
+                  LPARAM lParam)
 {
     BOOL ret;
 
     UserEnterExclusive();
 
-    ret = co_IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo);
+    ret = UserPostMessage(hWnd, Msg, wParam, lParam);
 
     UserLeave();
 
     return ret;
 }
-//////////
 
 BOOL APIENTRY
-NtUserWaitMessage(VOID)
+NtUserPostThreadMessage(DWORD idThread,
+                        UINT Msg,
+                        WPARAM wParam,
+                        LPARAM lParam)
 {
     BOOL ret;
 
     UserEnterExclusive();
 
-    ret = co_IntWaitMessage(NULL, 0, 0);
+    ret = UserPostThreadMessage( idThread, Msg, wParam, lParam);
 
     UserLeave();
-    
+
     return ret;
 }
 
-
 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.
-*/
+NtUserWaitMessage(VOID)
 {
-    NTUSERGETMESSAGEINFO Info;
-    NTSTATUS Status;
-    PMSGMEMORY MsgMemoryEntry;
-    PVOID UserMem;
-    ULONG Size;
-    MSG Msg;
-    BOOL GotMessage;
-
-    if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
-    {
-        SetLastWin32Error(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
+    BOOL ret;
 
     UserEnterExclusive();
-
-    RtlZeroMemory(&Msg, sizeof(MSG));
-
-    GotMessage = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
-
+    DPRINT("NtUserWaitMessage Enter\n");
+    ret = co_IntWaitMessage(NULL, 0, 0);
+    DPRINT("NtUserWaitMessage Leave\n");
     UserLeave();
 
-    Info.Msg = Msg;
-    /* See if this message type is present in the table */
-    MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
-
-    _SEH2_TRY
-    {
-        ProbeForWrite(UnsafeInfo, sizeof(NTUSERGETMESSAGEINFO), 1);
-        RtlCopyMemory(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
-
-        if (NULL == MsgMemoryEntry)
-        {
-            /* Not present, no copying needed */
-            UnsafeInfo->LParamSize = 0;
-        }
-        else
-        {
-            /* Determine required size */
-            Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam, Info.Msg.lParam);
-
-            /* Allocate required amount of user-mode memory */
-            Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 
-                                             &UserMem, 
-                                             0,
-                                             &Size, 
-                                             MEM_COMMIT, 
-                                             PAGE_READWRITE);
-            if (! NT_SUCCESS(Status))
-            {
-                SetLastNtError(Status);
-                _SEH2_YIELD(return (BOOL) -1);
-            }
-
-            /* Transfer lParam data to user-mode mem */
-            ProbeForWrite(UserMem, Size, 1);
-            RtlCopyMemory(UserMem, (PVOID)Info.Msg.lParam, Size);
-
-            UnsafeInfo->LParamSize = Size;
-            UnsafeInfo->Msg.lParam = (LPARAM) UserMem;
-        }
-    }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-    {
-        SetLastNtError(_SEH2_GetExceptionCode());
-
-        if(UserMem != NULL)
-        {
-            ZwFreeVirtualMemory(NtCurrentProcess(), &UserMem, &Size, MEM_RELEASE);
-        }
-
-        _SEH2_YIELD(return (BOOL) -1);
-    }
-    _SEH2_END;
-    
-    return GotMessage;
+    return ret;
 }
 
-
 BOOL APIENTRY
-NtUserGetMessageX(PMSG pMsg,
+NtUserGetMessage(PMSG pMsg,
                   HWND hWnd,
                   UINT MsgFilterMin,
-                  UINT MsgFilterMax)
+                  UINT MsgFilterMax )
 {
     MSG Msg;
     BOOL Ret;
 
     if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
     {
-        SetLastWin32Error(ERROR_INVALID_PARAMETER);
+        EngSetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
 
@@ -2195,7 +1875,7 @@ NtUserGetMessageX(PMSG pMsg,
 
     UserLeave();
 
-    if (Ret)
+    if (Ret == TRUE)
     {
         _SEH2_TRY
         {
@@ -2210,109 +1890,25 @@ NtUserGetMessageX(PMSG pMsg,
         _SEH2_END;
     }
 
+    if ((INT)Ret != -1)
+       Ret = Ret ? (WM_QUIT != pMsg->message) : FALSE;
+
     return Ret;
 }
 
 BOOL APIENTRY
-NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
+NtUserPeekMessage( PMSG pMsg,
                   HWND hWnd,
                   UINT MsgFilterMin,
                   UINT MsgFilterMax,
                   UINT RemoveMsg)
-{
-    NTSTATUS Status;
-    NTUSERGETMESSAGEINFO Info;
-    PMSGMEMORY MsgMemoryEntry;
-    PVOID UserMem = NULL;
-    ULONG Size;
-    MSG Msg;
-    BOOL Ret;
-
-    if ( RemoveMsg & PM_BADMSGFLAGS )
-    {
-        SetLastWin32Error(ERROR_INVALID_FLAGS);
-        return FALSE;
-    }
-
-    UserEnterExclusive();
-
-    RtlZeroMemory(&Msg, sizeof(MSG));
-
-    Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
-
-    UserLeave();
-
-    if (Ret)
-    {
-        Info.Msg = Msg;
-        /* See if this message type is present in the table */
-        MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
-
-        _SEH2_TRY
-        {
-            ProbeForWrite(UnsafeInfo, sizeof(NTUSERGETMESSAGEINFO), 1);
-            RtlCopyMemory(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
-
-            if (NULL == MsgMemoryEntry)
-            {
-                /* Not present, no copying needed */
-                UnsafeInfo->LParamSize = 0;
-            }
-            else
-            {
-                /* Determine required size */
-                Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam, Info.Msg.lParam);
-
-                /* Allocate required amount of user-mode memory */
-                Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 
-                                                 &UserMem, 
-                                                 0,
-                                                 &Size, 
-                                                 MEM_COMMIT, 
-                                                 PAGE_READWRITE);
-                if (! NT_SUCCESS(Status))
-                {
-                    SetLastNtError(Status);
-                    _SEH2_YIELD(return (BOOL) -1);
-                }
-
-                /* Transfer lParam data to user-mode mem */
-                ProbeForWrite(UserMem, Size, 1);
-                RtlCopyMemory(UserMem, (PVOID)Info.Msg.lParam, Size);
-
-                UnsafeInfo->LParamSize = Size;
-                UnsafeInfo->Msg.lParam = (LPARAM) UserMem;
-            }
-        }
-        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-        {
-            SetLastNtError(_SEH2_GetExceptionCode());
-            Ret = (BOOL) -1;
-
-            if(UserMem != NULL)
-            {
-                ZwFreeVirtualMemory(NtCurrentProcess(), &UserMem, &Size, MEM_RELEASE);
-            }
-        }
-        _SEH2_END;
-    }
-
-    return Ret;
-}
-
-BOOL APIENTRY
-NtUserPeekMessageX( PMSG pMsg,
-                    HWND hWnd,
-                    UINT MsgFilterMin,
-                    UINT MsgFilterMax,
-                    UINT RemoveMsg)
 {
     MSG Msg;
     BOOL Ret;
 
     if ( RemoveMsg & PM_BADMSGFLAGS )
     {
-        SetLastWin32Error(ERROR_INVALID_FLAGS);
+        EngSetLastError(ERROR_INVALID_FLAGS);
         return FALSE;
     }
 
@@ -2338,7 +1934,7 @@ NtUserPeekMessageX( PMSG pMsg,
         }
         _SEH2_END;
     }
-    
+
     return Ret;
 }
 
@@ -2442,7 +2038,7 @@ NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
 
 BOOL APIENTRY
 NtUserMessageCall( HWND hWnd,
-                   UINT Msg, 
+                   UINT Msg,
                    WPARAM wParam,
                    LPARAM lParam,
                    ULONG_PTR ResultInfo,
@@ -2456,24 +2052,23 @@ NtUserMessageCall( HWND hWnd,
 
     UserEnterExclusive();
 
-    /* Validate input */
-    if (hWnd && (hWnd != INVALID_HANDLE_VALUE))
-    {
-        Window = UserGetWindowObject(hWnd);
-        if (!Window)
-        {
-            UserLeave();
-            return FALSE;
-        }
-    }
-
     switch(dwType)
     {
     case FNID_DEFWINDOWPROC:
-        if (Window) UserRefObjectCo(Window, &Ref);
+        /* Validate input */
+        if (hWnd && (hWnd != INVALID_HANDLE_VALUE))
+        {
+           Window = UserGetWindowObject(hWnd);
+           if (!Window)
+           {
+               UserLeave();
+               return FALSE;
+           }
+        }
+        UserRefObjectCo(Window, &Ref);
         lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
         Ret = TRUE;
-        if (Window) UserDerefObjectCo(Window);
+        UserDerefObjectCo(Window);
         break;
     case FNID_SENDNOTIFYMESSAGE:
         Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
@@ -2492,7 +2087,6 @@ NtUserMessageCall( HWND hWnd,
                 }
                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                 {
-                    Ret = FALSE;
                     _SEH2_YIELD(break);
                 }
                 _SEH2_END;
@@ -2511,32 +2105,32 @@ NtUserMessageCall( HWND hWnd,
                     if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
                     {
                         co_IntSendMessageTimeout( HWND_BROADCAST,
-                                                                         Msg,
-                                                                         wParam,
-                                                                         lParam,
-                                                                         SMTO_ABORTIFHUNG,
-                                                                         2000,
-                                                                         &RetVal);
+                                                  Msg,
+                                                  wParam,
+                                                  lParam,
+                                                  SMTO_ABORTIFHUNG,
+                                                  2000,
+                                                 &RetVal);
                     }
                     else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
                     {
                         co_IntSendMessageTimeout( HWND_BROADCAST,
-                                                                         Msg,
+                                                  Msg,
                                                   wParam,
-                                                                         lParam,
-                                                                         SMTO_NOTIMEOUTIFNOTHUNG,
-                                                                         2000,
-                                                                         &RetVal);
+                                                  lParam,
+                                                  SMTO_NOTIMEOUTIFNOTHUNG,
+                                                  2000,
+                                                 &RetVal);
                     }
                     else
                     {
                         co_IntSendMessageTimeout( HWND_BROADCAST,
-                                                                         Msg,
-                                                                         wParam,
-                                                                         lParam,
-                                                                         SMTO_NORMAL,
-                                                                         2000,
-                                                                         &RetVal);
+                                                  Msg,
+                                                 wParam,
+                                                  lParam,
+                                                  SMTO_NORMAL,
+                                                  2000,
+                                                 &RetVal);
                     }
                     Ret = RetVal;
                 }
@@ -2553,19 +2147,88 @@ NtUserMessageCall( HWND hWnd,
         break;
     case FNID_SENDMESSAGECALLBACK:
         {
-            PCALL_BACK_INFO CallBackInfo = (PCALL_BACK_INFO)ResultInfo;
+            CALL_BACK_INFO CallBackInfo;
             ULONG_PTR uResult;
 
-            if (!CallBackInfo)
-                break;
+            _SEH2_TRY
+            {
+                ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
+                RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                _SEH2_YIELD(break);
+            }
+            _SEH2_END;
+
+            if (is_pointer_message(Msg))
+            {
+               EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
+               break;
+            }
 
-            if (!co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
-                        CallBackInfo->CallBack, CallBackInfo->Context, &uResult))
+            if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
+                        CallBackInfo.CallBack, CallBackInfo.Context, &uResult)))
             {
                 DPRINT1("Callback failure!\n");
             }
         }
         break;
+    case FNID_SENDMESSAGE:
+        {
+            Ret = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
+
+            if (ResultInfo)
+            {
+                _SEH2_TRY
+                {
+                    ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
+                    RtlCopyMemory((PVOID)ResultInfo, &Ret, sizeof(ULONG_PTR));
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    Ret = FALSE;
+                    _SEH2_YIELD(break);
+                }
+                _SEH2_END;
+            }
+            break;
+        }
+    case FNID_SENDMESSAGETIMEOUT:
+        {
+            DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
+            if (ResultInfo)
+            {
+                _SEH2_TRY
+                {
+                    ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
+                    RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    _SEH2_YIELD(break);
+                }
+                _SEH2_END;
+            }
+
+            Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, &dsm );
+
+            if (pdsm)
+            {
+                _SEH2_TRY
+                {
+                    ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
+                    RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    Ret = FALSE;
+                    _SEH2_YIELD(break);
+                }
+                _SEH2_END;
+            }
+            break;
+        }
         // CallNextHook bypass.
     case FNID_CALLWNDPROC:
     case FNID_CALLWNDPROCRET:
@@ -2704,7 +2367,7 @@ NtUserWaitForInputIdle( IN HANDLE hProcess,
     {
         ObDereferenceObject(Process);
         UserLeave();
-        SetLastWin32Error(ERROR_INVALID_PARAMETER);
+        EngSetLastError(ERROR_INVALID_PARAMETER);
         return WAIT_FAILED;
     }
 
@@ -2722,6 +2385,13 @@ NtUserWaitForInputIdle( IN HANDLE hProcess,
     if (dwMilliseconds != INFINITE)
        Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
 
+    W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
+    for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
+    {
+       pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
+       pti->pClientInfo->dwTIFlags = pti->TIF_flags;
+    }
+
     DPRINT("WFII: ppi 0x%x\n",W32Process);
     DPRINT("WFII: waiting for %p\n", Handles[1] );
     do
@@ -2752,7 +2422,7 @@ NtUserWaitForInputIdle( IN HANDLE hProcess,
         case STATUS_WAIT_2:
             {
                MSG Msg;
-               co_IntPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE );
+               co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
                DPRINT1("WFII: WAIT 2\n");
             }
             break;
@@ -2771,6 +2441,12 @@ NtUserWaitForInputIdle( IN HANDLE hProcess,
     while (TRUE);
 
 WaitExit:
+    for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
+    {
+       pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
+       pti->pClientInfo->dwTIFlags = pti->TIF_flags;
+    }
+    W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
     ObDereferenceObject(Process);
     UserLeave();
     return Status;