[SYSSETUP] Use a $winnt$.inf file to retrieve setup information for the 2nd-stage...
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Thu, 10 Aug 2017 19:21:08 +0000 (19:21 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 27 Oct 2018 16:13:38 +0000 (18:13 +0200)
Following r75518, we use the $winnt$.inf file (created in System32
by the 1st-stage installer) as the setup information file for the
2nd-stage setup for:

- retrieving the installation source media path;
- retrieving the unattended information that was copied from the
  unattend.inf file from the installation source media.

The installation source media path is converted from NT format to
Win32 format for usage with Win32 functions and storage in the registry:
this is done by GetInstallSourceWin32(), which replaces the hackish
GetRosInstallCD() function.

The $winnt$.inf file is also updated, and the registry values "SourcePath"
and "ServicePackSourcePath" are created / updated in:
HKLM\Software\Microsoft\Windows\CurrentVersion\Setup .

svn path=/branches/setup_improvements/; revision=75524

dll/win32/syssetup/wizard.c
sdk/include/reactos/libs/syssetup/syssetup.h

index 2eafef7..2d95f1c 100644 (file)
@@ -50,9 +50,6 @@ typedef struct _REGISTRATIONDATA
 
 extern void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow);
 
-BOOL
-GetRosInstallCD(WCHAR *pwszPath, DWORD cchPathMax);
-
 
 static VOID
 CenterWindow(HWND hWnd)
@@ -983,16 +980,9 @@ LocalePageDlgProc(HWND hwndDlg,
                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
                     if (SetupData->UnattendSetup)
                     {
-                        WCHAR wszPath[MAX_PATH];
-                        if (GetRosInstallCD(wszPath, _countof(wszPath)))
-                        {
-                            WCHAR wszParams[1024];
-                            swprintf(wszParams, L"intl.cpl,,/f:\"%sreactos\\unattend.inf\"", wszPath);
-                            RunControlPanelApplet(hwndDlg, wszParams);
-                        }
-                        else
+                        // if (!*SetupData->SourcePath)
                         {
-                            RunControlPanelApplet(hwndDlg, L"intl.cpl,,/f:\"unattend.inf\"");
+                            RunControlPanelApplet(hwndDlg, L"intl.cpl,,/f:\"$winnt$.inf\""); // Should be in System32
                         }
 
                         SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_OWNERPAGE);
@@ -2176,9 +2166,70 @@ FinishDlgProc(HWND hwndDlg,
 }
 
 
+/*
+ * GetInstallSourceWin32 retrieves the path to the ReactOS installation medium
+ * in Win32 format, for later use by syssetup and storage in the registry.
+ */
+static BOOL
+GetInstallSourceWin32(
+    OUT PWSTR pwszPath,
+    IN DWORD cchPathMax,
+    IN PCWSTR pwszNTPath)
+{
+    WCHAR wszDrives[512];
+    WCHAR wszNTPath[512]; // MAX_PATH ?
+    DWORD cchDrives;
+    PWCHAR pwszDrive;
+
+    *pwszPath = UNICODE_NULL;
+
+    cchDrives = GetLogicalDriveStringsW(_countof(wszDrives) - 1, wszDrives);
+    if (cchDrives == 0 || cchDrives >= _countof(wszDrives))
+    {
+        /* Buffer too small or failure */
+        LogItem(NULL, L"GetLogicalDriveStringsW failed");
+        return FALSE;
+    }
+
+    for (pwszDrive = wszDrives; *pwszDrive; pwszDrive += wcslen(pwszDrive) + 1)
+    {
+        WCHAR wszBuf[MAX_PATH];
+
+        /* Retrieve the NT path corresponding to the current Win32 DOS path */
+        pwszDrive[2] = UNICODE_NULL; // Temporarily remove the backslash
+        QueryDosDeviceW(pwszDrive, wszNTPath, _countof(wszNTPath));
+        pwszDrive[2] = L'\\';        // Restore the backslash
+
+        wcscat(wszNTPath, L"\\");    // Concat a backslash
+
+        /* Logging */
+        wsprintf(wszBuf, L"Testing '%s' --> '%s' %s a CD",
+                 pwszDrive, wszNTPath,
+                 (GetDriveTypeW(pwszDrive) == DRIVE_CDROM) ? L"is" : L"is not");
+        LogItem(NULL, wszBuf);
+
+        /* Check whether the NT path corresponds to the NT installation source path */
+        if (!_wcsicmp(wszNTPath, pwszNTPath))
+        {
+            /* Found it! */
+            wcscpy(pwszPath, pwszDrive); // cchPathMax
+
+            /* Logging */
+            wsprintf(wszBuf, L"GetInstallSourceWin32: %s", pwszPath);
+            LogItem(NULL, wszBuf);
+            wcscat(wszBuf, L"\n");
+            OutputDebugStringW(wszBuf);
+
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
 VOID
-ProcessUnattendInf(
-    PSETUPDATA pSetupData)
+ProcessUnattendSection(
+    IN OUT PSETUPDATA pSetupData)
 {
     INFCONTEXT InfContext;
     WCHAR szName[256];
@@ -2186,7 +2237,7 @@ ProcessUnattendInf(
     DWORD LineLength;
     HKEY hKey;
 
-    if (!SetupFindFirstLineW(pSetupData->hUnattendedInf,
+    if (!SetupFindFirstLineW(pSetupData->hSetupInf,
                              L"Unattend",
                              L"UnattendSetupEnabled",
                              &InfContext))
@@ -2213,7 +2264,7 @@ ProcessUnattendInf(
 
     pSetupData->UnattendSetup = TRUE;
 
-    if (!SetupFindFirstLineW(pSetupData->hUnattendedInf,
+    if (!SetupFindFirstLineW(pSetupData->hSetupInf,
                              L"Unattend",
                              NULL,
                              &InfContext))
@@ -2290,7 +2341,7 @@ ProcessUnattendInf(
 
     } while (SetupFindNextLine(&InfContext, &InfContext));
 
-    if (SetupFindFirstLineW(pSetupData->hUnattendedInf,
+    if (SetupFindFirstLineW(pSetupData->hSetupInf,
                             L"Display",
                             NULL,
                             &InfContext))
@@ -2363,7 +2414,7 @@ ProcessUnattendInf(
         return;
     }
 
-    if (SetupFindFirstLineW(pSetupData->hUnattendedInf,
+    if (SetupFindFirstLineW(pSetupData->hSetupInf,
                             L"GuiRunOnce",
                             NULL,
                             &InfContext))
@@ -2401,84 +2452,135 @@ ProcessUnattendInf(
     RegCloseKey(hKey);
 }
 
-/*
- * GetRosInstallCD should find the path to ros installation medium
- * BUG 1
- * If there are more than one CDDrive in it containing a ReactOS
- * installation cd, then it will pick the first one regardless if
- * it is really the installation cd
- *
- * The best way to implement this is to set the key
- * HKLM\Software\Microsoft\Windows NT\CurrentVersion\SourcePath (REG_SZ)
- */
-
-BOOL
-GetRosInstallCD(WCHAR *pwszPath, DWORD cchPathMax)
+VOID
+ProcessSetupInf(
+    IN OUT PSETUPDATA pSetupData)
 {
-    WCHAR wszDrives[512];
-    DWORD cchDrives;
-    WCHAR *pwszDrive;
+    WCHAR szPath[MAX_PATH];
+    WCHAR szValue[MAX_PATH];
+    INFCONTEXT InfContext;
+    DWORD LineLength;
+    HKEY hKey;
+    LONG res;
 
-    cchDrives = GetLogicalDriveStringsW(_countof(wszDrives) - 1, wszDrives);
-    if (cchDrives == 0 || cchDrives >= _countof(wszDrives))
+    pSetupData->hSetupInf = INVALID_HANDLE_VALUE;
+
+    /* Retrieve the path of the setup INF */
+    GetSystemDirectoryW(szPath, _countof(szPath));
+    wcscat(szPath, L"\\$winnt$.inf");
+
+    /* Open the setup INF */
+    pSetupData->hSetupInf = SetupOpenInfFileW(szPath,
+                                              NULL,
+                                              INF_STYLE_OLDNT,
+                                              NULL);
+    if (pSetupData->hSetupInf == INVALID_HANDLE_VALUE)
     {
-        /* buffer too small or failure */
-        LogItem(NULL, L"GetLogicalDriveStringsW failed");
-        return FALSE;
+        DPRINT1("Error: Cannot open the setup information file %S with error %d\n", szPath, GetLastError());
+        return;
     }
 
-    for (pwszDrive = wszDrives; pwszDrive[0]; pwszDrive += wcslen(pwszDrive) + 1)
+
+    /* Retrieve the NT source path from which the 1st-stage installer was run */
+    if (!SetupFindFirstLineW(pSetupData->hSetupInf,
+                             L"data",
+                             L"sourcepath",
+                             &InfContext))
     {
-        if (GetDriveTypeW(pwszDrive) == DRIVE_CDROM)
-        {
-            WCHAR wszBuf[MAX_PATH];
-            wsprintf(wszBuf, L"%sreactos\\system32\\ntoskrnl.exe", pwszDrive);
-            LogItem(NULL, wszBuf);
-            if (GetFileAttributesW(wszBuf) != INVALID_FILE_ATTRIBUTES)
-            {
-                /* the file exists, so this is the right drive */
-                wcsncpy(pwszPath, pwszDrive, cchPathMax);
-                OutputDebugStringW(L"GetRosInstallCD: ");OutputDebugStringW(pwszPath);OutputDebugStringW(L"\n");
-                return TRUE;
-            }
-        }
+        DPRINT1("Error: Cannot find UnattendSetupEnabled Key! %d\n", GetLastError());
+        return;
     }
-    return FALSE;
-}
 
+    if (!SetupGetStringFieldW(&InfContext,
+                              1,
+                              szValue,
+                              ARRAYSIZE(szValue),
+                              &LineLength))
+    {
+        DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
+        return;
+    }
+
+    *pSetupData->SourcePath = UNICODE_NULL;
+
+    /* Close the setup INF as we are going to modify it manually */
+    if (pSetupData->hSetupInf != INVALID_HANDLE_VALUE)
+        SetupCloseInfFile(pSetupData->hSetupInf);
 
-VOID
-ProcessUnattendSetup(
-    PSETUPDATA pSetupData)
-{
-    WCHAR szPath[MAX_PATH];
-    DWORD dwLength;
 
-    if (!GetRosInstallCD(szPath, MAX_PATH))
+    /* Find the installation source path in Win32 format */
+    if (!GetInstallSourceWin32(pSetupData->SourcePath,
+                               _countof(pSetupData->SourcePath),
+                               szValue))
     {
-        /* no cd drive found */
-        return;
+        *pSetupData->SourcePath = UNICODE_NULL;
     }
 
-    dwLength = wcslen(szPath);
-    if (dwLength + 21 > MAX_PATH)
+    /* Save the path in Win32 format in the setup INF */
+    swprintf(szValue, L"\"%s\"", pSetupData->SourcePath);
+    WritePrivateProfileStringW(L"data", L"dospath", szValue, szPath);
+
+    /*
+     * Save it also in the registry, in the following keys:
+     * - HKLM\Software\Microsoft\Windows\CurrentVersion\Setup ,
+     *   values "SourcePath" and "ServicePackSourcePath" (REG_SZ);
+     * - HKLM\Software\Microsoft\Windows NT\CurrentVersion ,
+     *   value "SourcePath" (REG_SZ); set to the full path (e.g. D:\I386).
+     */
+#if 0
+    res = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                        L"Software\\Microsoft\\Windows NT\\CurrentVersion",
+                        0,
+                        KEY_ALL_ACCESS,
+                        &hKey);
+
+    if (res != ERROR_SUCCESS)
     {
-        /* FIXME
-         * allocate bigger buffer
-         */
-        return;
+        return FALSE;
+    }
+#endif
+
+    res = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
+                          L"Software\\Microsoft\\Windows\\CurrentVersion\\Setup",
+                          0, NULL,
+                          REG_OPTION_NON_VOLATILE,
+                          KEY_ALL_ACCESS, // KEY_WRITE
+                          NULL,
+                          &hKey,
+                          NULL);
+    if (res == ERROR_SUCCESS)
+    {
+        res = RegSetValueExW(hKey,
+                             L"SourcePath",
+                             0,
+                             REG_SZ,
+                             (LPBYTE)pSetupData->SourcePath,
+                             (wcslen(pSetupData->SourcePath) + 1) * sizeof(WCHAR));
+
+        res = RegSetValueExW(hKey,
+                             L"ServicePackSourcePath",
+                             0,
+                             REG_SZ,
+                             (LPBYTE)pSetupData->SourcePath,
+                             (wcslen(pSetupData->SourcePath) + 1) * sizeof(WCHAR));
+
+        RegCloseKey(hKey);
     }
 
-    wcscat(szPath, L"reactos\\unattend.inf");
 
-    pSetupData->hUnattendedInf = SetupOpenInfFileW(szPath,
-                                                   NULL,
-                                                   INF_STYLE_OLDNT,
-                                                   NULL);
-    if (pSetupData->hUnattendedInf != INVALID_HANDLE_VALUE)
+    /* Now, re-open the setup INF (this must succeed) */
+    pSetupData->hSetupInf = SetupOpenInfFileW(szPath,
+                                              NULL,
+                                              INF_STYLE_OLDNT,
+                                              NULL);
+    if (pSetupData->hSetupInf == INVALID_HANDLE_VALUE)
     {
-        ProcessUnattendInf(pSetupData);
+        DPRINT1("Error: Cannot open the setup information file %S with error %d\n", szPath, GetLastError());
+        return;
     }
+
+    /* Process the unattended section of the setup file */
+    ProcessUnattendSection(pSetupData);
 }
 
 typedef DWORD(WINAPI *PFNREQUESTWIZARDPAGES)(PDWORD, HPROPSHEETPAGE *, PSETUPDATA);
@@ -2542,8 +2644,8 @@ InstallWizard(VOID)
         goto done;
     }
 
-    pSetupData->hUnattendedInf = INVALID_HANDLE_VALUE;
-    ProcessUnattendSetup(pSetupData);
+    /* Process the $winnt$.inf setup file */
+    ProcessSetupInf(pSetupData);
 
     /* Create the Welcome page */
     psp.dwSize = sizeof(PROPSHEETPAGE);
@@ -2658,8 +2760,8 @@ InstallWizard(VOID)
     DeleteObject(pSetupData->hBoldFont);
     DeleteObject(pSetupData->hTitleFont);
 
-    if (pSetupData->hUnattendedInf != INVALID_HANDLE_VALUE)
-        SetupCloseInfFile(pSetupData->hUnattendedInf);
+    if (pSetupData->hSetupInf != INVALID_HANDLE_VALUE)
+        SetupCloseInfFile(pSetupData->hSetupInf);
 
 done:
     if (phpage != NULL)
index 03c7c70..a29a342 100644 (file)
@@ -44,15 +44,19 @@ typedef struct _TIMEZONE_ENTRY
     ULONG Index;
 } TIMEZONE_ENTRY, *PTIMEZONE_ENTRY;
 
+/* Private Setup data shared between syssetup.dll and netshell.dll */
 typedef struct _SETUPDATA
 {
     HFONT hTitleFont;
     HFONT hBoldFont;
 
+    WCHAR SourcePath[MAX_PATH];   // PCWSTR
+    WCHAR UnattendFile[MAX_PATH]; // PCWSTR
+
     WCHAR OwnerName[51];
     WCHAR OwnerOrganization[51];
     WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];  /* max. 15 characters */
-    WCHAR AdminPassword[128];              /* max. 127 characters */
+    WCHAR AdminPassword[128];                         /* max. 127 characters */
     BOOL  UnattendSetup;
     BOOL  DisableGeckoInst;
 
@@ -63,7 +67,7 @@ typedef struct _SETUPDATA
     DWORD DisableAutoDaylightTimeSet;
     LCID LocaleID;
 
-    HINF hUnattendedInf;
+    HINF hSetupInf;
 
     UINT uFirstNetworkWizardPage;
     UINT uPostNetworkWizardPage;