[USETUP] Minor code formatting only.
[reactos.git] / base / setup / usetup / usetup.c
index 1a7940c..c87a3fe 100644 (file)
 #include "chkdsk.h"
 #include "cmdcons.h"
 #include "format.h"
-#include "drivesup.h"
 #include "settings.h"
 
 #define NDEBUG
 #include <debug.h>
 
+// HACK!
+#include <strsafe.h>
+
 
 /* GLOBALS ******************************************************************/
 
 HANDLE ProcessHeap;
-UNICODE_STRING SourceRootPath;
-UNICODE_STRING SourceRootDir;
-UNICODE_STRING SourcePath;
+
+static UNICODE_STRING SourceRootPath;
+static UNICODE_STRING SourceRootDir;
+static UNICODE_STRING SourcePath;
+
 BOOLEAN IsUnattendedSetup = FALSE;
 LONG UnattendDestinationDiskNumber;
 LONG UnattendDestinationPartitionNumber;
@@ -56,18 +60,22 @@ PWCHAR SelectedLanguageId;
 WCHAR LocaleID[9];
 WCHAR DefaultLanguage[20];
 WCHAR DefaultKBLayout[20];
-BOOLEAN RepairUpdateFlag = FALSE;
-HANDLE hPnpThread = INVALID_HANDLE_VALUE;
+static BOOLEAN RepairUpdateFlag = FALSE;
+static HANDLE hPnpThread = INVALID_HANDLE_VALUE;
 
-PPARTLIST PartitionList = NULL;
-PPARTENTRY TempPartition = NULL;
-FORMATMACHINESTATE FormatState = Start;
+static PPARTLIST PartitionList = NULL;
+static PPARTENTRY TempPartition = NULL;
+static FORMATMACHINESTATE FormatState = Start;
 
 
 /* LOCALS *******************************************************************/
 
 static PFILE_SYSTEM_LIST FileSystemList = NULL;
 
+/*
+ * NOTE: Technically only used for the COPYCONTEXT InstallPath member
+ * for the filequeue functionality.
+ */
 static UNICODE_STRING InstallPath;
 
 /*
@@ -85,21 +93,25 @@ static UNICODE_STRING InstallPath;
  */
 static UNICODE_STRING SystemRootPath;
 
-/* Path to the install directory inside the ReactOS boot partition */
+/* Path to the installation directory inside the ReactOS boot partition */
 static UNICODE_STRING DestinationPath;
 static UNICODE_STRING DestinationArcPath;
 static UNICODE_STRING DestinationRootPath;
 
-static WCHAR DestinationDriveLetter;    // FIXME: Is it really useful??
+// FIXME: Is it really useful?? Just used for SetDefaultPagefile...
+static WCHAR DestinationDriveLetter;
 
 static HINF SetupInf;
 
 static HSPFILEQ SetupFileQueue = NULL;
 
+static PNTOS_INSTALLATION CurrentInstallation = NULL;
+static PGENERIC_LIST NtOsInstallsList = NULL;
+
 static PGENERIC_LIST ComputerList = NULL;
-static PGENERIC_LIST DisplayList = NULL;
+static PGENERIC_LIST DisplayList  = NULL;
 static PGENERIC_LIST KeyboardList = NULL;
-static PGENERIC_LIST LayoutList = NULL;
+static PGENERIC_LIST LayoutList   = NULL;
 static PGENERIC_LIST LanguageList = NULL;
 
 static LANGID LanguageId = 0;
@@ -136,7 +148,7 @@ DrawBox(IN SHORT xLeft,
     COORD coPos;
     DWORD Written;
 
-    /* draw upper left corner */
+    /* Draw upper left corner */
     coPos.X = xLeft;
     coPos.Y = yTop;
     FillConsoleOutputCharacterA(StdOutput,
@@ -145,7 +157,7 @@ DrawBox(IN SHORT xLeft,
                                 coPos,
                                 &Written);
 
-    /* draw upper edge */
+    /* Draw upper edge */
     coPos.X = xLeft + 1;
     coPos.Y = yTop;
     FillConsoleOutputCharacterA(StdOutput,
@@ -154,7 +166,7 @@ DrawBox(IN SHORT xLeft,
                                 coPos,
                                 &Written);
 
-    /* draw upper right corner */
+    /* Draw upper right corner */
     coPos.X = xLeft + Width - 1;
     coPos.Y = yTop;
     FillConsoleOutputCharacterA(StdOutput,
@@ -188,7 +200,7 @@ DrawBox(IN SHORT xLeft,
                                     &Written);
     }
 
-    /* draw lower left corner */
+    /* Draw lower left corner */
     coPos.X = xLeft;
     coPos.Y = yTop + Height - 1;
     FillConsoleOutputCharacterA(StdOutput,
@@ -197,7 +209,7 @@ DrawBox(IN SHORT xLeft,
                                 coPos,
                                 &Written);
 
-    /* draw lower edge */
+    /* Draw lower edge */
     coPos.X = xLeft + 1;
     coPos.Y = yTop + Height - 1;
     FillConsoleOutputCharacterA(StdOutput,
@@ -206,7 +218,7 @@ DrawBox(IN SHORT xLeft,
                                 coPos,
                                 &Written);
 
-    /* draw lower right corner */
+    /* Draw lower right corner */
     coPos.X = xLeft + Width - 1;
     coPos.Y = yTop + Height - 1;
     FillConsoleOutputCharacterA(StdOutput,
@@ -417,7 +429,7 @@ ConfirmQuit(PINPUT_RECORD Ir)
 }
 
 
-VOID
+static VOID
 CheckUnattendedSetup(VOID)
 {
     WCHAR UnattendInfPath[MAX_PATH];
@@ -427,7 +439,7 @@ CheckUnattendedSetup(VOID)
     INT IntValue;
     PWCHAR Value;
 
-    CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2, SourcePath.Buffer, L"\\unattend.inf");
+    CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2, SourcePath.Buffer, L"unattend.inf");
 
     if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
     {
@@ -436,15 +448,15 @@ CheckUnattendedSetup(VOID)
     }
 
     /* Load 'unattend.inf' from install media. */
-    UnattendInf = SetupOpenInfFileW(UnattendInfPath,
-                                    NULL,
-                                    INF_STYLE_WIN4,
-                                    LanguageId,
-                                    &ErrorLine);
+    UnattendInf = SetupOpenInfFileExW(UnattendInfPath,
+                                      NULL,
+                                      INF_STYLE_WIN4,
+                                      LanguageId,
+                                      &ErrorLine);
 
     if (UnattendInf == INVALID_HANDLE_VALUE)
     {
-        DPRINT("SetupOpenInfFileW() failed\n");
+        DPRINT("SetupOpenInfFileExW() failed\n");
         return;
     }
 
@@ -547,6 +559,7 @@ CheckUnattendedSetup(VOID)
     wcscpy(UnattendInstallationDirectory, Value);
 
     IsUnattendedSetup = TRUE;
+    DPRINT("Running unattended setup\n");
 
     /* Search for 'MBRInstallType' in the 'Unattend' section */
     if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"MBRInstallType", &Context))
@@ -580,17 +593,15 @@ CheckUnattendedSetup(VOID)
         if (INF_GetData(&Context, NULL, &Value))
         {
             LONG Id = wcstol(Value, NULL, 16);
-            swprintf(LocaleID,L"%08lx", Id);
+            swprintf(LocaleID, L"%08lx", Id);
        }
     }
 
     SetupCloseInfFile(UnattendInf);
-
-    DPRINT("Running unattended setup\n");
 }
 
 
-VOID
+static VOID
 UpdateKBLayout(VOID)
 {
     PGENERIC_LIST_ENTRY ListEntry;
@@ -630,7 +641,7 @@ UpdateKBLayout(VOID)
 /*
  * Displays the LanguagePage.
  *
- * Next pages: IntroPage, QuitPage
+ * Next pages: WelcomePage, QuitPage
  *
  * SIDEEFFECTS
  *  Init SelectedLanguageId
@@ -653,7 +664,7 @@ LanguagePage(PINPUT_RECORD Ir)
         if (LanguageList == NULL)
         {
            PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE);
-           return INTRO_PAGE;
+           return WELCOME_PAGE;
         }
     }
 
@@ -667,7 +678,7 @@ LanguagePage(PINPUT_RECORD Ir)
     if (GenericListHasSingleEntry(LanguageList))
     {
         LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
-        return INTRO_PAGE;
+        return WELCOME_PAGE;
     }
 
     InitGenericListUi(&ListUi, LanguageList);
@@ -731,7 +742,7 @@ LanguagePage(PINPUT_RECORD Ir)
             /* Load the font */
             SetConsoleCodePage();
 
-            return INTRO_PAGE;
+            return WELCOME_PAGE;
         }
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
         {
@@ -762,7 +773,66 @@ LanguagePage(PINPUT_RECORD Ir)
         }
     }
 
-    return INTRO_PAGE;
+    return WELCOME_PAGE;
+}
+
+
+static NTSTATUS
+GetSourcePaths(
+    OUT PUNICODE_STRING SourcePath,
+    OUT PUNICODE_STRING SourceRootPath,
+    OUT PUNICODE_STRING SourceRootDir)
+{
+    NTSTATUS Status;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING LinkName = RTL_CONSTANT_STRING(L"\\SystemRoot");
+    UNICODE_STRING SourceName;
+    WCHAR SourceBuffer[MAX_PATH] = L"";
+    HANDLE Handle;
+    ULONG Length;
+    PWCHAR Ptr;
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &LinkName,
+                               OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+
+    Status = NtOpenSymbolicLinkObject(&Handle,
+                                      SYMBOLIC_LINK_ALL_ACCESS,
+                                      &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    RtlInitEmptyUnicodeString(&SourceName, SourceBuffer, sizeof(SourceBuffer));
+
+    Status = NtQuerySymbolicLinkObject(Handle,
+                                       &SourceName,
+                                       &Length);
+    NtClose(Handle);
+
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    RtlCreateUnicodeString(SourcePath,
+                           SourceName.Buffer);
+
+    /* Strip trailing directory */
+    Ptr = wcsrchr(SourceName.Buffer, OBJ_NAME_PATH_SEPARATOR);
+    if (Ptr)
+    {
+        RtlCreateUnicodeString(SourceRootDir, Ptr);
+        *Ptr = UNICODE_NULL;
+    }
+    else
+    {
+        RtlCreateUnicodeString(SourceRootDir, L"");
+    }
+
+    RtlCreateUnicodeString(SourceRootPath,
+                           SourceName.Buffer);
+
+    return STATUS_SUCCESS;
 }
 
 
@@ -806,29 +876,23 @@ SetupStartPage(PINPUT_RECORD Ir)
     Status = GetSourcePaths(&SourcePath,
                             &SourceRootPath,
                             &SourceRootDir);
-
     if (!NT_SUCCESS(Status))
     {
         CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status);
         MUIDisplayError(ERROR_NO_SOURCE_DRIVE, Ir, POPUP_WAIT_ENTER);
         return QUIT_PAGE;
     }
-#if 0
-    else
-    {
-        CONSOLE_PrintTextXY(6, 15, "SourcePath: '%wZ'", &SourcePath);
-        CONSOLE_PrintTextXY(6, 16, "SourceRootPath: '%wZ'", &SourceRootPath);
-        CONSOLE_PrintTextXY(6, 17, "SourceRootDir: '%wZ'", &SourceRootDir);
-    }
-#endif
+    DPRINT1("SourcePath: '%wZ'\n", &SourcePath);
+    DPRINT1("SourceRootPath: '%wZ'\n", &SourceRootPath);
+    DPRINT1("SourceRootDir: '%wZ'\n", &SourceRootDir);
 
     /* Load txtsetup.sif from install media. */
-    CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2, SourcePath.Buffer, L"\\txtsetup.sif");
-    SetupInf = SetupOpenInfFileW(FileNameBuffer,
-                                 NULL,
-                                 INF_STYLE_WIN4,
-                                 LanguageId,
-                                 &ErrorLine);
+    CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2, SourcePath.Buffer, L"txtsetup.sif");
+    SetupInf = SetupOpenInfFileExW(FileNameBuffer,
+                                   NULL,
+                                   INF_STYLE_WIN4,
+                                   LanguageId,
+                                   &ErrorLine);
 
     if (SetupInf == INVALID_HANDLE_VALUE)
     {
@@ -874,10 +938,10 @@ SetupStartPage(PINPUT_RECORD Ir)
     RequiredPartitionDiskSpace = (ULONG)IntValue;
 
     /* Start the PnP thread */
-    if (hPnpThread != INVALID_HANDLE_VALUE)
+    if (hPnpThread != NULL)
     {
         NtResumeThread(hPnpThread, NULL);
-        hPnpThread = INVALID_HANDLE_VALUE;
+        hPnpThread = NULL;
     }
 
     CheckUnattendedSetup();
@@ -933,11 +997,12 @@ SetupStartPage(PINPUT_RECORD Ir)
 
 
 /*
- * Displays the IntroPage.
+ * Displays the WelcomePage.
  *
  * Next pages:
  *  InstallIntroPage (default)
  *  RepairIntroPage
+ *  RecoveryPage
  *  LicensePage
  *  QuitPage
  *
@@ -945,9 +1010,9 @@ SetupStartPage(PINPUT_RECORD Ir)
  *   Number of the next page.
  */
 static PAGE_NUMBER
-IntroPage(PINPUT_RECORD Ir)
+WelcomePage(PINPUT_RECORD Ir)
 {
-    MUIDisplayPage(START_PAGE);
+    MUIDisplayPage(WELCOME_PAGE);
 
     while (TRUE)
     {
@@ -967,7 +1032,7 @@ IntroPage(PINPUT_RECORD Ir)
         }
         else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
         {
-            return REPAIR_INTRO_PAGE;
+            return RECOVERY_PAGE; // REPAIR_INTRO_PAGE;
         }
         else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* L */
         {
@@ -975,7 +1040,7 @@ IntroPage(PINPUT_RECORD Ir)
         }
     }
 
-    return INTRO_PAGE;
+    return WELCOME_PAGE;
 }
 
 
@@ -983,7 +1048,7 @@ IntroPage(PINPUT_RECORD Ir)
  * Displays the License page.
  *
  * Next page:
- *  IntroPage (default)
+ *  WelcomePage (default)
  *
  * RETURNS
  *   Number of the next page.
@@ -999,7 +1064,7 @@ LicensePage(PINPUT_RECORD Ir)
 
         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)  /* ENTER */
         {
-            return INTRO_PAGE;
+            return WELCOME_PAGE;
         }
     }
 
@@ -1044,13 +1109,141 @@ RepairIntroPage(PINPUT_RECORD Ir)
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE))  /* ESC */
         {
-            return INTRO_PAGE;
+            return WELCOME_PAGE;
         }
     }
 
     return REPAIR_INTRO_PAGE;
 }
 
+/*
+ * Displays the UpgradeRepairPage.
+ *
+ * Next pages:
+ *  RebootPage (default)
+ *  InstallIntroPage
+ *  RecoveryPage
+ *  WelcomePage
+ *
+ * RETURNS
+ *   Number of the next page.
+ */
+static PAGE_NUMBER
+UpgradeRepairPage(PINPUT_RECORD Ir)
+{
+    GENERIC_LIST_UI ListUi;
+
+/*** HACK!! ***/
+    if (PartitionList == NULL)
+    {
+        PartitionList = CreatePartitionList();
+        if (PartitionList == NULL)
+        {
+            /* FIXME: show an error dialog */
+            MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
+            return QUIT_PAGE;
+        }
+        else if (IsListEmpty(&PartitionList->DiskListHead))
+        {
+            MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
+            return QUIT_PAGE;
+        }
+
+        TempPartition = NULL;
+        FormatState = Start;
+    }
+/**************/
+
+    NtOsInstallsList = CreateNTOSInstallationsList(PartitionList);
+    if (!NtOsInstallsList)
+        DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
+    if (!NtOsInstallsList || GetNumberOfListEntries(NtOsInstallsList) == 0)
+    {
+        RepairUpdateFlag = FALSE;
+
+        // return INSTALL_INTRO_PAGE;
+        return DEVICE_SETTINGS_PAGE;
+        // return SCSI_CONTROLLER_PAGE;
+    }
+
+    MUIDisplayPage(UPGRADE_REPAIR_PAGE);
+
+    InitGenericListUi(&ListUi, NtOsInstallsList);
+    DrawGenericList(&ListUi,
+                    2, 23,
+                    xScreen - 3,
+                    yScreen - 3);
+
+    SaveGenericListState(NtOsInstallsList);
+
+    // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
+    while (TRUE)
+    {
+        CONSOLE_ConInKey(Ir);
+
+        if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00)
+        {
+            switch (Ir->Event.KeyEvent.wVirtualKeyCode)
+            {
+            case VK_DOWN:   /* DOWN */
+                ScrollDownGenericList(&ListUi);
+                break;
+            case VK_UP:     /* UP */
+                ScrollUpGenericList(&ListUi);
+                break;
+            case VK_NEXT:   /* PAGE DOWN */
+                ScrollPageDownGenericList(&ListUi);
+                break;
+            case VK_PRIOR:  /* PAGE UP */
+                ScrollPageUpGenericList(&ListUi);
+                break;
+            case VK_F3:     /* F3 */
+            {
+                if (ConfirmQuit(Ir) == TRUE)
+                    return QUIT_PAGE;
+                else
+                    RedrawGenericList(&ListUi);
+                break;
+            }
+            case VK_ESCAPE: /* ESC */
+            {
+                RestoreGenericListState(NtOsInstallsList);
+                // return nextPage;    // prevPage;
+
+                // return INSTALL_INTRO_PAGE;
+                return DEVICE_SETTINGS_PAGE;
+                // return SCSI_CONTROLLER_PAGE;
+            }
+            }
+        }
+        else
+        {
+            // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
+            // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+            if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U')  /* U */
+            {
+                /* Retrieve the current installation */
+                CurrentInstallation = (PNTOS_INSTALLATION)GetListEntryUserData(GetCurrentListEntry(NtOsInstallsList));
+                DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
+                        CurrentInstallation->InstallationName, CurrentInstallation->DiskNumber, CurrentInstallation->PartitionNumber);
+
+                RepairUpdateFlag = TRUE;
+
+                // return nextPage;
+                /***/return INSTALL_INTRO_PAGE;/***/
+            }
+            else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) &&
+                     (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))   /* a-z */
+            {
+                GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
+            }
+        }
+    }
+
+    return UPGRADE_REPAIR_PAGE;
+}
+
+
 /*
  * Displays the InstallIntroPage.
  *
@@ -1066,18 +1259,25 @@ RepairIntroPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 InstallIntroPage(PINPUT_RECORD Ir)
 {
-    MUIDisplayPage(INSTALL_INTRO_PAGE);
-
     if (RepairUpdateFlag)
     {
-        //return SELECT_PARTITION_PAGE;
+#if 1 /* Old code that looks good */
+
+        // return SELECT_PARTITION_PAGE;
         return DEVICE_SETTINGS_PAGE;
+
+#else /* Possible new code? */
+
+        return DEVICE_SETTINGS_PAGE;
+        // return SCSI_CONTROLLER_PAGE;
+
+#endif
     }
 
     if (IsUnattendedSetup)
-    {
         return SELECT_PARTITION_PAGE;
-    }
+
+    MUIDisplayPage(INSTALL_INTRO_PAGE);
 
     while (TRUE)
     {
@@ -1093,8 +1293,7 @@ InstallIntroPage(PINPUT_RECORD Ir)
         }
         else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
         {
-            return DEVICE_SETTINGS_PAGE;
-            // return SCSI_CONTROLLER_PAGE;
+            return UPGRADE_REPAIR_PAGE;
         }
     }
 
@@ -1106,19 +1305,20 @@ InstallIntroPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 ScsiControllerPage(PINPUT_RECORD Ir)
 {
-    SetTextXY(6, 8, "Setup detected the following mass storage devices:");
+    // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
+
+    CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
 
     /* FIXME: print loaded mass storage driver descriptions */
 #if 0
-    SetTextXY(8, 10, "TEST device");
+    CONSOLE_SetTextXY(8, 10, "TEST device");
 #endif
 
-
-    SetStatusText("   ENTER = Continue   F3 = Quit");
+    CONSOLE_SetStatusText("   ENTER = Continue   F3 = Quit");
 
     while (TRUE)
     {
-        ConInKey(Ir);
+        CONSOLE_ConInKey(Ir);
 
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
@@ -1136,6 +1336,38 @@ ScsiControllerPage(PINPUT_RECORD Ir)
 
     return SCSI_CONTROLLER_PAGE;
 }
+
+static PAGE_NUMBER
+OemDriverPage(PINPUT_RECORD Ir)
+{
+    // MUIDisplayPage(OEM_DRIVER_PAGE);
+
+    CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
+
+    /* FIXME: Implement!! */
+
+    CONSOLE_SetStatusText("   ENTER = Continue   F3 = Quit");
+
+    while (TRUE)
+    {
+        CONSOLE_ConInKey(Ir);
+
+        if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+            (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
+        {
+            if (ConfirmQuit(Ir) == TRUE)
+                return QUIT_PAGE;
+
+            break;
+        }
+        else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+        {
+            return DEVICE_SETTINGS_PAGE;
+        }
+    }
+
+    return OEM_DRIVER_PAGE;
+}
 #endif
 
 
@@ -1164,7 +1396,6 @@ static PAGE_NUMBER
 DeviceSettingsPage(PINPUT_RECORD Ir)
 {
     static ULONG Line = 16;
-    MUIDisplayPage(DEVICE_SETTINGS_PAGE);
 
     /* Initialize the computer settings list */
     if (ComputerList == NULL)
@@ -1211,20 +1442,20 @@ DeviceSettingsPage(PINPUT_RECORD Ir)
         }
     }
 
-    MUIDisplayPage(DEVICE_SETTINGS_PAGE);
+    if (RepairUpdateFlag)
+        return SELECT_PARTITION_PAGE;
 
+    // if (IsUnattendedSetup)
+        // return SELECT_PARTITION_PAGE;
 
-    CONSOLE_SetTextXY(25, 11, GetListEntryText(GetCurrentListEntry((ComputerList))));
-    CONSOLE_SetTextXY(25, 12, GetListEntryText(GetCurrentListEntry((DisplayList))));
-    CONSOLE_SetTextXY(25, 13, GetListEntryText(GetCurrentListEntry((KeyboardList))));
-    CONSOLE_SetTextXY(25, 14, GetListEntryText(GetCurrentListEntry((LayoutList))));
+    MUIDisplayPage(DEVICE_SETTINGS_PAGE);
 
-    CONSOLE_InvertTextXY(24, Line, 48, 1);
+    CONSOLE_SetTextXY(25, 11, GetListEntryText(GetCurrentListEntry(ComputerList)));
+    CONSOLE_SetTextXY(25, 12, GetListEntryText(GetCurrentListEntry(DisplayList)));
+    CONSOLE_SetTextXY(25, 13, GetListEntryText(GetCurrentListEntry(KeyboardList)));
+    CONSOLE_SetTextXY(25, 14, GetListEntryText(GetCurrentListEntry(LayoutList)));
 
-    if (RepairUpdateFlag)
-    {
-        return SELECT_PARTITION_PAGE;
-    }
+    CONSOLE_InvertTextXY(24, Line, 48, 1);
 
     while (TRUE)
     {
@@ -1471,11 +1702,11 @@ IsDiskSizeValid(PPARTENTRY PartEntry)
     ULONGLONG size;
 
     size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
-    size = (size + 524288) / 1048576;  /* in MBytes */
+    size = (size + (512 * KB)) / MB;  /* in MBytes */
 
     if (size < RequiredPartitionDiskSpace)
     {
-        /* partition is too small so ask for another partition */
+        /* Partition is too small so ask for another one */
         DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, RequiredPartitionDiskSpace);
         return FALSE;
     }
@@ -1500,7 +1731,6 @@ IsDiskSizeValid(PPARTENTRY PartEntry)
  *  QuitPage
  *
  * SIDEEFFECTS
- *  Init DestinationDriveLetter (only if unattended or not free space is selected)
  *  Set InstallShortcut (only if not unattended + free space is selected)
  *
  * RETURNS
@@ -1512,8 +1742,6 @@ SelectPartitionPage(PINPUT_RECORD Ir)
     PARTLIST_UI ListUi;
     ULONG Error;
 
-    MUIDisplayPage(SELECT_PARTITION_PAGE);
-
     if (PartitionList == NULL)
     {
         PartitionList = CreatePartitionList();
@@ -1533,6 +1761,22 @@ SelectPartitionPage(PINPUT_RECORD Ir)
         FormatState = Start;
     }
 
+    if (RepairUpdateFlag)
+    {
+        /* Determine the selected installation disk & partition */
+        if (!SelectPartition(PartitionList,
+                             CurrentInstallation->DiskNumber,
+                             CurrentInstallation->PartitionNumber))
+        {
+            DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
+            ASSERT(FALSE);
+        }
+
+        return SELECT_FILE_SYSTEM_PAGE;
+    }
+
+    MUIDisplayPage(SELECT_PARTITION_PAGE);
+
     InitPartitionListUi(&ListUi, PartitionList,
                         2,
                         23,
@@ -1567,8 +1811,6 @@ SelectPartitionPage(PINPUT_RECORD Ir)
                     return SELECT_PARTITION_PAGE; /* let the user select another partition */
                 }
 
-                DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
-
                 return SELECT_FILE_SYSTEM_PAGE;
             }
         }
@@ -1584,8 +1826,6 @@ SelectPartitionPage(PINPUT_RECORD Ir)
                 return SELECT_PARTITION_PAGE; /* let the user select another partition */
             }
 
-            DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
-
             return SELECT_FILE_SYSTEM_PAGE;
         }
     }
@@ -1680,8 +1920,6 @@ SelectPartitionPage(PINPUT_RECORD Ir)
                 return SELECT_PARTITION_PAGE; /* let the user select another partition */
             }
 
-            DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
-
             return SELECT_FILE_SYSTEM_PAGE;
         }
         else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P')  /* P */
@@ -1977,15 +2215,15 @@ CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
 
     DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
 #if 0
-    if (DiskSize >= 10737418240) /* 10 GB */
+    if (DiskSize >= 10 * GB) /* 10 GB */
     {
-        DiskSize = DiskSize / 1073741824;
+        DiskSize = DiskSize / GB;
         Unit = MUIGetString(STRING_GB);
     }
     else
 #endif
     {
-        DiskSize = DiskSize / 1048576;
+        DiskSize = DiskSize / MB;
         if (DiskSize == 0)
             DiskSize = 1;
 
@@ -1995,32 +2233,34 @@ CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
     if (DiskEntry->DriverName.Length > 0)
     {
         CONSOLE_PrintTextXY(6, 10,
-                            MUIGetString(STRING_HDINFOPARTCREATE),
+                            MUIGetString(STRING_HDINFOPARTCREATE_1),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            &DiskEntry->DriverName);
+                            &DiskEntry->DriverName,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
     else
     {
         CONSOLE_PrintTextXY(6, 10,
-                            MUIGetString(STRING_HDDINFOUNK1),
+                            MUIGetString(STRING_HDINFOPARTCREATE_2),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
-                            DiskEntry->Id);
+                            DiskEntry->Id,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
 
     CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
 
 #if 0
     CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
-                        PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
+                        PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
 #endif
 
     CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
@@ -2028,7 +2268,7 @@ CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
     PartEntry = PartitionList->CurrentPartition;
     while (TRUE)
     {
-        MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576;  /* in MBytes (rounded) */
+        MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB;  /* in MBytes (rounded) */
 
         if (MaxSize > PARTITION_MAXSIZE)
             MaxSize = PARTITION_MAXSIZE;
@@ -2072,7 +2312,7 @@ CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
             else
             {
                 /* Calculate the sector count from the size in MB */
-                SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
+                SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
 
                 /* But never get larger than the unpartitioned disk space */
                 if (SectorCount > PartEntry->SectorCount.QuadPart)
@@ -2134,15 +2374,15 @@ CreateExtendedPartitionPage(PINPUT_RECORD Ir)
 
     DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
 #if 0
-    if (DiskSize >= 10737418240) /* 10 GB */
+    if (DiskSize >= 10 * GB) /* 10 GB */
     {
-        DiskSize = DiskSize / 1073741824;
+        DiskSize = DiskSize / GB;
         Unit = MUIGetString(STRING_GB);
     }
     else
 #endif
     {
-        DiskSize = DiskSize / 1048576;
+        DiskSize = DiskSize / MB;
         if (DiskSize == 0)
             DiskSize = 1;
 
@@ -2152,32 +2392,34 @@ CreateExtendedPartitionPage(PINPUT_RECORD Ir)
     if (DiskEntry->DriverName.Length > 0)
     {
         CONSOLE_PrintTextXY(6, 10,
-                            MUIGetString(STRING_HDINFOPARTCREATE),
+                            MUIGetString(STRING_HDINFOPARTCREATE_1),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            &DiskEntry->DriverName);
+                            &DiskEntry->DriverName,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
     else
     {
         CONSOLE_PrintTextXY(6, 10,
-                            MUIGetString(STRING_HDDINFOUNK1),
+                            MUIGetString(STRING_HDINFOPARTCREATE_2),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
-                            DiskEntry->Id);
+                            DiskEntry->Id,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
 
     CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
 
 #if 0
     CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
-                        PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
+                        PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
 #endif
 
     CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
@@ -2185,7 +2427,7 @@ CreateExtendedPartitionPage(PINPUT_RECORD Ir)
     PartEntry = PartitionList->CurrentPartition;
     while (TRUE)
     {
-        MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576;  /* in MBytes (rounded) */
+        MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB;  /* in MBytes (rounded) */
 
         if (MaxSize > PARTITION_MAXSIZE)
             MaxSize = PARTITION_MAXSIZE;
@@ -2229,7 +2471,7 @@ CreateExtendedPartitionPage(PINPUT_RECORD Ir)
             else
             {
                 /* Calculate the sector count from the size in MB */
-                SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
+                SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
 
                 /* But never get larger than the unpartitioned disk space */
                 if (SectorCount > PartEntry->SectorCount.QuadPart)
@@ -2290,15 +2532,15 @@ CreateLogicalPartitionPage(PINPUT_RECORD Ir)
 
     DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
 #if 0
-    if (DiskSize >= 10737418240) /* 10 GB */
+    if (DiskSize >= 10 * GB) /* 10 GB */
     {
-        DiskSize = DiskSize / 1073741824;
+        DiskSize = DiskSize / GB;
         Unit = MUIGetString(STRING_GB);
     }
     else
 #endif
     {
-        DiskSize = DiskSize / 1048576;
+        DiskSize = DiskSize / MB;
         if (DiskSize == 0)
             DiskSize = 1;
 
@@ -2308,32 +2550,34 @@ CreateLogicalPartitionPage(PINPUT_RECORD Ir)
     if (DiskEntry->DriverName.Length > 0)
     {
         CONSOLE_PrintTextXY(6, 10,
-                            MUIGetString(STRING_HDINFOPARTCREATE),
+                            MUIGetString(STRING_HDINFOPARTCREATE_1),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            &DiskEntry->DriverName);
+                            &DiskEntry->DriverName,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
     else
     {
         CONSOLE_PrintTextXY(6, 10,
-                            MUIGetString(STRING_HDDINFOUNK1),
+                            MUIGetString(STRING_HDINFOPARTCREATE_2),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
-                            DiskEntry->Id);
+                            DiskEntry->Id,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
 
     CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
 
 #if 0
     CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
-                        PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
+                        PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
 #endif
 
     CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
@@ -2341,7 +2585,7 @@ CreateLogicalPartitionPage(PINPUT_RECORD Ir)
     PartEntry = PartitionList->CurrentPartition;
     while (TRUE)
     {
-        MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576;  /* in MBytes (rounded) */
+        MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB;  /* in MBytes (rounded) */
 
         if (MaxSize > PARTITION_MAXSIZE)
             MaxSize = PARTITION_MAXSIZE;
@@ -2385,7 +2629,7 @@ CreateLogicalPartitionPage(PINPUT_RECORD Ir)
             else
             {
                 /* Calculate the sector count from the size in MB */
-                SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
+                SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
 
                 /* But never get larger than the unpartitioned disk space */
                 if (SectorCount > PartEntry->SectorCount.QuadPart)
@@ -2486,21 +2730,21 @@ DeletePartitionPage(PINPUT_RECORD Ir)
 
     PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
 #if 0
-    if (PartSize >= 10737418240) /* 10 GB */
+    if (PartSize >= 10 * GB) /* 10 GB */
     {
-        PartSize = PartSize / 1073741824;
+        PartSize = PartSize / GB;
         Unit = MUIGetString(STRING_GB);
     }
     else
 #endif
-    if (PartSize >= 10485760) /* 10 MB */
+    if (PartSize >= 10 * MB) /* 10 MB */
     {
-        PartSize = PartSize / 1048576;
+        PartSize = PartSize / MB;
         Unit = MUIGetString(STRING_MB);
     }
     else
     {
-        PartSize = PartSize / 1024;
+        PartSize = PartSize / KB;
         Unit = MUIGetString(STRING_KB);
     }
 
@@ -2527,15 +2771,15 @@ DeletePartitionPage(PINPUT_RECORD Ir)
 
     DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
 #if 0
-    if (DiskSize >= 10737418240) /* 10 GB */
+    if (DiskSize >= 10 * GB) /* 10 GB */
     {
-        DiskSize = DiskSize / 1073741824;
+        DiskSize = DiskSize / GB;
         Unit = MUIGetString(STRING_GB);
     }
     else
 #endif
     {
-        DiskSize = DiskSize / 1048576;
+        DiskSize = DiskSize / MB;
         if (DiskSize == 0)
             DiskSize = 1;
 
@@ -2545,25 +2789,27 @@ DeletePartitionPage(PINPUT_RECORD Ir)
     if (DiskEntry->DriverName.Length > 0)
     {
         CONSOLE_PrintTextXY(6, 12,
-                            MUIGetString(STRING_HDINFOPARTDELETE),
+                            MUIGetString(STRING_HDINFOPARTDELETE_1),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            &DiskEntry->DriverName);
+                            &DiskEntry->DriverName,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
     else
     {
         CONSOLE_PrintTextXY(6, 12,
-                            MUIGetString(STRING_HDDINFOUNK3),
+                            MUIGetString(STRING_HDINFOPARTDELETE_2),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
-                            DiskEntry->Id);
+                            DiskEntry->Id,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
 
     while (TRUE)
@@ -2639,6 +2885,13 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
     if (PartitionList->SystemPartition == NULL)
     {
         /* FIXME: show an error dialog */
+        //
+        // Error dialog should say that we cannot find a suitable
+        // system partition and create one on the system. At this point,
+        // it may be nice to ask the user whether he wants to continue,
+        // or use an external drive as the system drive/partition
+        // (e.g. floppy, USB drive, etc...)
+        //
         return QUIT_PAGE;
     }
 
@@ -2727,27 +2980,27 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
 
     /* Adjust disk size */
     DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
-    if (DiskSize >= 10737418240) /* 10 GB */
+    if (DiskSize >= 10 * GB) /* 10 GB */
     {
-        DiskSize = DiskSize / 1073741824;
+        DiskSize = DiskSize / GB;
         DiskUnit = MUIGetString(STRING_GB);
     }
     else
     {
-        DiskSize = DiskSize / 1048576;
+        DiskSize = DiskSize / MB;
         DiskUnit = MUIGetString(STRING_MB);
     }
 
     /* Adjust partition size */
     PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
-    if (PartSize >= 10737418240) /* 10 GB */
+    if (PartSize >= 10 * GB) /* 10 GB */
     {
-        PartSize = PartSize / 1073741824;
+        PartSize = PartSize / GB;
         PartUnit = MUIGetString(STRING_GB);
     }
     else
     {
-        PartSize = PartSize / 1048576;
+        PartSize = PartSize / MB;
         PartUnit = MUIGetString(STRING_MB);
     }
 
@@ -2768,14 +3021,15 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
                             PartTypeString);
 #endif
 
-        CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED),
+        CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1),
                             DiskEntry->DiskNumber,
                             DiskSize,
                             DiskUnit,
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            &DiskEntry->DriverName);
+                            &DiskEntry->DriverName,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
 
         CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
 
@@ -2828,14 +3082,15 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
                                 PartUnit);
         }
 
-        CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS),
+        CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1),
                             DiskEntry->DiskNumber,
                             DiskSize,
                             DiskUnit,
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            &DiskEntry->DriverName);
+                            &DiskEntry->DriverName,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
 
     MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
@@ -2851,8 +3106,6 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
         }
     }
 
-    DrawFileSystemList(FileSystemList);
-
     if (RepairUpdateFlag)
     {
         return CHECK_FILE_SYSTEM_PAGE;
@@ -2876,6 +3129,8 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
         return CHECK_FILE_SYSTEM_PAGE;
     }
 
+    DrawFileSystemList(FileSystemList);
+
     while (TRUE)
     {
         CONSOLE_ConInKey(Ir);
@@ -3026,12 +3281,11 @@ FormatPartitionPage(PINPUT_RECORD Ir)
             }
 
             /* Set PartitionRootPath */
-            swprintf(PathBuffer,
-                     L"\\Device\\Harddisk%lu\\Partition%lu",
-                     DiskEntry->DiskNumber,
-                     PartEntry->PartitionNumber);
-            RtlInitUnicodeString(&PartitionRootPath,
-                                 PathBuffer);
+            StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+                    L"\\Device\\Harddisk%lu\\Partition%lu",
+                    DiskEntry->DiskNumber,
+                    PartEntry->PartitionNumber);
+            RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
             DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
 
             /* Format the partition */
@@ -3100,10 +3354,10 @@ CheckFileSystemPage(PINPUT_RECORD Ir)
     }
 
     /* Set PartitionRootPath */
-    swprintf(PathBuffer,
-             L"\\Device\\Harddisk%lu\\Partition%lu",
-             DiskEntry->DiskNumber,
-             PartEntry->PartitionNumber);
+    StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+            L"\\Device\\Harddisk%lu\\Partition%lu",
+            DiskEntry->DiskNumber,
+            PartEntry->PartitionNumber);
     RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
     DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
 
@@ -3177,41 +3431,46 @@ CheckFileSystemPage(PINPUT_RECORD Ir)
 }
 
 
-static
-VOID
-BuildInstallPaths(PWCHAR InstallDir,
+static VOID
+BuildInstallPaths(PWSTR InstallDir,
                   PDISKENTRY DiskEntry,
                   PPARTENTRY PartEntry)
 {
     WCHAR PathBuffer[MAX_PATH];
 
+/** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/
     /* Create 'InstallPath' string */
     RtlFreeUnicodeString(&InstallPath);
     RtlCreateUnicodeString(&InstallPath, InstallDir);
 
     /* Create 'DestinationRootPath' string */
     RtlFreeUnicodeString(&DestinationRootPath);
-    swprintf(PathBuffer,
-             L"\\Device\\Harddisk%lu\\Partition%lu",
-             DiskEntry->DiskNumber,
-             PartEntry->PartitionNumber);
+    StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+            L"\\Device\\Harddisk%lu\\Partition%lu\\",
+            DiskEntry->DiskNumber,
+            PartEntry->PartitionNumber);
     RtlCreateUnicodeString(&DestinationRootPath, PathBuffer);
     DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath);
 
+/** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
     /* Create 'DestinationPath' string */
     RtlFreeUnicodeString(&DestinationPath);
     CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
                  DestinationRootPath.Buffer, InstallDir);
     RtlCreateUnicodeString(&DestinationPath, PathBuffer);
 
+/** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
     /* Create 'DestinationArcPath' */
     RtlFreeUnicodeString(&DestinationArcPath);
-    swprintf(PathBuffer,
-             L"multi(0)disk(0)rdisk(%lu)partition(%lu)",
-             DiskEntry->BiosDiskNumber,
-             PartEntry->PartitionNumber);
+    StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+            L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
+            DiskEntry->BiosDiskNumber,
+            PartEntry->PartitionNumber);
     ConcatPaths(PathBuffer, ARRAYSIZE(PathBuffer), 1, InstallDir);
     RtlCreateUnicodeString(&DestinationArcPath, PathBuffer);
+
+    /* Initialize DestinationDriveLetter */
+    DestinationDriveLetter = (WCHAR)PartEntry->DriveLetter;
 }
 
 
@@ -3219,7 +3478,7 @@ BuildInstallPaths(PWCHAR InstallDir,
  * Displays the InstallDirectoryPage.
  *
  * Next pages:
- *  PrepareCopyPage (As the direct result of InstallDirectoryPage1)
+ *  PrepareCopyPage
  *  QuitPage
  *
  * RETURNS
@@ -3234,7 +3493,7 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
     WCHAR c;
     ULONG Length, Pos;
 
-    /* We do not need the filesystem list any more */
+    /* We do not need the filesystem list anymore */
     if (FileSystemList != NULL)
     {
         DestroyFileSystemList(FileSystemList);
@@ -3253,28 +3512,35 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
     PartEntry = PartitionList->CurrentPartition;
 
     if (IsUnattendedSetup)
-    {
-        if (!IsValidPath(UnattendInstallationDirectory))
-        {
-            /* FIXME: Log the error? */
-            return QUIT_PAGE;
-        }
+        wcscpy(InstallDir, UnattendInstallationDirectory);
+    else if (RepairUpdateFlag)
+        wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath
+    else
+        wcscpy(InstallDir, L"\\ReactOS");
 
-        BuildInstallPaths(UnattendInstallationDirectory,
+    /*
+     * Check the validity of the predefined 'InstallDir'. If we are either
+     * in unattended setup or in update/repair mode, and the installation path
+     * is valid, just perform the installation. Otherwise (either in the case
+     * of an invalid path, or we are in regular setup), display the UI and allow
+     * the user to specify a new installation path.
+     */
+    if ((RepairUpdateFlag || IsUnattendedSetup) && IsValidPath(InstallDir))
+    {
+        BuildInstallPaths(InstallDir,
                           DiskEntry,
                           PartEntry);
 
         return PREPARE_COPY_PAGE;
     }
 
-    wcscpy(InstallDir, L"\\ReactOS");
-
     Length = wcslen(InstallDir);
     Pos = Length;
+
+    MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
     CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
     CONSOLE_SetCursorXY(8 + Pos, 11);
     CONSOLE_SetCursorType(TRUE, TRUE);
-    MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
 
     while (TRUE)
     {
@@ -3413,18 +3679,23 @@ AddSectionToCopyQueueCab(HINF InfFile,
     PWCHAR DirKeyValue;
     PWCHAR TargetFileName;
 
+    /*
+     * This code enumerates the list of files in reactos.dff / reactos.inf
+     * that need to be extracted from reactos.cab and be installed in their
+     * respective directories.
+     */
+
     /* Search for the SectionName section */
     if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
     {
-        char Buffer[128];
+        CHAR Buffer[128];
         sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
         PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
         return FALSE;
     }
 
     /*
-     * Enumerate the files in the section
-     * and add them to the file queue.
+     * Enumerate the files in the section and add them to the file queue.
      */
     do
     {
@@ -3447,13 +3718,20 @@ AddSectionToCopyQueueCab(HINF InfFile,
         {
             /* FIXME: Handle error! */
             DPRINT1("SetupFindFirstLine() failed\n");
+            INF_FreeData(FileKeyName);
+            INF_FreeData(FileKeyValue);
+            INF_FreeData(TargetFileName);
             break;
         }
 
+        INF_FreeData(FileKeyValue);
+
         if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
         {
             /* FIXME: Handle error! */
             DPRINT1("INF_GetData() failed\n");
+            INF_FreeData(FileKeyName);
+            INF_FreeData(TargetFileName);
             break;
         }
 
@@ -3468,6 +3746,10 @@ AddSectionToCopyQueueCab(HINF InfFile,
             /* FIXME: Handle error! */
             DPRINT1("SetupQueueCopy() failed\n");
         }
+
+        INF_FreeData(FileKeyName);
+        INF_FreeData(TargetFileName);
+        INF_FreeData(DirKeyValue);
     } while (SetupFindNextLine(&FilesContext, &FilesContext));
 
     return TRUE;
@@ -3487,29 +3769,32 @@ AddSectionToCopyQueue(HINF InfFile,
     PWCHAR FileKeyValue;
     PWCHAR DirKeyValue;
     PWCHAR TargetFileName;
-    ULONG Length;
-    WCHAR CompleteOrigDirName[512];
+    WCHAR CompleteOrigDirName[512]; // FIXME: MAX_PATH is not enough?
 
     if (SourceCabinet)
         return AddSectionToCopyQueueCab(InfFile, L"SourceFiles", SourceCabinet, DestinationPath, Ir);
 
+    /*
+     * This code enumerates the list of files in txtsetup.sif
+     * that need to be installed in their respective directories.
+     */
+
     /* Search for the SectionName section */
     if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
     {
-        char Buffer[128];
+        CHAR Buffer[128];
         sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
         PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
         return FALSE;
     }
 
     /*
-     * Enumerate the files in the section
-     * and add them to the file queue.
+     * Enumerate the files in the section and add them to the file queue.
      */
     do
     {
-        /* Get source file name and target directory id */
-        if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
+        /* Get source file name */
+        if (!INF_GetDataField(&FilesContext, 0, &FileKeyName))
         {
             /* FIXME: Handle error! */
             DPRINT1("INF_GetData() failed\n");
@@ -3521,6 +3806,7 @@ AddSectionToCopyQueue(HINF InfFile,
         {
             /* FIXME: Handle error! */
             DPRINT1("INF_GetData() failed\n");
+            INF_FreeData(FileKeyName);
             break;
         }
 
@@ -3537,38 +3823,52 @@ AddSectionToCopyQueue(HINF InfFile,
         {
             /* FIXME: Handle error! */
             DPRINT1("SetupFindFirstLine() failed\n");
+            INF_FreeData(FileKeyName);
+            INF_FreeData(FileKeyValue);
+            INF_FreeData(TargetFileName);
             break;
         }
 
+        INF_FreeData(FileKeyValue);
+
         if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
         {
             /* FIXME: Handle error! */
             DPRINT1("INF_GetData() failed\n");
+            INF_FreeData(FileKeyName);
+            INF_FreeData(TargetFileName);
             break;
         }
 
         if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
         {
             /* Installation path */
-            wcscpy(CompleteOrigDirName, SourceRootDir.Buffer);
+            DPRINT("InstallationPath: '%S'\n", DirKeyValue);
+
+            StringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
+                           SourceRootDir.Buffer);
+
+            DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName);
         }
         else if (DirKeyValue[0] == L'\\')
         {
             /* Absolute path */
-            wcscpy(CompleteOrigDirName, DirKeyValue);
+            DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
+
+            StringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
+                           DirKeyValue);
+
+            DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName);
         }
         else // if (DirKeyValue[0] != L'\\')
         {
             /* Path relative to the installation path */
+            DPRINT("RelativePath: '%S'\n", DirKeyValue);
+
             CombinePaths(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName), 2,
                          SourceRootDir.Buffer, DirKeyValue);
-        }
 
-        /* Remove trailing backslash */
-        Length = wcslen(CompleteOrigDirName);
-        if ((Length > 0) && (CompleteOrigDirName[Length - 1] == L'\\'))
-        {
-            CompleteOrigDirName[Length - 1] = UNICODE_NULL;
+            DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
         }
 
         if (!SetupQueueCopy(SetupFileQueue,
@@ -3582,6 +3882,10 @@ AddSectionToCopyQueue(HINF InfFile,
             /* FIXME: Handle error! */
             DPRINT1("SetupQueueCopy() failed\n");
         }
+
+        INF_FreeData(FileKeyName);
+        INF_FreeData(TargetFileName);
+        INF_FreeData(DirKeyValue);
     } while (SetupFindNextLine(&FilesContext, &FilesContext));
 
     return TRUE;
@@ -3593,12 +3897,11 @@ PrepareCopyPageInfFile(HINF InfFile,
                        PWCHAR SourceCabinet,
                        PINPUT_RECORD Ir)
 {
-    WCHAR PathBuffer[MAX_PATH];
+    NTSTATUS Status;
     INFCONTEXT DirContext;
     PWCHAR AdditionalSectionName = NULL;
     PWCHAR DirKeyValue;
-    ULONG Length;
-    NTSTATUS Status;
+    WCHAR PathBuffer[MAX_PATH];
 
     /* Add common files */
     if (!AddSectionToCopyQueue(InfFile, L"SourceDisksFiles", SourceCabinet, &DestinationPath, Ir))
@@ -3621,28 +3924,22 @@ PrepareCopyPageInfFile(HINF InfFile,
 
     /*
      * FIXME:
-     * - Install directories like '\reactos\test' are not handled yet.
-     * - Copying files to DestinationRootPath should be done from within
-     *   the SystemPartitionFiles section.
-     *   At the moment we check whether we specify paths like '\foo' or '\\' for that.
-     *   For installing to DestinationPath specify just '\' .
+     * Copying files to DestinationRootPath should be done from within
+     * the SystemPartitionFiles section.
+     * At the moment we check whether we specify paths like '\foo' or '\\' for that.
+     * For installing to DestinationPath specify just '\' .
      */
 
     /* Get destination path */
-    wcscpy(PathBuffer, DestinationPath.Buffer);
+    StringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), DestinationPath.Buffer);
 
-    /* Remove trailing backslash */
-    Length = wcslen(PathBuffer);
-    if ((Length > 0) && (PathBuffer[Length - 1] == L'\\'))
-    {
-        PathBuffer[Length - 1] = UNICODE_NULL;
-    }
+    DPRINT("FullPath(1): '%S'\n", PathBuffer);
 
     /* Create the install directory */
     Status = SetupCreateDirectory(PathBuffer);
     if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
     {
-        DPRINT1("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
+        DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer, Status);
         MUIDisplayError(ERROR_CREATE_INSTALL_DIR, Ir, POPUP_WAIT_ENTER);
         return FALSE;
     }
@@ -3676,30 +3973,25 @@ PrepareCopyPageInfFile(HINF InfFile,
             /* Installation path */
             DPRINT("InstallationPath: '%S'\n", DirKeyValue);
 
-            wcscpy(PathBuffer, DestinationPath.Buffer);
+            StringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
+                           DestinationPath.Buffer);
 
-            DPRINT("FullPath: '%S'\n", PathBuffer);
+            DPRINT("InstallationPath(2): '%S'\n", PathBuffer);
         }
         else if (DirKeyValue[0] == L'\\')
         {
             /* Absolute path */
-            DPRINT("Absolute Path: '%S'\n", DirKeyValue);
+            DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
 
             CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
                          DestinationRootPath.Buffer, DirKeyValue);
 
-            /* Remove trailing backslash */
-            Length = wcslen(PathBuffer);
-            if ((Length > 0) && (PathBuffer[Length - 1] == L'\\'))
-            {
-                PathBuffer[Length - 1] = UNICODE_NULL;
-            }
-
-            DPRINT("FullPath: '%S'\n", PathBuffer);
+            DPRINT("AbsolutePath(2): '%S'\n", PathBuffer);
 
             Status = SetupCreateDirectory(PathBuffer);
             if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
             {
+                INF_FreeData(DirKeyValue);
                 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
                 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
                 return FALSE;
@@ -3713,23 +4005,19 @@ PrepareCopyPageInfFile(HINF InfFile,
             CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
                          DestinationPath.Buffer, DirKeyValue);
 
-            /* Remove trailing backslash */
-            Length = wcslen(PathBuffer);
-            if ((Length > 0) && (PathBuffer[Length - 1] == L'\\'))
-            {
-                PathBuffer[Length - 1] = UNICODE_NULL;
-            }
-
-            DPRINT("FullPath: '%S'\n", PathBuffer);
+            DPRINT("RelativePath(2): '%S'\n", PathBuffer);
 
             Status = SetupCreateDirectory(PathBuffer);
             if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
             {
+                INF_FreeData(DirKeyValue);
                 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
                 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
                 return FALSE;
             }
         }
+
+        INF_FreeData(DirKeyValue);
     } while (SetupFindNextLine(&DirContext, &DirContext));
 
     return TRUE;
@@ -3817,9 +4105,9 @@ PrepareCopyPage(PINPUT_RECORD Ir)
             return QUIT_PAGE;
         }
 
-        InfHandle = INF_OpenBufferedFileA((CHAR*) InfFileData,
+        InfHandle = INF_OpenBufferedFileA((PSTR)InfFileData,
                                           InfFileSize,
-                                          (const CHAR*) NULL,
+                                          NULL,
                                           INF_STYLE_WIN4,
                                           LanguageId,
                                           &ErrorLine);
@@ -4012,8 +4300,7 @@ FileCopyPage(PINPUT_RECORD Ir)
  *  QuitPage
  *
  * SIDEEFFECTS
- *  Calls SetInstallPathValue
- *  Calls NtInitializeRegistry
+ *  Calls RegInitializeRegistry
  *  Calls ImportRegistryFile
  *  Calls SetDefaultPagefile
  *  Calls SetMountedDeviceValues
@@ -4024,44 +4311,91 @@ FileCopyPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 RegistryPage(PINPUT_RECORD Ir)
 {
+    NTSTATUS Status;
     INFCONTEXT InfContext;
     PWSTR Action;
     PWSTR File;
     PWSTR Section;
+    BOOLEAN Success;
+    BOOLEAN ShouldRepairRegistry = FALSE;
     BOOLEAN Delete;
-    NTSTATUS Status;
 
     MUIDisplayPage(REGISTRY_PAGE);
 
     if (RepairUpdateFlag)
     {
-        return SUCCESS_PAGE;
-    }
+        DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n");
 
-    if (!SetInstallPathValue(&DestinationPath))
-    {
-        DPRINT1("SetInstallPathValue() failed\n");
-        MUIDisplayError(ERROR_INITIALIZE_REGISTRY, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
+        /* Verify the registry hives and check whether we need to update or repair any of them */
+        Status = VerifyRegistryHives(&DestinationPath, &ShouldRepairRegistry);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status);
+            ShouldRepairRegistry = FALSE;
+        }
+        if (!ShouldRepairRegistry)
+            DPRINT1("No need to repair the registry\n");
     }
 
-    /* Create the default hives */
-    Status = NtInitializeRegistry(CM_BOOT_FLAG_SETUP);
+DoUpdate:
+    /* Update the registry */
+    CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE));
+
+    /* Initialize the registry and setup the registry hives */
+    Status = RegInitializeRegistry(&DestinationPath);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("NtInitializeRegistry() failed (Status %lx)\n", Status);
-        MUIDisplayError(ERROR_CREATE_HIVE, Ir, POPUP_WAIT_ENTER);
+        DPRINT1("RegInitializeRegistry() failed\n");
+        /********** HACK!!!!!!!!!!! **********/
+        if (Status == STATUS_NOT_IMPLEMENTED)
+        {
+            /* The hack was called, display its corresponding error */
+            MUIDisplayError(ERROR_INITIALIZE_REGISTRY, Ir, POPUP_WAIT_ENTER);
+        }
+        else
+        /*************************************/
+        {
+            /* Something else failed */
+            MUIDisplayError(ERROR_CREATE_HIVE, Ir, POPUP_WAIT_ENTER);
+        }
         return QUIT_PAGE;
     }
 
-    /* Update registry */
-    CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE));
+    if (!RepairUpdateFlag || ShouldRepairRegistry)
+    {
+        /*
+         * We fully setup the hives, in case we are doing a fresh installation
+         * (RepairUpdateFlag == FALSE), or in case we are doing an update
+         * (RepairUpdateFlag == TRUE) BUT we have some registry hives to
+         * "repair" (aka. recreate: ShouldRepairRegistry == TRUE).
+         */
 
-    if (!SetupFindFirstLineW(SetupInf, L"HiveInfs.Install", NULL, &InfContext))
+        Success = SetupFindFirstLineW(SetupInf, L"HiveInfs.Fresh", NULL, &InfContext);       // Windows-compatible
+        if (!Success)
+            Success = SetupFindFirstLineW(SetupInf, L"HiveInfs.Install", NULL, &InfContext); // ReactOS-specific
+
+        if (!Success)
+        {
+            DPRINT1("SetupFindFirstLine() failed\n");
+            MUIDisplayError(ERROR_FIND_REGISTRY, Ir, POPUP_WAIT_ENTER);
+            goto Cleanup;
+        }
+    }
+    else // if (RepairUpdateFlag && !ShouldRepairRegistry)
     {
-        DPRINT1("SetupFindFirstLine() failed\n");
-        MUIDisplayError(ERROR_FIND_REGISTRY, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
+        /*
+         * In case we are doing an update (RepairUpdateFlag == TRUE) and
+         * NO registry hives need a repair (ShouldRepairRegistry == FALSE),
+         * we only update the hives.
+         */
+
+        Success = SetupFindFirstLineW(SetupInf, L"HiveInfs.Upgrade", NULL, &InfContext);
+        if (!Success)
+        {
+            /* Nothing to do for update! */
+            DPRINT1("No update needed for the registry!\n");
+            goto Cleanup;
+        }
     }
 
     do
@@ -4073,91 +4407,130 @@ RegistryPage(PINPUT_RECORD Ir)
         DPRINT("Action: %S  File: %S  Section %S\n", Action, File, Section);
 
         if (Action == NULL)
+        {
+            INF_FreeData(Action);
+            INF_FreeData(File);
+            INF_FreeData(Section);
             break; // Hackfix
+        }
 
         if (!_wcsicmp(Action, L"AddReg"))
-        {
             Delete = FALSE;
-        }
         else if (!_wcsicmp(Action, L"DelReg"))
-        {
             Delete = TRUE;
-        }
         else
         {
+            DPRINT1("Unrecognized registry INF action '%S'\n", Action);
+            INF_FreeData(Action);
+            INF_FreeData(File);
+            INF_FreeData(Section);
             continue;
         }
 
+        INF_FreeData(Action);
+
         CONSOLE_SetStatusText(MUIGetString(STRING_IMPORTFILE), File);
 
-        if (!ImportRegistryFile(File, Section, LanguageId, Delete))
+        if (!ImportRegistryFile(SourcePath.Buffer, File, Section, LanguageId, Delete))
         {
             DPRINT1("Importing %S failed\n", File);
-
+            INF_FreeData(File);
+            INF_FreeData(Section);
             MUIDisplayError(ERROR_IMPORT_HIVE, Ir, POPUP_WAIT_ENTER);
-            return QUIT_PAGE;
+            goto Cleanup;
         }
     } while (SetupFindNextLine(&InfContext, &InfContext));
 
-    /* Update display registry settings */
-    CONSOLE_SetStatusText(MUIGetString(STRING_DISPLAYETTINGSUPDATE));
-    if (!ProcessDisplayRegistry(SetupInf, DisplayList))
+    if (!RepairUpdateFlag || ShouldRepairRegistry)
     {
-        MUIDisplayError(ERROR_UPDATE_DISPLAY_SETTINGS, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
+        /* See the explanation for this test above */
 
-    /* Set the locale */
-    CONSOLE_SetStatusText(MUIGetString(STRING_LOCALESETTINGSUPDATE));
-    if (!ProcessLocaleRegistry(LanguageList))
-    {
-        MUIDisplayError(ERROR_UPDATE_LOCALESETTINGS, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
+        /* Update display registry settings */
+        CONSOLE_SetStatusText(MUIGetString(STRING_DISPLAYETTINGSUPDATE));
+        if (!ProcessDisplayRegistry(SetupInf, DisplayList))
+        {
+            MUIDisplayError(ERROR_UPDATE_DISPLAY_SETTINGS, Ir, POPUP_WAIT_ENTER);
+            goto Cleanup;
+        }
 
-    /* Add keyboard layouts */
-    CONSOLE_SetStatusText(MUIGetString(STRING_ADDKBLAYOUTS));
-    if (!AddKeyboardLayouts())
-    {
-        MUIDisplayError(ERROR_ADDING_KBLAYOUTS, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
+        /* Set the locale */
+        CONSOLE_SetStatusText(MUIGetString(STRING_LOCALESETTINGSUPDATE));
+        if (!ProcessLocaleRegistry(LanguageList))
+        {
+            MUIDisplayError(ERROR_UPDATE_LOCALESETTINGS, Ir, POPUP_WAIT_ENTER);
+            goto Cleanup;
+        }
+
+        /* Add keyboard layouts */
+        CONSOLE_SetStatusText(MUIGetString(STRING_ADDKBLAYOUTS));
+        if (!AddKeyboardLayouts())
+        {
+            MUIDisplayError(ERROR_ADDING_KBLAYOUTS, Ir, POPUP_WAIT_ENTER);
+            goto Cleanup;
+        }
+
+        /* Set GeoID */
+        if (!SetGeoID(MUIGetGeoID()))
+        {
+            MUIDisplayError(ERROR_UPDATE_GEOID, Ir, POPUP_WAIT_ENTER);
+            goto Cleanup;
+        }
+
+        if (!IsUnattendedSetup)
+        {
+            /* Update keyboard layout settings */
+            CONSOLE_SetStatusText(MUIGetString(STRING_KEYBOARDSETTINGSUPDATE));
+            if (!ProcessKeyboardLayoutRegistry(LayoutList))
+            {
+                MUIDisplayError(ERROR_UPDATE_KBSETTINGS, Ir, POPUP_WAIT_ENTER);
+                goto Cleanup;
+            }
+        }
+
+        /* Add codepage information to registry */
+        CONSOLE_SetStatusText(MUIGetString(STRING_CODEPAGEINFOUPDATE));
+        if (!AddCodePage())
+        {
+            MUIDisplayError(ERROR_ADDING_CODEPAGE, Ir, POPUP_WAIT_ENTER);
+            goto Cleanup;
+        }
+
+        /* Set the default pagefile entry */
+        SetDefaultPagefile(DestinationDriveLetter);
+
+        /* Update the mounted devices list */
+        // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)!
+        SetMountedDeviceValues(PartitionList);
     }
 
-    /* Set GeoID */
-    if (!SetGeoID(MUIGetGeoID()))
+Cleanup:
+    //
+    // TODO: Unload all the registry stuff, perform cleanup,
+    // and copy the created hive files into .sav files.
+    //
+    RegCleanupRegistry(&DestinationPath);
+
+    /*
+     * Check whether we were in update/repair mode but we were actually
+     * repairing the registry hives. If so, we have finished repairing them,
+     * and we now reset the flag and run the proper registry update.
+     * Otherwise we have finished the registry update!
+     */
+    if (RepairUpdateFlag && ShouldRepairRegistry)
     {
-        MUIDisplayError(ERROR_UPDATE_GEOID, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
+        ShouldRepairRegistry = FALSE;
+        goto DoUpdate;
     }
 
-    if (!IsUnattendedSetup)
+    if (NT_SUCCESS(Status))
     {
-        /* Update keyboard layout settings */
-        CONSOLE_SetStatusText(MUIGetString(STRING_KEYBOARDSETTINGSUPDATE));
-        if (!ProcessKeyboardLayoutRegistry(LayoutList))
-        {
-            MUIDisplayError(ERROR_UPDATE_KBSETTINGS, Ir, POPUP_WAIT_ENTER);
-            return QUIT_PAGE;
-        }
+        CONSOLE_SetStatusText(MUIGetString(STRING_DONE));
+        return BOOT_LOADER_PAGE;
     }
-
-    /* Add codepage information to registry */
-    CONSOLE_SetStatusText(MUIGetString(STRING_CODEPAGEINFOUPDATE));
-    if (!AddCodePage())
+    else
     {
-        MUIDisplayError(ERROR_ADDING_CODEPAGE, Ir, POPUP_WAIT_ENTER);
         return QUIT_PAGE;
     }
-
-    /* Set the default pagefile entry */
-    SetDefaultPagefile(DestinationDriveLetter);
-
-    /* Update the mounted devices list */
-    SetMountedDeviceValues(PartitionList);
-
-    CONSOLE_SetStatusText(MUIGetString(STRING_DONE));
-
-    return BOOT_LOADER_PAGE;
 }
 
 
@@ -4173,8 +4546,7 @@ RegistryPage(PINPUT_RECORD Ir)
  *  QuitPage
  *
  * SIDEEFFECTS
- *  Calls SetInstallPathValue
- *  Calls NtInitializeRegistry
+ *  Calls RegInitializeRegistry
  *  Calls ImportRegistryFile
  *  Calls SetDefaultPagefile
  *  Calls SetMountedDeviceValues
@@ -4193,10 +4565,10 @@ BootLoaderPage(PINPUT_RECORD Ir)
     CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
 
     RtlFreeUnicodeString(&SystemRootPath);
-    swprintf(PathBuffer,
-             L"\\Device\\Harddisk%lu\\Partition%lu",
-             PartitionList->SystemPartition->DiskEntry->DiskNumber,
-             PartitionList->SystemPartition->PartitionNumber);
+    StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+            L"\\Device\\Harddisk%lu\\Partition%lu\\",
+            PartitionList->SystemPartition->DiskEntry->DiskNumber,
+            PartitionList->SystemPartition->PartitionNumber);
     RtlCreateUnicodeString(&SystemRootPath, PathBuffer);
     DPRINT1("SystemRootPath: %wZ\n", &SystemRootPath);
 
@@ -4241,9 +4613,9 @@ BootLoaderPage(PINPUT_RECORD Ir)
     }
     else if ((PartitionType == PARTITION_FAT_12) ||
              (PartitionType == PARTITION_FAT_16) ||
-             (PartitionType == PARTITION_HUGE) ||
+             (PartitionType == PARTITION_HUGE)   ||
              (PartitionType == PARTITION_XINT13) ||
-             (PartitionType == PARTITION_FAT32) ||
+             (PartitionType == PARTITION_FAT32)  ||
              (PartitionType == PARTITION_FAT32_XINT13))
     {
         DPRINT("Found FAT partition\n");
@@ -4280,11 +4652,11 @@ BootLoaderPage(PINPUT_RECORD Ir)
             CONSOLE_NormalTextXY(8, Line, 60, 1);
 
             Line++;
-            if (Line<12)
-                Line=15;
+            if (Line < 12)
+                Line = 15;
 
-            if (Line>15)
-                Line=12;
+            if (Line > 15)
+                Line = 12;
 
             CONSOLE_InvertTextXY(8, Line, 60, 1);
         }
@@ -4294,11 +4666,11 @@ BootLoaderPage(PINPUT_RECORD Ir)
             CONSOLE_NormalTextXY(8, Line, 60, 1);
 
             Line--;
-            if (Line<12)
-                Line=15;
+            if (Line < 12)
+                Line = 15;
 
-            if (Line>15)
-                Line=12;
+            if (Line > 15)
+                Line = 12;
 
             CONSOLE_InvertTextXY(8, Line, 60, 1);
         }
@@ -4410,15 +4782,12 @@ BootLoaderFloppyPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
 {
-    UCHAR PartitionType;
     NTSTATUS Status;
 
-    PartitionType = PartitionList->SystemPartition->PartitionType;
-
     Status = InstallVBRToPartition(&SystemRootPath,
                                    &SourceRootPath,
                                    &DestinationArcPath,
-                                   PartitionType);
+                                   PartitionList->SystemPartition->PartitionType);
     if (!NT_SUCCESS(Status))
     {
         MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
@@ -4438,7 +4807,7 @@ BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
  *
  * SIDEEFFECTS
  *  Calls InstallVBRToPartition()
- *  CallsInstallMbrBootCodeToDisk()
+ *  Calls InstallMbrBootCodeToDisk()
  *
  * RETURNS
  *   Number of the next page.
@@ -4446,19 +4815,16 @@ BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
 {
-    UCHAR PartitionType;
     NTSTATUS Status;
     WCHAR DestinationDevicePathBuffer[MAX_PATH];
     WCHAR SourceMbrPathBuffer[MAX_PATH];
     WCHAR DstPath[MAX_PATH];
 
     /* Step 1: Write the VBR */
-    PartitionType = PartitionList->SystemPartition->PartitionType;
-
     Status = InstallVBRToPartition(&SystemRootPath,
                                    &SourceRootPath,
                                    &DestinationArcPath,
-                                   PartitionType);
+                                   PartitionList->SystemPartition->PartitionType);
     if (!NT_SUCCESS(Status))
     {
         MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
@@ -4466,16 +4832,16 @@ BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
     }
 
     /* Step 2: Write the MBR */
-    swprintf(DestinationDevicePathBuffer,
-             L"\\Device\\Harddisk%d\\Partition0",
-             PartitionList->SystemPartition->DiskEntry->DiskNumber);
+    StringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
+            L"\\Device\\Harddisk%d\\Partition0",
+            PartitionList->SystemPartition->DiskEntry->DiskNumber);
 
     CombinePaths(SourceMbrPathBuffer, ARRAYSIZE(SourceMbrPathBuffer), 2, SourceRootPath.Buffer, L"\\loader\\dosmbr.bin");
 
     if (IsThereAValidBootSector(DestinationDevicePathBuffer))
     {
         /* Save current MBR */
-        CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath.Buffer, L"\\mbr.old");
+        CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath.Buffer, L"mbr.old");
 
         DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath);
         Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR));
@@ -4502,6 +4868,201 @@ BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
 }
 
 
+/**
+ * @name ProgressTimeOutStringHandler
+ *
+ * Handles the generation (displaying) of the timeout
+ * countdown to the screen dynamically.
+ *
+ * @param   Bar
+ *     A pointer to a progress bar.
+ *
+ * @param   AlwaysUpdate
+ *     Constantly update the progress bar (boolean type).
+ *
+ * @param   Buffer
+ *     A pointer to a string buffer.
+ *
+ * @param   cchBufferSize
+ *     The buffer's size in number of characters.
+ *
+ * @return
+ *     TRUE or FALSE on function termination.
+ *
+ */
+static
+BOOLEAN NTAPI
+ProgressTimeOutStringHandler(
+    IN PPROGRESSBAR Bar,
+    IN BOOLEAN AlwaysUpdate,
+    OUT PSTR Buffer,
+    IN SIZE_T cchBufferSize)
+{
+    ULONG OldProgress = Bar->Progress;
+
+    if (Bar->StepCount == 0)
+    {
+        Bar->Progress = 0;
+    }
+    else
+    {
+        Bar->Progress = Bar->StepCount - Bar->CurrentStep;
+    }
+
+    /* Build the progress string if it has changed */
+    if (Bar->ProgressFormatText &&
+        (AlwaysUpdate || (Bar->Progress != OldProgress)))
+    {
+        RtlStringCchPrintfA(Buffer, cchBufferSize,
+                            Bar->ProgressFormatText, Bar->Progress / max(1, Bar->Width) + 1);
+
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+/**
+ * @name ProgressCountdown
+ *
+ * Displays and draws a red-coloured progress bar with a countdown.
+ * When the timeout is reached, the flush page is displayed for reboot.
+ *
+ * @param   Ir
+ *     A pointer to an input keyboard record.
+ *
+ * @param   TimeOut
+ *     Initial countdown value in seconds.
+ *
+ * @return
+ *     Nothing.
+ *
+ */
+static VOID
+ProgressCountdown(
+    IN PINPUT_RECORD Ir,
+    IN LONG TimeOut)
+{
+    NTSTATUS Status;
+    ULONG StartTime, BarWidth, TimerDiv;
+    LONG TimeElapsed;
+    LONG TimerValue, OldTimerValue;
+    LARGE_INTEGER Timeout;
+    PPROGRESSBAR ProgressBar;
+    BOOLEAN RefreshProgress = TRUE;
+
+    /* Bail out if the timeout is already zero */
+    if (TimeOut <= 0)
+        return;
+
+    /* Create the timeout progress bar and set it up */
+    ProgressBar = CreateProgressBarEx(13,
+                                      26,
+                                      xScreen - 13,
+                                      yScreen - 20,
+                                      10,
+                                      24,
+                                      TRUE,
+                                      FOREGROUND_RED | BACKGROUND_BLUE,
+                                      0,
+                                      NULL,
+                                      MUIGetString(STRING_REBOOTPROGRESSBAR),
+                                      ProgressTimeOutStringHandler);
+
+    BarWidth = max(1, ProgressBar->Width);
+    TimerValue = TimeOut * BarWidth;
+    ProgressSetStepCount(ProgressBar, TimerValue);
+
+    StartTime = NtGetTickCount();
+    CONSOLE_Flush();
+
+    TimerDiv = 1000 / BarWidth;
+    TimerDiv = max(1, TimerDiv);
+    OldTimerValue = TimerValue;
+    while (TRUE)
+    {
+        /* Decrease the timer */
+
+        /*
+         * Compute how much time the previous operations took.
+         * This allows us in particular to take account for any time
+         * elapsed if something slowed down.
+         */
+        TimeElapsed = NtGetTickCount() - StartTime;
+        if (TimeElapsed >= TimerDiv)
+        {
+            /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
+            TimeElapsed /= TimerDiv;
+            StartTime += (TimerDiv * TimeElapsed);
+
+            if (TimeElapsed <= TimerValue)
+                TimerValue -= TimeElapsed;
+            else
+                TimerValue = 0;
+
+            RefreshProgress = TRUE;
+        }
+
+        if (RefreshProgress)
+        {
+            ProgressSetStep(ProgressBar, OldTimerValue - TimerValue);
+            RefreshProgress = FALSE;
+        }
+
+        /* Stop when the timer reaches zero */
+        if (TimerValue <= 0)
+            break;
+
+        /* Check for user key presses */
+
+        /*
+         * If the timer is used, use a passive wait of maximum 1 second
+         * while monitoring for incoming console input events, so that
+         * we are still able to display the timing count.
+         */
+
+        /* Wait a maximum of 1 second for input events */
+        TimeElapsed = NtGetTickCount() - StartTime;
+        if (TimeElapsed < TimerDiv)
+        {
+            /* Convert the time to NT Format */
+            Timeout.QuadPart = (TimerDiv - TimeElapsed) * -10000LL;
+            Status = NtWaitForSingleObject(StdInput, FALSE, &Timeout);
+        }
+        else
+        {
+            Status = STATUS_TIMEOUT;
+        }
+
+        /* Check whether the input event has been signaled, or a timeout happened */
+        if (Status == STATUS_TIMEOUT)
+        {
+            continue;
+        }
+        if (Status != STATUS_WAIT_0)
+        {
+            /* An error happened, bail out */
+            DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status);
+            break;
+        }
+
+        /* Check for an ENTER key press */
+        while (CONSOLE_ConInKeyPeek(Ir))
+        {
+            if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+            {
+                /* Found it, stop waiting */
+                goto Exit;
+            }
+        }
+    }
+
+Exit:
+    /* Destroy the progress bar and quit */
+    DestroyProgressBar(ProgressBar);
+}
+
+
 /*
  * Displays the QuitPage.
  *
@@ -4519,6 +5080,13 @@ QuitPage(PINPUT_RECORD Ir)
 {
     MUIDisplayPage(QUIT_PAGE);
 
+    /* Destroy the NTOS installations list */
+    if (NtOsInstallsList != NULL)
+    {
+        DestroyGenericList(NtOsInstallsList, TRUE);
+        NtOsInstallsList = NULL;
+    }
+
     /* Destroy the partition list */
     if (PartitionList != NULL)
     {
@@ -4572,15 +5140,9 @@ QuitPage(PINPUT_RECORD Ir)
 
     CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2));
 
-    while (TRUE)
-    {
-        CONSOLE_ConInKey(Ir);
-
-        if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
-        {
-            return FLUSH_PAGE;
-        }
-    }
+    /* Wait for maximum 15 seconds or an ENTER key before quitting */
+    ProgressCountdown(Ir, 15);
+    return FLUSH_PAGE;
 }
 
 
@@ -4602,19 +5164,11 @@ SuccessPage(PINPUT_RECORD Ir)
     MUIDisplayPage(SUCCESS_PAGE);
 
     if (IsUnattendedSetup)
-    {
         return FLUSH_PAGE;
-    }
 
-    while (TRUE)
-    {
-        CONSOLE_ConInKey(Ir);
-
-        if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
-        {
-            return FLUSH_PAGE;
-        }
-    }
+    /* Wait for maximum 15 seconds or an ENTER key before quitting */
+    ProgressCountdown(Ir, 15);
+    return FLUSH_PAGE;
 }
 
 
@@ -4642,16 +5196,20 @@ PnpEventThread(IN LPVOID lpParameter);
 /*
  * The start routine and page management
  */
-VOID
+NTSTATUS
 RunUSetup(VOID)
 {
+    NTSTATUS Status;
     INPUT_RECORD Ir;
     PAGE_NUMBER Page;
-    LARGE_INTEGER Time;
-    NTSTATUS Status;
     BOOLEAN Old;
 
-    NtQuerySystemTime(&Time);
+    InfSetHeap(ProcessHeap);
+
+    /* Tell the Cm this is a setup boot, and it has to behave accordingly */
+    Status = NtInitializeRegistry(CM_BOOT_FLAG_SETUP);
+    if (!NT_SUCCESS(Status))
+        DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status);
 
     /* Create the PnP thread in suspended state */
     Status = RtlCreateUserThread(NtCurrentProcess(),
@@ -4665,7 +5223,7 @@ RunUSetup(VOID)
                                  &hPnpThread,
                                  NULL);
     if (!NT_SUCCESS(Status))
-        hPnpThread = INVALID_HANDLE_VALUE;
+        hPnpThread = NULL;
 
     if (!CONSOLE_Init())
     {
@@ -4673,9 +5231,8 @@ RunUSetup(VOID)
         PrintString(MUIGetString(STRING_CONSOLEFAIL2));
         PrintString(MUIGetString(STRING_CONSOLEFAIL3));
 
-        /* Raise a hard error (crash the system/BSOD) */
-        NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
-                         0,0,0,0,0);
+        /* We failed to initialize the video, just quit the installer */
+        return STATUS_APP_INIT_FAILURE;
     }
 
     /* Initialize global unicode strings */
@@ -4691,37 +5248,36 @@ RunUSetup(VOID)
     /* Hide the cursor */
     CONSOLE_SetCursorType(TRUE, FALSE);
 
-    Page = START_PAGE;
+    /* Global Initialization page */
+    CONSOLE_ClearScreen();
+    CONSOLE_Flush();
+    Page = SetupStartPage(&Ir);
+
     while (Page != REBOOT_PAGE && Page != RECOVERY_PAGE)
     {
         CONSOLE_ClearScreen();
         CONSOLE_Flush();
 
-        //CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
-        //CONSOLE_Flush();
+        // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
+        // CONSOLE_Flush();
 
         switch (Page)
         {
-            /* Start page */
-            case START_PAGE:
-                Page = SetupStartPage(&Ir);
-                break;
-
             /* Language page */
             case LANGUAGE_PAGE:
                 Page = LanguagePage(&Ir);
                 break;
 
+            /* Welcome page */
+            case WELCOME_PAGE:
+                Page = WelcomePage(&Ir);
+                break;
+
             /* License page */
             case LICENSE_PAGE:
                 Page = LicensePage(&Ir);
                 break;
 
-            /* Intro page */
-            case INTRO_PAGE:
-                Page = IntroPage(&Ir);
-                break;
-
             /* Install pages */
             case INSTALL_INTRO_PAGE:
                 Page = InstallIntroPage(&Ir);
@@ -4830,6 +5386,10 @@ RunUSetup(VOID)
                 Page = RepairIntroPage(&Ir);
                 break;
 
+            case UPGRADE_REPAIR_PAGE:
+                Page = UpgradeRepairPage(&Ir);
+                break;
+
             case SUCCESS_PAGE:
                 Page = SuccessPage(&Ir);
                 break;
@@ -4853,26 +5413,50 @@ RunUSetup(VOID)
 
     FreeConsole();
 
-    /* Avoid bugcheck */
-    Time.QuadPart += 50000000;
-    NtDelayExecution(FALSE, &Time);
-
     /* Reboot */
     RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old);
     NtShutdownSystem(ShutdownReboot);
     RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old);
-    NtTerminateProcess(NtCurrentProcess(), 0);
+
+    return STATUS_SUCCESS;
 }
 
 
 VOID NTAPI
 NtProcessStartup(PPEB Peb)
 {
+    NTSTATUS Status;
+    LARGE_INTEGER Time;
+
     RtlNormalizeProcessParams(Peb->ProcessParameters);
 
     ProcessHeap = Peb->ProcessHeap;
-    InfSetHeap(ProcessHeap);
-    RunUSetup();
+
+    NtQuerySystemTime(&Time);
+
+    Status = RunUSetup();
+
+    if (NT_SUCCESS(Status))
+    {
+        /*
+         * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
+         * a protective waiting.
+         * This wait is needed because, since we are started as SMSS.EXE,
+         * the NT kernel explicitly waits 5 seconds for the initial process
+         * SMSS.EXE to initialize (as a protective measure), and otherwise
+         * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
+         */
+        Time.QuadPart += 50000000;
+        NtDelayExecution(FALSE, &Time);
+    }
+    else
+    {
+        /* The installer failed to start: raise a hard error (crash the system/BSOD) */
+        Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
+                                  0, 0, NULL, 0, NULL);
+    }
+
+    NtTerminateProcess(NtCurrentProcess(), Status);
 }
 
 /* EOF */