[WIN32K:NTUSER]
[reactos.git] / reactos / win32ss / user / ntuser / msgqueue.c
index 3a7f3b3..bba976a 100644 (file)
@@ -2,7 +2,7 @@
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS Win32k subsystem
  * PURPOSE:          Message queues
- * FILE:             subsystems/win32/win32k/ntuser/msgqueue.c
+ * FILE:             win32ss/user/ntuser/msgqueue.c
  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
                      Alexandre Julliard
                      Maarten Lankhorst
@@ -14,7 +14,13 @@ DBG_DEFAULT_CHANNEL(UserMsgQ);
 /* GLOBALS *******************************************************************/
 
 static PPAGED_LOOKASIDE_LIST pgMessageLookasideList;
+static PPAGED_LOOKASIDE_LIST pgSendMsgLookasideList;
+INT PostMsgCount = 0;
+INT SendMsgCount = 0;
 PUSER_MESSAGE_QUEUE gpqCursor;
+ULONG_PTR gdwMouseMoveExtraInfo = 0;
+DWORD gdwMouseMoveTimeStamp = 0;
+LIST_ENTRY usmList;
 
 /* FUNCTIONS *****************************************************************/
 
@@ -23,9 +29,10 @@ NTSTATUS
 NTAPI
 MsqInitializeImpl(VOID)
 {
-    pgMessageLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG);
-    if(!pgMessageLookasideList)
-        return STATUS_NO_MEMORY;
+   // Setup Post Messages
+   pgMessageLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG);
+   if (!pgMessageLookasideList)
+      return STATUS_NO_MEMORY;
    ExInitializePagedLookasideList(pgMessageLookasideList,
                                   NULL,
                                   NULL,
@@ -33,46 +40,21 @@ MsqInitializeImpl(VOID)
                                   sizeof(USER_MESSAGE),
                                   TAG_USRMSG,
                                   256);
+   // Setup Send Messages
+   pgSendMsgLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG);
+   if (!pgSendMsgLookasideList)
+      return STATUS_NO_MEMORY;
+   ExInitializePagedLookasideList(pgSendMsgLookasideList,
+                                  NULL,
+                                  NULL,
+                                  0,
+                                  sizeof(USER_SENT_MESSAGE),
+                                  TAG_USRMSG,
+                                  16);
 
-   return(STATUS_SUCCESS);
-}
-
-PWND FASTCALL
-IntChildrenWindowFromPoint(PWND pWndTop, INT x, INT y)
-{
-    PWND pWnd, pWndChild;
-
-    if ( !pWndTop )
-    {
-       pWndTop = UserGetDesktopWindow();
-       if ( !pWndTop ) return NULL;
-    }
-
-    if (!(pWndTop->style & WS_VISIBLE)) return NULL;
-    if ((pWndTop->style & WS_DISABLED)) return NULL;
-    if (!IntPtInWindow(pWndTop, x, y)) return NULL;
-
-    if (RECTL_bPointInRect(&pWndTop->rcClient, x, y))
-    {
-       for (pWnd = pWndTop->spwndChild;
-            pWnd != NULL;
-            pWnd = pWnd->spwndNext)
-       {
-           if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED )
-           {
-               TRACE("The Window is in DESTROY!\n");
-               continue;
-           }
-
-           pWndChild = IntChildrenWindowFromPoint(pWnd, x, y);
+   InitializeListHead(&usmList);
 
-           if (pWndChild)
-           {
-              return pWndChild;
-           }
-       }
-    }
-    return pWndTop;
+   return(STATUS_SUCCESS);
 }
 
 PWND FASTCALL
@@ -96,7 +78,9 @@ IntTopLevelWindowFromPoint(INT x, INT y)
             continue;
         }
 
-        if ((pWnd->style & WS_VISIBLE) && IntPtInWindow(pWnd, x, y))
+        if ((pWnd->style & WS_VISIBLE) &&
+            (pWnd->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) != (WS_EX_LAYERED|WS_EX_TRANSPARENT) &&
+            IntPtInWindow(pWnd, x, y))
             return pWnd;
     }
 
@@ -119,12 +103,6 @@ UserSetCursor(
     pti = PsGetCurrentThreadWin32Thread();
     MessageQueue = pti->MessageQueue;
 
-    /* Get the screen DC */
-    if(!(hdcScreen = IntGetScreenDC()))
-    {
-        return NULL;
-    }
-
     OldCursor = MessageQueue->CursorObject;
 
     /* Check if cursors are different */
@@ -138,14 +116,25 @@ UserSetCursor(
     if (MessageQueue->iCursorLevel < 0)
         return OldCursor;
 
+    // Fixes the error message "Not the same cursor!".
+    if (gpqCursor == NULL)
+    {
+       gpqCursor = MessageQueue;
+    }
+
     /* Update cursor if this message queue controls it */
     pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y);
     if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue)
     {
+       /* Get the screen DC */
+        if (!(hdcScreen = IntGetScreenDC()))
+        {
+            return NULL;
+        }
+
         if (NewCursor)
         {
             /* Call GDI to set the new screen cursor */
-#ifdef NEW_CURSORICON
             PCURICON_OBJECT CursorFrame = NewCursor;
             if(NewCursor->CURSORF_flags & CURSORF_ACON)
             {
@@ -160,16 +149,6 @@ UserSetCursor(
                                gpsi->ptCursor.x,
                                gpsi->ptCursor.y,
                                CursorFrame->hbmAlpha ? SPS_ALPHA : 0);
-#else
-            GreSetPointerShape(hdcScreen,
-                               NewCursor->IconInfo.hbmMask,
-                               NewCursor->IconInfo.hbmColor,
-                               NewCursor->IconInfo.xHotspot,
-                               NewCursor->IconInfo.yHotspot,
-                               gpsi->ptCursor.x,
-                               gpsi->ptCursor.y,
-                               0);
-#endif
         }
         else /* Note: OldCursor != NewCursor so we have to hide cursor */
         {
@@ -349,6 +328,36 @@ UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue, MSG* msg)
     }
 }
 
+/*
+    Get down key states from the queue of prior processed input message key states.
+
+    This fixes the left button dragging on the desktop and release sticking outline issue.
+    USB Tablet pointer seems to stick the most and leaves the box outline displayed.
+ */
+WPARAM FASTCALL
+MsqGetDownKeyState(PUSER_MESSAGE_QUEUE MessageQueue)
+{
+    WPARAM ret = 0;
+
+    if (gspv.bMouseBtnSwap)
+    {
+       if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_RBUTTON)) ret |= MK_LBUTTON;
+       if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_LBUTTON)) ret |= MK_RBUTTON;
+    }
+    else
+    {
+       if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_LBUTTON)) ret |= MK_LBUTTON;
+       if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_RBUTTON)) ret |= MK_RBUTTON;
+    }
+
+    if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_MBUTTON))  ret |= MK_MBUTTON;
+    if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_SHIFT))    ret |= MK_SHIFT;
+    if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_CONTROL))  ret |= MK_CONTROL;
+    if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_XBUTTON1)) ret |= MK_XBUTTON1;
+    if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_XBUTTON2)) ret |= MK_XBUTTON2;
+    return ret;
+}
+
 HANDLE FASTCALL
 IntMsqSetWakeMask(DWORD WakeMask)
 {
@@ -435,20 +444,19 @@ MsqWakeQueue(PTHREADINFO pti, DWORD MessageBits, BOOL KeyEvent)
 VOID FASTCALL
 ClearMsgBitsMask(PTHREADINFO pti, UINT MessageBits)
 {
-   PUSER_MESSAGE_QUEUE Queue;
    UINT ClrMask = 0;
 
-   Queue = pti->MessageQueue;
-
    if (MessageBits & QS_KEY)
    {
       if (--pti->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY;
    }
-   if (MessageBits & QS_MOUSEMOVE) // ReactOS hard coded.
+   if (MessageBits & QS_MOUSEMOVE)
    {  // Account for tracking mouse moves..
-      if (--pti->nCntsQBits[QSRosMouseMove] == 0) ClrMask |= QS_MOUSEMOVE;
-      // Handle mouse move bits here.
-      if (Queue->MouseMoved) ClrMask |= QS_MOUSEMOVE;
+      if (pti->nCntsQBits[QSRosMouseMove])
+      {
+         pti->nCntsQBits[QSRosMouseMove] = 0; // Throttle down count. Up to > 3:1 entries are ignored.
+         ClrMask |= QS_MOUSEMOVE;
+      }
    }
    if (MessageBits & QS_MOUSEBUTTON)
    {
@@ -502,12 +510,72 @@ MsqDecPaintCountQueue(PTHREADINFO pti)
    ClearMsgBitsMask(pti, QS_PAINT);
 }
 
+/*
+    Post the move or update the message still pending to be processed.
+    Do not overload the queue with mouse move messages.
+ */
+VOID FASTCALL
+MsqPostMouseMove(PTHREADINFO pti, MSG* Msg, LONG_PTR ExtraInfo)
+{
+    PUSER_MESSAGE Message;
+    PLIST_ENTRY ListHead;
+    PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
+
+    ListHead = &MessageQueue->HardwareMessagesListHead;
+
+    // Do nothing if empty.
+    if (!IsListEmpty(ListHead->Flink))
+    {
+       // Look at the end of the list,
+       Message = CONTAINING_RECORD(ListHead->Blink, USER_MESSAGE, ListEntry);
+
+       // If the mouse move message is existing on the list,
+       if (Message->Msg.message == WM_MOUSEMOVE)
+       {
+          // Overwrite the message with updated data!
+          Message->Msg = *Msg;
+
+          MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE);
+          return;
+       }
+    }
+
+    MsqPostMessage(pti, Msg, TRUE, QS_MOUSEMOVE, 0, ExtraInfo);
+}
+
+/*
+    Bring together the mouse move message.
+    Named "Coalesce" from Amine email ;^) (jt).
+ */
 VOID FASTCALL
-MsqPostMouseMove(PTHREADINFO pti, MSG* Msg)
+IntCoalesceMouseMove(PTHREADINFO pti)
 {
-    pti->MessageQueue->MouseMoveMsg = *Msg;
-    pti->MessageQueue->MouseMoved = TRUE;
-    MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE);
+    MSG Msg;
+    LARGE_INTEGER LargeTickCount;
+
+    // Force time stamp to update, keeping message time in sync.
+    if (gdwMouseMoveTimeStamp == 0)
+    {
+       KeQueryTickCount(&LargeTickCount);
+       gdwMouseMoveTimeStamp = MsqCalculateMessageTime(&LargeTickCount);
+    }
+
+    // Build mouse move message.
+    Msg.hwnd    = NULL;
+    Msg.message = WM_MOUSEMOVE;
+    Msg.wParam  = 0;
+    Msg.lParam  = MAKELONG(gpsi->ptCursor.x, gpsi->ptCursor.y);
+    Msg.time    = gdwMouseMoveTimeStamp;
+    Msg.pt      = gpsi->ptCursor;
+
+    // Post the move.
+    MsqPostMouseMove(pti, &Msg, gdwMouseMoveExtraInfo);
+
+    // Zero the time stamp.
+    gdwMouseMoveTimeStamp = 0;
+
+    // Clear flag since the move was posted.
+    pti->MessageQueue->QF_flags &= ~QF_MOUSEMOVED;
 }
 
 VOID FASTCALL
@@ -581,14 +649,21 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook
    {
        pti = pwnd->head.pti;
        MessageQueue = pti->MessageQueue;
-       // MessageQueue->ptiMouse = pti;
 
-       if ( pti->TIF_flags & TIF_INCLEANUP || MessageQueue->QF_flags & QF_INDESTROY)
+       if (MessageQueue->QF_flags & QF_INDESTROY)
        {
-          ERR("Mouse is over the Window Thread is Dead!\n");
+          ERR("Mouse is over a Window with a Dead Message Queue!\n");
           return;
        }
 
+       // Check to see if this is attached.
+       if ( pti != MessageQueue->ptiMouse &&
+            MessageQueue->cThreads > 1 )
+       {
+          // Set the send pti to the message queue mouse pti.
+          pti = MessageQueue->ptiMouse;
+       }
+
        if (Msg->message == WM_MOUSEMOVE)
        {
           /* Check if cursor should be visible */
@@ -600,7 +675,6 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook
                if(CurInfo->CurrentCursorObject != MessageQueue->CursorObject)
                {
                    /* Call GDI to set the new screen cursor */
-#ifdef NEW_CURSORICON
                     GreSetPointerShape(hdcScreen,
                                        MessageQueue->CursorObject->hbmAlpha ?
                                            NULL : MessageQueue->CursorObject->hbmMask,
@@ -611,20 +685,11 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook
                                        gpsi->ptCursor.x,
                                        gpsi->ptCursor.y,
                                        MessageQueue->CursorObject->hbmAlpha ? SPS_ALPHA : 0);
-#else
-                    GreSetPointerShape(hdcScreen,
-                                      MessageQueue->CursorObject->IconInfo.hbmMask,
-                                      MessageQueue->CursorObject->IconInfo.hbmColor,
-                                      MessageQueue->CursorObject->IconInfo.xHotspot,
-                                      MessageQueue->CursorObject->IconInfo.yHotspot,
-                                      gpsi->ptCursor.x,
-                                      gpsi->ptCursor.y,
-                                      0);
-#endif
+
                } else
                    GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
            }
-           /* Check if w have to hide cursor */
+           /* Check if we have to hide cursor */
            else if (CurInfo->ShowingCursor >= 0)
                GreMovePointer(hdcScreen, -1, -1);
 
@@ -634,7 +699,10 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook
            gpqCursor = MessageQueue;
 
            /* Mouse move is a special case */
-           MsqPostMouseMove(pti, Msg);
+           MessageQueue->QF_flags |= QF_MOUSEMOVED;
+           gdwMouseMoveExtraInfo = dwExtraInfo;
+           gdwMouseMoveTimeStamp = Msg->time;
+           MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE);
        }
        else
        {
@@ -642,9 +710,17 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook
            {
              // ERR("ptiLastInput is set\n");
              // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
+             // Find all the Move Mouse calls and fix mouse set active focus issues......
+           }
+
+           // Post mouse move before posting mouse buttons, keep it in sync.
+           if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED)
+           {
+              IntCoalesceMouseMove(pti);
            }
+
            TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd));
-           MsqPostMessage(pti, Msg, TRUE, QS_MOUSEBUTTON, 0);
+           MsqPostMessage(pti, Msg, TRUE, QS_MOUSEBUTTON, 0, dwExtraInfo);
        }
    }
    else if (hdcScreen)
@@ -666,25 +742,148 @@ MsqCreateMessage(LPMSG Msg)
       return NULL;
    }
 
+   RtlZeroMemory(Message, sizeof(*Message));
    RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
-
+   PostMsgCount++;
    return Message;
 }
 
 VOID FASTCALL
 MsqDestroyMessage(PUSER_MESSAGE Message)
 {
+   TRACE("Post Destroy %d\n",PostMsgCount)
+   if (Message->pti == NULL)
+   {
+      ERR("Double Free Message\n");
+      return;
+   }
+   RemoveEntryList(&Message->ListEntry);
+   Message->pti = NULL;
    ExFreeToPagedLookasideList(pgMessageLookasideList, Message);
+   PostMsgCount--;
+}
+
+PUSER_SENT_MESSAGE FASTCALL
+AllocateUserMessage(BOOL KEvent)
+{
+   PUSER_SENT_MESSAGE Message;
+
+   if(!(Message = ExAllocateFromPagedLookasideList(pgSendMsgLookasideList)))
+   {
+       ERR("AllocateUserMessage(): Not enough memory to allocate a message");
+       return NULL;
+   }
+   RtlZeroMemory(Message, sizeof(USER_SENT_MESSAGE));
+
+   if (KEvent)
+   {
+      Message->pkCompletionEvent = &Message->CompletionEvent;
+
+      KeInitializeEvent(Message->pkCompletionEvent, NotificationEvent, FALSE);
+   }
+   SendMsgCount++;
+   TRACE("AUM pti %p msg %p\n",PsGetCurrentThreadWin32Thread(),Message);
+   return Message;
+}
+
+VOID FASTCALL
+FreeUserMessage(PUSER_SENT_MESSAGE Message)
+{
+   Message->pkCompletionEvent = NULL;
+
+   /* Remove it from the list */
+   RemoveEntryList(&Message->ListEntry);
+
+   ExFreeToPagedLookasideList(pgSendMsgLookasideList, Message);
+   SendMsgCount--;
+}
+
+VOID APIENTRY
+MsqRemoveWindowMessagesFromQueue(PWND Window)
+{
+   PTHREADINFO pti;
+   PUSER_SENT_MESSAGE SentMessage;
+   PUSER_MESSAGE PostedMessage;
+   PLIST_ENTRY CurrentEntry, ListHead;
+
+   ASSERT(Window);
+
+   pti = Window->head.pti;
+
+   /* remove the posted messages for this window */
+   CurrentEntry = pti->PostedMessagesListHead.Flink;
+   ListHead = &pti->PostedMessagesListHead;
+   while (CurrentEntry != ListHead)
+   {
+      PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
+
+      if (PostedMessage->Msg.hwnd == Window->head.h)
+      {
+         if (PostedMessage->Msg.message == WM_QUIT && pti->QuitPosted == 0)
+         {
+            pti->QuitPosted = 1;
+            pti->exitCode = PostedMessage->Msg.wParam;
+         }
+         ClearMsgBitsMask(pti, PostedMessage->QS_Flags);
+         MsqDestroyMessage(PostedMessage);
+         CurrentEntry = pti->PostedMessagesListHead.Flink;
+      }
+      else
+      {
+         CurrentEntry = CurrentEntry->Flink;
+      }
+   }
+
+   /* remove the sent messages for this window */
+   CurrentEntry = pti->SentMessagesListHead.Flink;
+   ListHead = &pti->SentMessagesListHead;
+   while (CurrentEntry != ListHead)
+   {
+      SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
+
+      if(SentMessage->Msg.hwnd == Window->head.h)
+      {
+         ERR("Remove Window Messages %p From Sent Queue\n",SentMessage);
+#if 0 // Should mark these as invalid and allow the rest clean up, so far no harm by just commenting out. See CORE-9210.
+         ClearMsgBitsMask(pti, SentMessage->QS_Flags);
+
+         /* wake the sender's thread */
+         if (SentMessage->pkCompletionEvent != NULL)
+         {
+            KeSetEvent(SentMessage->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
+         }
+
+         if (SentMessage->HasPackedLParam)
+         {
+            if (SentMessage->Msg.lParam)
+               ExFreePool((PVOID)SentMessage->Msg.lParam);
+         }
+
+         /* free the message */
+         FreeUserMessage(SentMessage);
+
+         CurrentEntry = pti->SentMessagesListHead.Flink;
+#endif
+         CurrentEntry = CurrentEntry->Flink;
+      }
+      else
+      {
+         CurrentEntry = CurrentEntry->Flink;
+      }
+   }
 }
 
 BOOLEAN FASTCALL
-co_MsqDispatchOneSentMessage(PTHREADINFO pti)
+co_MsqDispatchOneSentMessage(
+    _In_ PTHREADINFO pti)
 {
    PUSER_SENT_MESSAGE SaveMsg, Message;
    PLIST_ENTRY Entry;
    BOOL Ret;
    LRESULT Result = 0;
 
+   ASSERT(pti == PsGetCurrentThreadWin32Thread());
+
    if (IsListEmpty(&pti->SentMessagesListHead))
    {
       return(FALSE);
@@ -694,6 +893,9 @@ co_MsqDispatchOneSentMessage(PTHREADINFO pti)
    Entry = RemoveHeadList(&pti->SentMessagesListHead);
    Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
 
+   // Signal this message is being processed.
+   Message->flags |= SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE;
+
    SaveMsg = pti->pusmCurrent;
    pti->pusmCurrent = Message;
 
@@ -704,27 +906,18 @@ co_MsqDispatchOneSentMessage(PTHREADINFO pti)
       pti->pcti->CTI_flags |= CTI_INSENDMESSAGE; // Let the user know...
    }
 
-   /* insert it to the list of messages that are currently dispatched by this
-      message queue */
-   InsertTailList(&pti->LocalDispatchingMessagesHead,
-                  &Message->ListEntry);
+   /* Now insert it to the global list of messages that can be removed Justin Case there's Trouble */
+   InsertTailList(&usmList, &Message->ListEntry);
 
    ClearMsgBitsMask(pti, Message->QS_Flags);
 
    if (Message->HookMessage == MSQ_ISHOOK)
    {  // Direct Hook Call processor
-      Result = co_CallHook( Message->Msg.message,     // HookId
+      Result = co_CallHook( Message->Msg.message,           // HookId
                            (INT)(INT_PTR)Message->Msg.hwnd, // Code
                             Message->Msg.wParam,
                             Message->Msg.lParam);
    }
-   else if (Message->HookMessage == MSQ_ISEVENT)
-   {  // Direct Event Call processor
-      Result = co_EVENT_CallEvents( Message->Msg.message,
-                                    Message->Msg.hwnd,
-                                    Message->Msg.wParam,
-                                    Message->Msg.lParam);
-   }
    else if(Message->HookMessage == MSQ_INJECTMODULE)
    {
        Result = IntLoadHookModule(Message->Msg.message,
@@ -749,7 +942,9 @@ co_MsqDispatchOneSentMessage(PTHREADINFO pti)
          /* The message has not been processed yet, reinsert it. */
          RemoveEntryList(&Message->ListEntry);
          InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
-         TRACE("Callback Message not processed yet. Requeuing the message\n");
+         // List is occupied need to set the bit.
+         MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE);
+         ERR("Callback Message not processed yet. Requeuing the message\n"); //// <---- Need to see if this happens.
          Ret = FALSE;
          goto Exit;
       }
@@ -762,10 +957,6 @@ co_MsqDispatchOneSentMessage(PTHREADINFO pti)
                                   Message->Msg.lParam);
    }
 
-   /* remove the message from the local dispatching list, because it doesn't need
-      to be cleaned up on thread termination anymore */
-   RemoveEntryList(&Message->ListEntry);
-
    /* If the message is a callback, insert it in the callback senders MessageQueue */
    if (Message->CompletionCallback)
    {
@@ -775,6 +966,7 @@ co_MsqDispatchOneSentMessage(PTHREADINFO pti)
          Message->QS_Flags |= QS_SMRESULT;
 
          /* insert it in the callers message queue */
+         RemoveEntryList(&Message->ListEntry);
          InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
          MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE);
       }
@@ -782,43 +974,37 @@ co_MsqDispatchOneSentMessage(PTHREADINFO pti)
       goto Exit;
    }
 
-   /* remove the message from the dispatching list if needed, so lock the sender's message queue */
-   if (Message->ptiSender)
-   {
-      if (Message->DispatchingListEntry.Flink != NULL)
-      {
-         /* only remove it from the dispatching list if not already removed by a timeout */
-         RemoveEntryList(&Message->DispatchingListEntry);
-      }
-   }
-   /* still keep the sender's message queue locked, so the sender can't exit the
-      MsqSendMessage() function (if timed out) */
-
+   // Retrieve the result from callback.
    if (Message->QS_Flags & QS_SMRESULT)
    {
       Result = Message->lResult;
    }
 
    /* Let the sender know the result. */
-   if (Message->Result != NULL)
-   {
-      *Message->Result = Result;
-   }
+   Message->lResult = Result;
 
-   if (Message->HasPackedLParam == TRUE)
+   if (Message->HasPackedLParam)
    {
       if (Message->Msg.lParam)
          ExFreePool((PVOID)Message->Msg.lParam);
    }
 
+   // Clear busy signal.
+   Message->flags &= ~SMF_RECEIVERBUSY;
+
    /* Notify the sender. */
-   if (Message->CompletionEvent != NULL)
+   if (Message->pkCompletionEvent != NULL)
    {
-      KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
+      KeSetEvent(Message->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
    }
 
    /* free the message */
-   ExFreePoolWithTag(Message, TAG_USRMSG);
+   if (Message->flags & SMF_RECEIVERFREE)
+   {
+      TRACE("Receiver Freeing Message %p\n",Message);
+      FreeUserMessage(Message);
+   }
+
    Ret = TRUE;
 Exit:
    /* do not hangup on the user if this is reentering */
@@ -828,83 +1014,6 @@ Exit:
    return Ret;
 }
 
-VOID APIENTRY
-MsqRemoveWindowMessagesFromQueue(PWND Window)
-{
-   PTHREADINFO pti;
-   PUSER_SENT_MESSAGE SentMessage;
-   PUSER_MESSAGE PostedMessage;
-   PLIST_ENTRY CurrentEntry, ListHead;
-
-   ASSERT(Window);
-
-   pti = Window->head.pti;
-
-   /* remove the posted messages for this window */
-   CurrentEntry = pti->PostedMessagesListHead.Flink;
-   ListHead = &pti->PostedMessagesListHead;
-   while (CurrentEntry != ListHead)
-   {
-      PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
-                                        ListEntry);
-      if (PostedMessage->Msg.hwnd == Window->head.h)
-      {
-         RemoveEntryList(&PostedMessage->ListEntry);
-         ClearMsgBitsMask(pti, PostedMessage->QS_Flags);
-         MsqDestroyMessage(PostedMessage);
-         CurrentEntry = pti->PostedMessagesListHead.Flink;
-      }
-      else
-      {
-         CurrentEntry = CurrentEntry->Flink;
-      }
-   }
-
-   /* remove the sent messages for this window */
-   CurrentEntry = pti->SentMessagesListHead.Flink;
-   ListHead = &pti->SentMessagesListHead;
-   while (CurrentEntry != ListHead)
-   {
-      SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
-                                      ListEntry);
-      if(SentMessage->Msg.hwnd == Window->head.h)
-      {
-         TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
-
-         RemoveEntryList(&SentMessage->ListEntry);
-         ClearMsgBitsMask(pti, SentMessage->QS_Flags);
-
-         /* Only if the message has a sender was the queue referenced */
-         if ((SentMessage->ptiSender)
-            && (SentMessage->DispatchingListEntry.Flink != NULL))
-         {
-            RemoveEntryList(&SentMessage->DispatchingListEntry);
-         }
-
-         /* wake the sender's thread */
-         if (SentMessage->CompletionEvent != NULL)
-         {
-            KeSetEvent(SentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
-         }
-
-         if (SentMessage->HasPackedLParam == TRUE)
-         {
-            if (SentMessage->Msg.lParam)
-               ExFreePool((PVOID)SentMessage->Msg.lParam);
-         }
-
-         /* free the message */
-         ExFreePoolWithTag(SentMessage, TAG_USRMSG);
-
-         CurrentEntry = pti->SentMessagesListHead.Flink;
-      }
-      else
-      {
-         CurrentEntry = CurrentEntry->Flink;
-      }
-   }
-}
-
 BOOL FASTCALL
 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
                        HWND hwnd,
@@ -920,9 +1029,9 @@ co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
     PTHREADINFO ptiSender;
     PUSER_SENT_MESSAGE Message;
 
-    if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
+    if(!(Message = AllocateUserMessage(FALSE)))
     {
-        ERR("MsqSendMessage(): Not enough memory to allocate a message");
+        ERR("MsqSendMessageAsync(): Not enough memory to allocate a message");
         return FALSE;
     }
 
@@ -932,18 +1041,15 @@ co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
     Message->Msg.message = Msg;
     Message->Msg.wParam = wParam;
     Message->Msg.lParam = lParam;
-    Message->CompletionEvent = NULL;
-    Message->Result = 0;
-    Message->lResult = 0;
+    Message->pkCompletionEvent = NULL; // No event needed.
     Message->ptiReceiver = ptiReceiver;
-    Message->ptiSender = NULL;
     Message->ptiCallBackSender = ptiSender;
-    Message->DispatchingListEntry.Flink = NULL;
     Message->CompletionCallback = CompletionCallback;
     Message->CompletionCallbackContext = CompletionCallbackContext;
     Message->HookMessage = HookMessage;
     Message->HasPackedLParam = HasPackedLParam;
     Message->QS_Flags = QS_SENDMESSAGE;
+    Message->flags = SMF_RECEIVERFREE;
 
     InsertTailList(&ptiReceiver->SentMessagesListHead, &Message->ListEntry);
     MsqWakeQueue(ptiReceiver, QS_SENDMESSAGE, TRUE);
@@ -953,17 +1059,22 @@ co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
 
 NTSTATUS FASTCALL
 co_MsqSendMessage(PTHREADINFO ptirec,
-                  HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
-                  UINT uTimeout, BOOL Block, INT HookMessage,
+                  HWND Wnd,
+                  UINT Msg,
+                  WPARAM wParam,
+                  LPARAM lParam,
+                  UINT uTimeout,
+                  BOOL Block,
+                  INT HookMessage,
                   ULONG_PTR *uResult)
 {
    PTHREADINFO pti;
-   PUSER_SENT_MESSAGE Message;
-   KEVENT CompletionEvent;
+   PUSER_SENT_MESSAGE SaveMsg, Message;
    NTSTATUS WaitStatus;
    LARGE_INTEGER Timeout;
    PLIST_ENTRY Entry;
    PWND pWnd;
+   BOOLEAN SwapStateEnabled;
    LRESULT Result = 0;   //// Result could be trashed. ////
 
    pti = PsGetCurrentThreadWin32Thread();
@@ -971,13 +1082,28 @@ co_MsqSendMessage(PTHREADINFO ptirec,
    ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!!
 
    /* Don't send from or to a dying thread */
-    if (pti->TIF_flags & TIF_INCLEANUP || ptirec->TIF_flags & TIF_INCLEANUP)
-    {
-        if (uResult) *uResult = -1;
-        ERR("MsqSM: Current pti %lu or Rec pti %lu\n", pti->TIF_flags & TIF_INCLEANUP, ptirec->TIF_flags & TIF_INCLEANUP);
-        return STATUS_UNSUCCESSFUL;
-    }
+   if (pti->TIF_flags & TIF_INCLEANUP || ptirec->TIF_flags & TIF_INCLEANUP)
+   {
+       // Unless we are dying and need to tell our parents.
+       if (pti->TIF_flags & TIF_INCLEANUP && !(ptirec->TIF_flags & TIF_INCLEANUP))
+       {
+           // Parent notify is the big one. Fire and forget!
+           TRACE("Send message from dying thread %u\n", Msg);
+           co_MsqSendMessageAsync(ptirec, Wnd, Msg, wParam, lParam, NULL, 0, FALSE, HookMessage);
+       }
+       if (uResult) *uResult = -1;
+       TRACE("MsqSM: Msg %u Current pti %lu or Rec pti %lu\n", Msg, pti->TIF_flags & TIF_INCLEANUP, ptirec->TIF_flags & TIF_INCLEANUP);
+       return STATUS_UNSUCCESSFUL;
+   }
+
+   if (IsThreadSuspended(ptirec))
+   {
+      ERR("Sending to Suspended Thread Msg %lx\n",Msg);
+      if (uResult) *uResult = -1;
+      return STATUS_UNSUCCESSFUL;
+   }
 
+   // Should we do the same for No Wait?
    if ( HookMessage == MSQ_NORMAL )
    {
       pWnd = ValidateHwndNoErr(Wnd);
@@ -1017,187 +1143,197 @@ co_MsqSendMessage(PTHREADINFO ptirec,
       }
    }
 
-   if(!(Message = ExAllocatePoolWithTag(PagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
+   if(!(Message = AllocateUserMessage(TRUE)))
    {
-      ERR("MsqSendMessage(): Not enough memory to allocate a message");
+      ERR("MsqSendMessage(): Not enough memory to allocate a message\n");
+      if (uResult) *uResult = -1;
       return STATUS_INSUFFICIENT_RESOURCES;
    }
 
-   KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE);
-
-   Timeout.QuadPart = (LONGLONG) uTimeout * (LONGLONG) -10000;
-
-   /* FIXME: Increase reference counter of sender's message queue here */
+   Timeout.QuadPart = Int32x32To64(-10000,uTimeout); // Pass SMTO test with a TO of 0x80000000.
+   TRACE("Timeout val %lld\n",Timeout.QuadPart)
 
    Message->Msg.hwnd = Wnd;
    Message->Msg.message = Msg;
    Message->Msg.wParam = wParam;
    Message->Msg.lParam = lParam;
-   Message->CompletionEvent = &CompletionEvent;
-   Message->Result = &Result;
-   Message->lResult = 0;
-   Message->QS_Flags = 0;
    Message->ptiReceiver = ptirec;
    Message->ptiSender = pti;
-   Message->ptiCallBackSender = NULL;
-   Message->CompletionCallback = NULL;
-   Message->CompletionCallbackContext = 0;
    Message->HookMessage = HookMessage;
-   Message->HasPackedLParam = FALSE;
+   Message->QS_Flags = QS_SENDMESSAGE;
 
-   /* Add it to the list of pending messages */
-   InsertTailList(&pti->DispatchingMessagesHead, &Message->DispatchingListEntry);
+   SaveMsg = pti->pusmSent;
+   pti->pusmSent = Message;
 
    /* Queue it in the destination's message queue */
    InsertTailList(&ptirec->SentMessagesListHead, &Message->ListEntry);
 
-   Message->QS_Flags = QS_SENDMESSAGE;
    MsqWakeQueue(ptirec, QS_SENDMESSAGE, TRUE);
 
-   /* We can't access the Message anymore since it could have already been deleted! */
+   // First time in, turn off swapping of the stack.
+   if (pti->cEnterCount == 0)
+   {
+      SwapStateEnabled = KeSetKernelStackSwapEnable(FALSE);
+   }
+   pti->cEnterCount++;
 
-   if(Block)
+   if (Block)
    {
+      PVOID WaitObjects[2];
+
+      WaitObjects[0] = Message->pkCompletionEvent; // Wait 0
+      WaitObjects[1] = ptirec->pEThread;           // Wait 1
+
       UserLeaveCo();
 
-      /* Don't process messages sent to the thread */
-      WaitStatus = KeWaitForSingleObject(&CompletionEvent, UserRequest, UserMode,
-                                         FALSE, (uTimeout ? &Timeout : NULL));
+      WaitStatus = KeWaitForMultipleObjects( 2,
+                                             WaitObjects,
+                                             WaitAny,
+                                             UserRequest,
+                                             UserMode,
+                                             FALSE,
+                                            (uTimeout ? &Timeout : NULL),
+                                             NULL );
 
       UserEnterCo();
 
-      if(WaitStatus == STATUS_TIMEOUT)
+      if (WaitStatus == STATUS_TIMEOUT)
       {
          /* Look up if the message has not yet dispatched, if so
             make sure it can't pass a result and it must not set the completion event anymore */
          Entry = ptirec->SentMessagesListHead.Flink;
          while (Entry != &ptirec->SentMessagesListHead)
          {
-            if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
-                  == Message)
+            if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message)
             {
-               /* We can access Message here, it's secure because the message queue is locked
-                  and the message is still hasn't been dispatched */
-               Message->CompletionEvent = NULL;
-               Message->Result = NULL;
+               Message->pkCompletionEvent = NULL;
+               RemoveEntryList(&Message->ListEntry);
+               ClearMsgBitsMask(ptirec, Message->QS_Flags);
+               InsertTailList(&usmList, &Message->ListEntry);
                break;
             }
             Entry = Entry->Flink;
          }
 
-         /* Remove from the local dispatching list so the other thread knows,
-            it can't pass a result and it must not set the completion event anymore */
-         Entry = pti->DispatchingMessagesHead.Flink;
-         while (Entry != &pti->DispatchingMessagesHead)
-         {
-            if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
-                  == Message)
-            {
-               /* We can access Message here, it's secure because the sender's message is locked
-                  and the message has definitely not yet been destroyed, otherwise it would
-                  have been removed from this list by the dispatching routine right after
-                  dispatching the message */
-               Message->CompletionEvent = NULL;
-               Message->Result = NULL;
-               RemoveEntryList(&Message->DispatchingListEntry);
-               Message->DispatchingListEntry.Flink = NULL;
-               break;
-            }
-            Entry = Entry->Flink;
-         }
-
-         TRACE("MsqSendMessage (blocked) timed out 1\n");
+         ERR("MsqSendMessage (blocked) timed out 1 Status %lx\n", WaitStatus);
       }
-      while (co_MsqDispatchOneSentMessage(ptirec))
+      // Receiving thread passed on and left us hanging with issues still pending.
+      else if (WaitStatus == STATUS_WAIT_1)
+      {
+         ERR("Bk Receiving Thread woken up dead!\n");
+         Message->flags |= SMF_RECEIVERDIED;
+      }
+
+      while (co_MsqDispatchOneSentMessage(pti))
          ;
    }
    else
    {
       PVOID WaitObjects[3];
 
-      WaitObjects[0] = &CompletionEvent;       // Wait 0
-      WaitObjects[1] = pti->pEventQueueServer; // Wait 1
-      WaitObjects[2] = ptirec->pEThread;       // Wait 2
+      WaitObjects[0] = Message->pkCompletionEvent; // Wait 0
+      WaitObjects[1] = pti->pEventQueueServer;     // Wait 1
+      WaitObjects[2] = ptirec->pEThread;           // Wait 2
 
       do
       {
          UserLeaveCo();
 
-         WaitStatus = KeWaitForMultipleObjects(3, WaitObjects, WaitAny, UserRequest,
-                                               UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL);
+         WaitStatus = KeWaitForMultipleObjects( 3,
+                                                WaitObjects,
+                                                WaitAny,
+                                                UserRequest,
+                                                UserMode,
+                                                FALSE,
+                                               (uTimeout ? &Timeout : NULL),
+                                                NULL);
 
          UserEnterCo();
 
-         if(WaitStatus == STATUS_TIMEOUT)
+         if (WaitStatus == STATUS_TIMEOUT)
          {
             /* Look up if the message has not yet been dispatched, if so
                make sure it can't pass a result and it must not set the completion event anymore */
             Entry = ptirec->SentMessagesListHead.Flink;
             while (Entry != &ptirec->SentMessagesListHead)
             {
-               if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
-                     == Message)
+               if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message)
                {
-                  /* We can access Message here, it's secure because the message queue is locked
-                     and the message is still hasn't been dispatched */
-                  Message->CompletionEvent = NULL;
-                  Message->Result = NULL;
+                  Message->pkCompletionEvent = NULL;
+                  RemoveEntryList(&Message->ListEntry);
+                  ClearMsgBitsMask(ptirec, Message->QS_Flags);
+                  InsertTailList(&usmList, &Message->ListEntry);
                   break;
                }
                Entry = Entry->Flink;
             }
 
-            /* Remove from the local dispatching list so the other thread knows,
-               it can't pass a result and it must not set the completion event anymore */
-            Entry = pti->DispatchingMessagesHead.Flink;
-            while (Entry != &pti->DispatchingMessagesHead)
-            {
-               if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
-                     == Message)
-               {
-                  /* We can access Message here, it's secure because the sender's message is locked
-                     and the message has definitely not yet been destroyed, otherwise it would
-                     have been removed from this list by the dispatching routine right after
-                     dispatching the message */
-                  Message->CompletionEvent = NULL;
-                  Message->Result = NULL;
-                  RemoveEntryList(&Message->DispatchingListEntry);
-                  Message->DispatchingListEntry.Flink = NULL;
-                  break;
-               }
-               Entry = Entry->Flink;
-            }
-
-            TRACE("MsqSendMessage timed out 2\n");
+            ERR("MsqSendMessage timed out 2 Status %lx\n", WaitStatus);
             break;
          }
          // Receiving thread passed on and left us hanging with issues still pending.
-         if ( WaitStatus == STATUS_WAIT_2 )
+         else if (WaitStatus == STATUS_WAIT_2)
          {
-            ERR("Receiving Thread woken up dead!\n");
-            Entry = pti->DispatchingMessagesHead.Flink;
-            while (Entry != &pti->DispatchingMessagesHead)
-            {
-               if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
-                     == Message)
-               {
-                  Message->CompletionEvent = NULL;
-                  Message->Result = NULL;
-                  RemoveEntryList(&Message->DispatchingListEntry);
-                  Message->DispatchingListEntry.Flink = NULL;
-                  break;
-               }
-               Entry = Entry->Flink;
-            }
+            ERR("NB Receiving Thread woken up dead!\n");
+            Message->flags |= SMF_RECEIVERDIED;
+            break;
          }
+
+         if (WaitStatus == STATUS_USER_APC) break;
+
          while (co_MsqDispatchOneSentMessage(pti))
             ;
-      }
-      while (NT_SUCCESS(WaitStatus) && WaitStatus == STATUS_WAIT_1);
+      } while (WaitStatus == STATUS_WAIT_1);
+   }
+
+   // Count is nil, restore swapping of the stack.
+   if (--pti->cEnterCount == 0 )
+   {
+      KeSetKernelStackSwapEnable(SwapStateEnabled);
+   }
+
+   // Handle User APC
+   if (WaitStatus == STATUS_USER_APC)
+   {
+     // The current thread is dying!
+     TRACE("User APC\n");
+
+     // The Message will be on the Trouble list until Thread cleanup.
+     Message->flags |= SMF_SENDERDIED;
+
+     co_IntDeliverUserAPC();
+     ERR("User APC Returned\n"); // Should not see this message.
+   }
+
+   // Force this thread to wake up for the next go around.
+   KeSetEvent(pti->pEventQueueServer, IO_NO_INCREMENT, FALSE);
+
+   Result = Message->lResult;
+
+   // Determine whether this message is being processed or not.
+   if ((Message->flags & (SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE)
+   {
+      Message->flags |= SMF_RECEIVERFREE;
+   }
+
+   if (!(Message->flags & SMF_RECEIVERFREE))
+   {
+      TRACE("Sender Freeing Message %p ptirec %p bit %d list empty %d\n",Message,ptirec,!!(ptirec->pcti->fsChangeBits & QS_SENDMESSAGE),IsListEmpty(&ptirec->SentMessagesListHead));
+      // Make it to this point, the message was received.
+      FreeUserMessage(Message);
    }
 
-   if(WaitStatus != STATUS_TIMEOUT)
-      if (uResult) *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1);
+   pti->pusmSent = SaveMsg;
+
+   TRACE("MSM Allocation Count %d Status %lx Result %d\n",SendMsgCount,WaitStatus,Result);
+
+   if (WaitStatus != STATUS_TIMEOUT)
+   {
+      if (uResult)
+      {
+         *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : 0);
+      }
+   }
 
    return WaitStatus;
 }
@@ -1207,7 +1343,8 @@ MsqPostMessage(PTHREADINFO pti,
                MSG* Msg,
                BOOLEAN HardwareMessage,
                DWORD MessageBits,
-               DWORD dwQEvent)
+               DWORD dwQEvent,
+               LONG_PTR ExtraInfo)
 {
    PUSER_MESSAGE Message;
    PUSER_MESSAGE_QUEUE MessageQueue;
@@ -1225,28 +1362,22 @@ MsqPostMessage(PTHREADINFO pti,
 
    MessageQueue = pti->MessageQueue;
 
-   if (dwQEvent)
-   {
-       ERR("Post Msg; System Qeued Event Message!\n");
-       InsertHeadList(&pti->PostedMessagesListHead,
-                      &Message->ListEntry);
-   }
-   else if (!HardwareMessage)
+   if (!HardwareMessage)
    {
-       InsertTailList(&pti->PostedMessagesListHead,
-                      &Message->ListEntry);
+       InsertTailList(&pti->PostedMessagesListHead, &Message->ListEntry);
    }
    else
    {
-       InsertTailList(&MessageQueue->HardwareMessagesListHead,
-                      &Message->ListEntry);
+       InsertTailList(&MessageQueue->HardwareMessagesListHead, &Message->ListEntry);
    }
 
    if (Msg->message == WM_HOTKEY) MessageBits |= QS_HOTKEY; // Justin Case, just set it.
    Message->dwQEvent = dwQEvent;
+   Message->ExtraInfo = ExtraInfo;
    Message->QS_Flags = MessageBits;
    Message->pti = pti;
    MsqWakeQueue(pti, MessageBits, TRUE);
+   TRACE("Post Message %d\n",PostMsgCount);
 }
 
 VOID FASTCALL
@@ -1341,7 +1472,7 @@ IntTrackMouseMove(PWND pwndTrack, PDESKTOP pDesk, PMSG msg, USHORT hittest)
    }
 }
 
-BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT last)
+BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, BOOL* NotForUs, LONG_PTR ExtraInfo, UINT first, UINT last)
 {
     MSG clk_msg;
     POINT pt;
@@ -1356,7 +1487,6 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
     PTHREADINFO pti;
     PSYSTEM_CURSORINFO CurInfo;
     PDESKTOP pDesk;
-    DECLARE_RETURN(BOOL);
 
     pti = PsGetCurrentThreadWin32Thread();
     pwndDesktop = UserGetDesktopWindow();
@@ -1371,20 +1501,35 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
     {
         hittest = HTCLIENT;
         pwndMsg = MessageQueue->spwndCapture;
-        if (pwndMsg) UserReferenceObject(pwndMsg);
     }
     else
     {
-        pwndMsg = co_WinPosWindowFromPoint(NULL, &msg->pt, &hittest, FALSE);//TRUE);
+        /*
+           Start with null window. See wine win.c:test_mouse_input:WM_COMMAND tests.
+        */
+        pwndMsg = co_WinPosWindowFromPoint( NULL, &msg->pt, &hittest, FALSE);
     }
 
     TRACE("Got mouse message for %p, hittest: 0x%x\n", msg->hwnd, hittest);
 
-    if (pwndMsg == NULL || pwndMsg->head.pti != pti)
+    // Null window or not the same "Hardware" message queue.
+    if (pwndMsg == NULL || pwndMsg->head.pti->MessageQueue != MessageQueue)
     {
+        // Crossing a boundary, so set cursor. See default message queue cursor.
+        IntSystemSetCursor(SYSTEMCUR(ARROW));
         /* Remove and ignore the message */
         *RemoveMessages = TRUE;
-        RETURN(FALSE);
+        return FALSE;
+    }
+
+    // Check to see if this is attached,
+    if ( pwndMsg->head.pti != pti &&  // window thread is not current,
+         MessageQueue->cThreads > 1 ) // and is attached...
+    {
+        // This is not for us and we should leave so the other thread can check for messages!!!
+        *NotForUs = TRUE;
+        *RemoveMessages = TRUE;
+        return FALSE;
     }
 
     if ( MessageQueue == gpqCursor ) // Cursor must use the same Queue!
@@ -1400,13 +1545,14 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
 
     pt = msg->pt;
     message = msg->message;
+
     /* Note: windows has no concept of a non-client wheel message */
     if (message != WM_MOUSEWHEEL)
     {
         if (hittest != HTCLIENT)
         {
             message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
-            msg->wParam = hittest;
+            msg->wParam = hittest; // Caution! This might break wParam check in DblClk.
         }
         else
         {
@@ -1440,7 +1586,8 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
         {
            if ((msg->message == clk_msg.message) &&
                (msg->hwnd == clk_msg.hwnd) &&
-               (msg->wParam == clk_msg.wParam) &&
+               // Only worry about XButton wParam.
+               (msg->message != WM_XBUTTONDOWN || GET_XBUTTON_WPARAM(msg->wParam) == GET_XBUTTON_WPARAM(clk_msg.wParam)) &&
                ((msg->time - clk_msg.time) < (ULONG)gspv.iDblClickTime) &&
                (abs(msg->pt.x - clk_msg.pt.x) < UserGetSystemMetrics(SM_CXDOUBLECLK)/2) &&
                (abs(msg->pt.y - clk_msg.pt.y) < UserGetSystemMetrics(SM_CYDOUBLECLK)/2))
@@ -1457,7 +1604,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
         if (!((first ==  0 && last == 0) || (message >= first || message <= last)))
         {
             TRACE("Message out of range!!!\n");
-            RETURN(FALSE);
+            return FALSE;
         }
 
         /* update static double click conditions */
@@ -1468,11 +1615,17 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
         if (!((first ==  0 && last == 0) || (message >= first || message <= last)))
         {
             TRACE("Message out of range!!!\n");
-            RETURN(FALSE);
+            return FALSE;
+        }
+
+        // Update mouse move down keys.
+        if (message == WM_MOUSEMOVE)
+        {
+           msg->wParam = MsqGetDownKeyState(MessageQueue);
         }
     }
 
-    if(gspv.bMouseClickLock)
+    if (gspv.bMouseClickLock)
     {
         BOOL IsClkLck = FALSE;
 
@@ -1499,11 +1652,18 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
         {
             /* Remove and ignore the message */
             *RemoveMessages = TRUE;
-            RETURN(FALSE);
+            TRACE("Remove and ignore the message\n");
+            return FALSE;
         }
     }
 
-    /* message is accepted now (but may still get dropped) */
+    if (pti->TIF_flags & TIF_MSGPOSCHANGED)
+    {
+        pti->TIF_flags &= ~TIF_MSGPOSCHANGED;
+        IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
+    }
+
+    /* message is accepted now (but still get dropped) */
 
     event.message = msg->message;
     event.time    = msg->time;
@@ -1515,38 +1675,37 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
     hook.pt           = msg->pt;
     hook.hwnd         = msg->hwnd;
     hook.wHitTestCode = hittest;
-    hook.dwExtraInfo  = 0 /* extra_info */ ;
+    hook.dwExtraInfo  = ExtraInfo;
     if (co_HOOK_CallHooks( WH_MOUSE, *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
                         message, (LPARAM)&hook ))
     {
         hook.pt           = msg->pt;
         hook.hwnd         = msg->hwnd;
         hook.wHitTestCode = hittest;
-        hook.dwExtraInfo  = 0 /* extra_info */ ;
+        hook.dwExtraInfo  = ExtraInfo;
         co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook );
 
         ERR("WH_MOUSE dropped mouse message!\n");
 
         /* Remove and skip message */
         *RemoveMessages = TRUE;
-        RETURN(FALSE);
+        return FALSE;
     }
 
-    if ((hittest == HTERROR) || (hittest == HTNOWHERE))
+    if ((hittest == (USHORT)HTERROR) || (hittest == (USHORT)HTNOWHERE))
     {
-        co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
-                      MAKELONG( hittest, msg->message ));
+        co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
 
         /* Remove and skip message */
         *RemoveMessages = TRUE;
-        RETURN(FALSE);
+        return FALSE;
     }
 
     if ((*RemoveMessages == FALSE) || MessageQueue->spwndCapture)
     {
         /* Accept the message */
         msg->message = message;
-        RETURN(TRUE);
+        return TRUE;
     }
 
     if ((msg->message == WM_LBUTTONDOWN) ||
@@ -1567,6 +1726,8 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
             PWND pwndTop = pwndMsg;
             pwndTop = IntGetNonChildAncestor(pwndTop);
 
+            TRACE("Mouse pti %p pwndMsg pti %p pwndTop pti %p\n",MessageQueue->ptiMouse,pwndMsg->head.pti,pwndTop->head.pti);
+
             if (pwndTop && pwndTop != pwndDesktop)
             {
                 LONG ret = co_IntSendMessage( msg->hwnd,
@@ -1602,18 +1763,23 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
     co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
 
     msg->message = message;
-    RETURN(!eatMsg);
-
-CLEANUP:
-    if(pwndMsg)
-        UserDereferenceObject(pwndMsg);
-
-    END_CLEANUP;
+    return !eatMsg;
 }
 
 BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
 {
     EVENTMSG Event;
+    USER_REFERENCE_ENTRY Ref;
+    PWND pWnd;
+    UINT ImmRet;
+    BOOL Ret = TRUE;
+    WPARAM wParam = Msg->wParam;
+    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+
+    if (Msg->message == VK_PACKET)
+    {
+       pti->wchInjected = HIWORD(Msg->wParam);
+    }
 
     if (Msg->message == WM_KEYDOWN || Msg->message == WM_SYSKEYDOWN ||
         Msg->message == WM_KEYUP || Msg->message == WM_SYSKEYUP)
@@ -1632,6 +1798,9 @@ BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
         }
     }
 
+    pWnd = ValidateHwndNoErr(Msg->hwnd);
+    if (pWnd) UserRefObjectCo(pWnd, &Ref);
+
     Event.message = Msg->message;
     Event.hwnd    = Msg->hwnd;
     Event.time    = Msg->time;
@@ -1640,8 +1809,117 @@ BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
     if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
     co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
 
+    if (*RemoveMessages)
+    {
+        if ((Msg->message == WM_KEYDOWN) &&
+            (Msg->hwnd != IntGetDesktopWindow()))
+        {
+            /* Handle F1 key by sending out WM_HELP message */
+            if (Msg->wParam == VK_F1)
+            {
+                UserPostMessage( Msg->hwnd, WM_KEYF1, 0, 0 );
+            }
+            else if (Msg->wParam >= VK_BROWSER_BACK &&
+                     Msg->wParam <= VK_LAUNCH_APP2)
+            {
+                /* FIXME: Process keystate */
+                co_IntSendMessage(Msg->hwnd, WM_APPCOMMAND, (WPARAM)Msg->hwnd, MAKELPARAM(0, (FAPPCOMMAND_KEY | (Msg->wParam - VK_BROWSER_BACK + 1))));
+            }
+        }
+        else if (Msg->message == WM_KEYUP)
+        {
+            /* Handle VK_APPS key by posting a WM_CONTEXTMENU message */
+            if (Msg->wParam == VK_APPS && pti->MessageQueue->MenuOwner == NULL)
+                UserPostMessage( Msg->hwnd, WM_CONTEXTMENU, (WPARAM)Msg->hwnd, -1 );
+        }
+    }
+
+    //// Key Down!
+    if ( *RemoveMessages && Msg->message == WM_SYSKEYDOWN )
+    {
+        if ( HIWORD(Msg->lParam) & KF_ALTDOWN )
+        {
+            if ( Msg->wParam == VK_ESCAPE || Msg->wParam == VK_TAB ) // Alt-Tab/ESC Alt-Shift-Tab/ESC
+            {
+                WPARAM wParamTmp;
+
+                wParamTmp = UserGetKeyState(VK_SHIFT) & 0x8000 ? SC_PREVWINDOW : SC_NEXTWINDOW;
+                TRACE("Send WM_SYSCOMMAND Alt-Tab/ESC Alt-Shift-Tab/ESC\n");
+                co_IntSendMessage( Msg->hwnd, WM_SYSCOMMAND, wParamTmp, Msg->wParam );
+
+                //// Keep looping.
+                Ret = FALSE;
+                //// Skip the rest.
+                goto Exit;
+            }
+        }
+    }
+
+    if ( *RemoveMessages && (Msg->message == WM_SYSKEYDOWN || Msg->message == WM_KEYDOWN) )
+    {
+        if (gdwLanguageToggleKey < 3)
+        {
+            if (IS_KEY_DOWN(gafAsyncKeyState, gdwLanguageToggleKey == 1 ? VK_LMENU : VK_CONTROL)) // L Alt 1 or Ctrl 2 .
+            {
+                if ( wParam == VK_LSHIFT ) gLanguageToggleKeyState = INPUTLANGCHANGE_FORWARD;  // Left Alt - Left Shift, Next
+                //// FIXME : It seems to always be VK_LSHIFT.
+                if ( wParam == VK_RSHIFT ) gLanguageToggleKeyState = INPUTLANGCHANGE_BACKWARD; // Left Alt - Right Shift, Previous
+            }
+         }
+    }
+
+    //// Key Up!                             Alt Key                        Ctrl Key
+    if ( *RemoveMessages && (Msg->message == WM_SYSKEYUP || Msg->message == WM_KEYUP) )
+    {
+        // When initializing win32k: Reading from the registry hotkey combination
+        // to switch the keyboard layout and store it to global variable.
+        // Using this combination of hotkeys in this function
+
+        if ( gdwLanguageToggleKey < 3 &&
+             IS_KEY_DOWN(gafAsyncKeyState, gdwLanguageToggleKey == 1 ? VK_LMENU : VK_CONTROL) )
+        {
+            if ( Msg->wParam == VK_SHIFT && !(IS_KEY_DOWN(gafAsyncKeyState, VK_SHIFT)))
+            {
+                WPARAM wParamILR;
+                PKL pkl = pti->KeyboardLayout;
+
+                if (pWnd) UserDerefObjectCo(pWnd);
+
+                //// Seems to override message window.
+                if (!(pWnd = pti->MessageQueue->spwndFocus))
+                {
+                     pWnd = pti->MessageQueue->spwndActive;
+                }
+                if (pWnd) UserRefObjectCo(pWnd, &Ref);
+
+                if (pkl != NULL && gLanguageToggleKeyState)
+                {
+                    TRACE("Posting WM_INPUTLANGCHANGEREQUEST KeyState %d\n", gLanguageToggleKeyState );
+
+                    wParamILR = gLanguageToggleKeyState;
+                    // If system character set and font signature send flag.
+                    if ( gSystemFS & pkl->dwFontSigs )
+                    {
+                       wParamILR |= INPUTLANGCHANGE_SYSCHARSET;
+                    }
+
+                    UserPostMessage( UserHMGetHandle(pWnd),
+                                     WM_INPUTLANGCHANGEREQUEST,
+                                     wParamILR,
+                                    (LPARAM)pkl->hkl );
+
+                    gLanguageToggleKeyState = 0;
+                    //// Keep looping.
+                    Ret = FALSE;
+                    //// Skip the rest.
+                    goto Exit;
+                }
+            }
+        }
+    }
+
     if (co_HOOK_CallHooks( WH_KEYBOARD,
-                           *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
+                          *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
                            LOWORD(Msg->wParam),
                            Msg->lParam))
     {
@@ -1650,17 +1928,38 @@ BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
                            HCBT_KEYSKIPPED,
                            LOWORD(Msg->wParam),
                            Msg->lParam );
-        ERR("KeyboardMessage WH_CBT Call Hook return!\n");
-        return FALSE;
+
+        ERR("KeyboardMessage WH_KEYBOARD Call Hook return!\n");
+
+        *RemoveMessages = TRUE;
+
+        Ret = FALSE;
     }
-    return TRUE;
+
+    if ( pWnd && Ret && *RemoveMessages && Msg->message == WM_KEYDOWN && !(pti->TIF_flags & TIF_DISABLEIME))
+    {
+        if ( (ImmRet = IntImmProcessKey(pti->MessageQueue, pWnd, Msg->message, Msg->wParam, Msg->lParam)) )
+        {
+            if ( ImmRet & (IPHK_HOTKEY|IPHK_SKIPTHISKEY) )
+            {
+               ImmRet = 0;
+            }
+            if ( ImmRet & IPHK_PROCESSBYIME )
+            {
+               Msg->wParam = VK_PROCESSKEY;
+            }
+        }
+    }
+Exit:
+    if (pWnd) UserDerefObjectCo(pWnd);
+    return Ret;
 }
 
-BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, UINT first, UINT last)
+BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, BOOL* NotForUs, LONG_PTR ExtraInfo, UINT first, UINT last)
 {
     if ( IS_MOUSE_MESSAGE(Msg->message))
     {
-        return co_IntProcessMouseMessage(Msg, RemoveMessages, first, last);
+        return co_IntProcessMouseMessage(Msg, RemoveMessages, NotForUs, ExtraInfo, first, last);
     }
     else if ( IS_KBD_MESSAGE(Msg->message))
     {
@@ -1670,51 +1969,6 @@ BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, UINT first, UI
     return TRUE;
 }
 
-BOOL APIENTRY
-co_MsqPeekMouseMove(IN PTHREADINFO pti,
-                   IN BOOL Remove,
-                   IN PWND Window,
-                   IN UINT MsgFilterLow,
-                   IN UINT MsgFilterHigh,
-                   OUT MSG* pMsg)
-{
-    BOOL AcceptMessage;
-    MSG msg;
-    PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
-
-    if(!(MessageQueue->MouseMoved))
-        return FALSE;
-
-    if (!MessageQueue->ptiSysLock)
-    {
-       MessageQueue->ptiSysLock = pti;
-       pti->pcti->CTI_flags |= CTI_THREADSYSLOCK;
-    }
-
-    if (MessageQueue->ptiSysLock != pti)
-    {
-       ERR("MsqPeekMouseMove: Thread Q is locked to another pti!\n");
-       return FALSE;
-    }
-
-    msg = MessageQueue->MouseMoveMsg;
-
-    AcceptMessage = co_IntProcessMouseMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
-
-    if(AcceptMessage)
-        *pMsg = msg;
-
-    if(Remove)
-    {
-        ClearMsgBitsMask(pti, QS_MOUSEMOVE);
-        MessageQueue->MouseMoved = FALSE;
-    }
-
-    MessageQueue->ptiSysLock = NULL;
-    pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK;
-    return AcceptMessage;
-}
-
 /* check whether a message filter contains at least one potential hardware message */
 static INT FASTCALL
 filter_contains_hw_range( UINT first, UINT last )
@@ -1732,6 +1986,16 @@ filter_contains_hw_range( UINT first, UINT last )
     return 1;
 }
 
+/* check whether message is in the range of mouse messages */
+static inline BOOL is_mouse_message( UINT message )
+{
+    return ( //( message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST )   || This seems to break tests...
+             ( message >= WM_MOUSEFIRST   && message <= WM_MOUSELAST )     ||
+             ( message >= WM_XBUTTONDOWN  && message <= WM_XBUTTONDBLCLK ) ||
+             ( message >= WM_MBUTTONDOWN  && message <= WM_MBUTTONDBLCLK ) ||
+             ( message >= WM_LBUTTONDOWN  && message <= WM_RBUTTONDBLCLK ) );
+}
+
 BOOL APIENTRY
 co_MsqPeekHardwareMessage(IN PTHREADINFO pti,
                          IN BOOL Remove,
@@ -1741,41 +2005,44 @@ co_MsqPeekHardwareMessage(IN PTHREADINFO pti,
                          IN UINT QSflags,
                          OUT MSG* pMsg)
 {
+   BOOL AcceptMessage, NotForUs;
+   PUSER_MESSAGE CurrentMessage;
+   PLIST_ENTRY ListHead;
+   MSG msg;
+   ULONG_PTR idSave;
+   DWORD QS_Flags;
+   LONG_PTR ExtraInfo;
+   BOOL Ret = FALSE;
+   PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
 
-    BOOL AcceptMessage;
-    PUSER_MESSAGE CurrentMessage;
-    PLIST_ENTRY ListHead, CurrentEntry = NULL;
-    MSG msg;
-    BOOL Ret = FALSE;
-    PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
+   if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE;
 
-    if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE;
+   ListHead = MessageQueue->HardwareMessagesListHead.Flink;
 
-    ListHead = &MessageQueue->HardwareMessagesListHead;
-    CurrentEntry = ListHead->Flink;
+   if (IsListEmpty(ListHead)) return FALSE;
 
-    if (IsListEmpty(CurrentEntry)) return FALSE;
+   if (!MessageQueue->ptiSysLock)
+   {
+      MessageQueue->ptiSysLock = pti;
+      pti->pcti->CTI_flags |= CTI_THREADSYSLOCK;
+   }
 
-    if (!MessageQueue->ptiSysLock)
-    {
-       MessageQueue->ptiSysLock = pti;
-       pti->pcti->CTI_flags |= CTI_THREADSYSLOCK;
-    }
+   if (MessageQueue->ptiSysLock != pti)
+   {
+      ERR("Thread Q is locked to ptiSysLock 0x%p pti 0x%p\n",MessageQueue->ptiSysLock,pti);
+      return FALSE;
+   }
 
-    if (MessageQueue->ptiSysLock != pti)
-    {
-       ERR("MsqPeekHardwareMessage: Thread Q is locked to another pti!\n");
-       return FALSE;
-    }
+   while (ListHead != &MessageQueue->HardwareMessagesListHead)
+   {
+      CurrentMessage = CONTAINING_RECORD(ListHead, USER_MESSAGE, ListEntry);
+      ListHead = ListHead->Flink;
 
-    CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
-                                          ListEntry);
-    do
-    {
-        if (IsListEmpty(CurrentEntry)) break;
-        if (!CurrentMessage) break;
-        CurrentEntry = CurrentMessage->ListEntry.Flink;
-        if (!CurrentEntry) break; //// Fix CORE-6734 reported crash.
+      if (MessageQueue->idSysPeek == (ULONG_PTR)CurrentMessage)
+      {
+         TRACE("Skip this message due to it is in play!\n");
+         continue;
+      }
 /*
  MSDN:
  1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
@@ -1784,36 +2051,60 @@ co_MsqPeekHardwareMessage(IN PTHREADINFO pti,
  */
       if ( ( !Window || // 1
             ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
-            ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3
+            ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) || // 3
+            ( is_mouse_message(CurrentMessage->Msg.message) ) ) && // Null window for anything mouse.
             ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
               ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
-        {
-           msg = CurrentMessage->Msg;
+      {
+         idSave = MessageQueue->idSysPeek;
+         MessageQueue->idSysPeek = (ULONG_PTR)CurrentMessage;
 
-           UpdateKeyStateFromMsg(MessageQueue, &msg);
-           AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
+         msg = CurrentMessage->Msg;
+         ExtraInfo = CurrentMessage->ExtraInfo;
+         QS_Flags = CurrentMessage->QS_Flags;
 
-           if (Remove)
-           {
-               RemoveEntryList(&CurrentMessage->ListEntry);
-               ClearMsgBitsMask(pti, CurrentMessage->QS_Flags);
-               MsqDestroyMessage(CurrentMessage);
-           }
+         NotForUs = FALSE;
 
-           if (AcceptMessage)
-           {
-              *pMsg = msg;
-              Ret = TRUE;
-              break;
-           }
-        }
-        CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
-    }
-    while(CurrentEntry != ListHead);
+         UpdateKeyStateFromMsg(MessageQueue, &msg);
+         AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, &NotForUs, ExtraInfo, MsgFilterLow, MsgFilterHigh);
 
-    MessageQueue->ptiSysLock = NULL;
-    pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK;
-    return Ret;
+         if (Remove)
+         {
+             if (CurrentMessage->pti != NULL && (MessageQueue->idSysPeek == (ULONG_PTR)CurrentMessage))
+             {
+                MsqDestroyMessage(CurrentMessage);
+             }
+             ClearMsgBitsMask(pti, QS_Flags);
+         }
+
+         MessageQueue->idSysPeek = idSave;
+
+         if (NotForUs)
+         {
+            Ret = FALSE;
+            break;
+         }
+
+         if (AcceptMessage)
+         {
+            *pMsg = msg;
+            // Fix all but one wine win:test_GetMessagePos WM_TIMER tests. See PostTimerMessages.
+            if (!RtlEqualMemory(&pti->ptLast, &msg.pt, sizeof(POINT)))
+            {
+               pti->TIF_flags |= TIF_MSGPOSCHANGED;
+            }
+            pti->ptLast   = msg.pt;
+            pti->timeLast = msg.time;
+            MessageQueue->ExtraInfo = ExtraInfo;
+            Ret = TRUE;
+            break;
+         }
+      }
+   }
+
+   MessageQueue->ptiSysLock = NULL;
+   pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK;
+   return Ret;
 }
 
 BOOLEAN APIENTRY
@@ -1823,25 +2114,23 @@ MsqPeekMessage(IN PTHREADINFO pti,
                   IN UINT MsgFilterLow,
                   IN UINT MsgFilterHigh,
                   IN UINT QSflags,
+                  OUT LONG_PTR *ExtraInfo,
+                  OUT DWORD *dwQEvent,
                   OUT PMSG Message)
 {
-   PLIST_ENTRY CurrentEntry;
    PUSER_MESSAGE CurrentMessage;
    PLIST_ENTRY ListHead;
+   DWORD QS_Flags;
    BOOL Ret = FALSE;
 
-   CurrentEntry = pti->PostedMessagesListHead.Flink;
-   ListHead = &pti->PostedMessagesListHead;
+   ListHead = pti->PostedMessagesListHead.Flink;
 
-   if (IsListEmpty(CurrentEntry)) return FALSE;
+   if (IsListEmpty(ListHead)) return FALSE;
 
-   CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
-                                         ListEntry);
-   do
+   while(ListHead != &pti->PostedMessagesListHead)
    {
-      if (IsListEmpty(CurrentEntry)) break;
-      if (!CurrentMessage) break;
-      CurrentEntry = CurrentEntry->Flink;
+      CurrentMessage = CONTAINING_RECORD(ListHead, USER_MESSAGE, ListEntry);
+      ListHead = ListHead->Flink;
 /*
  MSDN:
  1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
@@ -1854,21 +2143,23 @@ MsqPeekMessage(IN PTHREADINFO pti,
             ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
               ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
       {
-         *Message = CurrentMessage->Msg;
+         *Message   = CurrentMessage->Msg;
+         *ExtraInfo = CurrentMessage->ExtraInfo;
+         QS_Flags   = CurrentMessage->QS_Flags;
+         if (dwQEvent) *dwQEvent = CurrentMessage->dwQEvent;
 
          if (Remove)
          {
-             RemoveEntryList(&CurrentMessage->ListEntry);
-             ClearMsgBitsMask(pti, CurrentMessage->QS_Flags);
-             MsqDestroyMessage(CurrentMessage);
+             if (CurrentMessage->pti != NULL)
+             {
+                MsqDestroyMessage(CurrentMessage);
+             }
+             ClearMsgBitsMask(pti, QS_Flags);
          }
          Ret = TRUE;
          break;
       }
-      CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
-                                         ListEntry);
    }
-   while (CurrentEntry != ListHead);
 
    return Ret;
 }
@@ -1877,14 +2168,29 @@ NTSTATUS FASTCALL
 co_MsqWaitForNewMessages(PTHREADINFO pti, PWND WndFilter,
                          UINT MsgFilterMin, UINT MsgFilterMax)
 {
-   NTSTATUS ret;
+   NTSTATUS ret = STATUS_SUCCESS;
+
+   // Post mouse moves before waiting for messages.
+   if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED)
+   {
+      IntCoalesceMouseMove(pti);
+   }
+
    UserLeaveCo();
+
+   ZwYieldExecution(); // Let someone else run!
+
    ret = KeWaitForSingleObject( pti->pEventQueueServer,
                                 UserRequest,
                                 UserMode,
                                 FALSE,
                                 NULL );
    UserEnterCo();
+   if ( ret == STATUS_USER_APC )
+   {
+      TRACE("MWFNW User APC\n");
+      co_IntDeliverUserAPC();
+   }
    return ret;
 }
 
@@ -1894,7 +2200,26 @@ MsqIsHung(PTHREADINFO pti)
    LARGE_INTEGER LargeTickCount;
 
    KeQueryTickCount(&LargeTickCount);
-   return ((LargeTickCount.u.LowPart - pti->timeLast) > MSQ_HUNG);
+
+   if ((LargeTickCount.u.LowPart - pti->timeLast) > MSQ_HUNG &&
+       !(pti->pcti->fsWakeMask & QS_INPUT) &&
+       !PsGetThreadFreezeCount(pti->pEThread) &&
+       !(pti->ppi->W32PF_flags & W32PF_APPSTARTING))
+       return TRUE;
+
+   return FALSE;
+}
+
+BOOL FASTCALL
+IsThreadSuspended(PTHREADINFO pti)
+{
+   if (pti->pEThread)
+   {
+      BOOL Ret = TRUE;
+      if (!(pti->pEThread->Tcb.SuspendCount) && !PsGetThreadFreezeCount(pti->pEThread)) Ret = FALSE;
+      return Ret;
+   }
+   return FALSE;
 }
 
 VOID
@@ -1909,11 +2234,15 @@ HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
 BOOLEAN FASTCALL
 MsqInitializeMessageQueue(PTHREADINFO pti, PUSER_MESSAGE_QUEUE MessageQueue)
 {
-   MessageQueue->CaretInfo = (PTHRDCARETINFO)(MessageQueue + 1);
    InitializeListHead(&MessageQueue->HardwareMessagesListHead); // Keep here!
    MessageQueue->spwndFocus = NULL;
    MessageQueue->iCursorLevel = 0;
-   MessageQueue->CursorObject = NULL;
+   MessageQueue->CursorObject = SYSTEMCUR(WAIT); // See test_initial_cursor.
+   if (MessageQueue->CursorObject)
+   {
+      TRACE("Default cursor hcur %p\n",UserHMGetHandle(MessageQueue->CursorObject));
+      UserReferenceObject(MessageQueue->CursorObject);
+   }
    RtlCopyMemory(MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState));
    MessageQueue->ptiMouse = pti;
    MessageQueue->ptiKeyboard = pti;
@@ -1929,111 +2258,117 @@ MsqCleanupThreadMsgs(PTHREADINFO pti)
    PUSER_MESSAGE CurrentMessage;
    PUSER_SENT_MESSAGE CurrentSentMessage;
 
+   TRACE("MsqCleanupThreadMsgs %p\n",pti);
+
+   // Clear it all out.
+   if (pti->pcti)
+   {
+       pti->pcti->fsWakeBits = 0;
+       pti->pcti->fsChangeBits = 0;
+   }
+
+   pti->nCntsQBits[QSRosKey] = 0;
+   pti->nCntsQBits[QSRosMouseMove] = 0;
+   pti->nCntsQBits[QSRosMouseButton] = 0;
+   pti->nCntsQBits[QSRosPostMessage] = 0;
+   pti->nCntsQBits[QSRosSendMessage] = 0;
+   pti->nCntsQBits[QSRosHotKey] = 0;
+   pti->nCntsQBits[QSRosEvent] = 0;
+
    /* cleanup posted messages */
    while (!IsListEmpty(&pti->PostedMessagesListHead))
    {
-      CurrentEntry = RemoveHeadList(&pti->PostedMessagesListHead);
-      CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
-                                         ListEntry);
+      CurrentEntry = pti->PostedMessagesListHead.Flink;
+      CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
+      ERR("Thread Cleanup Post Messages %p\n",CurrentMessage);
+      if (CurrentMessage->dwQEvent)
+      {
+         if (CurrentMessage->dwQEvent == POSTEVENT_NWE)
+         {
+            ExFreePoolWithTag( (PVOID)CurrentMessage->ExtraInfo, TAG_HOOK);
+         }
+      }
       MsqDestroyMessage(CurrentMessage);
    }
 
    /* remove the messages that have not yet been dispatched */
    while (!IsListEmpty(&pti->SentMessagesListHead))
    {
-      CurrentEntry = RemoveHeadList(&pti->SentMessagesListHead);
-      CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
-                                             ListEntry);
+      CurrentEntry = pti->SentMessagesListHead.Flink;
+      CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
 
-      TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
-      /* Only if the message has a sender was the message in the DispatchingList */
-      if ((CurrentSentMessage->ptiSender)
-         && (CurrentSentMessage->DispatchingListEntry.Flink != NULL))
-      {
-         RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
-      }
+      ERR("Thread Cleanup Sent Messages %p\n",CurrentSentMessage);
 
       /* wake the sender's thread */
-      if (CurrentSentMessage->CompletionEvent != NULL)
+      if (CurrentSentMessage->pkCompletionEvent != NULL)
       {
-         KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
+         KeSetEvent(CurrentSentMessage->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
       }
 
-      if (CurrentSentMessage->HasPackedLParam == TRUE)
+      if (CurrentSentMessage->HasPackedLParam)
       {
          if (CurrentSentMessage->Msg.lParam)
             ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
       }
 
       /* free the message */
-      ExFreePool(CurrentSentMessage);
+      FreeUserMessage(CurrentSentMessage);
    }
 
-   /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
-      ExitThread() was called in a SendMessage() umode callback */
-   while (!IsListEmpty(&pti->LocalDispatchingMessagesHead))
+   // Process Trouble Message List
+   if (!IsListEmpty(&usmList))
    {
-      CurrentEntry = RemoveHeadList(&pti->LocalDispatchingMessagesHead);
-      CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
-                                             ListEntry);
-
-      /* remove the message from the dispatching list */
-      if(CurrentSentMessage->DispatchingListEntry.Flink != NULL)
+      CurrentEntry = usmList.Flink;
+      while (CurrentEntry != &usmList)
       {
-         RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
-      }
-
-      TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
+         CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
+         CurrentEntry = CurrentEntry->Flink;
 
-      /* wake the sender's thread */
-      if (CurrentSentMessage->CompletionEvent != NULL)
-      {
-         KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
-      }
+         TRACE("Found troubled messages %p on the list\n",CurrentSentMessage);
 
-      if (CurrentSentMessage->HasPackedLParam == TRUE)
-      {
-         if (CurrentSentMessage->Msg.lParam)
-            ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
-      }
+         if ( pti == CurrentSentMessage->ptiReceiver )
+         {
+            if (CurrentSentMessage->HasPackedLParam)
+            {
+               if (CurrentSentMessage->Msg.lParam)
+                  ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
+            }
 
-      /* free the message */
-      ExFreePool(CurrentSentMessage);
-   }
+            /* free the message */
+            FreeUserMessage(CurrentSentMessage);
+         }
+         else if ( pti == CurrentSentMessage->ptiSender ||
+                   pti == CurrentSentMessage->ptiCallBackSender )
+         {
+            // Determine whether this message is being processed or not.
+            if ((CurrentSentMessage->flags & (SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE)
+            {
+               CurrentSentMessage->flags |= SMF_RECEIVERFREE;
+            }
 
-   /* tell other threads not to bother returning any info to us */
-   while (! IsListEmpty(&pti->DispatchingMessagesHead))
-   {
-      CurrentEntry = RemoveHeadList(&pti->DispatchingMessagesHead);
-      CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
-                                             DispatchingListEntry);
-      CurrentSentMessage->CompletionEvent = NULL;
-      CurrentSentMessage->Result = NULL;
+            if (!(CurrentSentMessage->flags & SMF_RECEIVERFREE))
+            {
 
-      /* do NOT dereference our message queue as it might get attempted to be
-         locked later */
-   }
+               if (CurrentSentMessage->HasPackedLParam)
+               {
+                  if (CurrentSentMessage->Msg.lParam)
+                     ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
+               }
 
-   // Clear it all out.
-   if (pti->pcti)
-   {
-       pti->pcti->fsWakeBits = 0;
-       pti->pcti->fsChangeBits = 0;
+               /* free the message */
+               FreeUserMessage(CurrentSentMessage);
+            }
+         }
+      }
    }
-
-   pti->nCntsQBits[QSRosKey] = 0;
-   pti->nCntsQBits[QSRosMouseMove] = 0;
-   pti->nCntsQBits[QSRosMouseButton] = 0;
-   pti->nCntsQBits[QSRosPostMessage] = 0;
-   pti->nCntsQBits[QSRosSendMessage] = 0;
-   pti->nCntsQBits[QSRosHotKey] = 0;
-   pti->nCntsQBits[QSRosEvent] = 0;
 }
 
 VOID FASTCALL
 MsqCleanupMessageQueue(PTHREADINFO pti)
 {
    PUSER_MESSAGE_QUEUE MessageQueue;
+   PLIST_ENTRY CurrentEntry;
+   PUSER_MESSAGE CurrentMessage;
 
    MessageQueue = pti->MessageQueue;
    MessageQueue->cThreads--;
@@ -2043,6 +2378,18 @@ MsqCleanupMessageQueue(PTHREADINFO pti)
       if (MessageQueue->ptiSysLock == pti) MessageQueue->ptiSysLock = NULL;
    }
 
+   if (MessageQueue->cThreads == 0) //// Fix a crash related to CORE-10471 testing.
+   {
+      /* cleanup posted messages */
+      while (!IsListEmpty(&MessageQueue->HardwareMessagesListHead))
+      {
+         CurrentEntry = MessageQueue->HardwareMessagesListHead.Flink;
+         CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
+         ERR("MQ Cleanup Post Messages %p\n",CurrentMessage);
+         MsqDestroyMessage(CurrentMessage);
+      }
+   } ////
+
    if (MessageQueue->CursorObject)
    {
        PCURICON_OBJECT pCursor = MessageQueue->CursorObject;
@@ -2061,7 +2408,7 @@ MsqCleanupMessageQueue(PTHREADINFO pti)
            IntGetSysCursorInfo()->CurrentCursorObject = NULL;
        }
 
-       ERR("DereferenceObject pCursor\n");
+       TRACE("DereferenceObject pCursor\n");
        UserDereferenceObject(pCursor);
    }
 
@@ -2084,16 +2431,16 @@ MsqCreateMessageQueue(PTHREADINFO pti)
 {
    PUSER_MESSAGE_QUEUE MessageQueue;
 
-   MessageQueue = (PUSER_MESSAGE_QUEUE)ExAllocatePoolWithTag(NonPagedPool,
-                  sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO),
-                  USERTAG_Q);
+   MessageQueue = ExAllocatePoolWithTag(NonPagedPool,
+                                        sizeof(*MessageQueue),
+                                        USERTAG_Q);
 
    if (!MessageQueue)
    {
       return NULL;
    }
 
-   RtlZeroMemory(MessageQueue, sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO));
+   RtlZeroMemory(MessageQueue, sizeof(*MessageQueue));
    /* hold at least one reference until it'll be destroyed */
    IntReferenceMessageQueue(MessageQueue);
    /* initialize the queue */
@@ -2107,11 +2454,12 @@ MsqCreateMessageQueue(PTHREADINFO pti)
 }
 
 VOID FASTCALL
-MsqDestroyMessageQueue(PTHREADINFO pti)
+MsqDestroyMessageQueue(_In_ PTHREADINFO pti)
 {
    PDESKTOP desk;
    PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
 
+   NT_ASSERT(MessageQueue != NULL);
    MessageQueue->QF_flags |= QF_INDESTROY;
 
    /* remove the message queue from any desktops */
@@ -2125,6 +2473,7 @@ MsqDestroyMessageQueue(PTHREADINFO pti)
    MsqCleanupMessageQueue(pti);
 
    /* decrease the reference counter, if it hits zero, the queue will be freed */
+   _PRAGMA_WARNING_SUPPRESS(__WARNING_USING_UNINIT_VAR);
    IntDereferenceMessageQueue(MessageQueue);
 }
 
@@ -2178,7 +2527,7 @@ co_MsqReplyMessage( LRESULT lResult )
 
    if (Message->QS_Flags & QS_SMRESULT) return FALSE;
 
-   //     SendMessageXxx    || Callback msg and not a notify msg
+   //     SendMessageXxx  || Callback msg and not a notify msg
    if (Message->ptiSender || Message->CompletionCallback)
    {
       Message->lResult = lResult;
@@ -2193,7 +2542,7 @@ MsqSetStateWindow(PTHREADINFO pti, ULONG Type, HWND hWnd)
 {
    HWND Prev;
    PUSER_MESSAGE_QUEUE MessageQueue;
-   
+
    MessageQueue = pti->MessageQueue;
 
    switch(Type)
@@ -2219,9 +2568,8 @@ MsqSetStateWindow(PTHREADINFO pti, ULONG Type, HWND hWnd)
          MessageQueue->MoveSize = hWnd;
          return Prev;
       case MSQ_STATE_CARET:
-         ASSERT(MessageQueue->CaretInfo);
-         Prev = MessageQueue->CaretInfo->hWnd;
-         MessageQueue->CaretInfo->hWnd = hWnd;
+         Prev = MessageQueue->CaretInfo.hWnd;
+         MessageQueue->CaretInfo.hWnd = hWnd;
          return Prev;
    }