[SYSSETUP][BOOTDATA] Unattended execute GuiUnattended:DetachedProgram , SetupParams:UserExecute (#9276)

This PR implements two of the three hooks that allows you to run custom
applications during 2nd-stage setup (the 3rd hook is `...\$OEM$\Cmdlines.txt`,
but that requires file copy operations, etc.)

- `DetachedProgram` is documented[^1] for NT4...2003; it is started before
  installation and `UserExecute` after.
- `UserExecute` is a great place to install VM Guest Additions, one reboot
  less and you have shared folders/clipboard on the first normal boot.

[^1]: https://web.archive.org/web/20090902145959/http://technet.microsoft.com/en-us/library/cc757642(WS.10).aspx
This commit is contained in:
Whindmar Saksit
2026-07-16 23:22:27 +02:00
committed by GitHub
parent a5f51269c8
commit 30b02d038e
5 changed files with 80 additions and 25 deletions
+2
View File
@@ -235,6 +235,7 @@ InstallSetupInfFile(
if (!IniCache)
return;
#if 0 /* If you need to put something in this section, do it after the merge with Unattend.inf */
IniSection = IniAddSection(IniCache, L"SetupParams");
if (IniSection)
{
@@ -243,6 +244,7 @@ InstallSetupInfFile(
// L"\"%s\"", L"WinNt5.2");
// IniAddKey(IniSection, L"Version", PathBuffer);
}
#endif
IniSection = IniAddSection(IniCache, L"Data");
if (IniSection)
+9
View File
@@ -59,6 +59,15 @@ LocaleID = 409
; 3 - ReactOS Nano Server (Reserved)
InstallationType = 0
;[GuiUnattended]
; Run a program early in 2nd-stage setup.
;DetachedProgram=%SystemRoot%\system32\cmd.exe
;Arguments="/C echo.Early 2nd-stage setup...&choice>nul /N /T:Y,5"
;[SetupParams]
; Run a program at the end of 2nd-stage setup.
;UserExecute="cmd.exe /C echo.End of 2nd-stage setup...&choice>nul /N /T:Y,5"
; Enable this section to automatically launch programs after 3rd boot.
;[GuiRunOnce]
;%SystemRoot%\system32\cmd.exe
+9 -1
View File
@@ -73,6 +73,10 @@ HRESULT
InstallOptionalComponents(
_In_ PITEMSDATA pItemsData);
HRESULT
RunCommandAndWait(
_In_ PWCHAR Command);
/* install */
BOOL
@@ -109,6 +113,10 @@ VOID
SetAutoAdminLogon(VOID);
/* wizard.c */
VOID InstallWizard (VOID);
VOID
InstallWizard(VOID);
VOID
GetSetupInfPath(PWSTR szPath, UINT cchMax);
/* EOF */
+25 -2
View File
@@ -4,6 +4,7 @@
* PURPOSE: System setup
* FILE: dll/win32/syssetup/install.c
* PROGRAMER: Eric Kohl
* Whindmar Saksit <[email protected]>
*/
/* INCLUDES *****************************************************************/
@@ -985,6 +986,26 @@ cleanup:
return bConsoleBoot;
}
static VOID
ProcessDetachedProgram(
_In_ PCWSTR pszInf)
{
WCHAR szInfApp[MAX_PATH], szInfArg[MAX_PATH * 3];
WCHAR szCmd[_countof(szInfApp) + _countof(szInfArg)];
UINT cch;
if (!GetPrivateProfileStringW(L"GuiUnattended", L"DetachedProgram", L"", szInfApp, _countof(szInfApp), pszInf) || !*szInfApp)
return;
cch = ExpandEnvironmentStrings(szInfApp, szCmd, _countof(szCmd) - 1);
if (GetPrivateProfileStringW(L"GuiUnattended", L"Arguments", L"", szInfArg, _countof(szInfArg), pszInf) && cch)
{
szCmd[cch - 1] = L' ';
szCmd[cch] = UNICODE_NULL;
ExpandEnvironmentStrings(szInfArg, szCmd + cch, _countof(szCmd) - cch);
}
RunCommandAndWait(szCmd);
}
extern VOID
EnableVisualTheme(
_In_opt_ HWND hwndParent,
@@ -1010,8 +1031,7 @@ PreprocessUnattend(
{
/* See also wizard.c!ProcessSetupInf()
* Retrieve the path of the setup INF */
GetSystemDirectoryW(szPath, _countof(szPath));
wcscat(szPath, L"\\$winnt$.inf");
GetSetupInfPath(szPath, _countof(szPath));
}
else
{
@@ -1038,6 +1058,9 @@ PreprocessUnattend(
/* Enable the chosen theme, or use the classic theme */
EnableVisualTheme(NULL, bDefaultThemesOff ? NULL : szValue);
if (IsInstall)
ProcessDetachedProgram(szPath);
}
static BOOL
+35 -22
View File
@@ -53,6 +53,13 @@ typedef struct _TIMEZONE_ENTRY
extern void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow);
VOID
GetSetupInfPath(PWSTR szPath, UINT cchMax)
{
GetSystemDirectoryW(szPath, cchMax);
wcscat(szPath, L"\\$winnt$.inf");
}
static VOID
CenterWindow(HWND hWnd)
{
@@ -2740,31 +2747,38 @@ ProcessPageDlgProc(HWND hwndDlg,
static VOID
SetInstallationCompleted(VOID)
SetInstallationCompleted(IN BOOL Unattended)
{
HKEY hKey = 0;
DWORD InProgress = 0;
DWORD InstallDate;
if (RegOpenKeyExW( HKEY_LOCAL_MACHINE,
L"SYSTEM\\Setup",
0,
KEY_WRITE,
&hKey ) == ERROR_SUCCESS)
{
RegSetValueExW( hKey, L"SystemSetupInProgress", 0, REG_DWORD, (LPBYTE)&InProgress, sizeof(InProgress) );
RegCloseKey( hKey );
}
if (RegOpenKeyExW( HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows NT\\CurrentVersion",
0,
KEY_WRITE,
&hKey ) == ERROR_SUCCESS)
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion",
0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
{
InstallDate = (DWORD)time(NULL);
RegSetValueExW( hKey, L"InstallDate", 0, REG_DWORD, (LPBYTE)&InstallDate, sizeof(InstallDate) );
RegCloseKey( hKey );
RegSetValueExW(hKey, L"InstallDate", 0, REG_DWORD, (LPBYTE)&InstallDate, sizeof(InstallDate));
RegCloseKey(hKey);
}
if (Unattended)
{
WCHAR szInf[MAX_PATH];
WCHAR szInfCmd[MAX_PATH * 4], szCmd[_countof(szInfCmd)];
GetSetupInfPath(szInf, _countof(szInf));
if (GetPrivateProfileStringW(L"SetupParams", L"UserExecute", L"", szInfCmd, _countof(szInfCmd), szInf) && *szInfCmd)
{
*szCmd = UNICODE_NULL;
ExpandEnvironmentStringsW(szInfCmd, szCmd, _countof(szInfCmd));
RunCommandAndWait(szCmd);
}
}
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\Setup", 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
{
RegSetValueExW(hKey, L"SystemSetupInProgress", 0, REG_DWORD, (LPBYTE)&InProgress, sizeof(InProgress));
RegCloseKey(hKey);
}
}
@@ -2790,7 +2804,7 @@ FinishDlgProc(HWND hwndDlg,
if (SetupData->UnattendSetup)
{
KillTimer(hwndDlg, 1);
SetInstallationCompleted();
SetInstallationCompleted(TRUE);
PostQuitMessage(0);
}
@@ -2802,7 +2816,7 @@ FinishDlgProc(HWND hwndDlg,
case WM_DESTROY:
{
SetInstallationCompleted();
SetInstallationCompleted(FALSE);
PostQuitMessage(0);
return TRUE;
}
@@ -3335,8 +3349,7 @@ ProcessSetupInf(
pSetupData->hSetupInf = INVALID_HANDLE_VALUE;
/* Retrieve the path of the setup INF */
GetSystemDirectoryW(szPath, _countof(szPath));
wcscat(szPath, L"\\$winnt$.inf");
GetSetupInfPath(szPath, _countof(szPath));
/* Open the setup INF */
pSetupData->hSetupInf = SetupOpenInfFileW(szPath,