[SYSSETUP] Apply theming from unattend files very early on when booting the LiveCD or a new install (#7797)

Use a `[Shell]` section with `DefaultThemesOff` and `CustomDefaultThemeFile`
values, specifying respectively whether to use the classic theme or a
custom one, and the complete path to the custom .theme (or .msstyles) file.

These values are compatible with those documented in the
"MS Windows Preinstallation Reference" help file
of the Windows installation CD (DEPLOY.CAB\ref.chm)

[BOOTDATA] bootcd/unattend.inf: Use the Shell/CustomDefaultThemeFile value to specify which theme to use
This commit is contained in:
Hermès Bélusca-Maïto 2025-03-18 13:52:39 +01:00
parent 8e2d1b358c
commit 2e47094764
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
3 changed files with 153 additions and 16 deletions

View file

@ -59,16 +59,12 @@ LocaleID = 409
; 1: ReactOS Workstation
ProductOption = 0
; enable this section to automatically launch programs
; Enable this section to automatically launch programs
; after 3rd boot
;
; [GuiRunOnce]
; %SystemRoot%\system32\cmd.exe
; Enable the next line (+ the GuiRunOnce section) to enable the lautus theme
; "rundll32.exe shell32.dll,Control_RunDLL desk.cpl desk,@Appearance /Action:ActivateMSTheme /file:%SYSTEMROOT%\Resources\themes\lautus\lautus.msstyles"
; enable this section to change resolution / bpp
; Enable this section to change resolution / bpp
; setting a value to 0 or skipping it will leave it unchanged
; [Display]
; BitsPerPel = 32
@ -80,3 +76,8 @@ ProductOption = 0
;[Env]
;WINETEST_PLATFORM=reactos
; Enable this section to enable the default ReactOS theme
; [Shell]
; DefaultThemesOff = no
; CustomDefaultThemeFile = "%WINDIR%\Resources\Themes\Lautus\lautus.msstyles"

View file

@ -985,6 +985,61 @@ cleanup:
return bConsoleBoot;
}
extern VOID
EnableVisualTheme(
_In_opt_ HWND hwndParent,
_In_opt_ PCWSTR ThemeFile);
/**
* @brief
* Pre-process unattended file to apply early settings.
*
* @param[in] IsInstall
* TRUE if this is ReactOS installation, invoked from InstallReactOS(),
* FALSE if this is run as part of LiveCD, invoked form InstallLiveCD().
**/
static VOID
PreprocessUnattend(
_In_ BOOL IsInstall)
{
WCHAR szPath[MAX_PATH];
WCHAR szValue[MAX_PATH];
BOOL bDefaultThemesOff;
if (IsInstall)
{
/* See also wizard.c!ProcessSetupInf()
* Retrieve the path of the setup INF */
GetSystemDirectoryW(szPath, _countof(szPath));
wcscat(szPath, L"\\$winnt$.inf");
}
else
{
/* See also userinit/livecd.c!RunLiveCD() */
GetWindowsDirectoryW(szPath, _countof(szPath));
wcscat(szPath, L"\\unattend.inf");
}
/*
* Apply initial default theming
*/
/* Check whether to use the classic theme (TRUE) instead of the default theme */
bDefaultThemesOff = FALSE;
if (GetPrivateProfileStringW(L"Shell", L"DefaultThemesOff", L"no", szValue, _countof(szValue), szPath) && *szValue)
bDefaultThemesOff = (_wcsicmp(szValue, L"yes") == 0);
if (!bDefaultThemesOff)
{
/* Retrieve the complete path to a .theme (or for ReactOS, a .msstyles) file */
if (!GetPrivateProfileStringW(L"Shell", L"CustomDefaultThemeFile", NULL, szValue, _countof(szValue), szPath) || !*szValue)
bDefaultThemesOff = TRUE; // None specified, fall back to the classic theme.
}
/* Enable the chosen theme, or use the classic theme */
EnableVisualTheme(NULL, bDefaultThemesOff ? NULL : szValue);
}
static BOOL
CommonInstall(VOID)
{
@ -1007,7 +1062,7 @@ CommonInstall(VOID)
goto Exit;
}
if(!InstallSysSetupInfComponents())
if (!InstallSysSetupInfComponents())
{
FatalError("InstallSysSetupInfComponents() failed!\n");
goto Exit;
@ -1038,7 +1093,6 @@ CommonInstall(VOID)
bResult = TRUE;
Exit:
if (bResult == FALSE)
{
SetupCloseInfFile(hSysSetupInf);
@ -1062,6 +1116,7 @@ InstallLiveCD(VOID)
PROCESS_INFORMATION ProcessInformation;
BOOL bRes;
PreprocessUnattend(FALSE);
if (!CommonInstall())
goto error;
@ -1579,6 +1634,7 @@ InstallReactOS(VOID)
hHotkeyThread = CreateThread(NULL, 0, HotkeyThread, NULL, 0, NULL);
PreprocessUnattend(TRUE);
if (!CommonInstall())
return 0;

View file

@ -52,7 +52,6 @@ typedef struct _TIMEZONE_ENTRY
extern void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow);
static VOID
CenterWindow(HWND hWnd)
{
@ -1367,6 +1366,90 @@ RunControlPanelApplet(HWND hwnd, PCWSTR pwszCPLParameters)
return TRUE;
}
VOID
EnableVisualTheme(
_In_opt_ HWND hwndParent,
_In_opt_ PCWSTR ThemeFile)
{
enum { THEME_FILE, STYLE_FILE, UNKNOWN } fType;
WCHAR szPath[MAX_PATH]; // Expanded path of the file to use.
WCHAR szStyleFile[MAX_PATH];
fType = THEME_FILE; // Default to Classic theme.
if (ThemeFile)
{
/* Expand the path if possible */
if (ExpandEnvironmentStringsW(ThemeFile, szPath, _countof(szPath)) != 0)
ThemeFile = szPath;
/* Determine the file type from its extension */
fType = UNKNOWN; {
PCWSTR pszExt = wcsrchr(ThemeFile, L'.'); // PathFindExtensionW(ThemeFile);
if (pszExt)
{
if (_wcsicmp(pszExt, L".theme") == 0)
fType = THEME_FILE;
else if (_wcsicmp(pszExt, L".msstyles") == 0)
fType = STYLE_FILE;
} }
if (fType == UNKNOWN)
{
DPRINT1("EnableVisualTheme(): Unknown file '%S'\n", ThemeFile);
return;
}
}
DPRINT1("Applying visual %s '%S'\n",
(fType == THEME_FILE) ? "theme" : "style",
ThemeFile ? ThemeFile : L"(Classic)");
//
// TODO: Use instead uxtheme!SetSystemVisualStyle() once it is implemented,
// https://stackoverflow.com/a/1036903
// https://pinvoke.net/default.aspx/uxtheme.SetSystemVisualStyle
// or ApplyTheme(NULL, 0, NULL) for restoring the classic theme.
//
// NOTE: The '/Action:ActivateMSTheme' is ReactOS-specific.
//
if (ThemeFile && (fType == THEME_FILE))
{
/* Retrieve the visual style specified in the theme file.
* If none, fall back to the classic theme. */
if (GetPrivateProfileStringW(L"VisualStyles", L"Path", NULL,
szStyleFile, _countof(szStyleFile), ThemeFile) && *szStyleFile)
{
/* Expand the path if possible */
ThemeFile = szStyleFile;
if (ExpandEnvironmentStringsW(ThemeFile, szPath, _countof(szPath)) != 0)
ThemeFile = szPath;
}
else
{
ThemeFile = NULL;
}
DPRINT1("--> Applying visual style '%S'\n",
ThemeFile ? ThemeFile : L"(Classic)");
}
if (ThemeFile)
{
WCHAR wszParams[1024];
// FIXME: L"desk.cpl desk,@Appearance" regression, see commit 50d260a7f0
PCWSTR format = L"desk.cpl,,2 /Action:ActivateMSTheme /file:\"%s\"";
StringCchPrintfW(wszParams, _countof(wszParams), format, ThemeFile);
RunControlPanelApplet(hwndParent, wszParams);
}
else
{
RunControlPanelApplet(hwndParent, L"desk.cpl,,2 /Action:ActivateMSTheme");
}
}
static VOID
WriteUserLocale(VOID)
{
@ -1927,13 +2010,14 @@ ThemePageDlgProc(HWND hwndDlg,
/* Register the imagelist */
ListView_SetImageList(hListView, himl, LVSIL_NORMAL);
/* Transparant background */
/* Transparent background */
ListView_SetBkColor(hListView, CLR_NONE);
ListView_SetTextBkColor(hListView, CLR_NONE);
/* Reduce the size between the items */
ListView_SetIconSpacing(hListView, 190, 173);
break;
}
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code)
{
@ -1947,17 +2031,13 @@ ThemePageDlgProc(HWND hwndDlg,
if (Themes[iTheme].ThemeFile)
{
WCHAR wszParams[1024];
WCHAR wszTheme[MAX_PATH];
WCHAR* format = L"desk.cpl,,2 /Action:ActivateMSTheme /file:\"%s\"";
SHGetFolderPathAndSubDirW(0, CSIDL_RESOURCES, NULL, SHGFP_TYPE_DEFAULT, Themes[iTheme].ThemeFile, wszTheme);
swprintf(wszParams, format, wszTheme);
RunControlPanelApplet(hwndDlg, wszParams);
EnableVisualTheme(hwndDlg, wszTheme);
}
else
{
RunControlPanelApplet(hwndDlg, L"desk.cpl,,2 /Action:ActivateMSTheme");
EnableVisualTheme(hwndDlg, Themes[iTheme].ThemeFile);
}
}
break;