[SYSSETUP] Use a $winnt$.inf file to retrieve setup information for the 2nd-stage...
[reactos.git] / dll / win32 / syssetup / wizard.c
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)