Index: win32ss/user/ntuser/keyboard.c
===================================================================
--- win32ss/user/ntuser/keyboard.c	(revision 58555)
+++ win32ss/user/ntuser/keyboard.c	(working copy)
@@ -763,6 +763,7 @@
 {
     WORD wSimpleVk = 0, wFixedVk, wVk2;
     PUSER_MESSAGE_QUEUE pFocusQueue;
+    PTHREADINFO pti;
     BOOL bExt = (dwFlags & KEYEVENTF_EXTENDEDKEY) ? TRUE : FALSE;
     BOOL bIsDown = (dwFlags & KEYEVENTF_KEYUP) ? FALSE : TRUE;
     BOOL bPacket = (dwFlags & KEYEVENTF_UNICODE) ? TRUE : FALSE;
@@ -872,6 +873,12 @@
            // Focus can be null so going with Active. WM_SYSKEYXXX last wine Win test_keyboard_input.
            Wnd = pFocusQueue->spwndActive;
         }
+        if ( !Wnd || Wnd->state2 & WNDS2_INDESTROY || Wnd->state & WNDS_DESTROYED )
+        {
+           ERR("ProcessKeyEvent Active Focus window is dead!\n");
+           return FALSE;
+        }
+        pti = Wnd->head.pti;
 
         /* Init message */
         Msg.hwnd = UserHMGetHandle(Wnd);
@@ -900,7 +907,7 @@
 
         /* Post a keyboard message */
         TRACE("Posting keyboard msg %u wParam 0x%x lParam 0x%x\n", Msg.message, Msg.wParam, Msg.lParam);
-        MsqPostMessage(pFocusQueue, &Msg, TRUE, QS_KEY, 0);
+        MsqPostMessage(pti, &Msg, TRUE, QS_KEY, 0);
     }
 
     return TRUE;
@@ -913,7 +920,6 @@
     PKL pKl = NULL;
     PKBDTABLES pKbdTbl;
     PUSER_MESSAGE_QUEUE pFocusQueue;
-    struct _ETHREAD *pFocusThread;
     LARGE_INTEGER LargeTickCount;
     DWORD dwTime;
     BOOL bExt = (pKbdInput->dwFlags & KEYEVENTF_EXTENDEDKEY) ? TRUE : FALSE;
@@ -925,9 +931,16 @@
 
     if (pFocusQueue)
     {
-        pFocusThread = pFocusQueue->Thread;
-        if (pFocusThread && pFocusThread->Tcb.Win32Thread)
-            pKl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout;
+        PWND Wnd = pFocusQueue->spwndFocus;
+        if (!Wnd)
+        {
+           Wnd = pFocusQueue->spwndActive;
+        }
+        if (Wnd)
+        {
+           if (!(Wnd->state2 & WNDS2_INDESTROY) && !(Wnd->state & WNDS_DESTROYED) )
+              pKl = Wnd->head.pti->KeyboardLayout;
+        }
     }
 
     if (!pKl)
@@ -997,7 +1010,6 @@
     PKL pKl = NULL;
     PKBDTABLES pKbdTbl;
     PUSER_MESSAGE_QUEUE pFocusQueue;
-    struct _ETHREAD *pFocusThread;
 
     /* Calculate scan code with prefix */
     wScanCode = pKbdInputData->MakeCode & 0x7F;
@@ -1011,9 +1023,16 @@
 
     if (pFocusQueue)
     {
-        pFocusThread = pFocusQueue->Thread;
-        if (pFocusThread && pFocusThread->Tcb.Win32Thread)
-            pKl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout;
+        PWND Wnd = pFocusQueue->spwndFocus;
+        if (!Wnd)
+        {
+           Wnd = pFocusQueue->spwndActive;
+        }
+        if (Wnd)
+        {
+           if (!(Wnd->state2 & WNDS2_INDESTROY) && !(Wnd->state & WNDS_DESTROYED) )
+              pKl = Wnd->head.pti->KeyboardLayout;
+        }
     }
 
     if (!pKl)
@@ -1121,7 +1140,7 @@
         NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
         NewMsg.wParam = HIWORD(lpMsg->lParam);
         NewMsg.lParam = LOWORD(lpMsg->lParam);
-        MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY, 0);
+        MsqPostMessage(pti, &NewMsg, FALSE, QS_KEY, 0);
         return TRUE;
     }
 
@@ -1150,7 +1169,7 @@
         {
             TRACE("Msg: %x '%lc' (%04x) %08x\n", NewMsg.message, wch[i], wch[i], NewMsg.lParam);
             NewMsg.wParam = wch[i];
-            MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY, 0);
+            MsqPostMessage(pti, &NewMsg, FALSE, QS_KEY, 0);
         }
         bResult = TRUE;
     }
Index: win32ss/user/ntuser/msgqueue.h
===================================================================
--- win32ss/user/ntuser/msgqueue.h	(revision 58555)
+++ win32ss/user/ntuser/msgqueue.h	(working copy)
@@ -6,18 +6,6 @@
 #define MSQ_ISEVENT     2
 #define MSQ_INJECTMODULE 3
 
-#define QSIDCOUNTS 6
-
-typedef enum _QS_ROS_TYPES
-{
-    QSRosKey = 0,
-    QSRosMouseMove,
-    QSRosMouseButton,
-    QSRosPostMessage,
-    QSRosSendMessage,
-    QSRosHotKey,
-}QS_ROS_TYPES,*PQS_ROS_TYPES;
-
 typedef struct _USER_MESSAGE
 {
   LIST_ENTRY ListEntry;
@@ -38,9 +26,10 @@
   PKEVENT CompletionEvent;
   LRESULT* Result;
   LRESULT lResult;
-  struct _USER_MESSAGE_QUEUE* SenderQueue;
-  struct _USER_MESSAGE_QUEUE* CallBackSenderQueue;
+  PTHREADINFO ptiSender;
+  PTHREADINFO ptiReceiver;
   SENDASYNCPROC CompletionCallback;
+  PTHREADINFO ptiCallBackSender;
   ULONG_PTR CompletionCallbackContext;
   /* entry in the dispatching list of the sender's message queue */
   LIST_ENTRY DispatchingListEntry;
@@ -53,13 +42,14 @@
   /* Reference counter, only access this variable with interlocked functions! */
   LONG References;
 
+  PTHREADINFO ptiOwner; // temp..
+  /* Desktop that the message queue is attached to */
+  struct _DESKTOP *Desktop;
+
   PTHREADINFO ptiSysLock;
-  /* Owner of the message queue */
-  struct _ETHREAD *Thread;
-  /* Queue of messages sent to the queue. */
-  LIST_ENTRY SentMessagesListHead;
-  /* Queue of messages posted to the queue. */
-  LIST_ENTRY PostedMessagesListHead;
+  PTHREADINFO ptiMouse;
+  PTHREADINFO ptiKeyboard;
+
   /* Queue for hardware messages for the queue. */
   LIST_ENTRY HardwareMessagesListHead;
   /* True if a WM_MOUSEMOVE is pending */
@@ -68,16 +58,6 @@
   MSG MouseMoveMsg;
   /* Last click message for translating double clicks */
   MSG msgDblClk;
-  /* True if a WM_QUIT message is pending. */
-  BOOLEAN QuitPosted;
-  /* The quit exit code. */
-  ULONG QuitExitCode;
-  /* Set if there are new messages specified by WakeMask in any of the queues. */
-  PKEVENT NewMessages;
-  /* Handle for the above event (in the context of the process owning the queue). */
-  HANDLE NewMessagesHandle;
-  /* Last time PeekMessage() was called. */
-  ULONG LastMsgRead;
   /* Current capture window for this queue. */
   PWND spwndCapture;
   /* Current window with focus (ie. receives keyboard input) for this queue. */
@@ -97,13 +77,6 @@
   DWORD QF_flags;
   DWORD cThreads; // Shared message queue counter.
 
-  /* Queue state tracking */
-  // Send list QS_SENDMESSAGE
-  // Post list QS_POSTMESSAGE|QS_HOTKEY|QS_PAINT|QS_TIMER|QS_KEY
-  // Hard list QS_MOUSE|QS_KEY only
-  // Accounting of queue bit sets, the rest are flags. QS_TIMER QS_PAINT counts are handled in thread information.
-  DWORD nCntsQBits[QSIDCOUNTS]; // QS_KEY QS_MOUSEMOVE QS_MOUSEBUTTON QS_POSTMESSAGE QS_SENDMESSAGE QS_HOTKEY
-
   /* Extra message information */
   LPARAM ExtraInfo;
 
@@ -116,13 +89,6 @@
   /* Cursor object */
   PCURICON_OBJECT CursorObject;
 
-  /* Messages that are currently dispatched by other threads */
-  LIST_ENTRY DispatchingMessagesHead;
-  /* Messages that are currently dispatched by this message queue, required for cleanup */
-  LIST_ENTRY LocalDispatchingMessagesHead;
-
-  /* Desktop that the message queue is attached to */
-  struct _DESKTOP *Desktop;
 } USER_MESSAGE_QUEUE, *PUSER_MESSAGE_QUEUE;
 
 #define QF_UPDATEKEYSTATE         0x00000001
@@ -152,17 +118,17 @@
     WM_ASYNC_SETACTIVEWINDOW
 };
 
-BOOL FASTCALL MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue);
+BOOL FASTCALL MsqIsHung(PTHREADINFO pti);
 VOID CALLBACK HungAppSysTimerProc(HWND,UINT,UINT_PTR,DWORD);
-NTSTATUS FASTCALL co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
+NTSTATUS FASTCALL co_MsqSendMessage(PTHREADINFO ptirec,
            HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
            UINT uTimeout, BOOL Block, INT HookMessage, ULONG_PTR *uResult);
 PUSER_MESSAGE FASTCALL MsqCreateMessage(LPMSG Msg);
 VOID FASTCALL MsqDestroyMessage(PUSER_MESSAGE Message);
-VOID FASTCALL MsqPostMessage(PUSER_MESSAGE_QUEUE, MSG*, BOOLEAN, DWORD, DWORD);
-VOID FASTCALL MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode);
+VOID FASTCALL MsqPostMessage(PTHREADINFO, MSG*, BOOLEAN, DWORD, DWORD);
+VOID FASTCALL MsqPostQuitMessage(PTHREADINFO pti, ULONG ExitCode);
 BOOLEAN APIENTRY
-MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
+MsqPeekMessage(IN PTHREADINFO pti,
 	              IN BOOLEAN Remove,
 	              IN PWND Window,
 	              IN UINT MsgFilterLow,
@@ -170,7 +136,7 @@
 	              IN UINT QSflags,
 	              OUT PMSG Message);
 BOOL APIENTRY
-co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
+co_MsqPeekHardwareMessage(IN PTHREADINFO pti,
 	                      IN BOOL Remove,
 	                      IN PWND Window,
 	                      IN UINT MsgFilterLow,
@@ -178,7 +144,7 @@
 	                      IN UINT QSflags,
 	                      OUT MSG* pMsg);
 BOOL APIENTRY
-co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue,
+co_MsqPeekMouseMove(IN PTHREADINFO pti,
                     IN BOOL Remove,
                     IN PWND Window,
                     IN UINT MsgFilterLow,
@@ -186,14 +152,15 @@
                     OUT MSG* pMsg);
 BOOLEAN FASTCALL MsqInitializeMessageQueue(PTHREADINFO, PUSER_MESSAGE_QUEUE);
 PUSER_MESSAGE_QUEUE FASTCALL MsqCreateMessageQueue(PTHREADINFO);
+VOID FASTCALL MsqCleanupThreadMsgs(PTHREADINFO);
 VOID FASTCALL MsqDestroyMessageQueue(PTHREADINFO);
 INIT_FUNCTION NTSTATUS NTAPI MsqInitializeImpl(VOID);
-BOOLEAN FASTCALL co_MsqDispatchOneSentMessage(_In_ PUSER_MESSAGE_QUEUE MessageQueue);
+BOOLEAN FASTCALL co_MsqDispatchOneSentMessage(PTHREADINFO pti);
 NTSTATUS FASTCALL
-co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, PWND WndFilter,
+co_MsqWaitForNewMessages(PTHREADINFO pti, PWND WndFilter,
                       UINT MsgFilterMin, UINT MsgFilterMax);
-VOID FASTCALL MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue);
-VOID FASTCALL MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue);
+VOID FASTCALL MsqIncPaintCountQueue(PTHREADINFO);
+VOID FASTCALL MsqDecPaintCountQueue(PTHREADINFO);
 LRESULT FASTCALL co_IntSendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
 LRESULT FASTCALL co_IntPostOrSendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
 LRESULT FASTCALL
@@ -235,13 +202,13 @@
 VOID FASTCALL co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook);
 BOOL FASTCALL MsqIsClkLck(LPMSG Msg, BOOL Remove);
 BOOL FASTCALL MsqIsDblClk(LPMSG Msg, BOOL Remove);
-HWND FASTCALL MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd);
+HWND FASTCALL MsqSetStateWindow(PTHREADINFO pti, ULONG Type, HWND hWnd);
 BOOL APIENTRY IntInitMessagePumpHook(VOID);
 BOOL APIENTRY IntUninitMessagePumpHook(VOID);
 
 LPARAM FASTCALL MsqSetMessageExtraInfo(LPARAM lParam);
 LPARAM FASTCALL MsqGetMessageExtraInfo(VOID);
-VOID APIENTRY MsqRemoveWindowMessagesFromQueue(PVOID pWindow); /* F*(&$ headers, will be gone in the rewrite! */
+VOID APIENTRY MsqRemoveWindowMessagesFromQueue(PWND pWindow);
 
 #define IntReferenceMessageQueue(MsgQueue) \
   InterlockedIncrement(&(MsgQueue)->References)
@@ -250,9 +217,7 @@
   do { \
     if(InterlockedDecrement(&(MsgQueue)->References) == 0) \
     { \
-      TRACE("Free message queue 0x%p\n", (MsgQueue)); \
-      if ((MsgQueue)->NewMessages != NULL) \
-        ObDereferenceObject((MsgQueue)->NewMessages); \
+      ERR("Free message queue 0x%p\n", (MsgQueue)); \
       ExFreePoolWithTag((MsgQueue), USERTAG_Q); \
     } \
   } while(0)
@@ -289,8 +254,8 @@
 VOID FASTCALL IdlePing(VOID);
 VOID FASTCALL IdlePong(VOID);
 BOOL FASTCALL co_MsqReplyMessage(LRESULT);
-VOID FASTCALL MsqWakeQueue(PUSER_MESSAGE_QUEUE,DWORD,BOOL);
-VOID FASTCALL ClearMsgBitsMask(PUSER_MESSAGE_QUEUE,UINT);
+VOID FASTCALL MsqWakeQueue(PTHREADINFO,DWORD,BOOL);
+VOID FASTCALL ClearMsgBitsMask(PTHREADINFO,UINT);
 
 int UserShowCursor(BOOL bShow);
 PCURICON_OBJECT
Index: win32ss/user/ntuser/win32.h
===================================================================
--- win32ss/user/ntuser/win32.h	(revision 58555)
+++ win32ss/user/ntuser/win32.h	(working copy)
@@ -32,9 +32,9 @@
 #define W32PF_MANUALGUICHECK         (0x02000000)
 #define W32PF_CREATEDWINORDC         (0x04000000)
 #define W32PF_APIHOOKLOADED          (0x08000000)
-/*
-#define QSIDCOUNTS 6
 
+#define QSIDCOUNTS 7
+
 typedef enum _QS_ROS_TYPES
 {
     QSRosKey = 0,
@@ -43,8 +43,9 @@
     QSRosPostMessage,
     QSRosSendMessage,
     QSRosHotKey,
+    QSRosEvent,
 }QS_ROS_TYPES,*PQS_ROS_TYPES;
-*/
+
 extern BOOL ClientPfnInit;
 extern HINSTANCE hModClient;
 extern HANDLE hModuleWin;    // This Win32k Instance.
@@ -65,7 +66,7 @@
 typedef struct _W32THREAD
 {
     PETHREAD pEThread;
-    ULONG RefCount;
+    LONG RefCount;
     PTL ptlW32;
     PVOID pgdiDcattr;
     PVOID pgdiBrushAttr;
@@ -89,13 +90,18 @@
     PCLIENTINFO         pClientInfo;
     FLONG               TIF_flags;
     PUNICODE_STRING     pstrAppName;
-    LIST_ENTRY          psmsSent;        // DispatchingMessagesHead
+    /* Messages that are currently dispatched to other threads */
+    LIST_ENTRY          DispatchingMessagesHead; // psmsSent
     struct _USER_SENT_MESSAGE *pusmCurrent;
-    LIST_ENTRY          psmsReceiveList; // SentMessagesListHead
+    /* Queue of messages sent to the queue. */
+    LIST_ENTRY          SentMessagesListHead;    // psmsReceiveList
+    /* Last time PeekMessage() was called. */
     LONG                timeLast;
     ULONG_PTR           idLast;
+    /* True if a WM_QUIT message is pending. */
     BOOLEAN             QuitPosted;
-    INT                 exitCode;     // QuitExitCode
+    /* The quit exit code. */
+    INT                 exitCode;
     HDESK               hdesk;
     UINT                cPaintsReady; /* Count of paints pending. */
     UINT                cTimersReady; /* Count of timers pending. */
@@ -109,26 +115,32 @@
     LPARAM              lParamHkCurrent;
     WPARAM              wParamHkCurrent;
     struct tagSBTRACK*  pSBTrack;
-    HANDLE              hEventQueueClient; // NewMessagesHandle
-    PKEVENT             pEventQueueServer; // NewMessages
+    /* Set if there are new messages specified by WakeMask in any of the queues. */
+    HANDLE              hEventQueueClient;
+    /* Handle for the above event (in the context of the process owning the queue). */
+    PKEVENT             pEventQueueServer;
     LIST_ENTRY          PtiLink;
     INT                 iCursorLevel;
     POINT               ptLast;
 
-    LIST_ENTRY          mlPost; // PostedMessagesListHead
+    /* Queue of messages posted to the queue. */
+    LIST_ENTRY          PostedMessagesListHead; // mlPost
 
+    UINT                cWindows;
+    UINT                cVisWindows;
     LIST_ENTRY          aphkStart[NB_HOOKS];
     CLIENTTHREADINFO    cti;  // Used only when no Desktop or pcti NULL.
 
     /* ReactOS */
 
-    /* Queue state tracking */
+    /* Thread Queue state tracking */
     // Send list QS_SENDMESSAGE
     // Post list QS_POSTMESSAGE|QS_HOTKEY|QS_PAINT|QS_TIMER|QS_KEY
     // Hard list QS_MOUSE|QS_KEY only
     // Accounting of queue bit sets, the rest are flags. QS_TIMER QS_PAINT counts are handled in thread information.
-    //DWORD nCntsQBits[QSIDCOUNTS]; // QS_KEY QS_MOUSEMOVE QS_MOUSEBUTTON QS_POSTMESSAGE QS_SENDMESSAGE QS_HOTKEY
+    DWORD nCntsQBits[QSIDCOUNTS]; // QS_KEY QS_MOUSEMOVE QS_MOUSEBUTTON QS_POSTMESSAGE QS_SENDMESSAGE QS_HOTKEY
 
+    /* Messages that are currently dispatched by this message queue, required for cleanup */
     LIST_ENTRY LocalDispatchingMessagesHead;
     LIST_ENTRY WindowListHead;
     LIST_ENTRY W32CallbackListHead;
@@ -142,6 +154,22 @@
 
 #include <poppack.h>
 
+
+#define IntReferenceThreadInfo(pti) \
+  InterlockedIncrement(&(pti)->RefCount)
+
+VOID FASTCALL UserDeleteW32Thread(PTHREADINFO);
+
+#define IntDereferenceThreadInfo(pti) \
+  do { \
+    if(InterlockedDecrement(&(pti)->RefCount) == 0) \
+    { \
+      ASSERT(pti->TIF_flags &= (TIF_INCLEANUP|TIF_DONTATTACHQUEUE) == (TIF_INCLEANUP|TIF_DONTATTACHQUEUE)); \
+      UserDeleteW32Thread(pti); \
+    } \
+  } while(0)
+
+
 typedef struct _W32HEAP_USER_MAPPING
 {
     struct _W32HEAP_USER_MAPPING *Next;
@@ -195,9 +223,9 @@
   PTHREADINFO ptiList;
   PTHREADINFO ptiMainThread;
   struct _DESKTOP* rpdeskStartup;
-  PPROCESSINFO ppiNext;
   PCLS pclsPrivateList;
   PCLS pclsPublicList;
+  PPROCESSINFO ppiNext;
   INT cThreads;
   HDESK hdeskStartup;
   DWORD dwhmodLibLoadedMask;
Index: win32ss/user/ntuser/painting.c
===================================================================
--- win32ss/user/ntuser/painting.c	(revision 58555)
+++ win32ss/user/ntuser/painting.c	(working copy)
@@ -97,13 +97,12 @@
 VOID FASTCALL
 IntSendSyncPaint(PWND Wnd, ULONG Flags)
 {
-   PTHREADINFO ptiCur;
-   PUSER_MESSAGE_QUEUE MessageQueue;
+   PTHREADINFO ptiCur, ptiWnd;
    PUSER_SENT_MESSAGE Message;
    PLIST_ENTRY Entry;
    BOOL bSend = TRUE;
 
-   MessageQueue = Wnd->head.pti->MessageQueue;
+   ptiWnd = Wnd->head.pti;
    ptiCur = PsGetCurrentThreadWin32Thread();
    /*
       Not the current thread, Wnd is in send Nonclient paint also in send erase background and it is visiable.
@@ -115,10 +114,10 @@
    {
       // For testing, if you see this, break out the Champagne and have a party!
       ERR("SendSyncPaint Wnd in State!\n");
-      if (!IsListEmpty(&MessageQueue->SentMessagesListHead))
+      if (!IsListEmpty(&ptiWnd->SentMessagesListHead))
       {
          // Scan sent queue messages to see if we received sync paint messages.
-         Entry = MessageQueue->SentMessagesListHead.Flink;
+         Entry = ptiWnd->SentMessagesListHead.Flink;
          Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
          do
          {
@@ -133,7 +132,7 @@
             Entry = Message->ListEntry.Flink;
             Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
          }
-         while (Entry != &MessageQueue->SentMessagesListHead);
+         while (Entry != &ptiWnd->SentMessagesListHead);
       }
       if (bSend)
       {
@@ -270,7 +269,7 @@
             Window->state &= ~WNDS_UPDATEDIRTY;
             Window->hrgnUpdate = NULL;
             if (!(Window->state & WNDS_INTERNALPAINT))
-               MsqDecPaintCountQueue(Window->head.pti->MessageQueue);
+               MsqDecPaintCountQueue(Window->head.pti);
          }
       }
 
@@ -557,9 +556,9 @@
    if (HadPaintMessage != IntIsWindowDirty(Wnd))
    {
       if (HadPaintMessage)
-         MsqDecPaintCountQueue(Wnd->head.pti->MessageQueue);
+         MsqDecPaintCountQueue(Wnd->head.pti);
       else
-         MsqIncPaintCountQueue(Wnd->head.pti->MessageQueue);
+         MsqIncPaintCountQueue(Wnd->head.pti);
    }
    TRACE("IntInvalidateWindows exit\n");
 }
@@ -781,7 +780,7 @@
    {
       PaintWnd->state &= ~WNDS_INTERNALPAINT;
       if (!PaintWnd->hrgnUpdate)
-         MsqDecPaintCountQueue(Thread->MessageQueue);
+         MsqDecPaintCountQueue(Thread);
    }
    PaintWnd->state2 &= ~WNDS2_WMPAINTSENT;
    PaintWnd->state &= ~WNDS_UPDATEDIRTY;
@@ -955,7 +954,7 @@
 
    if (Window->hrgnUpdate != NULL)
    {
-      MsqDecPaintCountQueue(Window->head.pti->MessageQueue);
+      MsqDecPaintCountQueue(Window->head.pti);
       GdiGetClipBox(Ps->hdc, &Ps->rcPaint);
       IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
       /* The region is part of the dc now and belongs to the process! */
@@ -964,7 +963,7 @@
    else
    {
       if (Window->state & WNDS_INTERNALPAINT)
-         MsqDecPaintCountQueue(Window->head.pti->MessageQueue);
+         MsqDecPaintCountQueue(Window->head.pti);
 
       IntGetClientRect(Window, &Ps->rcPaint);
    }
Index: win32ss/user/ntuser/userfuncs.h
===================================================================
--- win32ss/user/ntuser/userfuncs.h	(revision 58555)
+++ win32ss/user/ntuser/userfuncs.h	(working copy)
@@ -83,6 +83,7 @@
 
 VOID FASTCALL IntSetWindowState(PWND, UINT);
 VOID FASTCALL IntClearWindowState(PWND, UINT);
+PTHREADINFO FASTCALL IntTID2PTI(HANDLE);
 
 /*************** MESSAGE.C ***************/
 
Index: win32ss/user/ntuser/message.c
===================================================================
--- win32ss/user/ntuser/message.c	(revision 58555)
+++ win32ss/user/ntuser/message.c	(working copy)
@@ -502,21 +502,15 @@
 IdlePing(VOID)
 {
    PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
-   PUSER_MESSAGE_QUEUE ForegroundQueue;
-   PTHREADINFO pti, ptiForeground = NULL;
+   PTHREADINFO pti;
 
-   ForegroundQueue = IntGetFocusMessageQueue();
-
-   if (ForegroundQueue)
-      ptiForeground = ForegroundQueue->Thread->Tcb.Win32Thread;
-
    pti = PsGetCurrentThreadWin32Thread();
 
    if ( pti )
    {
       pti->pClientInfo->cSpins = 0; // Reset spins.
 
-      if ( pti->pDeskInfo && pti == ptiForeground )
+      if ( pti->pDeskInfo && pti == gptiForeground )
       {
          if ( pti->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) ||
               pti->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) )
@@ -602,13 +596,14 @@
 {
     LRESULT lRes;
     USER_REFERENCE_ENTRY Ref;
+//    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
 
     if (!pWnd ||
          pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
          pWnd == UserGetMessageWindow() )  // pWnd->fnid == FNID_MESSAGEWND
        return 0;
 
-    TRACE("Internal Event Msg %p hWnd 0x%x\n",msg,pWnd->head.h);
+    ERR("Internal Event Msg %p hWnd 0x%x\n",msg,pWnd->head.h);
 
     switch(msg)
     {
@@ -632,7 +627,7 @@
        {
           PWND Window = (PWND)wparam;
           if (wparam) UserRefObjectCo(Window, &Ref);
-          lRes = (LRESULT)co_IntSetActiveWindow(Window,NULL,(BOOL)lparam,TRUE,TRUE);
+          lRes = (LRESULT)co_IntSetActiveWindow(Window,(BOOL)lparam,TRUE,TRUE);
           if (wparam) UserDerefObjectCo(Window);
           return lRes;
        }
@@ -751,6 +746,14 @@
 
 /*
  * Internal version of PeekMessage() doing all the work
+ *
+ * MSDN:
+ *   Sent messages
+ *   Posted messages
+ *   Input (hardware) messages and system internal events
+ *   Sent messages (again)
+ *   WM_PAINT messages
+ *   WM_TIMER messages
  */
 BOOL FASTCALL
 co_IntPeekMessage( PMSG Msg,
@@ -762,22 +765,15 @@
 {
     PTHREADINFO pti;
     LARGE_INTEGER LargeTickCount;
-    PUSER_MESSAGE_QUEUE ThreadQueue;
     BOOL RemoveMessages;
     UINT ProcessMask;
     BOOL Hit = FALSE;
 
     pti = PsGetCurrentThreadWin32Thread();
-    ThreadQueue = pti->MessageQueue;
 
     RemoveMessages = RemoveMsg & PM_REMOVE;
     ProcessMask = HIWORD(RemoveMsg);
 
-    if (ThreadQueue->ptiSysLock && ThreadQueue->ptiSysLock != pti)
-    {
-       ERR("PeekMessage: Thread Q 0x%p is locked 0x%p to another pti 0x%p!\n", ThreadQueue, ThreadQueue->ptiSysLock, pti );
-    }
-
  /* 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);
@@ -787,11 +783,11 @@
     do
     {
         KeQueryTickCount(&LargeTickCount);
-        ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
+        pti->timeLast = LargeTickCount.u.LowPart;
         pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart;
 
         /* Dispatch sent messages here. */
-        while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
+        while ( co_MsqDispatchOneSentMessage(pti) )
         {
            /* 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;
@@ -816,7 +812,7 @@
         /* Now check for normal messages. */
         if (( (ProcessMask & QS_POSTMESSAGE) ||
               (ProcessMask & QS_HOTKEY) ) &&
-            MsqPeekMessage( ThreadQueue,
+            MsqPeekMessage( pti,
                             RemoveMessages,
                             Window,
                             MsgFilterMin,
@@ -828,18 +824,18 @@
         }
 
         /* Now look for a quit message. */
-        if (ThreadQueue->QuitPosted)
+        if (pti->QuitPosted)
         {
             /* 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->wParam = pti->exitCode;
             Msg->lParam = 0;
             if (RemoveMessages)
             {
-                ThreadQueue->QuitPosted = FALSE;
-                ClearMsgBitsMask(ThreadQueue, QS_POSTMESSAGE);
+                pti->QuitPosted = FALSE;
+                ClearMsgBitsMask(pti, QS_POSTMESSAGE);
                 pti->pcti->fsWakeBits &= ~QS_ALLPOSTMESSAGE;
                 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
             }
@@ -848,7 +844,7 @@
 
         /* Check for hardware events. */
         if ((ProcessMask & QS_MOUSE) &&
-            co_MsqPeekMouseMove( ThreadQueue,
+            co_MsqPeekMouseMove( pti,
                                  RemoveMessages,
                                  Window,
                                  MsgFilterMin,
@@ -859,7 +855,7 @@
         }
 
         if ((ProcessMask & QS_INPUT) &&
-            co_MsqPeekHardwareMessage( ThreadQueue,
+            co_MsqPeekHardwareMessage( pti,
                                        RemoveMessages,
                                        Window,
                                        MsgFilterMin,
@@ -871,7 +867,7 @@
         }
 
         /* Check for sent messages again. */
-        while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
+        while ( co_MsqDispatchOneSentMessage(pti) )
         {
            if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE;
         }
@@ -912,12 +908,10 @@
                    UINT MsgFilterMax )
 {
     PTHREADINFO pti;
-    PUSER_MESSAGE_QUEUE ThreadQueue;
     NTSTATUS Status = STATUS_SUCCESS;
     MSG Msg;
 
     pti = PsGetCurrentThreadWin32Thread();
-    ThreadQueue = pti->MessageQueue;
 
     do
     {
@@ -932,7 +926,7 @@
         }
 
         /* Nothing found. Wait for new messages. */
-        Status = co_MsqWaitForNewMessages( ThreadQueue,
+        Status = co_MsqWaitForNewMessages( pti,
                                            Window,
                                            MsgFilterMin,
                                            MsgFilterMax);
@@ -1027,7 +1021,7 @@
 
         if ( bGMSG )
         {
-            Status = co_MsqWaitForNewMessages( pti->MessageQueue,
+            Status = co_MsqWaitForNewMessages( pti,
                                                Window,
                                                MsgFilterMin,
                                                MsgFilterMax);
@@ -1105,7 +1099,7 @@
 
         KeQueryTickCount(&LargeTickCount);
         Message.time = MsqCalculateMessageTime(&LargeTickCount);
-        MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE, 0);
+        MsqPostMessage(pThread, &Message, FALSE, QS_POSTMESSAGE, 0);
         ObDereferenceObject( peThread );
         return TRUE;
     }
@@ -1224,11 +1218,11 @@
 
         if (WM_QUIT == Msg)
         {
-            MsqPostQuitMessage(Window->head.pti->MessageQueue, wParam);
+            MsqPostQuitMessage(Window->head.pti, wParam);
         }
         else
         {
-            MsqPostMessage(Window->head.pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE, 0);
+            MsqPostMessage(Window->head.pti, &Message, FALSE, QS_POSTMESSAGE, 0);
         }
     }
     return TRUE;
@@ -1365,7 +1359,7 @@
         RETURN( TRUE);
     }
 
-    if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->head.pti->MessageQueue))
+    if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->head.pti))
     {
         // FIXME: Set window hung and add to a list.
         /* FIXME: Set a LastError? */
@@ -1381,7 +1375,7 @@
 
     do
     {
-        Status = co_MsqSendMessage( Window->head.pti->MessageQueue,
+        Status = co_MsqSendMessage( Window->head.pti,
                                     hWnd,
                                     Msg,
                                     wParam,
@@ -1393,7 +1387,7 @@
     }
     while ((STATUS_TIMEOUT == Status) &&
            (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
-           !MsqIsHung(Window->head.pti->MessageQueue)); // FIXME: Set window hung and add to a list.
+           !MsqIsHung(Window->head.pti)); // FIXME: Set window hung and add to a list.
 
     if (STATUS_TIMEOUT == Status)
     {
@@ -1646,11 +1640,11 @@
         RETURN( FALSE);
     }
 
-    IntReferenceMessageQueue(Window->head.pti->MessageQueue);
+    IntReferenceThreadInfo(Window->head.pti);
     /* 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);
+       IntReferenceThreadInfo(Win32Thread);
 
     Message->Msg.hwnd = hWnd;
     Message->Msg.message = Msg;
@@ -1660,8 +1654,9 @@
     Message->Result = 0;
     Message->lResult = 0;
     Message->QS_Flags = 0;
-    Message->SenderQueue = NULL; // mjmartin, you are right! This is null.
-    Message->CallBackSenderQueue = Win32Thread->MessageQueue;
+    Message->ptiReceiver = Window->head.pti;
+    Message->ptiSender = NULL; // mjmartin, you are right! This is null.
+    Message->ptiCallBackSender = Win32Thread;
     Message->DispatchingListEntry.Flink = NULL;
     Message->CompletionCallback = CompletionCallback;
     Message->CompletionCallbackContext = CompletionCallbackContext;
@@ -1669,9 +1664,12 @@
     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);
+    if (Msg & 0x80000000) // Higher priority event message!
+       InsertHeadList(&Window->head.pti->SentMessagesListHead, &Message->ListEntry);
+    else
+       InsertTailList(&Window->head.pti->SentMessagesListHead, &Message->ListEntry);
+    MsqWakeQueue(Window->head.pti, QS_SENDMESSAGE, TRUE);
+    IntDereferenceThreadInfo(Window->head.pti);
 
     RETURN(TRUE);
 
@@ -2812,7 +2810,7 @@
 
     Handles[0] = Process;
     Handles[1] = W32Process->InputIdleEvent;
-    Handles[2] = pti->MessageQueue->NewMessages; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
+    Handles[2] = pti->pEventQueueServer; // IntMsqSetWakeMask returns hEventQueueClient
 
     if (!Handles[1])
     {
Index: win32ss/user/ntuser/simplecall.c
===================================================================
--- win32ss/user/ntuser/simplecall.c	(revision 58555)
+++ win32ss/user/ntuser/simplecall.c	(working copy)
@@ -168,7 +168,7 @@
           {
                 PTHREADINFO pti;
                 pti = PsGetCurrentThreadWin32Thread();
-                MsqPostQuitMessage(pti->MessageQueue, Param);
+                MsqPostQuitMessage(pti, Param);
                 RETURN(TRUE);
           }
 
@@ -431,10 +431,12 @@
 
       case TWOPARAM_ROUTINE_SETGUITHRDHANDLE:
          {
-            PUSER_MESSAGE_QUEUE MsgQueue = ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->MessageQueue;
+            PTHREADINFO pti;
+            pti = (PTHREADINFO)PsGetCurrentThreadWin32Thread();
+            PUSER_MESSAGE_QUEUE MsgQueue = pti->MessageQueue;
 
             ASSERT(MsgQueue);
-            RETURN( (DWORD_PTR)MsqSetStateWindow(MsgQueue, (ULONG)Param1, (HWND)Param2));
+            RETURN( (DWORD_PTR)MsqSetStateWindow(pti, (ULONG)Param1, (HWND)Param2));
          }
 
       case TWOPARAM_ROUTINE_ENABLEWINDOW:
@@ -572,9 +574,9 @@
          break;
 
       case HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOW:
-         TRACE("co_IntSetForegroundWindow 1 %p\n",hWnd);
+         TRACE("co_IntSetForegroundWindow 1 0x%p\n",hWnd);
          Ret = co_IntSetForegroundWindow(Window);
-         TRACE("co_IntSetForegroundWindow 2 \n");
+         TRACE("co_IntSetForegroundWindow 2 0x%p\n",hWnd);
          break;
 
       case HWNDLOCK_ROUTINE_UPDATEWINDOW:
Index: win32ss/user/ntuser/ntstubs.c
===================================================================
--- win32ss/user/ntuser/ntstubs.c	(revision 58555)
+++ win32ss/user/ntuser/ntstubs.c	(working copy)
@@ -29,31 +29,22 @@
     IN BOOL fAttach)
 {
   NTSTATUS Status;
-  PETHREAD Thread, ThreadTo;
   PTHREADINFO pti, ptiTo;
   BOOL Ret = FALSE;
 
   UserEnterExclusive();
   ERR("Enter NtUserAttachThreadInput %s\n",(fAttach ? "TRUE" : "FALSE" ));
-  Status = PsLookupThreadByThreadId((HANDLE)idAttach, &Thread);
-  if (!NT_SUCCESS(Status))
+
+  pti = IntTID2PTI((HANDLE)idAttach);
+  ptiTo = IntTID2PTI((HANDLE)idAttachTo);
+
+  if ( !pti || !ptiTo )
   {
+     ERR("AttachThreadInput pti or ptiTo NULL.\n");
      EngSetLastError(ERROR_INVALID_PARAMETER);
      goto Exit;
   }
-  Status = PsLookupThreadByThreadId((HANDLE)idAttachTo, &ThreadTo);
-  if (!NT_SUCCESS(Status))
-  {
-     EngSetLastError(ERROR_INVALID_PARAMETER);
-     ObDereferenceObject(Thread);
-     goto Exit;
-  }
 
-  pti = PsGetThreadWin32Thread(Thread);
-  ptiTo = PsGetThreadWin32Thread(ThreadTo);
-  ObDereferenceObject(Thread);
-  ObDereferenceObject(ThreadTo);
-
   Status = UserAttachThreadInput( pti, ptiTo, fAttach);
   if (!NT_SUCCESS(Status))
   {
Index: win32ss/user/ntuser/event.c
===================================================================
--- win32ss/user/ntuser/event.c	(revision 58555)
+++ win32ss/user/ntuser/event.c	(working copy)
@@ -113,7 +113,7 @@
 
    /* FIXME: Should get timeout from
     * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
-   Status = co_MsqSendMessage( pEH->head.pti->MessageQueue,
+   Status = co_MsqSendMessage( pEH->head.pti,
                                hwnd,
                                event,
                                0,
Index: win32ss/user/ntuser/object.c
===================================================================
--- win32ss/user/ntuser/object.c	(revision 58555)
+++ win32ss/user/ntuser/object.c	(working copy)
@@ -475,7 +475,7 @@
   if (!(entry = handle_to_entry( gHandleTable, h )))
   {
      SetLastNtError( STATUS_INVALID_HANDLE );
-     return FALSE;
+     return TRUE;
   }
   return (entry->flags & HANDLEENTRY_INDESTROY);
 }
Index: win32ss/user/ntuser/input.c
===================================================================
--- win32ss/user/ntuser/input.c	(revision 58555)
+++ win32ss/user/ntuser/input.c	(working copy)
@@ -13,8 +13,6 @@
 /* GLOBALS *******************************************************************/
 
 PTHREADINFO ptiRawInput;
-PTHREADINFO ptiKeyboard;
-PTHREADINFO ptiMouse;
 PKTIMER MasterTimer = NULL;
 PATTACHINFO gpai = NULL;
 INT paiCount = 0;
@@ -396,24 +394,47 @@
     return ret;
 }
 
-PTHREADINFO FASTCALL
-IsThreadAttach(PTHREADINFO ptiTo)
+BOOL
+FASTCALL
+IsRemoveAttachThread(PTHREADINFO pti)
 {
+    NTSTATUS Status;
     PATTACHINFO pai;
+    BOOL Ret = TRUE;
+    PTHREADINFO ptiFrom = NULL, ptiTo = NULL;
 
-    if (!gpai) return NULL;
-
-    pai = gpai;
     do
     {
-        if (pai->pti2 == ptiTo) break;
-        pai = pai->paiNext;
-    } while (pai);
+       if (!gpai) return TRUE;
+ 
+       pai = gpai; // Bottom of the list.
 
-    if (!pai) return NULL;
+       do
+       {
+          if (pai->pti2 == pti)
+          {
+             ptiFrom = pai->pti1;
+             ptiTo = pti;
+             break;
+          }
+          if (pai->pti1 == pti)
+          {
+             ptiFrom = pti;
+             ptiTo = pai->pti2;
+             break;
+          }
+          pai = pai->paiNext;
+        
+       } while (pai);
 
-    // Return ptiFrom.
-    return pai->pti1;
+       if (!pai && !ptiFrom && !ptiTo) break;
+
+       Status = UserAttachThreadInput(ptiFrom, ptiTo, FALSE);
+       if (!NT_SUCCESS(Status)) Ret = FALSE;
+
+    } while (Ret);
+
+    return Ret;
 }
 
 NTSTATUS FASTCALL
@@ -448,44 +469,50 @@
         paiCount++;
         ERR("Attach Allocated! ptiFrom 0x%p  ptiTo 0x%p paiCount %d\n",ptiFrom,ptiTo,paiCount);
 
-        if (ptiTo->MessageQueue == ptiFrom->MessageQueue)
+        if (ptiTo->MessageQueue != ptiFrom->MessageQueue)
         {
-           ERR("Attach Threads are already associated!\n");
-        }
 
-        ptiTo->MessageQueue->iCursorLevel -= ptiFrom->iCursorLevel;
+           ptiTo->MessageQueue->iCursorLevel -= ptiFrom->iCursorLevel;
 
-        /* Keep the original queue in pqAttach (ie do not trash it in a second attachment) */
-        if (ptiFrom->pqAttach == NULL)
-           ptiFrom->pqAttach = ptiFrom->MessageQueue;
-        ptiFrom->MessageQueue = ptiTo->MessageQueue;
+           // FIXME: conditions?
+           if (ptiFrom->MessageQueue == gpqForeground)
+           {
+              ERR("ptiFrom is Foreground\n");
+              ptiTo->MessageQueue->spwndActive  = ptiFrom->MessageQueue->spwndActive;
+              ptiTo->MessageQueue->spwndFocus   = ptiFrom->MessageQueue->spwndFocus;
+              ptiTo->MessageQueue->CursorObject = ptiFrom->MessageQueue->CursorObject;
+              ptiTo->MessageQueue->spwndCapture = ptiFrom->MessageQueue->spwndCapture;
+              ptiTo->MessageQueue->QF_flags    ^= ((ptiTo->MessageQueue->QF_flags ^ ptiFrom->MessageQueue->QF_flags) & QF_CAPTURELOCKED);
+              ptiTo->MessageQueue->CaretInfo    = ptiFrom->MessageQueue->CaretInfo;
+              IntSetFocusMessageQueue(NULL);
+              IntSetFocusMessageQueue(ptiTo->MessageQueue);
+           }
+           else
+           {
+              ERR("ptiFrom NOT Foreground\n");
+           }
 
-        ptiFrom->MessageQueue->cThreads++;
-        ERR("ptiTo S Share count %d\n", ptiFrom->MessageQueue->cThreads);
+           if (ptiTo->MessageQueue == gpqForeground)
+           {
+              ERR("ptiTo is Foreground\n");
+           }
+           else
+           {
+              ERR("ptiTo NOT Foreground\n");
+           }
+           MsqDestroyMessageQueue(ptiFrom);
 
-        // FIXME: conditions?
-        if (ptiFrom->pqAttach == gpqForeground)
-        {
-           ERR("ptiFrom is Foreground\n");
-        ptiFrom->MessageQueue->spwndActive = ptiFrom->pqAttach->spwndActive;
-        ptiFrom->MessageQueue->spwndFocus = ptiFrom->pqAttach->spwndFocus;
-        ptiFrom->MessageQueue->CursorObject = ptiFrom->pqAttach->CursorObject;
-        ptiFrom->MessageQueue->spwndCapture = ptiFrom->pqAttach->spwndCapture;
-        ptiFrom->MessageQueue->QF_flags ^= ((ptiFrom->MessageQueue->QF_flags ^ ptiFrom->pqAttach->QF_flags) & QF_CAPTURELOCKED);
-        ptiFrom->MessageQueue->CaretInfo = ptiFrom->pqAttach->CaretInfo;
+           ptiFrom->MessageQueue = ptiTo->MessageQueue;
+
+           ptiFrom->MessageQueue->cThreads++;
+           ERR("ptiTo S Share count %d\n", ptiFrom->MessageQueue->cThreads);
+
+           IntReferenceMessageQueue(ptiTo->MessageQueue);
         }
         else
         {
-           ERR("ptiFrom NOT Foreground\n");
+           ERR("Attach Threads are already associated!\n");
         }
-        if (ptiTo->MessageQueue == gpqForeground)
-        {
-           ERR("ptiTo is Foreground\n");
-        }
-        else
-        {
-           ERR("ptiTo NOT Foreground\n");
-        }
     }
     else /* If clear, unlink and free it. */
     {
@@ -512,41 +539,25 @@
         }
 
         if (!Hit) return STATUS_INVALID_PARAMETER;
-
-        ASSERT(ptiFrom->pqAttach);
  
         ERR("Attach Free! ptiFrom 0x%p  ptiTo 0x%p paiCount %d\n",ptiFrom,ptiTo,paiCount);
+ 
+        if (ptiTo->MessageQueue == ptiFrom->MessageQueue)
+        {
+           ptiTo->MessageQueue->cThreads--;
+           ERR("ptiTo E Share count %d\n", ptiTo->MessageQueue->cThreads);
+           ASSERT(ptiTo->MessageQueue->cThreads >= 1);
 
-        /* Search list and check if the thread is attached one more time */
-        pai = gpai;
-        while(pai)
+           IntDereferenceMessageQueue(ptiTo->MessageQueue);
+
+           ptiFrom->MessageQueue = MsqCreateMessageQueue(ptiFrom);
+
+           ptiTo->MessageQueue->iCursorLevel -= ptiFrom->iCursorLevel;
+        }
+        else
         {
-            /* If the thread is attached again , we are done */
-            if (pai->pti1 == ptiFrom) 
-            {
-                ptiFrom->MessageQueue->cThreads--;
-                ERR("ptiTo L Share count %d\n", ptiFrom->MessageQueue->cThreads);
-                /* Use the message queue of the last attachment */
-                ptiFrom->MessageQueue = pai->pti2->MessageQueue;
-                ptiFrom->MessageQueue->CursorObject = NULL;
-                ptiFrom->MessageQueue->spwndActive = NULL;
-                ptiFrom->MessageQueue->spwndFocus = NULL;
-                ptiFrom->MessageQueue->spwndCapture = NULL;
-                return STATUS_SUCCESS;
-            }
-            pai = pai->paiNext;
+           ERR("Detaching Threads are not associated!\n");
         }
-
-        ptiFrom->MessageQueue->cThreads--;
-        ERR("ptiTo E Share count %d\n", ptiFrom->MessageQueue->cThreads);
-        ptiFrom->MessageQueue = ptiFrom->pqAttach;
-        // FIXME: conditions?
-        ptiFrom->MessageQueue->CursorObject = NULL;
-        ptiFrom->MessageQueue->spwndActive = NULL;
-        ptiFrom->MessageQueue->spwndFocus = NULL;
-        ptiFrom->MessageQueue->spwndCapture = NULL;
-        ptiFrom->pqAttach = NULL;
-        ptiTo->MessageQueue->iCursorLevel -= ptiFrom->iCursorLevel;
     }
     /* Note that key state, which can be ascertained by calls to the GetKeyState
        or GetKeyboardState function, is reset after a call to AttachThreadInput.
Index: win32ss/user/ntuser/hook.c
===================================================================
--- win32ss/user/ntuser/hook.c	(revision 58555)
+++ win32ss/user/ntuser/hook.c	(working copy)
@@ -295,7 +295,7 @@
 
     /* FIXME: Should get timeout from
      * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
-    Status = co_MsqSendMessage( pti->MessageQueue,
+    Status = co_MsqSendMessage( pti,
                                 IntToPtr(Code), // hWnd
                                 Hook->HookId,   // Msg
                                 wParam,
@@ -1456,7 +1456,6 @@
     UNICODE_STRING ModuleName;
     NTSTATUS Status;
     HHOOK Handle;
-    PETHREAD Thread = NULL;
     PTHREADINFO pti, ptiHook = NULL;
     DECLARE_RETURN(HHOOK);
 
@@ -1491,15 +1490,13 @@
            RETURN( NULL);
        }
 
-       if (!NT_SUCCESS(PsLookupThreadByThreadId((HANDLE)(DWORD_PTR) ThreadId, &Thread)))
+       if ( !(ptiHook = IntTID2PTI( (HANDLE)ThreadId )))
        {
           ERR("Invalid thread id 0x%x\n", ThreadId);
           EngSetLastError(ERROR_INVALID_PARAMETER);
           RETURN( NULL);
        }
 
-       ptiHook = Thread->Tcb.Win32Thread;
-
        if ( ptiHook->rpdesk != pti->rpdesk) // gptiCurrent->rpdesk)
        {
           ERR("Local hook wrong desktop HookId: %d\n",HookId);
@@ -1507,7 +1504,7 @@
           RETURN( NULL);
        }
 
-       if (Thread->ThreadsProcess != PsGetCurrentProcess())
+       if (ptiHook->ppi != pti->ppi)
        {
           if ( !Mod &&
               (HookId == WH_GETMESSAGE ||
@@ -1685,7 +1682,6 @@
 
 CLEANUP:
     TRACE("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_);
-    if (Thread) ObDereferenceObject(Thread);
     UserLeave();
     END_CLEANUP;
 }
Index: win32ss/user/ntuser/input.h
===================================================================
--- win32ss/user/ntuser/input.h	(revision 58555)
+++ win32ss/user/ntuser/input.h	(working copy)
@@ -63,7 +63,7 @@
 BOOL FASTCALL IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt);
 DWORD NTAPI CreateSystemThreads(UINT Type);
 NTSTATUS FASTCALL UserAttachThreadInput(PTHREADINFO,PTHREADINFO,BOOL);
-PTHREADINFO FASTCALL IsThreadAttach(PTHREADINFO);
+BOOL FASTCALL IsRemoveAttachThread(PTHREADINFO);
 VOID FASTCALL DoTheScreenSaver(VOID);
 #define ThreadHasInputAccess(W32Thread) (TRUE)
 
Index: win32ss/user/ntuser/window.c
===================================================================
--- win32ss/user/ntuser/window.c	(revision 58555)
+++ win32ss/user/ntuser/window.c	(working copy)
@@ -123,7 +123,12 @@
     styleNew = (pwnd->style | set_bits) & ~clear_bits;
     if (styleNew == styleOld) return styleNew;
     pwnd->style = styleNew;
-    if ((styleOld ^ styleNew) & WS_VISIBLE) DceResetActiveDCEs( pwnd );
+    if ((styleOld ^ styleNew) & WS_VISIBLE) // State Change.
+    {
+       if (styleOld & WS_VISIBLE) pwnd->head.pti->cVisWindows--; 
+       if (styleNew & WS_VISIBLE) pwnd->head.pti->cVisWindows++;
+       DceResetActiveDCEs( pwnd );
+    }
     return styleOld;
 }
 
@@ -159,21 +164,16 @@
 BOOL FASTCALL
 IntIsWindowVisible(PWND Wnd)
 {
-   BOOL Ret = TRUE;
-   do
+   PWND Temp = Wnd;
+   for (;;)
    {
-      if (!(Wnd->style & WS_VISIBLE))
-      {
-         Ret = FALSE;
-         break;
-      }
-      if (Wnd->spwndParent != NULL)
-         Wnd = Wnd->spwndParent;
-      else
-         break;
+      if (!Temp) return TRUE;
+      if (!(Temp->style & WS_VISIBLE)) break;
+      if (Temp->style & WS_MINIMIZE && Temp != Wnd) break;
+      if (Temp->fnid == FNID_DESKTOP) return TRUE;
+      Temp = Temp->spwndParent;
    }
-   while (Wnd != NULL);
-   return Ret;
+   return FALSE;
 }
 
 PWND FASTCALL
@@ -436,6 +436,7 @@
    }
    Window->state2 |= WNDS2_INDESTROY;
    Window->style &= ~WS_VISIBLE;
+   Window->head.pti->cVisWindows--;
 
    IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
 
@@ -497,8 +498,7 @@
    /* flush the message queue */
    MsqRemoveWindowMessagesFromQueue(Window);
 
-   NT_ASSERT(Window->head.pti);
-   IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
+   IntDereferenceThreadInfo(Window->head.pti);
 
    /* from now on no messages can be sent to this window anymore */
    Window->state |= WNDS_DESTROYED;
@@ -571,6 +571,7 @@
       GreDeleteObject(Window->hrgnClip);
       Window->hrgnClip = NULL;
    }
+   Window->head.pti->cWindows--;
 
 //   ASSERT(Window != NULL);
    UserFreeWindowInfo(Window->head.pti, Window);
@@ -1092,7 +1093,7 @@
               WndOldOwner->head.pti != WndNewOwner->head.pti )
          {
             ERR("ProcessOwnerSwap Old out.\n");
-            //UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
+            UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
          }
       }
    }
@@ -1104,7 +1105,7 @@
               WndOldOwner->head.pti != WndNewOwner->head.pti )
          {
             ERR("ProcessOwnerSwap New in.\n");
-            //UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
+            UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
          }
       }
    }
@@ -1133,6 +1134,8 @@
       goto Error;
    }
 
+   /* if parent belongs to a different thread and the window isn't */
+   /* top-level, attach the two threads */
    IntProcessOwnerSwap(Wnd, WndNewOwner, WndOldOwner);
 
    if (IntValidateOwnerDepth(Wnd, WndNewOwner))
@@ -1179,6 +1182,7 @@
    /* Some applications try to set a child as a parent */
    if (IntIsChildWindow(Wnd, WndNewParent))
    {
+      ERR("IntSetParent try to set a child as a parent.\n");
       EngSetLastError( ERROR_INVALID_PARAMETER );
       return NULL;
    }
@@ -1189,6 +1193,7 @@
    {
       if (Wnd == pWndExam)
       {
+         ERR("IntSetParent Failed Test for set parent to parent!\n");
          EngSetLastError(ERROR_INVALID_PARAMETER);
          return NULL;
       }
@@ -1203,7 +1208,10 @@
 
    /* Window must belong to current process */
    if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
+   {
+      ERR("IntSetParent Window must belong to current process!\n");
       return NULL;
+   }
 
    WndOldParent = Wnd->spwndParent;
 
@@ -1240,6 +1248,15 @@
 
    }
 
+   if ( WndNewParent == co_GetDesktopWindow(Wnd) &&
+       !(Wnd->style & WS_CLIPSIBLINGS) )
+   {
+      Wnd->style |= WS_CLIPSIBLINGS;
+      DceResetActiveDCEs(Wnd);
+   }
+
+   /* if parent belongs to a different thread and the window isn't */
+   /* top-level, attach the two threads */
    if ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
    {
       if ( Wnd->spwndParent != co_GetDesktopWindow(Wnd))
@@ -1247,7 +1264,7 @@
          if (Wnd->head.pti != WndOldParent->head.pti)
          {
             ERR("SetParent Old out.\n");
-            //UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
+            UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
          }
       }
       if ( WndNewParent != co_GetDesktopWindow(Wnd))
@@ -1255,7 +1272,7 @@
          if (Wnd->head.pti != WndNewParent->head.pti)
          {
             ERR("SetParent New in.\n");
-            //UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
+            UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
          }
       }
    }
@@ -1269,10 +1286,11 @@
     * in the z-order and send the expected WM_WINDOWPOSCHANGING and
     * WM_WINDOWPOSCHANGED notification messages.
     */
+   ERR("IntSetParent SetWindowPos 1\n");
    co_WinPosSetWindowPos( Wnd,
                          (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
                           pt.x, pt.y, 0, 0, swFlags);
-
+   ERR("IntSetParent SetWindowPos 2\n");
    if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
 
    return WndOldParent;
@@ -1293,6 +1311,7 @@
 
    if (hWndChild == IntGetDesktopWindow())
    {
+      ERR("UserSetParent Access Denied!\n");
       EngSetLastError(ERROR_ACCESS_DENIED);
       return( NULL);
    }
@@ -1301,6 +1320,7 @@
    {
       if (!(WndParent = UserGetWindowObject(hWndNewParent)))
       {
+         ERR("UserSetParent Bad New Parent!\n");
          return( NULL);
       }
    }
@@ -1314,6 +1334,7 @@
 
    if (!(Wnd = UserGetWindowObject(hWndChild)))
    {
+      ERR("UserSetParent Bad Child!\n");
       return( NULL);
    }
 
@@ -1753,13 +1774,15 @@
    pWnd->InternalPos.MaxPos.x  = pWnd->InternalPos.MaxPos.y  = -1;
    pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
 
-   IntReferenceMessageQueue(pWnd->head.pti->MessageQueue);
+   IntReferenceThreadInfo(pWnd->head.pti);
    if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
    {
        pWnd->HideFocus = pWnd->spwndParent->HideFocus;
        pWnd->HideAccel = pWnd->spwndParent->HideAccel;
    }
 
+   pWnd->head.pti->cWindows++;
+
    if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
       pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
 
@@ -1945,7 +1968,7 @@
             pti != pWnd->spwndOwner->head.pti)
        {
           ERR("CreateWindow Owner in.\n");
-          //UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
+          UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
        }
    }
 
@@ -2185,6 +2208,15 @@
    Cs->lpszName = (LPCWSTR) WindowName;
    Cs->lpszClass = (LPCWSTR) ClassName;
 
+   if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
+   {
+      if (ParentWindow != co_GetDesktopWindow(Window))
+      {
+         Cs->x += ParentWindow->rcClient.left;
+         Cs->y += ParentWindow->rcClient.top; 
+      }
+   }
+
    /* Send the WM_GETMINMAXINFO message */
    Size.cx = Cs->cx;
    Size.cy = Cs->cy;
@@ -2202,6 +2234,7 @@
    Window->rcWindow.top = Cs->y;
    Window->rcWindow.right = Cs->x + Size.cx;
    Window->rcWindow.bottom = Cs->y + Size.cy;
+/*
    if (0 != (Window->style & WS_CHILD) && ParentWindow)
    {
 //      ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
@@ -2209,6 +2242,7 @@
                         ParentWindow->rcClient.left,
                         ParentWindow->rcClient.top);
    }
+*/
    Window->rcClient = Window->rcWindow;
 
    /* Link the window */
@@ -2228,7 +2262,7 @@
          if (pti != Window->spwndParent->head.pti)
          {
             ERR("CreateWindow Parent in.\n");
-            //UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
+            UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
          }
       }
    }
@@ -2242,15 +2276,20 @@
    }
 
    /* Send the WM_NCCALCSIZE message */
+   {
+  // RECT rc;
    MaxPos.x = Window->rcWindow.left;
    MaxPos.y = Window->rcWindow.top;
 
    Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
+   //rc = Window->rcWindow;
+   //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
+   //Window->rcClient = rc;
 
    RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
                                      MaxPos.y - Window->rcWindow.top);
+   }
 
-
    /* Send the WM_CREATE message. */
    Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
    if (Result == (LRESULT)-1)
@@ -2569,7 +2608,7 @@
          if (Window->spwndOwner)
          {
             ERR("DestroyWindow Owner out.\n");
-            //UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
+            UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
          }
       }
    }
@@ -2608,7 +2647,7 @@
          if (!IntIsTopLevelWindow(Window))
          {
             ERR("DestroyWindow Parent out.\n");
-            //UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
+            UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
          }
       }
    }
@@ -3211,7 +3250,7 @@
 {
    DECLARE_RETURN(HWND);
 
-   TRACE("Enter NtUserSetParent\n");
+   ERR("Enter NtUserSetParent\n");
    UserEnterExclusive();
 
    /*
@@ -3229,7 +3268,7 @@
    RETURN( co_UserSetParent(hWndChild, hWndNewParent));
 
 CLEANUP:
-   TRACE("Leave NtUserSetParent, ret=%i\n",_ret_);
+   ERR("Leave NtUserSetParent, ret=%p\n",_ret_);
    UserLeave();
    END_CLEANUP;
 }
@@ -3554,6 +3593,12 @@
             else
                Window->ExStyle &= ~WS_EX_WINDOWEDGE;
 
+            if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
+            {
+               if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
+               if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
+               DceResetActiveDCEs( Window );
+            }
             Window->style = (DWORD)Style.styleNew;
             co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
             break;
@@ -3751,7 +3796,7 @@
          break;
 
       case QUERY_WINDOW_ISHUNG:
-         Result = (DWORD)MsqIsHung(pWnd->head.pti->MessageQueue);
+         Result = (DWORD)MsqIsHung(pWnd->head.pti);
          break;
 
       case QUERY_WINDOW_REAL_ID:
Index: win32ss/user/ntuser/desktop.h
===================================================================
--- win32ss/user/ntuser/desktop.h	(revision 58555)
+++ win32ss/user/ntuser/desktop.h	(working copy)
@@ -69,9 +69,10 @@
                             DESKTOP_SWITCHDESKTOP    | \
                             DESKTOP_WRITEOBJECTS
 
-extern PDESKTOP InputDesktop;
+extern PDESKTOP gpdeskInputDesktop;
 extern PCLS DesktopWindowClass;
 extern HDC ScreenDeviceContext;
+extern PTHREADINFO gptiForeground;
 extern PTHREADINFO gptiDesktopThread;
 
 typedef struct _SHELL_HOOK_WINDOW
Index: win32ss/user/ntuser/winpos.c
===================================================================
--- win32ss/user/ntuser/winpos.c	(revision 58555)
+++ win32ss/user/ntuser/winpos.c	(working copy)
@@ -139,6 +139,34 @@
     return MAKELONG(LOWORD(Delta.x), LOWORD(Delta.y));
 }
 
+BOOL FASTCALL
+IntClientToScreen(PWND Wnd, LPPOINT lpPoint)
+{
+   if (Wnd && Wnd->fnid != FNID_DESKTOP )
+   {
+      if (Wnd->ExStyle & WS_EX_LAYOUTRTL)
+         lpPoint->x = Wnd->rcClient.right - lpPoint->x;
+      else
+         lpPoint->x += Wnd->rcClient.left;
+      lpPoint->y += Wnd->rcClient.top;
+   }
+   return TRUE;
+}
+
+BOOL FASTCALL
+IntScreenToClient(PWND Wnd, LPPOINT lpPoint)
+{
+    if (Wnd && Wnd->fnid != FNID_DESKTOP )
+    {
+       if (Wnd->ExStyle & WS_EX_LAYOUTRTL)
+          lpPoint->x = Wnd->rcClient.right - lpPoint->x;
+       else
+          lpPoint->x -= Wnd->rcClient.left;
+       lpPoint->y -= Wnd->rcClient.top;
+    }
+    return TRUE;
+}
+
 BOOL FASTCALL IsChildVisible(PWND pWnd)
 {
     do
@@ -209,6 +237,7 @@
              if (!(pWndSetActive->ExStyle & WS_EX_TOOLWINDOW) )
              {
                 UserRefObjectCo(pWndSetActive, &Ref);
+                //ERR("ActivateOtherWindowMin Set FG 1\n");
                 co_IntSetForegroundWindow(pWndSetActive);
                 UserDerefObjectCo(pWndSetActive);
                 //ERR("AOWM 2 Exit Good\n");
@@ -245,6 +274,7 @@
     if ((pWndSetActive = pWndTemp))
     {
        UserRefObjectCo(pWndSetActive, &Ref);
+       //ERR("ActivateOtherWindowMin Set FG 2\n");
        co_IntSetForegroundWindow(pWndSetActive);
        UserDerefObjectCo(pWndSetActive);
        //ERR("AOWM 3 Exit Good\n");
@@ -271,7 +301,7 @@
     if (style & WS_MINIMIZE) return FALSE;
     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
     return TRUE;
-    /* FIXME: This window could be disable  because the child that closed
+    /* FIXME: This window could be disable because the child that closed
               was a popup. */
     //return !(style & WS_DISABLED);
 }
@@ -286,7 +316,6 @@
 co_WinPosActivateOtherWindow(PWND Wnd)
 {
    PWND WndTo = NULL;
-   HWND Fg, previous;
    USER_REFERENCE_ENTRY Ref;
 
    ASSERT_REFS_CO(Wnd);
@@ -317,26 +346,24 @@
 
    if (WndTo) UserRefObjectCo(WndTo, &Ref);
 
-   Fg = UserGetForegroundWindow();
-   if ((!Fg || Wnd->head.h == Fg) && WndTo) // FIXME: Ok if WndTo is NULL?? No, rule #4.
+   if (!gpqForeground || Wnd == gpqForeground->spwndActive)
    {
-      /* FIXME: Wine can pass WndTo = NULL to co_IntSetForegroundWindow. Hmm... */
+      /* ReactOS can pass WndTo = NULL to co_IntSetForegroundWindow and returns FALSE. */
+      //ERR("WinPosActivateOtherWindow Set FG 0x%p\n",WndTo);
       if (co_IntSetForegroundWindow(WndTo))
       {
-         UserDerefObjectCo(WndTo);
+         if (WndTo) UserDerefObjectCo(WndTo);
          return;
       }
    }
-
-   if (!co_IntSetActiveWindow(WndTo,&previous,FALSE,TRUE,FALSE) ||  /* Ok for WndTo to be NULL here */
-       !previous)
+   //ERR("WinPosActivateOtherWindow Set Active  0x%p\n",WndTo);
+   if (!co_IntSetActiveWindow(WndTo,FALSE,TRUE,FALSE))  /* Ok for WndTo to be NULL here */
    {
-      co_IntSetActiveWindow(0,NULL,FALSE,TRUE,FALSE);
+      co_IntSetActiveWindow(0,FALSE,TRUE,FALSE);
    }
    if (WndTo) UserDerefObjectCo(WndTo);
 }
 
-
 UINT
 FASTCALL
 co_WinPosArrangeIconicWindows(PWND parent)
@@ -1103,11 +1130,71 @@
       ClientRect->bottom = WindowRect->bottom;
    }
 }
+/***********************************************************************
+ *           get_valid_rects
+ *
+ * Compute the valid rects from the old and new client rect and WVR_* flags.
+ * Helper for WM_NCCALCSIZE handling.
+ */
+static
+VOID FASTCALL
+get_valid_rects( RECTL *old_client, RECTL *new_client, UINT flags, RECTL *valid )
+{
+    int cx, cy;
 
+    if (flags & WVR_REDRAW)
+    {
+        RECTL_vSetEmptyRect( &valid[0] );
+        RECTL_vSetEmptyRect( &valid[1] );
+        return;
+    }
+
+    if (flags & WVR_VALIDRECTS)
+    {
+        if (!RECTL_bIntersectRect( &valid[0], &valid[0], new_client ) ||
+            !RECTL_bIntersectRect( &valid[1], &valid[1], old_client ))
+        {
+            RECTL_vSetEmptyRect( &valid[0] );
+            RECTL_vSetEmptyRect( &valid[1] );
+            return;
+        }
+        flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
+    }
+    else
+    {
+        valid[0] = *new_client;
+        valid[1] = *old_client;
+    }
+
+    /* make sure the rectangles have the same size */
+    cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
+    cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
+
+    if (flags & WVR_ALIGNBOTTOM)
+    {
+        valid[0].top = valid[0].bottom - cy;
+        valid[1].top = valid[1].bottom - cy;
+    }
+    else
+    {
+        valid[0].bottom = valid[0].top + cy;
+        valid[1].bottom = valid[1].top + cy;
+    }
+    if (flags & WVR_ALIGNRIGHT)
+    {
+        valid[0].left = valid[0].right - cx;
+        valid[1].left = valid[1].right - cx;
+    }
+    else
+    {
+        valid[0].right = valid[0].left + cx;
+        valid[1].right = valid[1].left + cx;
+    }
+}
+
 static
 LONG FASTCALL
-co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos,
-                      RECT* WindowRect, RECT* ClientRect)
+co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos, RECTL* WindowRect, RECTL* ClientRect, RECTL* validRects)
 {
    PWND Parent;
    UINT wvrFlags = 0;
@@ -1120,9 +1207,10 @@
       NCCALCSIZE_PARAMS params;
       WINDOWPOS winposCopy;
 
-      params.rgrc[0] = *WindowRect;
-      params.rgrc[1] = Window->rcWindow;
-      params.rgrc[2] = Window->rcClient;
+      params.rgrc[0] = *WindowRect;      // new coordinates of a window that has been moved or resized
+      params.rgrc[1] = Window->rcWindow; // window before it was moved or resized
+      params.rgrc[2] = Window->rcClient; // client area before the window was moved or resized
+
       Parent = Window->spwndParent;
       if (0 != (Window->style & WS_CHILD) && Parent)
       {
@@ -1133,6 +1221,7 @@
          RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left,
                           - Parent->rcClient.top);
       }
+
       params.lppos = &winposCopy;
       winposCopy = *WinPos;
 
@@ -1142,7 +1231,7 @@
       if (params.rgrc[0].left <= params.rgrc[0].right &&
           params.rgrc[0].top <= params.rgrc[0].bottom)
       {
-         *ClientRect = params.rgrc[0];
+         *ClientRect = params.rgrc[0]; // First rectangle contains the coordinates of the new client rectangle resulting from the move or resize
          if ((Window->style & WS_CHILD) && Parent)
          {
             RECTL_vOffsetRect(ClientRect, Parent->rcClient.left,
@@ -1151,21 +1240,30 @@
          FixClientRect(ClientRect, WindowRect);
       }
 
-      /* FIXME: WVR_ALIGNxxx */
-
       if (ClientRect->left != Window->rcClient.left ||
           ClientRect->top != Window->rcClient.top)
       {
          WinPos->flags &= ~SWP_NOCLIENTMOVE;
       }
 
-      if ((ClientRect->right - ClientRect->left !=
-            Window->rcClient.right - Window->rcClient.left) ||
-          (ClientRect->bottom - ClientRect->top !=
-            Window->rcClient.bottom - Window->rcClient.top))
+      if (ClientRect->right - ClientRect->left !=
+          Window->rcClient.right - Window->rcClient.left)
       {
          WinPos->flags &= ~SWP_NOCLIENTSIZE;
       }
+      else
+         wvrFlags &= ~WVR_HREDRAW;
+
+      if (ClientRect->bottom - ClientRect->top !=
+          Window->rcClient.bottom - Window->rcClient.top)
+      {
+         WinPos->flags &= ~SWP_NOCLIENTSIZE;
+      }
+      else
+         wvrFlags &= ~WVR_VREDRAW;
+
+      validRects[0] = params.rgrc[1]; // second rectangle contains the valid destination rectangle
+      validRects[1] = params.rgrc[2]; // third rectangle contains the valid source rectangle
    }
    else
    {
@@ -1177,6 +1275,13 @@
       }
    }
 
+   if (WinPos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
+   {
+      RECTL_vSetEmptyRect( &validRects[0] );
+      RECTL_vSetEmptyRect( &validRects[1] );
+   }
+   else get_valid_rects( &Window->rcClient, ClientRect, wvrFlags, validRects );
+
    return wvrFlags;
 }
 
@@ -1210,6 +1315,7 @@
       PWND Parent;
       X = WinPos->x;
       Y = WinPos->y;
+
       Parent = Window->spwndParent;
       if ((0 != (Window->style & WS_CHILD)) && Parent)
       {
@@ -1368,6 +1474,21 @@
 BOOL FASTCALL
 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
 {
+   PWND Parent;
+   POINT pt;
+
+   /* Finally make sure that all coordinates are valid */
+   if (WinPos->x < -32768) WinPos->x = -32768;   
+   else if (WinPos->x > 32767) WinPos->x = 32767;
+   if (WinPos->y < -32768) WinPos->y = -32768;   
+   else if (WinPos->y > 32767) WinPos->y = 32767;
+
+   WinPos->cx = max(WinPos->cx, 0);
+   WinPos->cy = max(WinPos->cy, 0);
+
+   Parent = UserGetAncestor( Wnd, GA_PARENT );
+   if (!IntIsWindowVisible( Parent )) WinPos->flags |= SWP_NOREDRAW;
+
    if (Wnd->style & WS_VISIBLE)
    {
       WinPos->flags &= ~SWP_SHOWWINDOW;
@@ -1379,9 +1500,6 @@
          WinPos->flags |= SWP_NOREDRAW;
    }
 
-   WinPos->cx = max(WinPos->cx, 0);
-   WinPos->cy = max(WinPos->cy, 0);
-
    /* Check for right size */
    if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
        Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
@@ -1389,10 +1507,15 @@
       WinPos->flags |= SWP_NOSIZE;
    }
 
+   pt.x = WinPos->x;
+   pt.y = WinPos->y;
+   IntClientToScreen( Parent, &pt );
+//   ERR("WPFU C2S wpx %d wpy %d ptx %d pty %d\n",WinPos->x,WinPos->y,pt.x,pt.y);
    /* Check for right position */
-   if (Wnd->rcWindow.left == WinPos->x &&
-       Wnd->rcWindow.top == WinPos->y)
+   if (Wnd->rcWindow.left == pt.x &&
+       Wnd->rcWindow.top == pt.y)
    {
+//      ERR("In right pos\n");
       WinPos->flags |= SWP_NOMOVE;
    }
 
@@ -1498,6 +1621,7 @@
    WINDOWPOS WinPos;
    RECTL NewWindowRect;
    RECTL NewClientRect;
+   RECTL valid_rects[2];
    PROSRGNDATA VisRgn;
    HRGN VisBefore = NULL;
    HRGN VisAfter = NULL;
@@ -1515,7 +1639,7 @@
 
    ASSERT_REFS_CO(Window);
 
-   /* FIXME: Get current active window from active queue. */
+   /* FIXME: Get current active window from active queue. Why? since r2915. */
 
    bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y);
 
@@ -1527,6 +1651,27 @@
    WinPos.cy = cy;
    WinPos.flags = flags;
 
+   if ( flags & SWP_ASYNCWINDOWPOS )
+   {
+      LRESULT lRes;
+      PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
+      if ( ppos )
+      {
+         WinPos.flags &= ~SWP_ASYNCWINDOWPOS; // Clear flag.
+         *ppos = WinPos;
+         /* Yes it's a pointer inside Win32k! */
+         lRes = co_IntSendMessageNoWait( WinPos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
+         /* We handle this the same way as Event Hooks and Hooks. */
+         if ( !lRes )
+         {
+            ExFreePoolWithTag(ppos, USERTAG_SWP);
+            return FALSE;
+         }
+         return TRUE;
+      }
+      return FALSE;
+   }
+
    co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
 
    // HWND_NOTOPMOST is redirected in WinPosFixupFlags.
@@ -1582,9 +1727,11 @@
       }
    }
 
-   WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect);
+   WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect, valid_rects);
 
-   TRACE("co_WinPosDoNCCALCSize returned %d\n", WvrFlags);
+//   ERR("co_WinPosDoNCCALCSize returned 0x%x\n valid dest: %d %d %d %d\n valid src : %d %d %d %d\n", WvrFlags,
+//      valid_rects[0].left,valid_rects[0].top,valid_rects[0].right,valid_rects[0].bottom,
+//      valid_rects[1].left,valid_rects[1].top,valid_rects[1].right,valid_rects[1].bottom);
 
    /* Validate link windows. (also take into account shell window in hwndShellWindow) */
    if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
@@ -1596,6 +1743,7 @@
 
       if ((ParentWindow = Window->spwndParent)) // Must have a Parent window!
       {
+         //ERR("SetWindowPos has parent window.\n");
          if (WinPos.hwndInsertAfter == HWND_TOPMOST)
          {
             InsertAfterWindow = NULL;
@@ -1654,21 +1802,9 @@
 
    OldWindowRect = Window->rcWindow;
    OldClientRect = Window->rcClient;
+   //ERR("SetWindowPos OldWindowRect: %d %d %d %d\n", OldWindowRect.left,OldWindowRect.top,OldWindowRect.right,OldWindowRect.bottom);
+   //ERR("SetWindowPos OldClientRect: %d %d %d %d\n", OldClientRect.left,OldClientRect.top,OldClientRect.right,OldClientRect.bottom);
 
-   if (OldClientRect.bottom - OldClientRect.top ==
-         NewClientRect.bottom - NewClientRect.top)
-   {
-      WvrFlags &= ~WVR_VREDRAW;
-   }
-
-   if (OldClientRect.right - OldClientRect.left ==
-         NewClientRect.right - NewClientRect.left)
-   {
-      WvrFlags &= ~WVR_HREDRAW;
-   }
-
-   /* FIXME: Actually do something with WVR_VALIDRECTS */
-
    if (NewClientRect.left != OldClientRect.left ||
        NewClientRect.top  != OldClientRect.top)
    {
@@ -1680,6 +1816,9 @@
    Window->rcWindow = NewWindowRect;
    Window->rcClient = NewClientRect;
 
+   //ERR("SetWindowPos NewWindowRect: %d %d %d %d\n", NewWindowRect.left,NewWindowRect.top,NewWindowRect.right,NewWindowRect.bottom);
+   //ERR("SetWindowPos NewClientRect: %d %d %d %d\n", NewClientRect.left,NewClientRect.top,NewClientRect.right,NewClientRect.bottom);
+
    /* erase parent when hiding or resizing child */
    if (WinPos.flags & SWP_HIDEWINDOW)
    {
@@ -1693,6 +1832,7 @@
          co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM)Window->head.h, 0);
 
       Window->style &= ~WS_VISIBLE; //IntSetStyle( Window, 0, WS_VISIBLE );
+      Window->head.pti->cVisWindows--;
       IntNotifyWinEvent(EVENT_OBJECT_HIDE, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
    }
    else if (WinPos.flags & SWP_SHOWWINDOW)
@@ -1701,6 +1841,7 @@
          co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)Window->head.h, 0);
 
       Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 );
+      Window->head.pti->cVisWindows++;
       IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
    }
 
@@ -1927,7 +2068,10 @@
       else
       {
          //ERR("SetWindowPos Set FG Window!\n");
-         co_IntSetForegroundWindow(Window);
+         if (Window->state & WNDS_BEINGACTIVATED) // Inside SAW?
+            co_IntSetActiveWindow(Window, FALSE, TRUE, FALSE); // Fixes Api AttachThreadInput tests.
+         else
+            co_IntSetForegroundWindow(Window); // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow.
       }
    }
 
@@ -2008,7 +2152,7 @@
 
     co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
 
-    if (Wnd->spwndParent == UserGetDesktopWindow()) // Wnd->spwndParent->fnid != FNID_DESKTOP )
+    if (Wnd->spwndParent == UserGetDesktopWindow()) // Wnd->spwndParent->fnid == FNID_DESKTOP )
        lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
     else
        lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
@@ -2030,7 +2174,7 @@
    PTHREADINFO pti;
    BOOL ShowOwned = FALSE;
    //  HRGN VisibleRgn;
-
+   //ERR("co_WinPosShowWindow START\n");
    ASSERT_REFS_CO(Wnd);
 
    pti = PsGetCurrentThreadWin32Thread();
@@ -2043,6 +2187,7 @@
          {
             if (!WasVisible)
             {
+               //ERR("co_WinPosShowWindow Exit Bad\n");
                return(FALSE);
             }
             Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
@@ -2068,6 +2213,7 @@
                // Fix wine Win test_SetFocus todo #1 & #2,
                if (Cmd == SW_SHOWMINIMIZED)
                {
+                  //ERR("co_WinPosShowWindow Set focus 1\n");
                   if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
                      co_UserSetFocus(Wnd->spwndParent);
                   else
@@ -2086,7 +2232,10 @@
                   Swp |= SWP_FRAMECHANGED;
                }
                else ////
+               {
+                  //ERR("co_WinPosShowWindow Exit Good\n");
                   return TRUE;
+               }
                Swp |= SWP_NOSIZE | SWP_NOMOVE;
             }
             break;
@@ -2111,7 +2260,10 @@
                   Swp |= SWP_FRAMECHANGED;
                }
                else ////
+               {
+                  //ERR("co_WinPosShowWindow Exit Good 1\n");
                   return TRUE;
+               }
                Swp |= SWP_NOSIZE | SWP_NOMOVE;
             }
             break;
@@ -2149,7 +2301,10 @@
                Swp |= SWP_FRAMECHANGED;
             }
             else ////
+            {
+               //ERR("co_WinPosShowWindow Exit Good 3\n");
                return TRUE;
+            }
             Swp |= SWP_NOSIZE | SWP_NOMOVE;
          }
          if ( style & WS_CHILD &&
@@ -2159,6 +2314,7 @@
          break;
 
       default:
+         //ERR("co_WinPosShowWindow Exit Good 4\n");
          return WasVisible;
    }
 
@@ -2186,7 +2342,8 @@
         Wnd->pcls->style & CS_SAVEBITS &&
         ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
    {
-      co_IntSetActiveWindow(Wnd,NULL,FALSE,TRUE,FALSE);
+      ERR("WinPosShowWindow Set active\n");
+      UserSetActiveWindow(Wnd);
       Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
    }
 #endif
@@ -2208,8 +2365,14 @@
    {
       TRACE("Parent Vis?\n");
       /* if parent is not visible simply toggle WS_VISIBLE and return */
-      if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 );
-      else IntSetStyle( Wnd, 0, WS_VISIBLE );
+      if (ShowFlag)
+      {
+         IntSetStyle( Wnd, WS_VISIBLE, 0 );
+      }
+      else
+      {
+         IntSetStyle( Wnd, 0, WS_VISIBLE );
+      }
    }
 
    if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
@@ -2253,6 +2416,7 @@
       // Fix wine Win test_SetFocus todo #3,
       if (!(style & WS_CHILD)) co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0);
    }
+   //ERR("co_WinPosShowWindow EXIT\n");
    return(WasVisible);
 }
 
Index: win32ss/user/ntuser/focus.c
===================================================================
--- win32ss/user/ntuser/focus.c	(revision 58555)
+++ win32ss/user/ntuser/focus.c	(working copy)
@@ -132,6 +132,10 @@
             {
                UINT flags = SWP_NOSIZE | SWP_NOMOVE;
                if (Window == pwndTemp) flags |= SWP_NOACTIVATE;
+               //// Hack to force foreground in SetWindowPos when SetActiveWindow is used.
+               Window->head.pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
+               ////
+               //ERR("co_IntSendActivateMessages SetWindowPos!\n");
                co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, flags);
             }
          }
@@ -156,8 +160,7 @@
             if ( OldTID )
             {
                ptiOld->TIF_flags |= TIF_INACTIVATEAPPMSG;
-               ptiOld->pClientInfo->dwTIFlags = ptiOld->TIF_flags;
-
+               // Note: Do not set pci flags, this does crash!
                for (phWnd = List; *phWnd; ++phWnd)
                {
                   cWindow = ValidateHwndNoErr(*phWnd);
@@ -168,13 +171,11 @@
                   }
                }
                ptiOld->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
-               ptiOld->pClientInfo->dwTIFlags = ptiOld->TIF_flags;
             }
             if ( NewTID )
             {  //// Prevents a resource crash due to reentrance!
                InAAPM = TRUE;
                pti->TIF_flags |= TIF_INACTIVATEAPPMSG;
-               pti->pClientInfo->dwTIFlags = pti->TIF_flags;
                ////
                for (phWnd = List; *phWnd; ++phWnd)
                {
@@ -186,7 +187,7 @@
                   }
                }
             }
-            ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+            ExFreePool(List);//ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
          }
       }
       if (WindowPrev)
@@ -205,12 +206,11 @@
 
       co_IntMakeWindowActive(Window);
 
-      UserDerefObjectCo(Window);
+      /* FIXME: IntIsWindow */
 
-      /* FIXME: IntIsWindow */
       co_IntSendMessageNoWait( UserHMGetHandle(Window),
                                WM_NCACTIVATE,
-                              (WPARAM)(Window == gpqForeground->spwndActive),
+                              (WPARAM)(Window == (gpqForeground ? gpqForeground->spwndActive : NULL)),
                                0); //(LPARAM)hWndPrev);
 
       co_IntSendMessageNoWait( UserHMGetHandle(Window),
@@ -226,6 +226,7 @@
 
       Window->state &= ~WNDS_NONCPAINT;
 
+      UserDerefObjectCo(Window);
    }
    return InAAPM;
 }
@@ -294,37 +295,77 @@
 }
 
 VOID FASTCALL
-FindRemoveAsyncMsg(PWND Wnd)
+FindRemoveAsyncMsg(PWND Wnd, WPARAM wParam)
 {
-   PUSER_MESSAGE_QUEUE MessageQueue;
+   PTHREADINFO pti;
    PUSER_SENT_MESSAGE Message;
    PLIST_ENTRY Entry;
 
    if (!Wnd) return;
 
-   MessageQueue = Wnd->head.pti->MessageQueue;
+   pti = Wnd->head.pti;
 
-   if (!IsListEmpty(&MessageQueue->SentMessagesListHead))
+   if (!IsListEmpty(&pti->SentMessagesListHead))
    {
       // Scan sent queue messages to see if we received async messages.
-      Entry = MessageQueue->SentMessagesListHead.Flink;
+      Entry = pti->SentMessagesListHead.Flink;
       Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
       do
       {
+         if (IsListEmpty(Entry)) return;
+         if (!Message) return;
+         Entry = Message->ListEntry.Flink;
+
          if (Message->Msg.message == WM_ASYNC_SETACTIVEWINDOW &&
              Message->Msg.hwnd == UserHMGetHandle(Wnd) &&
-             Message->Msg.wParam == 0 )
+             Message->Msg.wParam == wParam )
          {
-             TRACE("ASYNC SAW: Found one in the Sent Msg Queue! %p\n", Message->Msg.hwnd);
-             RemoveEntryList(Entry); // Purge the entry.
+             ERR("ASYNC SAW: Found one in the Sent Msg Queue! %p Activate/Deactivate %d\n", Message->Msg.hwnd,!!wParam);
+             RemoveEntryList(&Message->ListEntry); // Purge the entry.
+             ExFreePoolWithTag(Message, TAG_USRMSG);
          }
-         Entry = Message->ListEntry.Flink;
          Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
       }
-      while (Entry != &MessageQueue->SentMessagesListHead);
+      while (Entry != &pti->SentMessagesListHead);
    }
 }
 
+BOOL FASTCALL
+ToggleFGActivate(PTHREADINFO pti)
+{
+   BOOL Ret;
+   PPROCESSINFO ppi = pti->ppi;
+
+   Ret = !!(pti->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE);
+   if (Ret)
+   {
+      pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE;
+   }
+   else
+      Ret = !!(ppi->W32PF_flags & W32PF_ALLOWFOREGROUNDACTIVATE);
+
+   if (Ret)
+      ppi->W32PF_flags &= ~W32PF_ALLOWFOREGROUNDACTIVATE;
+   //ERR("ToggleFGActivate is %d\n",Ret);
+   return Ret;
+}
+
+BOOL FASTCALL
+IsAllowedFGActive(PTHREADINFO pti, PWND Wnd)
+{
+   // Not allowed if one or more,,
+   if (!ToggleFGActivate(pti) ||              // bits not set,
+        pti->rpdesk != gpdeskInputDesktop ||  // not current Desktop,
+        pti->MessageQueue == gpqForeground || // if already the queue foreground,
+        IsFGLocked() ||                       // foreground is locked,
+        Wnd->ExStyle & WS_EX_NOACTIVATE )     // or,,, does not become the foreground window when the user clicks it.
+   {
+      return FALSE;
+   }
+   //ERR("IsAllowedFGActive is TRUE\n");
+   return TRUE;
+}
+
 /*
    Can the system force foreground from one or more conditions.
  */
@@ -356,37 +397,35 @@
     * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
     * No menus are active.
 */
-
-static BOOL FASTCALL
+static
+BOOL FASTCALL
 co_IntSetForegroundAndFocusWindow(
     _In_ PWND Wnd,
     _In_ BOOL MouseActivate)
 {
-   HWND hWnd;
+   HWND hWnd = Wnd ? UserHMGetHandle(Wnd) : NULL;
    HWND hWndPrev = NULL;
+   PWND pWndPrev = NULL;
    PUSER_MESSAGE_QUEUE PrevForegroundQueue;
    PTHREADINFO pti;
    BOOL fgRet = FALSE, Ret = FALSE;
 
-   ASSERT_REFS_CO(Wnd);
-   NT_ASSERT(Wnd != NULL);
+   if (Wnd) ASSERT_REFS_CO(Wnd);
 
-   hWnd = UserHMGetHandle(Wnd);
+   //ERR("SetForegroundAndFocusWindow(%x, %s)\n", hWnd, (MouseActivate ? "TRUE" : "FALSE"));
 
-   TRACE("SetForegroundAndFocusWindow(%x, %s)\n", hWnd, (MouseActivate ? "TRUE" : "FALSE"));
-
    PrevForegroundQueue = IntGetFocusMessageQueue(); // Use this active desktop.
    pti = PsGetCurrentThreadWin32Thread();
 
    if (PrevForegroundQueue)
    {  // Same Window Q as foreground just do active.
-      //ERR("Same Window Q as foreground just do active.\n");
       if (Wnd && Wnd->head.pti->MessageQueue == PrevForegroundQueue)
       {
+         //ERR("Same Window Q as foreground just do active.\n");
          if (pti->MessageQueue == PrevForegroundQueue)
          { // Same WQ and TQ go active.
             //ERR("Same WQ and TQ go active.\n");
-            Ret = co_IntSetActiveWindow(Wnd, NULL, MouseActivate, TRUE, FALSE);
+            Ret = co_IntSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE);
          }
          else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
          { // Same WQ and it is active.
@@ -396,13 +435,15 @@
          else
          { // Same WQ as FG but not the same TQ send active.
             //ERR("Same WQ as FG but not the same TQ send active.\n");
-            co_IntSendMessageNoWait(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
+            // Go ahead and wait for the activation to finish.
+            co_IntSendMessage(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
             Ret = TRUE;
          }
          return Ret;
       }
 
       hWndPrev = PrevForegroundQueue->spwndActive ? UserHMGetHandle(PrevForegroundQueue->spwndActive) : 0;
+      pWndPrev = PrevForegroundQueue->spwndActive;
    }
 
    if ( (( !IsFGLocked() || pti->ppi == gppiInputProvider ) &&
@@ -410,16 +451,28 @@
         pti->ppi == ppiScrnSaver
       )
    {
-      IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue);
-      gptiForeground = Wnd->head.pti;
-      TRACE("Set Foreground pti 0x%p Q 0x%p\n",Wnd->head.pti, Wnd->head.pti->MessageQueue);
+
+      //ToggleFGActivate(pti); // win.c line 2662 fail
+      if (Wnd)
+      {
+         IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue);
+         gptiForeground = Wnd->head.pti;
+         //ERR("Set Foreground pti 0x%p Q 0x%p hWnd 0x%p\n",Wnd->head.pti, Wnd->head.pti->MessageQueue,Wnd->head.h);
+      }
+      else
+      {
+         IntSetFocusMessageQueue(NULL);
+         gptiForeground = NULL;
+         //ERR("Set Foreground pti 0x0 Q 0x0 hWnd 0x0\n");
+      }
 /*
      Henri Verbeet,
      What happens is that we get the WM_WINE_SETACTIVEWINDOW message sent by the
      other thread after we already changed the foreground window back to our own
      window.
  */
-      FindRemoveAsyncMsg(Wnd); // Do this to fix test_SFW todos!
+      FindRemoveAsyncMsg(Wnd, 0); // Do this to fix test_SFW todos!
+
       fgRet = TRUE;
    }
 
@@ -428,34 +481,42 @@
    {
       if (PrevForegroundQueue &&
           fgRet &&
-          Wnd->head.pti->MessageQueue != PrevForegroundQueue &&
           PrevForegroundQueue->spwndActive)
       {
          //ERR("SFGW: Send NULL to 0x%x\n",hWndPrev);
          if (pti->MessageQueue == PrevForegroundQueue)
          {
             //ERR("SFGW: TI same as Prev TI\n");
-            co_IntSetActiveWindow(NULL, NULL, FALSE, TRUE, FALSE);
+            co_IntSetActiveWindow(NULL, FALSE, TRUE, FALSE);
          }
-         else
-         co_IntSendMessageNoWait(hWndPrev, WM_ASYNC_SETACTIVEWINDOW, 0, 0 );
+         else if (pWndPrev)
+         {
+            //ERR("SFGW Deactivate: TI not same as Prev TI\n");
+            // No real reason to wait here.
+            co_IntSendMessageNoWait(hWndPrev, WM_ASYNC_SETACTIVEWINDOW, 0, 0 );
+         }
       }
    }
 
+   if (!Wnd){ return FALSE; }// Always return false.
+
    if (pti->MessageQueue == Wnd->head.pti->MessageQueue)
    {
-       Ret = co_IntSetActiveWindow(Wnd, NULL, MouseActivate, TRUE, FALSE);
+       //ERR("Same PQ and WQ go active.\n");
+       Ret = co_IntSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE);
    }
    else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
    {
+       //ERR("Same Active and Wnd.\n");
        Ret = TRUE;
    }
    else
    {
-       co_IntSendMessageNoWait(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
+       //ERR("Activate Not same PQ and WQ and Wnd.\n");
+       // Due to synchronicity SendMessage is required. Just need to wait for the activation to finish.
+       co_IntSendMessage(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
        Ret = TRUE;
    }
-
    return Ret && fgRet;
 }
 
@@ -500,7 +561,7 @@
 }
 
 BOOL FASTCALL
-co_IntSetActiveWindow(PWND Wnd OPTIONAL, HWND * Prev, BOOL bMouse, BOOL bFocus, BOOL Async)
+co_IntSetActiveWindow(PWND Wnd OPTIONAL, BOOL bMouse, BOOL bFocus, BOOL Async)
 {
    PTHREADINFO pti;
    PUSER_MESSAGE_QUEUE ThreadQueue;
@@ -509,38 +570,83 @@
    HWND hWnd = 0;
    BOOL InAAPM;
    CBTACTIVATESTRUCT cbt;
-
+   //ERR("co_IntSetActiveWindow 1\n");
    if (Wnd)
    {
       ASSERT_REFS_CO(Wnd);
       hWnd = UserHMGetHandle(Wnd);
       if ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
       if (Wnd == UserGetDesktopWindow()) return FALSE;
+      //ERR("co_IntSetActiveWindow 1a hWnd 0x%p\n",hWnd);
    }
 
+   //ERR("co_IntSetActiveWindow 2\n");
    pti = PsGetCurrentThreadWin32Thread();
    ThreadQueue = pti->MessageQueue;
    ASSERT(ThreadQueue != 0);
 
    hWndPrev = ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : NULL;
-   if (Prev) *Prev = hWndPrev;
-   if (hWndPrev == hWnd) return TRUE;
 
    pWndChg = ThreadQueue->spwndActive; // Keep to notify of a preemptive switch.
 
-   if (Wnd)
+   while (Wnd)
    {
-      if (ThreadQueue != Wnd->head.pti->MessageQueue)
+      BOOL Ret, DoFG, AllowFG;
+
+      if (Wnd->state & WNDS_BEINGACTIVATED) return TRUE;
+
+      if (ThreadQueue == Wnd->head.pti->MessageQueue)
       {
-         PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
+         if (IsAllowedFGActive(pti, Wnd))
+         {
+             DoFG = TRUE;
+         }
+         else
+         {
+             //ERR("co_IntSetActiveWindow 3 Go Out!\n");
+             break;
+         }
+         AllowFG = !pti->cVisWindows; // Nothing is visable.
+         //ERR("co_IntSetActiveWindow 3a DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
+      }
+      else //if (ThreadQueue != Wnd->head.pti->MessageQueue)
+      {
+         //PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
          // Rule 1 & 4, We are foreground so set this FG window or NULL foreground....
-         if (!ForegroundQueue || ForegroundQueue == ThreadQueue)
+         //if (!ForegroundQueue || ForegroundQueue == ThreadQueue)
+         if (!gpqForeground || gpqForeground == ThreadQueue)
          {
-            return co_IntSetForegroundAndFocusWindow(Wnd, bMouse);
+            DoFG = TRUE;
          }
+         else
+            DoFG = FALSE;
+         if (DoFG)
+         {
+            if (pti->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE || pti->cVisWindows)
+               AllowFG = TRUE;
+            else
+               AllowFG = FALSE;
+         }
+         else
+            AllowFG = FALSE;
+         //ERR("co_IntSetActiveWindow 3b DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
       }
-
-      if (Wnd->state & WNDS_BEINGACTIVATED) return TRUE;
+      Ret = FALSE;
+      if (DoFG)
+      {
+         pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
+         //ERR("co_IntSetActiveWindow 3c FG set\n");
+         Ret = co_IntSetForegroundAndFocusWindow(Wnd, bMouse);
+         if (AllowFG)
+         {
+            pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
+         }
+         else
+         {
+            pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE;
+         }
+      }
+      return Ret;
    }
 
    /* Call CBT hook chain */
@@ -562,14 +668,16 @@
    if (WndPrev)
    {
       if (ThreadQueue == gpqForeground) gpqForegroundPrev = ThreadQueue;
-      if (!co_IntSendDeactivateMessages(hWndPrev, hWnd)) return FALSE;
+      if (!co_IntSendDeactivateMessages(UserHMGetHandle(WndPrev), hWnd)) return FALSE;
    }
 
+   WndPrev = ThreadQueue->spwndActive; // Again keep to save changing active.
+
    // While in calling message proc or hook:
    // Fail if a preemptive switch was made, current active not made previous,
    // focus window is dead or no longer the same thread queue.
    if ( ThreadQueue->spwndActivePrev != ThreadQueue->spwndActive ||
-        pWndChg != ThreadQueue->spwndActive ||
+        pWndChg != WndPrev ||
         (Wnd && !VerifyWnd(Wnd)) ||
         ThreadQueue != pti->MessageQueue )
    {
@@ -583,6 +691,8 @@
 
    IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
 
+   FindRemoveAsyncMsg(Wnd,(WPARAM)Wnd); // Clear out activate ASYNC messages.
+
    /* check if the specified window can be set in the input data of a given queue */
    if ( !Wnd || ThreadQueue == Wnd->head.pti->MessageQueue)
    {
@@ -590,6 +700,8 @@
       ThreadQueue->spwndActive = Wnd;
    }
 
+   WndPrev = VerifyWnd(ThreadQueue->spwndActivePrev); // Now should be set but verify it again.
+
    InAAPM = co_IntSendActivateMessages(WndPrev, Wnd, bMouse, Async);
 
    /* now change focus if necessary */
@@ -610,16 +722,40 @@
    if (InAAPM)
    {
       pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
-      pti->pClientInfo->dwTIFlags = pti->TIF_flags;
    }
 
    // FIXME: Used in the menu loop!!!
    //ThreadQueue->QF_flags |= QF_ACTIVATIONCHANGE;
 
+   //ERR("co_IntSetActiveWindow Exit\n");
    if (Wnd) Wnd->state &= ~WNDS_BEINGACTIVATED;
    return (ThreadQueue->spwndActive == Wnd);
 }
 
+BOOL FASTCALL
+UserSetActiveWindow(PWND Wnd)
+{
+  if (Wnd) // Must have a window!
+  {
+     if ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
+
+     return co_IntSetActiveWindow(Wnd, FALSE, TRUE, FALSE);
+  }
+  /*
+     Yes your eye are not deceiving you~!
+  
+     First part of wines Win.c test_SetActiveWindow:
+
+     flush_events( TRUE );
+     ShowWindow(hwnd, SW_HIDE);
+     SetFocus(0);
+     SetActiveWindow(0);
+     check_wnd_state(0, 0, 0, 0); <-- This should pass if ShowWindow does it's job!!! As of 10/28/2012 it does!
+
+  */
+  return FALSE;
+}
+
 HWND FASTCALL
 co_UserSetFocus(PWND Window)
 {
@@ -653,7 +789,7 @@
       }
 
       /* Check if we can set the focus to this window */
-      pwndTop = Window;
+/*      pwndTop = Window;
       for (;;)
       {
          if (pwndTop->style & (WS_MINIMIZED|WS_DISABLED)) return 0;
@@ -665,6 +801,12 @@
          if (pwndTop->spwndParent == UserGetMessageWindow()) return 0;
          pwndTop = pwndTop->spwndParent;
       }
+*/
+      for (pwndTop = Window; pwndTop != NULL; pwndTop = pwndTop->spwndParent)
+      {
+         if (pwndTop->style & (WS_MINIMIZED|WS_DISABLED)) return 0;
+         if ((pwndTop->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
+      }
 
       if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->head.h, (LPARAM)hWndPrev))
       {
@@ -676,8 +818,13 @@
       if (pwndTop != ThreadQueue->spwndActive)
       {
          PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue(); // Keep it based on desktop.
-         if (ThreadQueue != ForegroundQueue) // HACK see rule 2 & 3.
+         if (ThreadQueue != ForegroundQueue && IsAllowedFGActive(pti, pwndTop)) // Rule 2 & 3.
          {
+            //ERR("SetFocus: Set Foreground!\n");
+            if (!(pwndTop->style & WS_VISIBLE))
+            {
+                pti->ppi->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE;
+            }
             if (!co_IntSetForegroundAndFocusWindow(pwndTop, FALSE))
             {
                ERR("SetFocus: Set Foreground and Focus Failed!\n");
@@ -688,7 +835,8 @@
          /* Set Active when it is needed. */
          if (pwndTop != ThreadQueue->spwndActive)
          {
-            if (!co_IntSetActiveWindow(pwndTop, NULL, FALSE, FALSE, FALSE))
+            //ERR("SetFocus: Set Active!\n");
+            if (!co_IntSetActiveWindow(pwndTop, FALSE, FALSE, FALSE))
             {
                ERR("SetFocus: Set Active Failed!\n");
                return 0;
@@ -787,7 +935,7 @@
       }
    }
 
-   hWndPrev = MsqSetStateWindow(ThreadQueue, MSQ_STATE_CAPTURE, hWnd);
+   hWndPrev = MsqSetStateWindow(pti, MSQ_STATE_CAPTURE, hWnd);
 
    if (hWndPrev)
    {
@@ -815,8 +963,8 @@
       MOUSEINPUT mi;
    /// These are HACKS!
       /* Also remove other windows if not capturing anymore */
-      MsqSetStateWindow(ThreadQueue, MSQ_STATE_MENUOWNER, NULL);
-      MsqSetStateWindow(ThreadQueue, MSQ_STATE_MOVESIZE, NULL);
+      MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
+      MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL);
    ///
       /* Somebody may have missed some mouse movements */
       mi.dx = 0;
@@ -857,7 +1005,7 @@
 BOOL FASTCALL
 co_IntSetForegroundWindow(PWND Window)
 {
-   ASSERT_REFS_CO(Window);
+   if (Window) ASSERT_REFS_CO(Window);
 
    return co_IntSetForegroundAndFocusWindow(Window, FALSE);
 }
@@ -950,7 +1098,7 @@
    RETURN( UserGetForegroundWindow());
 
 CLEANUP:
-   TRACE("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_);
+   TRACE("Leave NtUserGetForegroundWindow, ret=%p\n",_ret_);
    UserLeave();
    END_CLEANUP;
 }
@@ -981,7 +1129,7 @@
    {
       hWndPrev = gptiCurrent->MessageQueue->spwndActive ? UserHMGetHandle(gptiCurrent->MessageQueue->spwndActive) : NULL;
       if (Window) UserRefObjectCo(Window, &Ref);
-      co_IntSetActiveWindow(Window, NULL, FALSE, TRUE, FALSE);
+      UserSetActiveWindow(Window);
       if (Window) UserDerefObjectCo(Window);
       RETURN( hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0 );
    }
Index: win32ss/user/ntuser/timer.c
===================================================================
--- win32ss/user/ntuser/timer.c	(revision 58555)
+++ win32ss/user/ntuser/timer.c	(working copy)
@@ -386,14 +386,12 @@
 PostTimerMessages(PWND Window)
 {
   PLIST_ENTRY pLE;
-  PUSER_MESSAGE_QUEUE ThreadQueue;
   MSG Msg;
   PTHREADINFO pti;
   BOOL Hit = FALSE;
   PTIMER pTmr;
 
   pti = PsGetCurrentThreadWin32Thread();
-  ThreadQueue = pti->MessageQueue;
 
   TimerEnterExclusive();
   pLE = TimersListHead.Flink;
@@ -409,7 +407,7 @@
            Msg.wParam  = (WPARAM) pTmr->nID;
            Msg.lParam  = (LPARAM) pTmr->pfn;
 
-           MsqPostMessage(ThreadQueue, &Msg, FALSE, QS_TIMER, 0);
+           MsqPostMessage(pti, &Msg, FALSE, QS_TIMER, 0);
            pTmr->flags &= ~TMRF_READY;
            pti->cTimersReady++;
            Hit = TRUE;
@@ -484,8 +482,8 @@
                 // Set thread message queue for this timer.
                 if (pTmr->pti->MessageQueue)
                 {  // Wakeup thread
-                   ASSERT(pTmr->pti->MessageQueue->NewMessages != NULL);
-                   KeSetEvent(pTmr->pti->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
+                   ASSERT(pTmr->pti->pEventQueueServer != NULL);
+                   KeSetEvent(pTmr->pti->pEventQueueServer, IO_NO_INCREMENT, FALSE);
                 }
              }
           }
Index: win32ss/user/ntuser/main.c
===================================================================
--- win32ss/user/ntuser/main.c	(revision 58555)
+++ win32ss/user/ntuser/main.c	(working copy)
@@ -154,6 +154,9 @@
            ppiCurrent->W32PF_flags |= W32PF_SCREENSAVER;
         }
 
+        // Fixme check if this process is allowed.
+        ppiCurrent->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE; // Starting application it will get toggled off.
+
         /* Create pools for GDI object attributes */
         ppiCurrent->pPoolDcAttr = GdiPoolCreate(sizeof(DC_ATTR), 'acdG');
         ppiCurrent->pPoolBrushAttr = GdiPoolCreate(sizeof(BRUSH_ATTR), 'arbG');
@@ -254,6 +257,7 @@
     int i;
     NTSTATUS Status = STATUS_SUCCESS;
     PTEB pTeb;
+    LARGE_INTEGER LargeTickCount;
 
     Process = Thread->ThreadsProcess;
 
@@ -274,25 +278,52 @@
 
     RtlZeroMemory(ptiCurrent, sizeof(THREADINFO));
 
+    /* Initialize the THREADINFO */
+
     PsSetThreadWin32Thread(Thread, ptiCurrent);
+    IntReferenceThreadInfo(ptiCurrent);
+    ptiCurrent->pEThread = Thread;
+    ptiCurrent->ppi = PsGetCurrentProcessWin32Process();
     pTeb->Win32ThreadInfo = ptiCurrent;
     ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
 
     TRACE_CH(UserThread, "Allocated pti 0x%p for TID %p\n", ptiCurrent, Thread->Cid.UniqueThread);
 
-    /* Initialize the THREADINFO */
     InitializeListHead(&ptiCurrent->WindowListHead);
     InitializeListHead(&ptiCurrent->W32CallbackListHead);
+    InitializeListHead(&ptiCurrent->PostedMessagesListHead);
+    InitializeListHead(&ptiCurrent->SentMessagesListHead);
+    InitializeListHead(&ptiCurrent->DispatchingMessagesHead);
+    InitializeListHead(&ptiCurrent->LocalDispatchingMessagesHead);
     InitializeListHead(&ptiCurrent->PtiLink);
     for (i = 0; i < NB_HOOKS; i++)
     {
         InitializeListHead(&ptiCurrent->aphkStart[i]);
     }
-    ptiCurrent->pEThread = Thread;
-    ptiCurrent->ppi = PsGetCurrentProcessWin32Process();
     ptiCurrent->ptiSibling = ptiCurrent->ppi->ptiList;
     ptiCurrent->ppi->ptiList = ptiCurrent;
     ptiCurrent->ppi->cThreads++;
+
+    ptiCurrent->hEventQueueClient = NULL;
+    Status = ZwCreateEvent(&ptiCurrent->hEventQueueClient, EVENT_ALL_ACCESS,
+                            NULL, SynchronizationEvent, FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+       goto error;
+    }
+    Status = ObReferenceObjectByHandle(ptiCurrent->hEventQueueClient, 0,
+                                       ExEventObjectType, KernelMode,
+                                       (PVOID*)&ptiCurrent->pEventQueueServer, NULL);
+    if (!NT_SUCCESS(Status))
+    {
+       ZwClose(ptiCurrent->hEventQueueClient);
+       ptiCurrent->hEventQueueClient = NULL;
+       goto error;
+    }
+
+    KeQueryTickCount(&LargeTickCount);
+    ptiCurrent->timeLast = LargeTickCount.u.LowPart;
+
     ptiCurrent->MessageQueue = MsqCreateMessageQueue(ptiCurrent);
     if(ptiCurrent->MessageQueue == NULL)
     {
@@ -390,6 +421,12 @@
 
     /* mark the thread as fully initialized */
     ptiCurrent->TIF_flags |= TIF_GUITHREADINITIALIZED;
+
+    if (!(ptiCurrent->ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_APPSTARTING)) &&
+         (gptiForeground && gptiForeground->ppi == ptiCurrent->ppi ))
+    {
+       ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
+    }
     ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
 
     return STATUS_SUCCESS;
@@ -400,6 +437,35 @@
     return Status;
 }
 
+/*
+  Called from IntDereferenceThreadInfo.
+ */
+VOID
+FASTCALL
+UserDeleteW32Thread(PTHREADINFO pti)
+{
+    if (!pti->RefCount)
+    {
+       ERR_CH(UserThread,"UserDeleteW32Thread pti 0x%p\n",pti);
+       if (pti->hEventQueueClient != NULL)
+          ZwClose(pti->hEventQueueClient);
+       pti->hEventQueueClient = NULL;
+
+       /* Free the message queue */
+       if (pti->MessageQueue)
+       {
+          MsqDestroyMessageQueue(pti);
+       }
+
+       MsqCleanupThreadMsgs(pti);
+
+       IntSetThreadDesktop(NULL, TRUE);
+
+       PsSetThreadWin32Thread(pti->pEThread, NULL);
+       ExFreePoolWithTag(pti, USERTAG_THREADINFO);
+    }
+}
+
 NTSTATUS
 NTAPI
 UserDestroyThreadInfo(struct _ETHREAD *Thread)
@@ -425,27 +491,10 @@
     ppiCurrent = ptiCurrent->ppi;
     ASSERT(ppiCurrent);
 
-    // ptiTo
-    if (IsThreadAttach(ptiCurrent))
-    {
-       PTHREADINFO ptiFrom = IsThreadAttach(ptiCurrent);
-       TRACE_CH(UserThread,"Attached Thread ptiTo is getting switched!\n");
-       UserAttachThreadInput(ptiFrom, ptiCurrent, FALSE);
-    }
+    IsRemoveAttachThread(ptiCurrent);
 
-    // ptiFrom
-    if (ptiCurrent->pqAttach && ptiCurrent->MessageQueue)
-    {
-       PTHREADINFO ptiTo;
-       ptiTo = PsGetThreadWin32Thread(ptiCurrent->MessageQueue->Thread);
-       TRACE_CH(UserThread,"Attached Thread ptiFrom is getting switched!\n");
-       if (ptiTo) UserAttachThreadInput( ptiCurrent, ptiTo, FALSE);
-       else
-       {
-          // eThread maybe okay but Win32Thread already made NULL!
-          ERR_CH(UserThread,"Attached Thread ptiFrom did not switch due to ptiTo is NULL!\n");
-       }
-    }
+    ptiCurrent->TIF_flags |= TIF_DONTATTACHQUEUE;
+    ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
 
     /* Decrement thread count and check if its 0 */
     ppiCurrent->cThreads--;
@@ -485,7 +534,7 @@
         HOOK_DestroyThreadHooks(Thread);
         EVENT_DestroyThreadEvents(Thread);
         DestroyTimersForThread(ptiCurrent);
-        KeSetEvent(ptiCurrent->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
+        KeSetEvent(ptiCurrent->pEventQueueServer, IO_NO_INCREMENT, FALSE);
         UnregisterThreadHotKeys(Thread);
 /*
         if (IsListEmpty(&ptiCurrent->WindowListHead))
@@ -518,12 +567,6 @@
         }
     }
 
-    /* Free the message queue */
-    if (ptiCurrent->MessageQueue)
-    {
-       MsqDestroyMessageQueue(ptiCurrent);
-    }
-
     /* Find the THREADINFO in the PROCESSINFO's list */
     ppti = &ppiCurrent->ptiList;
     while (*ppti != NULL && *ppti != ptiCurrent)
@@ -540,13 +583,12 @@
     if (ptiCurrent->KeyboardLayout)
         UserDereferenceObject(ptiCurrent->KeyboardLayout);
 
-    IntSetThreadDesktop(NULL, TRUE);
+    if (gptiForeground == ptiCurrent) gptiForeground = NULL;
 
     TRACE_CH(UserThread,"Freeing pti 0x%p\n", ptiCurrent);
 
     /* Free the THREADINFO */
-    PsSetThreadWin32Thread(Thread, NULL);
-    ExFreePoolWithTag(ptiCurrent, USERTAG_THREADINFO);
+    IntDereferenceThreadInfo(ptiCurrent);
 
     return STATUS_SUCCESS;
 }
Index: win32ss/user/ntuser/focus.h
===================================================================
--- win32ss/user/ntuser/focus.h	(revision 58555)
+++ win32ss/user/ntuser/focus.h	(working copy)
@@ -18,6 +18,7 @@
 HWND FASTCALL UserGetActiveWindow(VOID);
 BOOL FASTCALL co_IntMouseActivateWindow(PWND Window);
 BOOL FASTCALL co_IntSetForegroundWindow(PWND Window);
-BOOL FASTCALL co_IntSetActiveWindow(PWND,HWND *,BOOL,BOOL,BOOL);
+BOOL FASTCALL co_IntSetActiveWindow(PWND,BOOL,BOOL,BOOL);
+BOOL FASTCALL UserSetActiveWindow(PWND Wnd);
 BOOL FASTCALL IntLockSetForegroundWindow(UINT uLockCode);
 BOOL FASTCALL IntAllowSetForegroundWindow(DWORD dwProcessId);
Index: win32ss/user/ntuser/msgqueue.c
===================================================================
--- win32ss/user/ntuser/msgqueue.c	(revision 58555)
+++ win32ss/user/ntuser/msgqueue.c	(working copy)
@@ -347,7 +347,6 @@
 IntMsqSetWakeMask(DWORD WakeMask)
 {
    PTHREADINFO Win32Thread;
-   PUSER_MESSAGE_QUEUE MessageQueue;
    HANDLE MessageEventHandle;
    DWORD dwFlags = HIWORD(WakeMask);
 
@@ -355,9 +354,8 @@
    if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
       return 0;
 
-   MessageQueue = Win32Thread->MessageQueue;
 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
-   MessageEventHandle = MessageQueue->NewMessagesHandle;
+   MessageEventHandle = Win32Thread->hEventQueueClient;
 
    if (Win32Thread->pcti)
    {
@@ -365,7 +363,7 @@
            ( (dwFlags & MWMO_INPUTAVAILABLE) && (Win32Thread->pcti->fsWakeBits & LOWORD(WakeMask)) ) )
       {
          ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread->pcti->fsChangeBits, Win32Thread->pcti->fsWakeBits, WakeMask);
-         KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE); // Wake it up!
+         KeSetEvent(Win32Thread->pEventQueueServer, IO_NO_INCREMENT, FALSE); // Wake it up!
          return MessageEventHandle;
       }
    }
@@ -396,55 +394,65 @@
    and even if the bits are all cleared. The same as cTimers/cPaintsReady.
    I think this is the best solution... (jt) */
 VOID FASTCALL
-MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue, DWORD MessageBits, BOOL KeyEvent)
+MsqWakeQueue(PTHREADINFO pti, DWORD MessageBits, BOOL KeyEvent)
 {
-   PTHREADINFO pti;
+   PUSER_MESSAGE_QUEUE Queue;
 
+   Queue = pti->MessageQueue;
+
    if (Queue->QF_flags & QF_INDESTROY)
    {
       ERR("This Message Queue is in Destroy!\n");
    }
-   pti = Queue->Thread->Tcb.Win32Thread;
    pti->pcti->fsWakeBits |= MessageBits;
    pti->pcti->fsChangeBits |= MessageBits;
 
    // Start bit accounting to help clear the main set of bits.
-   if (MessageBits & QS_KEY)         Queue->nCntsQBits[QSRosKey]++;
-   if (MessageBits & QS_MOUSEMOVE)   Queue->nCntsQBits[QSRosMouseMove]++;
-   if (MessageBits & QS_MOUSEBUTTON) Queue->nCntsQBits[QSRosMouseButton]++;
-   if (MessageBits & QS_POSTMESSAGE) Queue->nCntsQBits[QSRosPostMessage]++;
-   if (MessageBits & QS_SENDMESSAGE) Queue->nCntsQBits[QSRosSendMessage]++;
-   if (MessageBits & QS_HOTKEY)      Queue->nCntsQBits[QSRosHotKey]++;
+   if (MessageBits & QS_KEY)
+   {
+      Queue->ptiKeyboard = pti;
+      pti->nCntsQBits[QSRosKey]++;
+   }
+   if (MessageBits & QS_MOUSE)
+   {
+      Queue->ptiMouse = pti;
+      if (MessageBits & QS_MOUSEMOVE)   pti->nCntsQBits[QSRosMouseMove]++;
+      if (MessageBits & QS_MOUSEBUTTON) pti->nCntsQBits[QSRosMouseButton]++;
+   }
+   if (MessageBits & QS_POSTMESSAGE) pti->nCntsQBits[QSRosPostMessage]++;
+   if (MessageBits & QS_SENDMESSAGE) pti->nCntsQBits[QSRosSendMessage]++;
+   if (MessageBits & QS_HOTKEY)      pti->nCntsQBits[QSRosHotKey]++;
+   if (MessageBits & QS_EVENT)       pti->nCntsQBits[QSRosEvent]++;
 
    if (KeyEvent)
-      KeSetEvent(Queue->NewMessages, IO_NO_INCREMENT, FALSE);
+      KeSetEvent(pti->pEventQueueServer, IO_NO_INCREMENT, FALSE);
 }
 
 VOID FASTCALL
-ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue, UINT MessageBits)
+ClearMsgBitsMask(PTHREADINFO pti, UINT MessageBits)
 {
-   PTHREADINFO pti;
+   PUSER_MESSAGE_QUEUE Queue;
    UINT ClrMask = 0;
 
-   pti = Queue->Thread->Tcb.Win32Thread;
+   Queue = pti->MessageQueue;
 
    if (MessageBits & QS_KEY)
    {
-      if (--Queue->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY;
+      if (--pti->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY;
    }
    if (MessageBits & QS_MOUSEMOVE) // ReactOS hard coded.
    {  // Account for tracking mouse moves..
-      if (--Queue->nCntsQBits[QSRosMouseMove] == 0) ClrMask |= QS_MOUSEMOVE;
+      if (--pti->nCntsQBits[QSRosMouseMove] == 0) ClrMask |= QS_MOUSEMOVE;
       // Handle mouse move bits here.
       if (Queue->MouseMoved) ClrMask |= QS_MOUSEMOVE;
    }
    if (MessageBits & QS_MOUSEBUTTON)
    {
-      if (--Queue->nCntsQBits[QSRosMouseButton] == 0) ClrMask |= QS_MOUSEBUTTON;
+      if (--pti->nCntsQBits[QSRosMouseButton] == 0) ClrMask |= QS_MOUSEBUTTON;
    }
    if (MessageBits & QS_POSTMESSAGE)
    {
-      if (--Queue->nCntsQBits[QSRosPostMessage] == 0) ClrMask |= QS_POSTMESSAGE;
+      if (--pti->nCntsQBits[QSRosPostMessage] == 0) ClrMask |= QS_POSTMESSAGE;
    }
    if (MessageBits & QS_TIMER) // ReactOS hard coded.
    {  // Handle timer bits here.
@@ -462,38 +470,40 @@
    }
    if (MessageBits & QS_SENDMESSAGE)
    {
-      if (--Queue->nCntsQBits[QSRosSendMessage] == 0) ClrMask |= QS_SENDMESSAGE;
+      if (--pti->nCntsQBits[QSRosSendMessage] == 0) ClrMask |= QS_SENDMESSAGE;
    }
    if (MessageBits & QS_HOTKEY)
    {
-      if (--Queue->nCntsQBits[QSRosHotKey] == 0) ClrMask |= QS_HOTKEY;
+      if (--pti->nCntsQBits[QSRosHotKey] == 0) ClrMask |= QS_HOTKEY;
    }
+   if (MessageBits & QS_EVENT)
+   {
+      if (--pti->nCntsQBits[QSRosEvent] == 0) ClrMask |= QS_EVENT;
+   }
 
    pti->pcti->fsWakeBits &= ~ClrMask;
    pti->pcti->fsChangeBits &= ~ClrMask;
 }
 
 VOID FASTCALL
-MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
+MsqIncPaintCountQueue(PTHREADINFO pti)
 {
-   PTHREADINFO pti;
-   pti = Queue->Thread->Tcb.Win32Thread;
    pti->cPaintsReady++;
-   MsqWakeQueue(Queue, QS_PAINT, TRUE);
+   MsqWakeQueue(pti, QS_PAINT, TRUE);
 }
 
 VOID FASTCALL
-MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
+MsqDecPaintCountQueue(PTHREADINFO pti)
 {
-   ClearMsgBitsMask(Queue, QS_PAINT);
+   ClearMsgBitsMask(pti, QS_PAINT);
 }
 
 VOID FASTCALL
-MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg)
+MsqPostMouseMove(PTHREADINFO pti, MSG* Msg)
 {
-    MessageQueue->MouseMoveMsg = *Msg;
-    MessageQueue->MouseMoved = TRUE;
-    MsqWakeQueue(MessageQueue, QS_MOUSEMOVE, TRUE);
+    pti->MessageQueue->MouseMoveMsg = *Msg;
+    pti->MessageQueue->MouseMoved = TRUE;
+    MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE);
 }
 
 VOID FASTCALL
@@ -504,6 +514,7 @@
    PDESKTOP pDesk;
    PWND pwnd, pwndDesktop;
    HDC hdcScreen;
+   PTHREADINFO pti;
    PUSER_MESSAGE_QUEUE MessageQueue;
    PSYSTEM_CURSORINFO CurInfo;
 
@@ -564,9 +575,10 @@
    /* Check if we found a window */
    if (Msg->hwnd != NULL && pwnd != NULL)
    {
-       MessageQueue = pwnd->head.pti->MessageQueue;
+       pti = pwnd->head.pti;
+       MessageQueue = pti->MessageQueue;
 
-       if ( pwnd->head.pti->TIF_flags & TIF_INCLEANUP || MessageQueue->QF_flags & QF_INDESTROY)
+       if ( pti->TIF_flags & TIF_INCLEANUP || MessageQueue->QF_flags & QF_INDESTROY)
        {
           ERR("Mouse is over the Window Thread is Dead!\n");
           return;
@@ -617,12 +629,12 @@
            gpqCursor = MessageQueue;
 
            /* Mouse move is a special case */
-           MsqPostMouseMove(MessageQueue, Msg);
+           MsqPostMouseMove(pti, Msg);
        }
        else
        {
            TRACE("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd));
-           MsqPostMessage(MessageQueue, Msg, TRUE, QS_MOUSEBUTTON, 0);
+           MsqPostMessage(pti, Msg, TRUE, QS_MOUSEBUTTON, 0);
        }
    }
    else if (hdcScreen)
@@ -675,7 +687,7 @@
    KeQueryTickCount(&LargeTickCount);
    Mesg.time    = MsqCalculateMessageTime(&LargeTickCount);
    Mesg.pt      = gpsi->ptCursor;
-   MsqPostMessage(Window->head.pti->MessageQueue, &Mesg, FALSE, Type, 0);
+   MsqPostMessage(Window->head.pti, &Mesg, FALSE, Type, 0);
    UserDereferenceObject(Window);
    ObDereferenceObject (Thread);
 
@@ -704,41 +716,38 @@
 }
 
 BOOLEAN FASTCALL
-co_MsqDispatchOneSentMessage(_In_ PUSER_MESSAGE_QUEUE MessageQueue)
+co_MsqDispatchOneSentMessage(PTHREADINFO pti)
 {
    PUSER_SENT_MESSAGE SaveMsg, Message;
    PLIST_ENTRY Entry;
-   PTHREADINFO pti;
    BOOL Ret;
    LRESULT Result = 0;
 
-   if (IsListEmpty(&MessageQueue->SentMessagesListHead))
+   if (IsListEmpty(&pti->SentMessagesListHead))
    {
       return(FALSE);
    }
 
    /* remove it from the list of pending messages */
-   Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
+   Entry = RemoveHeadList(&pti->SentMessagesListHead);
    Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
 
-   pti = MessageQueue->Thread->Tcb.Win32Thread;
-
    SaveMsg = pti->pusmCurrent;
    pti->pusmCurrent = Message;
 
    // Processing a message sent to it from another thread.
-   if ( ( Message->SenderQueue && MessageQueue != Message->SenderQueue) ||
-        ( Message->CallBackSenderQueue && MessageQueue != Message->CallBackSenderQueue ))
+   if ( ( Message->ptiSender && pti != Message->ptiSender) ||
+        ( Message->ptiCallBackSender && pti != Message->ptiCallBackSender ))
    {  // most likely, but, to be sure.
       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(&MessageQueue->LocalDispatchingMessagesHead,
+   InsertTailList(&pti->LocalDispatchingMessagesHead,
                   &Message->ListEntry);
 
-   ClearMsgBitsMask(MessageQueue, Message->QS_Flags);
+   ClearMsgBitsMask(pti, Message->QS_Flags);
 
    if (Message->HookMessage == MSQ_ISHOOK)
    {  // Direct Hook Call processor
@@ -761,7 +770,7 @@
                                   Message->Msg.wParam);
    }
    else if ((Message->CompletionCallback) &&
-            (Message->CallBackSenderQueue == MessageQueue))
+            (Message->ptiCallBackSender == pti))
    {   /* Call the callback routine */
       if (Message->QS_Flags & QS_SMRESULT)
       {
@@ -777,7 +786,7 @@
       {
          /* The message has not been processed yet, reinsert it. */
          RemoveEntryList(&Message->ListEntry);
-         InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead, &Message->ListEntry);
+         InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
          TRACE("Callback Message not processed yet. Requeuing the message\n");
          Ret = FALSE;
          goto Exit;
@@ -798,22 +807,22 @@
    /* If the message is a callback, insert it in the callback senders MessageQueue */
    if (Message->CompletionCallback)
    {
-      if (Message->CallBackSenderQueue)
+      if (Message->ptiCallBackSender)
       {
          Message->lResult = Result;
          Message->QS_Flags |= QS_SMRESULT;
 
          /* insert it in the callers message queue */
-         InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead, &Message->ListEntry);
-         MsqWakeQueue(Message->CallBackSenderQueue, QS_SENDMESSAGE, TRUE);
-         IntDereferenceMessageQueue(Message->CallBackSenderQueue);
+         InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
+         MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE);
+         IntDereferenceThreadInfo(Message->ptiCallBackSender);
       }
       Ret = TRUE;
       goto Exit;
    }
 
    /* remove the message from the dispatching list if needed, so lock the sender's message queue */
-   if (Message->SenderQueue)
+   if (Message->ptiSender)
    {
       if (Message->DispatchingListEntry.Flink != NULL)
       {
@@ -848,11 +857,11 @@
    }
 
    /* if the message has a sender */
-   if (Message->SenderQueue)
+   if (Message->ptiSender)
    {
        /* dereference our and the sender's message queue */
-      IntDereferenceMessageQueue(Message->SenderQueue);
-      IntDereferenceMessageQueue(MessageQueue);
+       IntDereferenceThreadInfo(Message->ptiSender);
+       IntDereferenceThreadInfo(pti);
    }
 
    /* free the message */
@@ -867,22 +876,20 @@
 }
 
 VOID APIENTRY
-MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
+MsqRemoveWindowMessagesFromQueue(PWND Window)
 {
+   PTHREADINFO pti;
    PUSER_SENT_MESSAGE SentMessage;
    PUSER_MESSAGE PostedMessage;
-   PUSER_MESSAGE_QUEUE MessageQueue;
    PLIST_ENTRY CurrentEntry, ListHead;
-   PWND Window = pWindow;
 
    ASSERT(Window);
 
-   MessageQueue = Window->head.pti->MessageQueue;
-   ASSERT(MessageQueue);
+   pti = Window->head.pti;
 
    /* remove the posted messages for this window */
-   CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
-   ListHead = &MessageQueue->PostedMessagesListHead;
+   CurrentEntry = pti->PostedMessagesListHead.Flink;
+   ListHead = &pti->PostedMessagesListHead;
    while (CurrentEntry != ListHead)
    {
       PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
@@ -890,9 +897,9 @@
       if (PostedMessage->Msg.hwnd == Window->head.h)
       {
          RemoveEntryList(&PostedMessage->ListEntry);
-         ClearMsgBitsMask(MessageQueue, PostedMessage->QS_Flags);
+         ClearMsgBitsMask(pti, PostedMessage->QS_Flags);
          MsqDestroyMessage(PostedMessage);
-         CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
+         CurrentEntry = pti->PostedMessagesListHead.Flink;
       }
       else
       {
@@ -900,12 +907,12 @@
       }
    }
 
-   /* Reference we message queue, so it won't get deleted */
-   IntReferenceMessageQueue(MessageQueue);
+   /* Reference we message thread information, so it won't get deleted */
+   IntReferenceThreadInfo(pti);
 
    /* remove the sent messages for this window */
-   CurrentEntry = MessageQueue->SentMessagesListHead.Flink;
-   ListHead = &MessageQueue->SentMessagesListHead;
+   CurrentEntry = pti->SentMessagesListHead.Flink;
+   ListHead = &pti->SentMessagesListHead;
    while (CurrentEntry != ListHead)
    {
       SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
@@ -915,15 +922,15 @@
          TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
 
          RemoveEntryList(&SentMessage->ListEntry);
-         ClearMsgBitsMask(MessageQueue, SentMessage->QS_Flags);
+         ClearMsgBitsMask(pti, SentMessage->QS_Flags);
 
          /* if it is a callback and this queue is not the sender queue, dereference queue */
-         if ((SentMessage->CompletionCallback) && (SentMessage->CallBackSenderQueue != MessageQueue))
+         if ((SentMessage->CompletionCallback) && (SentMessage->ptiCallBackSender != pti))
          {
-            IntDereferenceMessageQueue(SentMessage->CallBackSenderQueue);
+            IntDereferenceThreadInfo(SentMessage->ptiCallBackSender);
          }
          /* Only if the message has a sender was the queue referenced */
-         if ((SentMessage->SenderQueue)
+         if ((SentMessage->ptiSender)
             && (SentMessage->DispatchingListEntry.Flink != NULL))
          {
             RemoveEntryList(&SentMessage->DispatchingListEntry);
@@ -942,17 +949,17 @@
          }
 
          /* if the message has a sender */
-         if (SentMessage->SenderQueue)
+         if (SentMessage->ptiSender)
          {
             /* dereference our and the sender's message queue */
-            IntDereferenceMessageQueue(MessageQueue);
-            IntDereferenceMessageQueue(SentMessage->SenderQueue);
+            IntDereferenceThreadInfo(pti);
+            IntDereferenceThreadInfo(SentMessage->ptiSender);
          }
 
          /* free the message */
          ExFreePoolWithTag(SentMessage, TAG_USRMSG);
 
-         CurrentEntry = MessageQueue->SentMessagesListHead.Flink;
+         CurrentEntry = pti->SentMessagesListHead.Flink;
       }
       else
       {
@@ -961,7 +968,7 @@
    }
 
    /* Remove the reference we added */
-   IntDereferenceMessageQueue(MessageQueue);
+   IntDereferenceThreadInfo(pti);
 }
 
 BOOL FASTCALL
@@ -987,11 +994,11 @@
 
     ptiSender = PsGetCurrentThreadWin32Thread();
 
-    IntReferenceMessageQueue(ptiReceiver->MessageQueue);
+    IntReferenceThreadInfo(ptiReceiver);
     /* 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(ptiSender->MessageQueue);
+       IntReferenceThreadInfo(ptiSender);
 
     Message->Msg.hwnd = hwnd;
     Message->Msg.message = Msg;
@@ -1000,8 +1007,9 @@
     Message->CompletionEvent = NULL;
     Message->Result = 0;
     Message->lResult = 0;
-    Message->SenderQueue = NULL;
-    Message->CallBackSenderQueue = ptiSender->MessageQueue;
+    Message->ptiReceiver = ptiReceiver;
+    Message->ptiSender = NULL;
+    Message->ptiCallBackSender = ptiSender;
     Message->DispatchingListEntry.Flink = NULL;
     Message->CompletionCallback = CompletionCallback;
     Message->CompletionCallbackContext = CompletionCallbackContext;
@@ -1009,33 +1017,30 @@
     Message->HasPackedLParam = HasPackedLParam;
     Message->QS_Flags = QS_SENDMESSAGE;
 
-    InsertTailList(&ptiReceiver->MessageQueue->SentMessagesListHead, &Message->ListEntry);
-    MsqWakeQueue(ptiReceiver->MessageQueue, QS_SENDMESSAGE, TRUE);
-    IntDereferenceMessageQueue(ptiReceiver->MessageQueue);
+    InsertTailList(&ptiReceiver->SentMessagesListHead, &Message->ListEntry);
+    MsqWakeQueue(ptiReceiver, QS_SENDMESSAGE, TRUE);
+    IntDereferenceThreadInfo(ptiReceiver);
 
     return TRUE;
 }
 
 NTSTATUS FASTCALL
-co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
+co_MsqSendMessage(PTHREADINFO ptirec,
                   HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
                   UINT uTimeout, BOOL Block, INT HookMessage,
                   ULONG_PTR *uResult)
 {
-   PTHREADINFO pti, ptirec;
+   PTHREADINFO pti;
    PUSER_SENT_MESSAGE Message;
    KEVENT CompletionEvent;
    NTSTATUS WaitStatus;
-   PUSER_MESSAGE_QUEUE ThreadQueue;
    LARGE_INTEGER Timeout;
    PLIST_ENTRY Entry;
    PWND pWnd;
    LRESULT Result = 0;   //// Result could be trashed. ////
 
    pti = PsGetCurrentThreadWin32Thread();
-   ThreadQueue = pti->MessageQueue;
-   ptirec = MessageQueue->Thread->Tcb.Win32Thread;
-   ASSERT(ThreadQueue != MessageQueue);
+   ASSERT(pti != ptirec);
    ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!!
 
    /* Don't send from or to a dying thread */
@@ -1105,24 +1110,25 @@
    Message->Result = &Result;
    Message->lResult = 0;
    Message->QS_Flags = 0;
-   Message->SenderQueue = ThreadQueue;
-   Message->CallBackSenderQueue = NULL;
-   IntReferenceMessageQueue(ThreadQueue);
+   Message->ptiReceiver = ptirec;
+   Message->ptiSender = pti;
+   Message->ptiCallBackSender = NULL;
    Message->CompletionCallback = NULL;
    Message->CompletionCallbackContext = 0;
    Message->HookMessage = HookMessage;
    Message->HasPackedLParam = FALSE;
 
-   IntReferenceMessageQueue(MessageQueue);
+   IntReferenceThreadInfo(pti);
+   IntReferenceThreadInfo(ptirec);
 
    /* Add it to the list of pending messages */
-   InsertTailList(&ThreadQueue->DispatchingMessagesHead, &Message->DispatchingListEntry);
+   InsertTailList(&pti->DispatchingMessagesHead, &Message->DispatchingListEntry);
 
    /* Queue it in the destination's message queue */
-   InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry);
+   InsertTailList(&ptirec->SentMessagesListHead, &Message->ListEntry);
 
    Message->QS_Flags = QS_SENDMESSAGE;
-   MsqWakeQueue(MessageQueue, QS_SENDMESSAGE, TRUE);
+   MsqWakeQueue(ptirec, QS_SENDMESSAGE, TRUE);
 
    /* We can't access the Message anymore since it could have already been deleted! */
 
@@ -1140,8 +1146,8 @@
       {
          /* 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 = MessageQueue->SentMessagesListHead.Flink;
-         while (Entry != &MessageQueue->SentMessagesListHead)
+         Entry = ptirec->SentMessagesListHead.Flink;
+         while (Entry != &ptirec->SentMessagesListHead)
          {
             if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
                   == Message)
@@ -1157,8 +1163,8 @@
 
          /* 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 = ThreadQueue->DispatchingMessagesHead.Flink;
-         while (Entry != &ThreadQueue->DispatchingMessagesHead)
+         Entry = pti->DispatchingMessagesHead.Flink;
+         while (Entry != &pti->DispatchingMessagesHead)
          {
             if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
                   == Message)
@@ -1178,7 +1184,7 @@
 
          TRACE("MsqSendMessage (blocked) timed out 1\n");
       }
-      while (co_MsqDispatchOneSentMessage(ThreadQueue))
+      while (co_MsqDispatchOneSentMessage(ptirec))
          ;
    }
    else
@@ -1186,7 +1192,7 @@
       PVOID WaitObjects[2];
 
       WaitObjects[0] = &CompletionEvent;
-      WaitObjects[1] = ThreadQueue->NewMessages;
+      WaitObjects[1] = pti->pEventQueueServer;
       do
       {
          UserLeaveCo();
@@ -1200,8 +1206,8 @@
          {
             /* 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 = MessageQueue->SentMessagesListHead.Flink;
-            while (Entry != &MessageQueue->SentMessagesListHead)
+            Entry = ptirec->SentMessagesListHead.Flink;
+            while (Entry != &ptirec->SentMessagesListHead)
             {
                if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
                      == Message)
@@ -1217,8 +1223,8 @@
 
             /* 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 = ThreadQueue->DispatchingMessagesHead.Flink;
-            while (Entry != &ThreadQueue->DispatchingMessagesHead)
+            Entry = pti->DispatchingMessagesHead.Flink;
+            while (Entry != &pti->DispatchingMessagesHead)
             {
                if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
                      == Message)
@@ -1239,7 +1245,7 @@
             TRACE("MsqSendMessage timed out 2\n");
             break;
          }
-         while (co_MsqDispatchOneSentMessage(ThreadQueue))
+         while (co_MsqDispatchOneSentMessage(pti))
             ;
       }
       while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
@@ -1252,14 +1258,23 @@
 }
 
 VOID FASTCALL
-MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue,
+MsqPostMessage(PTHREADINFO pti,
                MSG* Msg,
                BOOLEAN HardwareMessage,
                DWORD MessageBits,
                DWORD dwQEvent)
 {
    PUSER_MESSAGE Message;
+   PUSER_MESSAGE_QUEUE MessageQueue;
 
+   if ( pti->TIF_flags & TIF_INCLEANUP || pti->MessageQueue->QF_flags & QF_INDESTROY )
+   {
+      ERR("Post Msg; Thread or Q is Dead!\n");
+      return;
+   }
+
+   MessageQueue = pti->MessageQueue;
+
    if(!(Message = MsqCreateMessage(Msg)))
    {
       return;
@@ -1267,12 +1282,13 @@
 
    if (dwQEvent)
    {
-       InsertHeadList(&MessageQueue->PostedMessagesListHead,
+       ERR("Post Msg; System Qeued Event Message!\n");
+       InsertHeadList(&pti->PostedMessagesListHead,
                       &Message->ListEntry);
    }
    else if (!HardwareMessage)
    {
-       InsertTailList(&MessageQueue->PostedMessagesListHead,
+       InsertTailList(&pti->PostedMessagesListHead,
                       &Message->ListEntry);
    }
    else
@@ -1283,16 +1299,16 @@
 
    Message->dwQEvent = dwQEvent;
    Message->QS_Flags = MessageBits;
-   //Message->pti = pti; Fixed in ATI changes. See CORE-6551
-   MsqWakeQueue(MessageQueue, MessageBits, (MessageBits & QS_TIMER ? FALSE : TRUE));
+   Message->pti = pti;
+   MsqWakeQueue(pti, MessageBits, (MessageBits & QS_TIMER ? FALSE : TRUE));
 }
 
 VOID FASTCALL
-MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode)
+MsqPostQuitMessage(PTHREADINFO pti, ULONG ExitCode)
 {
-   MessageQueue->QuitPosted = TRUE;
-   MessageQueue->QuitExitCode = ExitCode;
-   MsqWakeQueue(MessageQueue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE);
+   pti->QuitPosted = TRUE;
+   pti->exitCode = ExitCode;
+   MsqWakeQueue(pti, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE);
 }
 
 /***********************************************************************
@@ -1331,7 +1347,7 @@
 IntTrackMouseMove(PWND pwndTrack, PDESKTOP pDesk, PMSG msg, USHORT hittest)
 {
 //   PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
-   hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
+//   hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
 
    if ( pDesk->spwndTrack != pwndTrack || // Change with tracking window or
         msg->message != WM_MOUSEMOVE   || // Mouse click changes or
@@ -1568,7 +1584,7 @@
         hook.dwExtraInfo  = 0 /* extra_info */ ;
         co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook );
 
-        ERR("WH_MOUSE dorpped mouse message!\n");
+        ERR("WH_MOUSE dropped mouse message!\n");
 
         /* Remove and skip message */
         *RemoveMessages = TRUE;
@@ -1719,7 +1735,7 @@
 }
 
 BOOL APIENTRY
-co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue,
+co_MsqPeekMouseMove(IN PTHREADINFO pti,
                    IN BOOL Remove,
                    IN PWND Window,
                    IN UINT MsgFilterLow,
@@ -1728,7 +1744,7 @@
 {
     BOOL AcceptMessage;
     MSG msg;
-    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+    PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
 
     if(!(MessageQueue->MouseMoved))
         return FALSE;
@@ -1754,7 +1770,7 @@
 
     if(Remove)
     {
-        ClearMsgBitsMask(MessageQueue, QS_MOUSEMOVE);
+        ClearMsgBitsMask(pti, QS_MOUSEMOVE);
         MessageQueue->MouseMoved = FALSE;
     }
 
@@ -1781,7 +1797,7 @@
 }
 
 BOOL APIENTRY
-co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
+co_MsqPeekHardwareMessage(IN PTHREADINFO pti,
                          IN BOOL Remove,
                          IN PWND Window,
                          IN UINT MsgFilterLow,
@@ -1795,7 +1811,7 @@
     PLIST_ENTRY ListHead, CurrentEntry = NULL;
     MSG msg;
     BOOL Ret = FALSE;
-    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+    PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
 
     if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE;
 
@@ -1843,7 +1859,7 @@
            if (Remove)
            {
                RemoveEntryList(&CurrentMessage->ListEntry);
-               ClearMsgBitsMask(MessageQueue, CurrentMessage->QS_Flags);
+               ClearMsgBitsMask(pti, CurrentMessage->QS_Flags);
                MsqDestroyMessage(CurrentMessage);
            }
 
@@ -1865,7 +1881,7 @@
 }
 
 BOOLEAN APIENTRY
-MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
+MsqPeekMessage(IN PTHREADINFO pti,
                   IN BOOLEAN Remove,
                   IN PWND Window,
                   IN UINT MsgFilterLow,
@@ -1877,25 +1893,12 @@
    PUSER_MESSAGE CurrentMessage;
    PLIST_ENTRY ListHead;
    BOOL Ret = FALSE;
-   PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
 
-   CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
-   ListHead = &MessageQueue->PostedMessagesListHead;
+   CurrentEntry = pti->PostedMessagesListHead.Flink;
+   ListHead = &pti->PostedMessagesListHead;
 
    if (IsListEmpty(CurrentEntry)) return FALSE;
 
-   if (!MessageQueue->ptiSysLock)
-   {
-      MessageQueue->ptiSysLock = pti;
-      pti->pcti->CTI_flags |= CTI_THREADSYSLOCK;
-   }
-
-   if (MessageQueue->ptiSysLock != pti)
-   {
-      ERR("MsqPeekMessage: Thread Q is locked to another pti!\n");
-      return FALSE;
-   }
-
    CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
                                          ListEntry);
    do
@@ -1920,7 +1923,7 @@
          if (Remove)
          {
              RemoveEntryList(&CurrentMessage->ListEntry);
-             ClearMsgBitsMask(MessageQueue, CurrentMessage->QS_Flags);
+             ClearMsgBitsMask(pti, CurrentMessage->QS_Flags);
              MsqDestroyMessage(CurrentMessage);
          }
          Ret = TRUE;
@@ -1931,18 +1934,16 @@
    }
    while (CurrentEntry != ListHead);
 
-   MessageQueue->ptiSysLock = NULL;
-   pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK;
    return Ret;
 }
 
 NTSTATUS FASTCALL
-co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, PWND WndFilter,
+co_MsqWaitForNewMessages(PTHREADINFO pti, PWND WndFilter,
                          UINT MsgFilterMin, UINT MsgFilterMax)
 {
    NTSTATUS ret;
    UserLeaveCo();
-   ret = KeWaitForSingleObject( MessageQueue->NewMessages,
+   ret = KeWaitForSingleObject( pti->pEventQueueServer,
                                 UserRequest,
                                 UserMode,
                                 FALSE,
@@ -1952,12 +1953,12 @@
 }
 
 BOOL FASTCALL
-MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue)
+MsqIsHung(PTHREADINFO pti)
 {
    LARGE_INTEGER LargeTickCount;
 
    KeQueryTickCount(&LargeTickCount);
-   return ((LargeTickCount.u.LowPart - MessageQueue->LastMsgRead) > MSQ_HUNG);
+   return ((LargeTickCount.u.LowPart - pti->timeLast) > MSQ_HUNG);
 }
 
 VOID
@@ -1972,83 +1973,53 @@
 BOOLEAN FASTCALL
 MsqInitializeMessageQueue(PTHREADINFO pti, PUSER_MESSAGE_QUEUE MessageQueue)
 {
-   struct _ETHREAD *Thread;
-   LARGE_INTEGER LargeTickCount;
-   NTSTATUS Status;
+   MessageQueue->ptiOwner = pti;
 
-   Thread = pti->pEThread;
-   MessageQueue->Thread = Thread;
    MessageQueue->CaretInfo = (PTHRDCARETINFO)(MessageQueue + 1);
-   InitializeListHead(&MessageQueue->PostedMessagesListHead);
-   InitializeListHead(&MessageQueue->SentMessagesListHead);
-   InitializeListHead(&MessageQueue->HardwareMessagesListHead);
-   InitializeListHead(&MessageQueue->DispatchingMessagesHead);
-   InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead);
-   MessageQueue->QuitPosted = FALSE;
-   MessageQueue->QuitExitCode = 0;
-   KeQueryTickCount(&LargeTickCount);
-   MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
+   InitializeListHead(&MessageQueue->HardwareMessagesListHead); // Keep here!
    MessageQueue->spwndFocus = NULL;
-   MessageQueue->NewMessagesHandle = NULL;
    MessageQueue->iCursorLevel = 0;
    MessageQueue->CursorObject = NULL;
    RtlCopyMemory(MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState));
+   MessageQueue->ptiMouse = pti;
+   MessageQueue->ptiKeyboard = pti;
+   MessageQueue->cThreads++;
 
-   Status = ZwCreateEvent(&MessageQueue->NewMessagesHandle, EVENT_ALL_ACCESS,
-                          NULL, SynchronizationEvent, FALSE);
-   if (!NT_SUCCESS(Status))
-   {
-      return FALSE;
-   }
-
-   Status = ObReferenceObjectByHandle(MessageQueue->NewMessagesHandle, 0,
-                                      ExEventObjectType, KernelMode,
-                                      (PVOID*)&MessageQueue->NewMessages, NULL);
-   if (!NT_SUCCESS(Status))
-   {
-      ZwClose(MessageQueue->NewMessagesHandle);
-      MessageQueue->NewMessagesHandle = NULL;
-      return FALSE;
-   }
-
    return TRUE;
 }
 
 VOID FASTCALL
-MsqCleanupMessageQueue(PTHREADINFO pti)
+MsqCleanupThreadMsgs(PTHREADINFO pti)
 {
-   PUSER_MESSAGE_QUEUE MessageQueue;
    PLIST_ENTRY CurrentEntry;
    PUSER_MESSAGE CurrentMessage;
    PUSER_SENT_MESSAGE CurrentSentMessage;
 
-   MessageQueue = pti->MessageQueue;
-
    /* cleanup posted messages */
-   while (!IsListEmpty(&MessageQueue->PostedMessagesListHead))
+   while (!IsListEmpty(&pti->PostedMessagesListHead))
    {
-      CurrentEntry = RemoveHeadList(&MessageQueue->PostedMessagesListHead);
+      CurrentEntry = RemoveHeadList(&pti->PostedMessagesListHead);
       CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
                                          ListEntry);
       MsqDestroyMessage(CurrentMessage);
    }
 
    /* remove the messages that have not yet been dispatched */
-   while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
+   while (!IsListEmpty(&pti->SentMessagesListHead))
    {
-      CurrentEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
+      CurrentEntry = RemoveHeadList(&pti->SentMessagesListHead);
       CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
                                              ListEntry);
 
       /* if it is a callback and this queue is not the sender queue, dereference queue */
-      if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue))
+      if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->ptiCallBackSender != pti))
       {
-         IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue);
+         IntDereferenceThreadInfo(CurrentSentMessage->ptiCallBackSender);
       }
 
       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->SenderQueue)
+      if ((CurrentSentMessage->ptiSender)
          && (CurrentSentMessage->DispatchingListEntry.Flink != NULL))
       {
          RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
@@ -2067,11 +2038,11 @@
       }
 
       /* if the message has a sender */
-      if (CurrentSentMessage->SenderQueue)
+      if (CurrentSentMessage->ptiSender)
       {
          /* dereference our and the sender's message queue */
-         IntDereferenceMessageQueue(MessageQueue);
-         IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);
+         IntDereferenceThreadInfo(pti);
+         IntDereferenceThreadInfo(CurrentSentMessage->ptiSender);
       }
 
       /* free the message */
@@ -2080,16 +2051,16 @@
 
    /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
       ExitThread() was called in a SendMessage() umode callback */
-   while (!IsListEmpty(&MessageQueue->LocalDispatchingMessagesHead))
+   while (!IsListEmpty(&pti->LocalDispatchingMessagesHead))
    {
-      CurrentEntry = RemoveHeadList(&MessageQueue->LocalDispatchingMessagesHead);
+      CurrentEntry = RemoveHeadList(&pti->LocalDispatchingMessagesHead);
       CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
                                              ListEntry);
 
       /* if it is a callback and this queue is not the sender queue, dereference queue */
-      if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue))
+      if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->ptiCallBackSender != pti))
       {
-         IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue);
+         IntDereferenceThreadInfo(CurrentSentMessage->ptiCallBackSender);
       }
 
       /* remove the message from the dispatching list */
@@ -2113,11 +2084,11 @@
       }
 
       /* if the message has a sender */
-      if (CurrentSentMessage->SenderQueue)
+      if (CurrentSentMessage->ptiSender)
       {
          /* dereference our and the sender's message queue */
-         IntDereferenceMessageQueue(MessageQueue);
-         IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);
+         IntDereferenceThreadInfo(pti);
+         IntDereferenceThreadInfo(CurrentSentMessage->ptiSender);
       }
 
       /* free the message */
@@ -2125,9 +2096,9 @@
    }
 
    /* tell other threads not to bother returning any info to us */
-   while (! IsListEmpty(&MessageQueue->DispatchingMessagesHead))
+   while (! IsListEmpty(&pti->DispatchingMessagesHead))
    {
-      CurrentEntry = RemoveHeadList(&MessageQueue->DispatchingMessagesHead);
+      CurrentEntry = RemoveHeadList(&pti->DispatchingMessagesHead);
       CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
                                              DispatchingListEntry);
       CurrentSentMessage->CompletionEvent = NULL;
@@ -2144,13 +2115,28 @@
        pti->pcti->fsChangeBits = 0;
    }
 
-   MessageQueue->nCntsQBits[QSRosKey] = 0;
-   MessageQueue->nCntsQBits[QSRosMouseMove] = 0;
-   MessageQueue->nCntsQBits[QSRosMouseButton] = 0;
-   MessageQueue->nCntsQBits[QSRosPostMessage] = 0;
-   MessageQueue->nCntsQBits[QSRosSendMessage] = 0;
-   MessageQueue->nCntsQBits[QSRosHotKey] = 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;
+}
 
+VOID FASTCALL
+MsqCleanupMessageQueue(PTHREADINFO pti)
+{
+   PUSER_MESSAGE_QUEUE MessageQueue;
+
+   MessageQueue = pti->MessageQueue;
+   MessageQueue->cThreads--;
+
+   if (MessageQueue->cThreads)
+   {
+      if (MessageQueue->ptiSysLock == pti) MessageQueue->ptiSysLock = NULL;
+   }
+
    if (MessageQueue->CursorObject)
    {
        PCURICON_OBJECT pCursor = MessageQueue->CursorObject;
@@ -2169,8 +2155,22 @@
            IntGetSysCursorInfo()->CurrentCursorObject = NULL;
        }
 
+       ERR("DereferenceObject pCursor\n");
        UserDereferenceObject(pCursor);
    }
+
+   if (gpqForeground == MessageQueue)
+   {
+      IntSetFocusMessageQueue(NULL);
+   }
+   if (gpqForegroundPrev == MessageQueue)
+   {
+      gpqForegroundPrev = NULL;
+   }
+   if (gpqCursor == MessageQueue)
+   {
+      gpqCursor = NULL;
+   }
 }
 
 PUSER_MESSAGE_QUEUE FASTCALL
@@ -2218,9 +2218,6 @@
    /* clean it up */
    MsqCleanupMessageQueue(pti);
 
-   if (MessageQueue->NewMessagesHandle != NULL)
-      ZwClose(MessageQueue->NewMessagesHandle);
-   MessageQueue->NewMessagesHandle = NULL;
    /* decrease the reference counter, if it hits zero, the queue will be freed */
    IntDereferenceMessageQueue(MessageQueue);
 }
@@ -2276,7 +2273,7 @@
    if (Message->QS_Flags & QS_SMRESULT) return FALSE;
 
    //     SendMessageXxx    || Callback msg and not a notify msg
-   if (Message->SenderQueue || Message->CompletionCallback)
+   if (Message->ptiSender || Message->CompletionCallback)
    {
       Message->lResult = lResult;
       Message->QS_Flags |= QS_SMRESULT;
@@ -2286,9 +2283,12 @@
 }
 
 HWND FASTCALL
-MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd)
+MsqSetStateWindow(PTHREADINFO pti, ULONG Type, HWND hWnd)
 {
    HWND Prev;
+   PUSER_MESSAGE_QUEUE MessageQueue;
+   
+   MessageQueue = pti->MessageQueue;
 
    switch(Type)
    {
Index: win32ss/user/ntuser/misc.c
===================================================================
--- win32ss/user/ntuser/misc.c	(revision 58555)
+++ win32ss/user/ntuser/misc.c	(working copy)
@@ -2,13 +2,52 @@
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS Win32k subsystem
  * PURPOSE:          Miscellaneous User functions
- * FILE:             subsystems/win32/win32k/ntuser/misc.c
+ * FILE:             win32ss/user/ntuser/misc.c
  * PROGRAMER:        Ge van Geldorp (ge@gse.nl)
  */
 
 #include <win32k.h>
 DBG_DEFAULT_CHANNEL(UserMisc);
 
+PTHREADINFO
+FASTCALL
+IntTID2PTI(HANDLE id)
+{
+   NTSTATUS Status;
+   PETHREAD Thread;
+   PTHREADINFO pti;
+   Status = PsLookupThreadByThreadId(id, &Thread);
+   if (!NT_SUCCESS(Status))
+   {
+      return NULL;
+   }
+   if (PsIsThreadTerminating(Thread))
+   {
+      ObDereferenceObject(Thread);
+      return NULL;
+   }
+   pti = PsGetThreadWin32Thread(Thread);
+   if (!pti)
+   {
+      ObDereferenceObject(Thread);
+      return NULL;
+   }
+   // Validate and verify!
+   _SEH2_TRY
+   {
+      if (pti->TIF_flags & TIF_INCLEANUP) pti = NULL;
+      if (pti && !(pti->TIF_flags & TIF_GUITHREADINITIALIZED)) pti = NULL;
+      if (PsGetThreadId(Thread) != id) pti = NULL;
+   }
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+   {
+      pti = NULL;
+   }
+   _SEH2_END
+   ObDereferenceObject(Thread);
+   return pti;
+}
+
 SHORT
 FASTCALL
 UserGetLanguageID(VOID)
@@ -188,7 +227,7 @@
            ret = ISMEX_NOSEND;
            if (Message)
            {
-             if (Message->SenderQueue)
+             if (Message->ptiSender)
                 ret = ISMEX_SEND;
              else
              {
@@ -213,7 +252,7 @@
            LARGE_INTEGER LargeTickCount;
            pti = PsGetCurrentThreadWin32Thread();
            KeQueryTickCount(&LargeTickCount);
-           pti->MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
+           pti->timeLast = LargeTickCount.u.LowPart;
            pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart;
          }
          break;
@@ -620,8 +659,11 @@
         ASSERT(pti->pDeskInfo == pti->rpdesk->pDeskInfo);
 
     /*too bad we still get this assertion*/
+
+    // Why? Not all flags are passed to the user and doing so could crash the system........
+
     /* ASSERT(pci->dwTIFlags == pti->TIF_flags); */
-    if(pci->dwTIFlags != pti->TIF_flags)
+/*    if(pci->dwTIFlags != pti->TIF_flags)
     {
         ERR("pci->dwTIFlags(0x%x) doesn't match pti->TIF_flags(0x%x)\n", pci->dwTIFlags, pti->TIF_flags);
         if(showCaller)
@@ -631,6 +673,7 @@
         }
         pci->dwTIFlags = pti->TIF_flags;
     }
+*/
 }
 
 void
Index: include/reactos/undocuser.h
===================================================================
--- include/reactos/undocuser.h	(revision 58555)
+++ include/reactos/undocuser.h	(working copy)
@@ -76,6 +76,10 @@
 
 /* Non SDK Queue state flags. */
 #define QS_SMRESULT 0x8000 /* see "Undoc. Windows" */
+//
+#define QS_EVENT          0x2000
+#define QS_SYSEVENT       (QS_EVENT|QS_SENDMESSAGE)
+//
 
 //
 // Definitions used by WM_CLIENTSHUTDOWN
