[CMAKE]
[reactos.git] / subsystems / win32 / win32k / ntuser / desktop.c
index 6547225..3dbfdcf 100644 (file)
@@ -168,10 +168,34 @@ IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters)
    IntFreeDesktopHeap(Desktop);
 }
 
+NTSTATUS NTAPI
+IntDesktopOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters)
+{
+    PTHREADINFO pti;
+
+    pti = PsGetCurrentThreadWin32Thread();
+
+    if( pti == NULL)
+    {
+        /* This happens when we leak desktop handles */
+        return TRUE;
+    }
+
+    /* Do not allow the current desktop or the initial desktop to be closed */
+    if( Parameters->Handle == pti->ppi->hdeskStartup ||
+        Parameters->Handle == pti->hdesk)
+    {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
 /* PRIVATE FUNCTIONS **********************************************************/
 
+INIT_FUNCTION
 NTSTATUS
-FASTCALL
+NTAPI
 InitDesktopImpl(VOID)
 {
     /* Set Desktop Object Attributes */
@@ -515,7 +539,7 @@ HWND FASTCALL IntGetDesktopWindow(VOID)
    return pdo->DesktopWindow;
 }
 
-PWINDOW_OBJECT FASTCALL UserGetDesktopWindow(VOID)
+PWND FASTCALL UserGetDesktopWindow(VOID)
 {
    PDESKTOP pdo = IntGetActiveDesktop();
 
@@ -531,7 +555,7 @@ PWINDOW_OBJECT FASTCALL UserGetDesktopWindow(VOID)
 HWND FASTCALL IntGetMessageWindow(VOID)
 {
    PDESKTOP pdo = IntGetActiveDesktop();
-   
+
    if (!pdo)
    {
       DPRINT("No active desktop\n");
@@ -571,7 +595,7 @@ BOOL FASTCALL IntDesktopUpdatePerUserSettings(BOOL bEnable)
                                       QueryTable, NULL, NULL);
       if (!NT_SUCCESS(Status))
       {
-         DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
+         DPRINT("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
                  Status);
          g_PaintDesktopVersion = FALSE;
          return FALSE;
@@ -593,11 +617,11 @@ BOOL FASTCALL IntDesktopUpdatePerUserSettings(BOOL bEnable)
 HDC FASTCALL
 UserGetDesktopDC(ULONG DcType, BOOL EmptyDC, BOOL ValidatehWnd)
 {
-    PWINDOW_OBJECT DesktopObject = 0;
+    PWND DesktopObject = 0;
     HDC DesktopHDC = 0;
 
     if (DcType == DC_TYPE_DIRECT)
-    {        
+    {
         DesktopObject = UserGetDesktopWindow();
         DesktopHDC = (HDC)UserGetWindowDC(DesktopObject);
     }
@@ -614,16 +638,20 @@ UserGetDesktopDC(ULONG DcType, BOOL EmptyDC, BOOL ValidatehWnd)
 VOID APIENTRY
 UserRedrawDesktop()
 {
-    PWINDOW_OBJECT Window = NULL;
+    PWND Window = NULL;
+    HRGN hRgn;
 
     Window = UserGetDesktopWindow();
+    hRgn = IntSysCreateRectRgnIndirect(&Window->rcWindow);
 
     IntInvalidateWindows( Window,
-              Window->hrgnUpdate,
+                            hRgn,
                        RDW_FRAME |
                        RDW_ERASE |
                   RDW_INVALIDATE |
                  RDW_ALLCHILDREN);
+
+    GreDeleteObject(hRgn);
 }
 
 
@@ -653,15 +681,13 @@ IntHideDesktop(PDESKTOP Desktop)
    return NotifyCsrss(&Request, &Reply);
 #else
 
-   PWINDOW_OBJECT DesktopWindow;
    PWND DesktopWnd;
 
-   DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
-   if (! DesktopWindow)
+   DesktopWnd = IntGetWindowObject(Desktop->DesktopWindow);
+   if (! DesktopWnd)
    {
       return ERROR_INVALID_WINDOW_HANDLE;
    }
-   DesktopWnd = DesktopWindow->Wnd;
    DesktopWnd->style &= ~WS_VISIBLE;
 
    return STATUS_SUCCESS;
@@ -685,7 +711,7 @@ UserBuildShellHookHwndList(PDESKTOP Desktop)
 
    if (!entries) return NULL;
 
-   list = ExAllocatePool(PagedPool, sizeof(HWND) * (entries + 1)); /* alloc one extra for nullterm */
+   list = ExAllocatePoolWithTag(PagedPool, sizeof(HWND) * (entries + 1), USERTAG_WINDOWLIST); /* alloc one extra for nullterm */
    if (list)
    {
       HWND* cursor = list;
@@ -709,23 +735,21 @@ VOID co_IntShellHookNotify(WPARAM Message, LPARAM lParam)
    PDESKTOP Desktop = IntGetActiveDesktop();
    HWND* HwndList;
 
-   static UINT MsgType = 0;
-
-   if (!MsgType)
+   if (!gpsi->uiShellMsg)
    {
 
       /* Too bad, this doesn't work.*/
 #if 0
       UNICODE_STRING Str;
       RtlInitUnicodeString(&Str, L"SHELLHOOK");
-      MsgType = UserRegisterWindowMessage(&Str);
+      gpsi->uiShellMsg = UserRegisterWindowMessage(&Str);
 #endif
 
-      MsgType = IntAddAtom(L"SHELLHOOK");
+      gpsi->uiShellMsg = IntAddAtom(L"SHELLHOOK");
 
-      DPRINT("MsgType = %x\n", MsgType);
-      if (!MsgType)
-         DPRINT1("LastError: %x\n", GetLastNtError());
+      DPRINT("MsgType = %x\n", gpsi->uiShellMsg);
+      if (!gpsi->uiShellMsg)
+         DPRINT1("LastError: %x\n", EngGetLastError());
    }
 
    if (!Desktop)
@@ -743,7 +767,7 @@ VOID co_IntShellHookNotify(WPARAM Message, LPARAM lParam)
       {
          DPRINT("Sending notify\n");
          co_IntPostOrSendMessage(*cursor,
-                                 MsgType,
+                                 gpsi->uiShellMsg,
                                  Message,
                                  lParam);
       }
@@ -858,15 +882,12 @@ IntFreeDesktopHeap(IN OUT PDESKTOP Desktop)
 
 HDESK APIENTRY
 NtUserCreateDesktop(
-   POBJECT_ATTRIBUTES poa,
+   POBJECT_ATTRIBUTES ObjectAttributes,
    PUNICODE_STRING lpszDesktopDevice,
    LPDEVMODEW lpdmw,
    DWORD dwFlags,
    ACCESS_MASK dwDesiredAccess)
 {
-   OBJECT_ATTRIBUTES ObjectAttributes;
-   PTHREADINFO W32Thread;
-   PWINSTATION_OBJECT WinStaObject;
    PDESKTOP DesktopObject;
    UNICODE_STRING DesktopName;
    NTSTATUS Status = STATUS_SUCCESS;
@@ -874,81 +895,28 @@ NtUserCreateDesktop(
    CSR_API_MESSAGE Request;
    PVOID DesktopHeapSystemBase = NULL;
    SIZE_T DesktopInfoSize;
-   UNICODE_STRING SafeDesktopName;
    ULONG DummyContext;
    ULONG_PTR HeapSize = 4 * 1024 * 1024; /* FIXME */
-   HWINSTA hWindowStation = NULL ;
-   PUNICODE_STRING lpszDesktopName = NULL;
-   UNICODE_STRING ClassName, MenuName;
+   UNICODE_STRING ClassName;
    LARGE_STRING WindowName;
+   BOOL NoHooks = FALSE;
    PWND pWnd = NULL;
    CREATESTRUCTW Cs;
+   INT i;
+   PTHREADINFO ptiCurrent;
    DECLARE_RETURN(HDESK);
 
-   DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName);
+   DPRINT("Enter NtUserCreateDesktop\n");
    UserEnterExclusive();
 
-   _SEH2_TRY
-   {
-      ProbeForRead( poa,
-                    sizeof(OBJECT_ATTRIBUTES),
-                    1);
-
-      hWindowStation = poa->RootDirectory;
-      lpszDesktopName = poa->ObjectName;
-   }
-   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-   {
-      Status =_SEH2_GetExceptionCode();
-   }
-   _SEH2_END
-
-   if (! NT_SUCCESS(Status))
+   ptiCurrent = PsGetCurrentThreadWin32Thread();
+   if (ptiCurrent)
    {
-      DPRINT1("Failed reading Object Attributes from user space.\n");
-      SetLastNtError(Status);
-      RETURN( NULL);
+   /* Turn off hooks when calling any CreateWindowEx from inside win32k. */
+      NoHooks = (ptiCurrent->TIF_flags & TIF_DISABLEHOOKS);
+      ptiCurrent->TIF_flags |= TIF_DISABLEHOOKS;
    }
-
-   Status = IntValidateWindowStationHandle(
-               hWindowStation,
-               KernelMode,
-               0, /* FIXME - WINSTA_CREATEDESKTOP */
-               &WinStaObject);
-
-   if (! NT_SUCCESS(Status))
-   {
-      DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
-              hWindowStation, lpszDesktopName);
-      SetLastNtError(Status);
-      RETURN( NULL);
-   }
-   if(lpszDesktopName != NULL)
-   {
-      Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
-      if(!NT_SUCCESS(Status))
-      {
-         SetLastNtError(Status);
-         RETURN( NULL);
-         }
-   }
-   else
-   {
-      RtlInitUnicodeString(&SafeDesktopName, NULL);
-   }
-
-   if (! IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
-                                     &SafeDesktopName))
-   {
-      SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
-      ObDereferenceObject(WinStaObject);
-      if (lpszDesktopName)
-         ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
-      RETURN( NULL);
-   }
-   if (lpszDesktopName)
-      ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
-   ObDereferenceObject(WinStaObject);
+   DesktopName.Buffer = NULL;
 
    /*
     * Try to open already existing desktop
@@ -956,18 +924,10 @@ NtUserCreateDesktop(
 
    DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
 
-   /* Initialize ObjectAttributes for the desktop object */
-   InitializeObjectAttributes(
-      &ObjectAttributes,
-      &DesktopName,
-      0,
-      NULL,
-      NULL);
-
    Status = ObOpenObjectByName(
-               &ObjectAttributes,
+               ObjectAttributes,
                ExDesktopObjectType,
-               KernelMode,
+               UserMode,
                NULL,
                dwDesiredAccess,
                (PVOID)&DummyContext,
@@ -975,10 +935,29 @@ NtUserCreateDesktop(
    if (!NT_SUCCESS(Status)) RETURN(NULL);
    if (Status == STATUS_OBJECT_NAME_EXISTS)
    {
-      ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
       RETURN( Desktop);
    }
 
+   /* Capture desktop name */
+   _SEH2_TRY
+   {
+      ProbeForRead( ObjectAttributes, sizeof(OBJECT_ATTRIBUTES),  1);
+
+      Status = IntSafeCopyUnicodeString(&DesktopName, ObjectAttributes->ObjectName);
+   }
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+   {
+      Status = _SEH2_GetExceptionCode();
+   }
+   _SEH2_END
+
+   if (! NT_SUCCESS(Status))
+   {
+      DPRINT1("Failed reading Object Attributes from user space.\n");
+      SetLastNtError(Status);
+      RETURN( NULL);
+   }
+
    /* Reference the desktop */
    Status = ObReferenceObjectByHandle(Desktop,
                                       0,
@@ -999,12 +978,11 @@ NtUserCreateDesktop(
        RETURN(NULL);
    }
 
-   DesktopInfoSize = FIELD_OFFSET(DESKTOPINFO,
-                                  szDesktopName[(lpszDesktopName->Length / sizeof(WCHAR)) + 1]);
+   DesktopInfoSize = sizeof(DESKTOPINFO) + DesktopName.Length;
 
    DesktopObject->pDeskInfo = RtlAllocateHeap(DesktopObject->pheapDesktop,
-                                                HEAP_NO_SERIALIZE,
-                                                DesktopInfoSize);
+                                              HEAP_NO_SERIALIZE,
+                                              DesktopInfoSize);
 
    if (DesktopObject->pDeskInfo == NULL)
    {
@@ -1019,20 +997,28 @@ NtUserCreateDesktop(
    DesktopObject->pDeskInfo->pvDesktopBase = DesktopHeapSystemBase;
    DesktopObject->pDeskInfo->pvDesktopLimit = (PVOID)((ULONG_PTR)DesktopHeapSystemBase + HeapSize);
    RtlCopyMemory(DesktopObject->pDeskInfo->szDesktopName,
-                 lpszDesktopName->Buffer,
-                 lpszDesktopName->Length);
+                 DesktopName.Buffer,
+                 DesktopName.Length);
 
    /* Initialize some local (to win32k) desktop state. */
    InitializeListHead(&DesktopObject->PtiList);
    DesktopObject->ActiveMessageQueue = NULL;
-   ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
+   /* Setup Global Hooks. */
+   for (i = 0; i < NB_HOOKS; i++)
+   {
+      InitializeListHead(&DesktopObject->pDeskInfo->aphkStart[i]);
+   }
 
+//// why is this here?
+#if 0
    if (! NT_SUCCESS(Status))
    {
       DPRINT1("Failed to create desktop handle\n");
       SetLastNtError(Status);
       RETURN( NULL);
    }
+#endif
+////
 
    /*
     * Create a handle for CSRSS and notify CSRSS for Creating Desktop Window.
@@ -1063,10 +1049,36 @@ NtUserCreateDesktop(
       SetLastNtError(Status);
       RETURN( NULL);
    }
+#if 0 // Turn on when server side proc is ready.
+   //
+   // Create desktop window.
+   //
+   ClassName.Buffer = ((PWSTR)((ULONG_PTR)(WORD)(gpsi->atomSysClass[ICLS_DESKTOP])));
+   ClassName.Length = 0;
+   RtlZeroMemory(&WindowName, sizeof(WindowName));
 
-   W32Thread = PsGetCurrentThreadWin32Thread();
+   RtlZeroMemory(&Cs, sizeof(Cs));
+   Cs.x = UserGetSystemMetrics(SM_XVIRTUALSCREEN);
+   Cs.y = UserGetSystemMetrics(SM_YVIRTUALSCREEN);
+   Cs.cx = UserGetSystemMetrics(SM_CXVIRTUALSCREEN);
+   Cs.cy = UserGetSystemMetrics(SM_CYVIRTUALSCREEN);
+   Cs.style = WS_POPUP|WS_CLIPCHILDREN;
+   Cs.hInstance = hModClient; // Experimental mode... Move csr stuff to User32. hModuleWin; // Server side winproc!
+   Cs.lpszName = (LPCWSTR) &WindowName;
+   Cs.lpszClass = (LPCWSTR) &ClassName;
 
-   if (!W32Thread->rpdesk) IntSetThreadDesktop(DesktopObject,FALSE);
+   pWndDesktop = co_UserCreateWindowEx(&Cs, &ClassName, &WindowName);
+   if (!pWnd)
+   {
+      DPRINT1("Failed to create Desktop window handle\n");
+   }
+   else
+   {
+      DesktopObject->pDeskInfo->spwnd = pWndDesktop;
+   }
+#endif
+
+   if (!ptiCurrent->rpdesk) IntSetThreadDesktop(Desktop,FALSE);
 
   /*
      Based on wine/server/window.c in get_desktop_window.
@@ -1074,13 +1086,12 @@ NtUserCreateDesktop(
 
    ClassName.Buffer = ((PWSTR)((ULONG_PTR)(WORD)(gpsi->atomSysClass[ICLS_HWNDMESSAGE])));
    ClassName.Length = 0;
-   RtlZeroMemory(&MenuName, sizeof(MenuName));
    RtlZeroMemory(&WindowName, sizeof(WindowName));
 
    RtlZeroMemory(&Cs, sizeof(Cs));
    Cs.cx = Cs.cy = 100;
    Cs.style = WS_POPUP|WS_CLIPCHILDREN;
-   Cs.hInstance = hModClient;
+   Cs.hInstance = hModClient; // hModuleWin; // Server side winproc! Leave it to Timo to not pass on notes!
    Cs.lpszName = (LPCWSTR) &WindowName;
    Cs.lpszClass = (LPCWSTR) &ClassName;
 
@@ -1094,9 +1105,22 @@ NtUserCreateDesktop(
       DesktopObject->spwndMessage = pWnd;
    }
 
+   /* Now,,,
+      if !(WinStaObject->Flags & WSF_NOIO) is (not set) for desktop input output mode (see wiki)
+      Create Tooltip. Saved in DesktopObject->spwndTooltip.
+      Tooltip dwExStyle: WS_EX_TOOLWINDOW|WS_EX_TOPMOST
+      hWndParent are spwndMessage. Use hModuleWin for server side winproc!
+      The rest is same as message window.
+      http://msdn.microsoft.com/en-us/library/bb760250(VS.85).aspx
+   */
    RETURN( Desktop);
 
 CLEANUP:
+   if(DesktopName.Buffer != NULL)
+   {
+       ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
+   }
+   if (!NoHooks && ptiCurrent) ptiCurrent->TIF_flags &= ~TIF_DISABLEHOOKS;
    DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_);
    UserLeave();
    END_CLEANUP;
@@ -1126,85 +1150,17 @@ CLEANUP:
 
 HDESK APIENTRY
 NtUserOpenDesktop(
-   PUNICODE_STRING lpszDesktopName,
+   POBJECT_ATTRIBUTES ObjectAttributes,
    DWORD dwFlags,
    ACCESS_MASK dwDesiredAccess)
 {
-   OBJECT_ATTRIBUTES ObjectAttributes;
-   HWINSTA WinSta;
-   PWINSTATION_OBJECT WinStaObject;
-   UNICODE_STRING DesktopName;
-   UNICODE_STRING SafeDesktopName;
    NTSTATUS Status;
    HDESK Desktop;
-   BOOL Result;
-   DECLARE_RETURN(HDESK);
-
-   DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName);
-   UserEnterExclusive();
-
-   /*
-    * Validate the window station handle and compose the fully
-    * qualified desktop name
-    */
-
-   WinSta = UserGetProcessWindowStation();
-   Status = IntValidateWindowStationHandle(
-               WinSta,
-               KernelMode,
-               0,
-               &WinStaObject);
-
-   if (!NT_SUCCESS(Status))
-   {
-      DPRINT1("Failed validation of window station handle (0x%X)\n", WinSta);
-      SetLastNtError(Status);
-      RETURN( 0);
-   }
-
-   if(lpszDesktopName != NULL)
-   {
-      Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
-      if(!NT_SUCCESS(Status))
-      {
-         SetLastNtError(Status);
-         RETURN( NULL);
-         }
-   }
-   else
-   {
-      RtlInitUnicodeString(&SafeDesktopName, NULL);
-   }
-
-   Result = IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
-                                        &SafeDesktopName);
-
-   if (lpszDesktopName)
-      ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
-   ObDereferenceObject(WinStaObject);
-
-
-   if (!Result)
-   {
-      SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
-      RETURN( 0);
-   }
-
-
-   DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
-
-   /* Initialize ObjectAttributes for the desktop object */
-   InitializeObjectAttributes(
-      &ObjectAttributes,
-      &DesktopName,
-      0,
-      NULL,
-      NULL);
 
    Status = ObOpenObjectByName(
-               &ObjectAttributes,
+               ObjectAttributes,
                ExDesktopObjectType,
-               KernelMode,
+               UserMode,
                NULL,
                dwDesiredAccess,
                NULL,
@@ -1213,19 +1169,10 @@ NtUserOpenDesktop(
    if (!NT_SUCCESS(Status))
    {
       SetLastNtError(Status);
-      ExFreePool(DesktopName.Buffer);
-      RETURN( 0);
+      return 0;
    }
 
-   DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
-   ExFreePool(DesktopName.Buffer);
-
-   RETURN( Desktop);
-
-CLEANUP:
-   DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_);
-   UserLeave();
-   END_CLEANUP;
+   return Desktop;
 }
 
 /*
@@ -1398,7 +1345,7 @@ NtUserPaintDesktop(HDC hDC)
    HBRUSH DesktopBrush, PreviousBrush;
    HWND hWndDesktop;
    BOOL doPatBlt = TRUE;
-   PWINDOW_OBJECT WndDesktop;
+   PWND WndDesktop;
    int len;
    COLORREF color_old;
    UINT align_old;
@@ -1420,7 +1367,7 @@ NtUserPaintDesktop(HDC hDC)
       RETURN(FALSE);
    }
 
-   DesktopBrush = (HBRUSH)WndDesktop->Wnd->pcls->hbrBackground;
+   DesktopBrush = (HBRUSH)WndDesktop->pcls->hbrBackground;
 
 
    /*
@@ -1429,7 +1376,7 @@ NtUserPaintDesktop(HDC hDC)
 
    if (WinSta->hbmWallpaper != NULL)
    {
-      PWINDOW_OBJECT DeskWin;
+      PWND DeskWin;
 
       DeskWin = UserGetWindowObject(hWndDesktop);
 
@@ -1439,8 +1386,8 @@ NtUserPaintDesktop(HDC hDC)
          int x, y;
          HDC hWallpaperDC;
 
-         sz.cx = DeskWin->Wnd->rcWindow.right - DeskWin->Wnd->rcWindow.left;
-         sz.cy = DeskWin->Wnd->rcWindow.bottom - DeskWin->Wnd->rcWindow.top;
+         sz.cx = DeskWin->rcWindow.right - DeskWin->rcWindow.left;
+         sz.cy = DeskWin->rcWindow.bottom - DeskWin->rcWindow.top;
 
          if (WinSta->WallpaperMode == wmStretch ||
              WinSta->WallpaperMode == wmTile)
@@ -1669,20 +1616,6 @@ CLEANUP:
    END_CLEANUP;
 }
 
-/*
- * NtUserResolveDesktopForWOW
- *
- * Status
- *    @unimplemented
- */
-
-DWORD APIENTRY
-NtUserResolveDesktopForWOW(DWORD Unknown0)
-{
-   UNIMPLEMENTED
-   return 0;
-}
-
 /*
  * NtUserGetThreadDesktop
  *
@@ -1705,14 +1638,14 @@ NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
 
    if(!dwThreadId)
    {
-      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      EngSetLastError(ERROR_INVALID_PARAMETER);
       RETURN(0);
    }
 
    Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread);
    if(!NT_SUCCESS(Status))
    {
-      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      EngSetLastError(ERROR_INVALID_PARAMETER);
       RETURN(0);
    }
 
@@ -1819,7 +1752,6 @@ IntUnmapDesktopView(IN PDESKTOP DesktopObject)
 static NTSTATUS
 IntMapDesktopView(IN PDESKTOP DesktopObject)
 {
-    PTHREADINFO ti;
     PPROCESSINFO CurrentWin32Process;
     PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
     PVOID UserBase = NULL;
@@ -1882,102 +1814,139 @@ IntMapDesktopView(IN PDESKTOP DesktopObject)
 
     ObReferenceObject(DesktopObject);
 
-    /* create a W32THREADINFO structure if not already done, or update it */
-    ti = GetW32ThreadInfo();
-    GetWin32ClientInfo()->ulClientDelta = DesktopHeapGetUserDelta();
-    if (ti != NULL)
-    {
-        if (GetWin32ClientInfo()->pDeskInfo == NULL)
-        {
-           GetWin32ClientInfo()->pDeskInfo = 
-                (PVOID)((ULONG_PTR)DesktopObject->pDeskInfo - 
-                                          GetWin32ClientInfo()->ulClientDelta);
-        }
-    }
-
     return STATUS_SUCCESS;
 }
 
 BOOL
-IntSetThreadDesktop(IN PDESKTOP DesktopObject,
+IntSetThreadDesktop(IN HDESK hDesktop,
                     IN BOOL FreeOnFailure)
 {
-    PDESKTOP OldDesktop;
+    PDESKTOP DesktopObject = NULL, OldDesktop;
+    HDESK hOldDesktop;
     PTHREADINFO W32Thread;
     NTSTATUS Status;
     BOOL MapHeap;
+    CLIENTTHREADINFO ctiSave;
 
-    DPRINT("IntSetThreadDesktop() DO=%p, FOF=%d\n", DesktopObject, FreeOnFailure);
+    DPRINT("IntSetThreadDesktop() , FOF=%d\n", FreeOnFailure);
     MapHeap = (PsGetCurrentProcess() != PsInitialSystemProcess);
     W32Thread = PsGetCurrentThreadWin32Thread();
 
-    if (W32Thread->rpdesk != DesktopObject)
+    if(hDesktop != NULL)
     {
-        OldDesktop = W32Thread->rpdesk;
-
-        if (!IsListEmpty(&W32Thread->WindowListHead))
+        /* Validate the new desktop. */
+        Status = IntValidateDesktopHandle(
+                    hDesktop,
+                    UserMode,
+                    0,
+                    &DesktopObject);
+
+        if (!NT_SUCCESS(Status))
         {
-            DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
-            SetLastWin32Error(ERROR_BUSY);
+            DPRINT1("Validation of desktop handle (0x%X) failed\n", hDesktop);
             return FALSE;
         }
 
-        W32Thread->rpdesk = DesktopObject;
-
-        if (MapHeap && DesktopObject != NULL)
+        if (W32Thread->rpdesk == DesktopObject)
         {
-            Status = IntMapDesktopView(DesktopObject);
-            if (!NT_SUCCESS(Status))
-            {
-                SetLastNtError(Status);
-                return FALSE;
-            }
+            /* Nothing to do */
+            ObDereferenceObject(DesktopObject);
+            return TRUE;
         }
 
-        /* Hack for system threads */
-        if (NtCurrentTeb())
-        {
-            PCLIENTINFO pci = GetWin32ClientInfo();
-            pci->ulClientDelta = DesktopHeapGetUserDelta();
-            if (DesktopObject)
-            {
-                pci->pDeskInfo = (PVOID)((ULONG_PTR)DesktopObject->pDeskInfo - pci->ulClientDelta);
-            }
-        }
+    }
 
-        if (OldDesktop != NULL &&
-            !IntCheckProcessDesktopClasses(OldDesktop,
-                                           FreeOnFailure))
-        {
-            DPRINT1("Failed to move process classes to shared heap!\n");
+    if (!IsListEmpty(&W32Thread->WindowListHead))
+    {
+        DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
+        EngSetLastError(ERROR_BUSY);
+        return FALSE;
+    }
 
-            /* failed to move desktop classes to the shared heap,
-               unmap the view and return the error */
-            if (MapHeap && DesktopObject != NULL)
-                IntUnmapDesktopView(DesktopObject);
+    OldDesktop = W32Thread->rpdesk;
+    hOldDesktop = W32Thread->hdesk;
 
+    W32Thread->rpdesk = DesktopObject;
+    W32Thread->hdesk = hDesktop;
+
+    if (MapHeap && DesktopObject != NULL)
+    {
+        Status = IntMapDesktopView(DesktopObject);
+        if (!NT_SUCCESS(Status))
+        {
+            SetLastNtError(Status);
             return FALSE;
         }
+        W32Thread->pDeskInfo = DesktopObject->pDeskInfo;
+    }
+
+    RtlZeroMemory(&ctiSave, sizeof(CLIENTTHREADINFO));
+
+    if (W32Thread->pcti && OldDesktop && NtCurrentTeb())
+    {
+        RtlCopyMemory(&ctiSave, W32Thread->pcti, sizeof(CLIENTTHREADINFO));
+        DPRINT("Free ClientThreadInfo\n");
+        DesktopHeapFree(OldDesktop, W32Thread->pcti);
+        W32Thread->pcti = NULL;
+    }
 
-        /* Remove the thread from the old desktop's list */
-        RemoveEntryList(&W32Thread->PtiLink);
+    if (!W32Thread->pcti && DesktopObject && NtCurrentTeb())
+    {
+        DPRINT("Allocate ClientThreadInfo\n");
+        W32Thread->pcti = DesktopHeapAlloc( DesktopObject,
+                                            sizeof(CLIENTTHREADINFO));
+        RtlCopyMemory(W32Thread->pcti, &ctiSave, sizeof(CLIENTTHREADINFO));
+    }
 
-        if (DesktopObject != NULL)
+    if (NtCurrentTeb())
+    {
+        PCLIENTINFO pci = GetWin32ClientInfo();
+        pci->ulClientDelta = DesktopHeapGetUserDelta();
+        if (DesktopObject)
         {
-            ObReferenceObject(DesktopObject);
-            /* Insert into new desktop's list */
-            InsertTailList(&DesktopObject->PtiList, &W32Thread->PtiLink);
+            pci->pDeskInfo = (PVOID)((ULONG_PTR)DesktopObject->pDeskInfo - pci->ulClientDelta);
+            if (W32Thread->pcti) pci->pClientThreadInfo = (PVOID)((ULONG_PTR)W32Thread->pcti - pci->ulClientDelta);
         }
+    }
 
-        if (OldDesktop != NULL)
-        {
-            if (MapHeap)
-            {
-                IntUnmapDesktopView(OldDesktop);
-            }
+    if (OldDesktop != NULL &&
+        !IntCheckProcessDesktopClasses(OldDesktop,
+                                        FreeOnFailure))
+    {
+        DPRINT1("Failed to move process classes to shared heap!\n");
+
+        /* failed to move desktop classes to the shared heap,
+            unmap the view and return the error */
+        if (MapHeap && DesktopObject != NULL)
+            IntUnmapDesktopView(DesktopObject);
+
+        return FALSE;
+    }
+
+    /* Remove the thread from the old desktop's list */
+    RemoveEntryList(&W32Thread->PtiLink);
 
-            ObDereferenceObject(OldDesktop);
+    if (DesktopObject != NULL)
+    {
+        ObReferenceObject(DesktopObject);
+        /* Insert into new desktop's list */
+        InsertTailList(&DesktopObject->PtiList, &W32Thread->PtiLink);
+    }
+
+    /* Close the old desktop */
+    if (OldDesktop != NULL)
+    {
+        if (MapHeap)
+        {
+            IntUnmapDesktopView(OldDesktop);
         }
+
+        ObDereferenceObject(OldDesktop);
+    }
+
+    if (hOldDesktop != NULL)
+    {
+        ZwClose(hOldDesktop);
     }
 
     return TRUE;
@@ -1993,40 +1962,15 @@ IntSetThreadDesktop(IN PDESKTOP DesktopObject,
 BOOL APIENTRY
 NtUserSetThreadDesktop(HDESK hDesktop)
 {
-   PDESKTOP DesktopObject;
-   NTSTATUS Status;
-   DECLARE_RETURN(BOOL);
+   BOOL ret;
 
    UserEnterExclusive();
-   DPRINT("Enter NtUserSetThreadDesktop\n");
-
-   /* Validate the new desktop. */
-   Status = IntValidateDesktopHandle(
-               hDesktop,
-               UserMode,
-               0,
-               &DesktopObject);
-
-   if (!NT_SUCCESS(Status))
-   {
-      DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
-      RETURN(FALSE);
-   }
 
-   /* FIXME: Should check here to see if the thread has any windows. */
+   ret = IntSetThreadDesktop(hDesktop, FALSE);
 
-   if (!IntSetThreadDesktop(DesktopObject,
-                            FALSE))
-   {
-       RETURN(FALSE);
-   }
-
-   RETURN(TRUE);
-
-CLEANUP:
-   DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_);
    UserLeave();
-   END_CLEANUP;
+
+   return ret;
 }
 
 /* EOF */