From 9c0efba4b3157001862668f877df3edbc2e174b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Tue, 20 Jan 2026 21:29:01 +0100 Subject: [PATCH] [USERINIT] Hide install option on LiveCD when no installer is available (#8614) RELEASE-8 --- base/setup/welcome/welcome.c | 2 +- base/system/userinit/livecd.c | 15 ++++-- base/system/userinit/userinit.c | 81 +++++++++++++++++++++------------ base/system/userinit/userinit.h | 7 ++- 4 files changed, 71 insertions(+), 34 deletions(-) diff --git a/base/setup/welcome/welcome.c b/base/setup/welcome/welcome.c index 921588bb269..9c642d9c4c7 100644 --- a/base/setup/welcome/welcome.c +++ b/base/setup/welcome/welcome.c @@ -212,7 +212,7 @@ VOID TranslateEscapes(IN OUT LPTSTR lpString) /* * Expands the path for the ReactOS Installer "reactos.exe". - * See also base/system/userinit/userinit.c!StartInstaller() + * See also base/system/userinit/userinit.c!ExpandInstallerPath() */ BOOL ExpandInstallerPath( diff --git a/base/system/userinit/livecd.c b/base/system/userinit/livecd.c index a3479d2dd59..25322e46a9f 100644 --- a/base/system/userinit/livecd.c +++ b/base/system/userinit/livecd.c @@ -630,7 +630,7 @@ LocaleDlgProc( switch (uMsg) { case WM_INITDIALOG: - /* Save pointer to the global state */ + /* Save pointer to the state */ pState = (PSTATE)lParam; SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pState); @@ -768,6 +768,9 @@ StartDlgProc( switch (uMsg) { case WM_INITDIALOG: + { + WCHAR Installer[MAX_PATH]; + /* Save pointer to the state */ pState = (PSTATE)lParam; SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pState); @@ -775,13 +778,19 @@ StartDlgProc( /* Center the dialog window */ CenterWindow(hwndDlg); - if (pState->Unattend->bEnabled) + /* Check whether we can find the ReactOS installer. If not, + * disable the "Install" button and directly start the LiveCD. */ + *Installer = UNICODE_NULL; + if (!ExpandInstallerPath(L"reactos.exe", Installer, ARRAYSIZE(Installer))) + EnableWindow(GetDlgItem(hwndDlg, IDC_INSTALL), FALSE); + + if (pState->Unattend->bEnabled || (*Installer == UNICODE_NULL)) { /* Click on the 'Run' button */ PostMessageW(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_RUN, BN_CLICKED), 0L); } - return FALSE; + } case WM_DRAWITEM: OnDrawItem((LPDRAWITEMSTRUCT)lParam, diff --git a/base/system/userinit/userinit.c b/base/system/userinit/userinit.c index e2438b64ea2..d525601bc10 100644 --- a/base/system/userinit/userinit.c +++ b/base/system/userinit/userinit.c @@ -480,20 +480,26 @@ NotifyLogon(VOID) FreeLibrary(hModule); } -static BOOL -StartInstaller(IN LPCTSTR lpInstallerName) +/* + * Expands the path for the ReactOS Installer "reactos.exe". + * See also base/setup/welcome/welcome.c!ExpandInstallerPath() + */ +BOOL +ExpandInstallerPath( + IN LPCWSTR lpInstallerName, + OUT LPWSTR lpInstallerPath, + IN SIZE_T PathSize) { SYSTEM_INFO SystemInfo; SIZE_T cchInstallerNameLen; PWSTR ptr; DWORD dwAttribs; - WCHAR Installer[MAX_PATH]; - WCHAR szMsg[RC_STRING_MAX_SIZE]; cchInstallerNameLen = wcslen(lpInstallerName); - if (ARRAYSIZE(Installer) < cchInstallerNameLen) + if (PathSize < cchInstallerNameLen) { /* The buffer is not large enough to contain the installer file name */ + *lpInstallerPath = UNICODE_NULL; return FALSE; } @@ -504,52 +510,52 @@ StartInstaller(IN LPCTSTR lpInstallerName) */ GetSystemInfo(&SystemInfo); - *Installer = UNICODE_NULL; + *lpInstallerPath = UNICODE_NULL; /* Alternatively one can use SharedUserData->NtSystemRoot */ - GetSystemWindowsDirectoryW(Installer, ARRAYSIZE(Installer) - cchInstallerNameLen - 1); - ptr = wcschr(Installer, L'\\'); + GetSystemWindowsDirectoryW(lpInstallerPath, PathSize - cchInstallerNameLen - 1); + ptr = wcschr(lpInstallerPath, L'\\'); if (ptr) *++ptr = UNICODE_NULL; else - *Installer = UNICODE_NULL; + *lpInstallerPath = UNICODE_NULL; /* Append the corresponding CPU architecture */ switch (SystemInfo.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL: - StringCchCatW(Installer, ARRAYSIZE(Installer), L"I386"); + StringCchCatW(lpInstallerPath, PathSize, L"I386"); break; case PROCESSOR_ARCHITECTURE_MIPS: - StringCchCatW(Installer, ARRAYSIZE(Installer), L"MIPS"); + StringCchCatW(lpInstallerPath, PathSize, L"MIPS"); break; case PROCESSOR_ARCHITECTURE_ALPHA: - StringCchCatW(Installer, ARRAYSIZE(Installer), L"ALPHA"); + StringCchCatW(lpInstallerPath, PathSize, L"ALPHA"); break; case PROCESSOR_ARCHITECTURE_PPC: - StringCchCatW(Installer, ARRAYSIZE(Installer), L"PPC"); + StringCchCatW(lpInstallerPath, PathSize, L"PPC"); break; case PROCESSOR_ARCHITECTURE_SHX: - StringCchCatW(Installer, ARRAYSIZE(Installer), L"SHX"); + StringCchCatW(lpInstallerPath, PathSize, L"SHX"); break; case PROCESSOR_ARCHITECTURE_ARM: - StringCchCatW(Installer, ARRAYSIZE(Installer), L"ARM"); + StringCchCatW(lpInstallerPath, PathSize, L"ARM"); break; case PROCESSOR_ARCHITECTURE_IA64: - StringCchCatW(Installer, ARRAYSIZE(Installer), L"IA64"); + StringCchCatW(lpInstallerPath, PathSize, L"IA64"); break; case PROCESSOR_ARCHITECTURE_ALPHA64: - StringCchCatW(Installer, ARRAYSIZE(Installer), L"ALPHA64"); + StringCchCatW(lpInstallerPath, PathSize, L"ALPHA64"); break; case PROCESSOR_ARCHITECTURE_AMD64: - StringCchCatW(Installer, ARRAYSIZE(Installer), L"AMD64"); + StringCchCatW(lpInstallerPath, PathSize, L"AMD64"); break; // case PROCESSOR_ARCHITECTURE_MSIL: /* .NET CPU-independent code */ @@ -561,33 +567,50 @@ StartInstaller(IN LPCTSTR lpInstallerName) } if (SystemInfo.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_UNKNOWN) - StringCchCatW(Installer, ARRAYSIZE(Installer), L"\\"); - StringCchCatW(Installer, ARRAYSIZE(Installer), lpInstallerName); + StringCchCatW(lpInstallerPath, PathSize, L"\\"); + StringCchCatW(lpInstallerPath, PathSize, lpInstallerName); - dwAttribs = GetFileAttributesW(Installer); + dwAttribs = GetFileAttributesW(lpInstallerPath); if ((dwAttribs != INVALID_FILE_ATTRIBUTES) && !(dwAttribs & FILE_ATTRIBUTE_DIRECTORY)) { /* We have found the installer */ - if (StartProcess(Installer)) - return TRUE; + return TRUE; } - ERR("Failed to start the installer '%s', trying alternative.\n", debugstr_w(Installer)); + WARN("Couldn't find the installer '%s', trying alternative.\n", debugstr_w(lpInstallerPath)); /* * We failed. Try to find the installer from either the current * ReactOS installation directory, or from our current directory. */ - *Installer = UNICODE_NULL; + *lpInstallerPath = UNICODE_NULL; /* Alternatively one can use SharedUserData->NtSystemRoot */ - if (GetSystemWindowsDirectoryW(Installer, ARRAYSIZE(Installer) - cchInstallerNameLen - 1)) - StringCchCatW(Installer, ARRAYSIZE(Installer), L"\\"); - StringCchCatW(Installer, ARRAYSIZE(Installer), lpInstallerName); + if (GetSystemWindowsDirectoryW(lpInstallerPath, PathSize - cchInstallerNameLen - 1)) + StringCchCatW(lpInstallerPath, PathSize, L"\\"); + StringCchCatW(lpInstallerPath, PathSize, lpInstallerName); - dwAttribs = GetFileAttributesW(Installer); + dwAttribs = GetFileAttributesW(lpInstallerPath); if ((dwAttribs != INVALID_FILE_ATTRIBUTES) && !(dwAttribs & FILE_ATTRIBUTE_DIRECTORY)) + { + /* We have found the installer */ + return TRUE; + } + + /* Installer not found */ + ERR("Couldn't find the installer '%s'.\n", debugstr_w(lpInstallerPath)); + *lpInstallerPath = UNICODE_NULL; + return FALSE; +} + +static BOOL +StartInstaller(IN LPCWSTR lpInstallerName) +{ + WCHAR Installer[MAX_PATH]; + WCHAR szMsg[RC_STRING_MAX_SIZE]; + + if (ExpandInstallerPath(lpInstallerName, Installer, ARRAYSIZE(Installer))) { /* We have found the installer */ if (StartProcess(Installer)) diff --git a/base/system/userinit/userinit.h b/base/system/userinit/userinit.h index c34f287d09c..ecb0fa8205c 100644 --- a/base/system/userinit/userinit.h +++ b/base/system/userinit/userinit.h @@ -71,8 +71,13 @@ ReadRegSzKey( OUT LPWSTR *pValue); BOOL -IsLiveCD(VOID); +ExpandInstallerPath( + IN LPCWSTR lpInstallerName, + OUT LPWSTR lpInstallerPath, + IN SIZE_T PathSize); +BOOL +IsLiveCD(VOID); VOID RunLiveCD(