[NTUSER] Release WinSta->spklList at IntWinStaObjectDelete (#4593)
[reactos.git] / win32ss / user / ntuser / winsta.c
index 13b9685..4c91558 100644 (file)
@@ -28,7 +28,7 @@ UNICODE_STRING gustrWindowStationsDir;
 
 /* INITIALIZATION FUNCTIONS ****************************************************/
 
-INIT_FUNCTION
+CODE_SEG("INIT")
 NTSTATUS
 NTAPI
 InitWindowStationImpl(VOID)
@@ -128,6 +128,8 @@ IntWinStaObjectDelete(
 
     RtlDestroyAtomTable(WinSta->AtomTable);
 
+    UserAssignmentUnlock((PVOID*)&WinSta->spklList);
+
     return STATUS_SUCCESS;
 }
 
@@ -263,6 +265,12 @@ co_IntInitializeDesktopGraphics(VOID)
     UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
     PDESKTOP pdesk;
 
+    if (PDEVOBJ_lChangeDisplaySettings(NULL, NULL, NULL, &gpmdev, TRUE) != DISP_CHANGE_SUCCESSFUL)
+    {
+        ERR("PDEVOBJ_lChangeDisplaySettings() failed.\n");
+        return FALSE;
+    }
+
     ScreenDeviceContext = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, FALSE);
     if (NULL == ScreenDeviceContext)
     {
@@ -271,7 +279,7 @@ co_IntInitializeDesktopGraphics(VOID)
     }
     GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_PUBLIC);
 
-    if (! IntCreatePrimarySurface())
+    if (!IntCreatePrimarySurface())
     {
         return FALSE;
     }
@@ -281,9 +289,15 @@ co_IntInitializeDesktopGraphics(VOID)
     NtGdiSelectFont(hSystemBM, NtGdiGetStockObject(SYSTEM_FONT));
     GreSetDCOwner(hSystemBM, GDI_OBJ_HMGR_PUBLIC);
 
+    /* Update the system metrics */
+    InitMetrics();
+
+    /* Set new size of the monitor */
+    UserUpdateMonitorSize((HDEV)gpmdev->ppdevGlobal);
+
     /* Update the SERVERINFO */
-    gpsi->aiSysMet[SM_CXSCREEN] = gppdevPrimary->gdiinfo.ulHorzRes;
-    gpsi->aiSysMet[SM_CYSCREEN] = gppdevPrimary->gdiinfo.ulVertRes;
+    gpsi->aiSysMet[SM_CXSCREEN] = gpmdev->ppdevGlobal->gdiinfo.ulHorzRes;
+    gpsi->aiSysMet[SM_CYSCREEN] = gpmdev->ppdevGlobal->gdiinfo.ulVertRes;
     gpsi->Planes        = NtGdiGetDeviceCaps(ScreenDeviceContext, PLANES);
     gpsi->BitsPixel     = NtGdiGetDeviceCaps(ScreenDeviceContext, BITSPIXEL);
     gpsi->BitCount      = gpsi->Planes * gpsi->BitsPixel;
@@ -293,7 +307,9 @@ co_IntInitializeDesktopGraphics(VOID)
         gpsi->PUSIFlags |= PUSIF_PALETTEDISPLAY;
     }
     else
+    {
         gpsi->PUSIFlags &= ~PUSIF_PALETTEDISPLAY;
+    }
     // Font is realized and this dc was previously set to internal DC_ATTR.
     gpsi->cxSysFontChar = IntGetCharDimensions(hSystemBM, &tmw, (DWORD*)&gpsi->cySysFontChar);
     gpsi->tmSysFont     = tmw;
@@ -303,7 +319,7 @@ co_IntInitializeDesktopGraphics(VOID)
     gpsi->ptCursor.y = gpsi->aiSysMet[SM_CYSCREEN] / 2;
 
     /* Attach monitor */
-    UserAttachMonitor((HDEV)gppdevPrimary);
+    UserAttachMonitor((HDEV)gpmdev->ppdevGlobal);
 
     /* Setup the cursor */
     co_IntLoadDefaultCursors();
@@ -319,6 +335,22 @@ co_IntInitializeDesktopGraphics(VOID)
     ASSERT(pdesk);
     co_IntShowDesktop(pdesk, gpsi->aiSysMet[SM_CXSCREEN], gpsi->aiSysMet[SM_CYSCREEN], TRUE);
 
+    /* HACK: display wallpaper on all secondary displays */
+    {
+        PGRAPHICS_DEVICE pGraphicsDevice;
+        UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
+        UNICODE_STRING DisplayName;
+        HDC hdc;
+        ULONG iDevNum;
+
+        for (iDevNum = 1; (pGraphicsDevice = EngpFindGraphicsDevice(NULL, iDevNum)) != NULL; iDevNum++)
+        {
+            RtlInitUnicodeString(&DisplayName, pGraphicsDevice->szWinDeviceName);
+            hdc = IntGdiCreateDC(&DriverName, &DisplayName, NULL, NULL, FALSE);
+            IntPaintDesktop(hdc);
+        }
+    }
+
     return TRUE;
 }
 
@@ -497,7 +529,20 @@ IntCreateWindowStation(
 
         InputWindowStation = WindowStation;
         WindowStation->Flags &= ~WSS_NOIO;
+
         InitCursorImpl();
+
+        UserCreateSystemThread(ST_DESKTOP_THREAD);
+        UserCreateSystemThread(ST_RIT);
+
+        /* Desktop functions require the desktop thread running so wait for it to initialize */
+        UserLeaveCo();
+        KeWaitForSingleObject(gpDesktopThreadStartedEvent,
+                              UserRequest,
+                              UserMode,
+                              FALSE,
+                              NULL);
+        UserEnterCo();
     }
     else
     {
@@ -508,6 +553,8 @@ IntCreateWindowStation(
           ObjectAttributes->ObjectName, WindowStation, hWinSta);
 
     *phWinSta = hWinSta;
+    EngSetLastError(ERROR_SUCCESS);
+
     return STATUS_SUCCESS;
 }
 
@@ -742,6 +789,8 @@ NtUserCreateWindowStation(
         return NULL;
     }
 
+    UserEnterExclusive();
+
     /* Create the window station */
     Status = IntCreateWindowStation(&hWinSta,
                                     ObjectAttributes,
@@ -753,6 +802,8 @@ NtUserCreateWindowStation(
                                     Unknown4,
                                     Unknown5,
                                     Unknown6);
+    UserLeave();
+
     if (NT_SUCCESS(Status))
     {
         TRACE("NtUserCreateWindowStation created window station '%wZ' with handle 0x%p\n",
@@ -972,7 +1023,6 @@ NtUserCloseWindowStation(
                                             0,
                                             &Object,
                                             NULL);
-
     if (!NT_SUCCESS(Status))
     {
         ERR("Validation of window station handle (%p) failed\n", hWinSta);
@@ -1319,11 +1369,11 @@ NtUserGetProcessWindowStation(VOID)
 BOOL FASTCALL
 UserSetProcessWindowStation(HWINSTA hWindowStation)
 {
-    PPROCESSINFO ppi;
     NTSTATUS Status;
-    HWINSTA hwinstaOld;
+    PPROCESSINFO ppi;
     OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
     PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
+    HWINSTA hCacheWinSta;
 
     ppi = PsGetCurrentProcessWin32Process();
 
@@ -1337,15 +1387,14 @@ UserSetProcessWindowStation(HWINSTA hWindowStation)
                                                 &ObjectHandleInfo);
         if (!NT_SUCCESS(Status))
         {
-            TRACE("Validation of window station handle (%p) failed\n",
-                  hWindowStation);
+            TRACE("Validation of window station handle 0x%p failed\n", hWindowStation);
             SetLastNtError(Status);
             return FALSE;
         }
     }
 
     OldWinSta = ppi->prpwinsta;
-    hwinstaOld = PsGetProcessWin32WindowStation(ppi->peProcess);
+    hCacheWinSta = PsGetProcessWin32WindowStation(ppi->peProcess);
 
     /* Dereference the previous window station */
     if (OldWinSta != NULL)
@@ -1353,17 +1402,64 @@ UserSetProcessWindowStation(HWINSTA hWindowStation)
         ObDereferenceObject(OldWinSta);
     }
 
-    /* Check if we have a stale handle (it should happen for console apps) */
-    if (hwinstaOld != ppi->hwinsta)
-    {
-        ObCloseHandle(hwinstaOld, UserMode);
-    }
-
     /*
-     * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
+     * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects?
      */
 
-    PsSetProcessWindowStation(ppi->peProcess, hWindowStation);
+    /* Close the cached EPROCESS window station handle if needed */
+    if (hCacheWinSta != NULL)
+    {
+        /* Reference the window station */
+        Status = ObReferenceObjectByHandle(hCacheWinSta,
+                                           0,
+                                           ExWindowStationObjectType,
+                                           UserMode,
+                                           (PVOID*)&OldWinSta,
+                                           NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("Failed to reference the inherited window station, Status 0x%08lx\n", Status);
+            /* We failed, reset the cache */
+            hCacheWinSta = NULL;
+            PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
+        }
+        else
+        {
+            /*
+             * Close the old handle and reset the cache only
+             * if we are setting a different window station.
+             */
+            if (NewWinSta != OldWinSta)
+            {
+                ObCloseHandle(hCacheWinSta, UserMode);
+                hCacheWinSta = NULL;
+                PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
+            }
+
+            /* Dereference the window station */
+            ObDereferenceObject(OldWinSta);
+        }
+    }
+
+    /* Duplicate and save a new cached EPROCESS window station handle */
+    if ((hCacheWinSta == NULL) && (hWindowStation != NULL))
+    {
+        Status = ZwDuplicateObject(ZwCurrentProcess(),
+                                   hWindowStation,
+                                   ZwCurrentProcess(),
+                                   (PHANDLE)&hCacheWinSta,
+                                   0,
+                                   0,
+                                   DUPLICATE_SAME_ACCESS);
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("UserSetProcessWindowStation: Failed to duplicate the window station handle, Status 0x%08lx\n", Status);
+        }
+        else
+        {
+            PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
+        }
+    }
 
     ppi->prpwinsta = NewWinSta;
     ppi->hwinsta = hWindowStation;
@@ -1383,7 +1479,7 @@ UserSetProcessWindowStation(HWINSTA hWindowStation)
     {
         ppi->W32PF_flags |= W32PF_IOWINSTA;
     }
-    else // Might be closed if the handle is null.
+    else /* Might be closed if the handle is NULL */
     {
         ppi->W32PF_flags &= ~W32PF_IOWINSTA;
     }