[SETUPLIB][USETUP] Use NT RTL String Safe functions instead of Win32-oriented ones...
[reactos.git] / base / setup / usetup / usetup.c
index c87a3fe..b9ba8ee 100644 (file)
 #include "chkdsk.h"
 #include "cmdcons.h"
 #include "format.h"
-#include "settings.h"
 
 #define NDEBUG
 #include <debug.h>
 
-// HACK!
-#include <strsafe.h>
 
-
-/* GLOBALS ******************************************************************/
+/* GLOBALS & LOCALS *********************************************************/
 
 HANDLE ProcessHeap;
 
-static UNICODE_STRING SourceRootPath;
-static UNICODE_STRING SourceRootDir;
-static UNICODE_STRING SourcePath;
-
 BOOLEAN IsUnattendedSetup = FALSE;
-LONG UnattendDestinationDiskNumber;
-LONG UnattendDestinationPartitionNumber;
-LONG UnattendMBRInstallType = -1;
-LONG UnattendFormatPartition = 0;
-LONG AutoPartition = 0;
-WCHAR UnattendInstallationDirectory[MAX_PATH];
-PWCHAR SelectedLanguageId;
-WCHAR LocaleID[9];
-WCHAR DefaultLanguage[20];
-WCHAR DefaultKBLayout[20];
-static BOOLEAN RepairUpdateFlag = FALSE;
-static HANDLE hPnpThread = INVALID_HANDLE_VALUE;
-
-static PPARTLIST PartitionList = NULL;
-static PPARTENTRY TempPartition = NULL;
-static FORMATMACHINESTATE FormatState = Start;
-
-
-/* LOCALS *******************************************************************/
-
-static PFILE_SYSTEM_LIST FileSystemList = NULL;
+static USETUP_DATA USetupData;
 
 /*
  * NOTE: Technically only used for the COPYCONTEXT InstallPath member
@@ -78,29 +50,27 @@ static PFILE_SYSTEM_LIST FileSystemList = NULL;
  */
 static UNICODE_STRING InstallPath;
 
-/*
- * Path to the system partition, where the boot manager resides.
- * On x86 PCs, this is usually the active partition.
- * On ARC, (u)EFI, ... platforms, this is a dedicated partition.
- *
- * For more information, see:
- * https://en.wikipedia.org/wiki/System_partition_and_boot_partition
- * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/boot-and-system-volumes.html
- * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/arc-boot-process.html
- * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/efi-boot-process.html
- * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-system-volume.html
- * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-boot-volume.html
- */
-static UNICODE_STRING SystemRootPath;
-
-/* Path to the installation directory inside the ReactOS boot partition */
-static UNICODE_STRING DestinationPath;
-static UNICODE_STRING DestinationArcPath;
-static UNICODE_STRING DestinationRootPath;
-
 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
 static WCHAR DestinationDriveLetter;
 
+
+/* OTHER Stuff *****/
+
+PWCHAR SelectedLanguageId;
+static WCHAR DefaultLanguage[20];   // Copy of string inside LanguageList
+static WCHAR DefaultKBLayout[20];   // Copy of string inside KeyboardList
+
+static BOOLEAN RepairUpdateFlag = FALSE;
+
+static HANDLE hPnpThread = NULL;
+
+static PPARTLIST PartitionList = NULL;
+static PPARTENTRY TempPartition = NULL;
+static PFILE_SYSTEM_LIST FileSystemList = NULL;
+static FORMATMACHINESTATE FormatState = Start;
+
+/*****************************************************/
+
 static HINF SetupInf;
 
 static HSPFILEQ SetupFileQueue = NULL;
@@ -114,9 +84,6 @@ static PGENERIC_LIST KeyboardList = NULL;
 static PGENERIC_LIST LayoutList   = NULL;
 static PGENERIC_LIST LanguageList = NULL;
 
-static LANGID LanguageId = 0;
-
-static ULONG RequiredPartitionDiskSpace = ~0;
 
 /* FUNCTIONS ****************************************************************/
 
@@ -273,7 +240,7 @@ PopupError(PCCH Text,
         if (Length > MaxLength)
             MaxLength = Length;
 
-        if (LastLine != FALSE)
+        if (LastLine)
             break;
 
         pnext = p + 1;
@@ -339,7 +306,7 @@ PopupError(PCCH Text,
                                          &Written);
         }
 
-        if (LastLine != FALSE)
+        if (LastLine)
             break;
 
         coPos.Y++;
@@ -429,189 +396,17 @@ ConfirmQuit(PINPUT_RECORD Ir)
 }
 
 
-static VOID
-CheckUnattendedSetup(VOID)
-{
-    WCHAR UnattendInfPath[MAX_PATH];
-    INFCONTEXT Context;
-    HINF UnattendInf;
-    UINT ErrorLine;
-    INT IntValue;
-    PWCHAR Value;
-
-    CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2, SourcePath.Buffer, L"unattend.inf");
-
-    if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
-    {
-        DPRINT("Does not exist: %S\n", UnattendInfPath);
-        return;
-    }
-
-    /* Load 'unattend.inf' from install media. */
-    UnattendInf = SetupOpenInfFileExW(UnattendInfPath,
-                                      NULL,
-                                      INF_STYLE_WIN4,
-                                      LanguageId,
-                                      &ErrorLine);
-
-    if (UnattendInf == INVALID_HANDLE_VALUE)
-    {
-        DPRINT("SetupOpenInfFileExW() failed\n");
-        return;
-    }
-
-    /* Open 'Unattend' section */
-    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"Signature", &Context))
-    {
-        DPRINT("SetupFindFirstLineW() failed for section 'Unattend'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    /* Get pointer 'Signature' key */
-    if (!INF_GetData(&Context, NULL, &Value))
-    {
-        DPRINT("INF_GetData() failed for key 'Signature'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    /* Check 'Signature' string */
-    if (_wcsicmp(Value, L"$ReactOS$") != 0)
-    {
-        DPRINT("Signature not $ReactOS$\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    /* Check if Unattend setup is enabled */
-    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"UnattendSetupEnabled", &Context))
-    {
-        DPRINT("Can't find key 'UnattendSetupEnabled'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    if (!INF_GetData(&Context, NULL, &Value))
-    {
-        DPRINT("Can't read key 'UnattendSetupEnabled'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    if (_wcsicmp(Value, L"yes") != 0)
-    {
-        DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
-    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"DestinationDiskNumber", &Context))
-    {
-        DPRINT("SetupFindFirstLine() failed for key 'DestinationDiskNumber'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    if (!SetupGetIntField(&Context, 1, &IntValue))
-    {
-        DPRINT("SetupGetIntField() failed for key 'DestinationDiskNumber'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    UnattendDestinationDiskNumber = (LONG)IntValue;
-
-    /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
-    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"DestinationPartitionNumber", &Context))
-    {
-        DPRINT("SetupFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    if (!SetupGetIntField(&Context, 1, &IntValue))
-    {
-        DPRINT("SetupGetIntField() failed for key 'DestinationPartitionNumber'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    UnattendDestinationPartitionNumber = (LONG)IntValue;
-
-    /* Search for 'InstallationDirectory' in the 'Unattend' section */
-    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"InstallationDirectory", &Context))
-    {
-        DPRINT("SetupFindFirstLine() failed for key 'InstallationDirectory'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    /* Get pointer 'InstallationDirectory' key */
-    if (!INF_GetData(&Context, NULL, &Value))
-    {
-        DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    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))
-    {
-        if (SetupGetIntField(&Context, 1, &IntValue))
-        {
-            UnattendMBRInstallType = IntValue;
-        }
-    }
-
-    /* Search for 'FormatPartition' in the 'Unattend' section */
-    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"FormatPartition", &Context))
-    {
-        if (SetupGetIntField(&Context, 1, &IntValue))
-        {
-            UnattendFormatPartition = IntValue;
-        }
-    }
-
-    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"AutoPartition", &Context))
-    {
-        if (SetupGetIntField(&Context, 1, &IntValue))
-        {
-            AutoPartition = IntValue;
-        }
-    }
-
-    /* search for LocaleID in the 'Unattend' section*/
-    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"LocaleID", &Context))
-    {
-        if (INF_GetData(&Context, NULL, &Value))
-        {
-            LONG Id = wcstol(Value, NULL, 16);
-            swprintf(LocaleID, L"%08lx", Id);
-       }
-    }
-
-    SetupCloseInfFile(UnattendInf);
-}
-
-
 static VOID
 UpdateKBLayout(VOID)
 {
     PGENERIC_LIST_ENTRY ListEntry;
-    LPCWSTR pszNewLayout;
+    PCWSTR pszNewLayout;
 
-    pszNewLayout = MUIDefaultKeyboardLayout();
+    pszNewLayout = MUIDefaultKeyboardLayout(SelectedLanguageId);
 
     if (LayoutList == NULL)
     {
-        LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
+        LayoutList = CreateKeyboardLayoutList(SetupInf, SelectedLanguageId, DefaultKBLayout);
         if (LayoutList == NULL)
         {
             /* FIXME: Handle error! */
@@ -645,7 +440,7 @@ UpdateKBLayout(VOID)
  *
  * SIDEEFFECTS
  *  Init SelectedLanguageId
- *  Init LanguageId
+ *  Init USetupData.LanguageId
  *
  * RETURNS
  *   Number of the next page.
@@ -668,8 +463,10 @@ LanguagePage(PINPUT_RECORD Ir)
         }
     }
 
-    /* Load the font */
     SelectedLanguageId = DefaultLanguage;
+    USetupData.LanguageId = 0;
+
+    /* Load the font */
     SetConsoleCodePage();
     UpdateKBLayout();
 
@@ -677,7 +474,7 @@ LanguagePage(PINPUT_RECORD Ir)
      * the language selection process altogether! */
     if (GenericListHasSingleEntry(LanguageList))
     {
-        LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
+        USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
         return WELCOME_PAGE;
     }
 
@@ -723,7 +520,7 @@ LanguagePage(PINPUT_RECORD Ir)
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
             else
                 RedrawGenericList(&ListUi);
@@ -732,7 +529,7 @@ LanguagePage(PINPUT_RECORD Ir)
         {
             SelectedLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
 
-            LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
+            USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
 
             if (wcscmp(SelectedLanguageId, DefaultLanguage))
             {
@@ -755,7 +552,7 @@ LanguagePage(PINPUT_RECORD Ir)
         {
             NewLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
 
-            if (SelectedLanguageId != NewLanguageId)
+            if (wcscmp(SelectedLanguageId, NewLanguageId))
             {
                 /* Clear the language page */
                 MUIClearPage(LANGUAGE_PAGE);
@@ -777,65 +574,6 @@ LanguagePage(PINPUT_RECORD Ir)
 }
 
 
-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;
-}
-
-
 /*
  * Start page
  *
@@ -846,15 +584,15 @@ GetSourcePaths(
  *
  * SIDEEFFECTS
  *  Init Sdi
- *  Init SourcePath
- *  Init SourceRootPath
- *  Init SourceRootDir
+ *  Init USetupData.SourcePath
+ *  Init USetupData.SourceRootPath
+ *  Init USetupData.SourceRootDir
  *  Init SetupInf
- *  Init RequiredPartitionDiskSpace
+ *  Init USetupData.RequiredPartitionDiskSpace
  *  Init IsUnattendedSetup
  *  If unattended, init *List and sets the Codepage
  *  If unattended, init SelectedLanguageId
- *  If unattended, init LanguageId
+ *  If unattended, init USetupData.LanguageId
  *
  * RETURNS
  *   Number of the next page.
@@ -863,80 +601,33 @@ static PAGE_NUMBER
 SetupStartPage(PINPUT_RECORD Ir)
 {
     NTSTATUS Status;
-    WCHAR FileNameBuffer[MAX_PATH];
-    INFCONTEXT Context;
-    PWCHAR Value;
-    UINT ErrorLine;
+    ULONG Error;
     PGENERIC_LIST_ENTRY ListEntry;
-    INT IntValue;
 
     CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
 
     /* Get the source path and source root path */
-    Status = GetSourcePaths(&SourcePath,
-                            &SourceRootPath,
-                            &SourceRootDir);
+    Status = GetSourcePaths(&USetupData.SourcePath,
+                            &USetupData.SourceRootPath,
+                            &USetupData.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;
     }
-    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 = SetupOpenInfFileExW(FileNameBuffer,
-                                   NULL,
-                                   INF_STYLE_WIN4,
-                                   LanguageId,
-                                   &ErrorLine);
-
-    if (SetupInf == INVALID_HANDLE_VALUE)
-    {
-        MUIDisplayError(ERROR_LOAD_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    /* Open 'Version' section */
-    if (!SetupFindFirstLineW(SetupInf, L"Version", L"Signature", &Context))
-    {
-        MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    /* Get pointer 'Signature' key */
-    if (!INF_GetData(&Context, NULL, &Value))
-    {
-        MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    /* Check 'Signature' string */
-    if (_wcsicmp(Value, L"$ReactOS$") != 0)
-    {
-        MUIDisplayError(ERROR_SIGNATURE_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
+    DPRINT1("SourcePath: '%wZ'\n", &USetupData.SourcePath);
+    DPRINT1("SourceRootPath: '%wZ'\n", &USetupData.SourceRootPath);
+    DPRINT1("SourceRootDir: '%wZ'\n", &USetupData.SourceRootDir);
 
-    /* Open 'DiskSpaceRequirements' section */
-    if (!SetupFindFirstLineW(SetupInf, L"DiskSpaceRequirements", L"FreeSysPartDiskSpace", &Context))
+    /* Load 'txtsetup.sif' from the installation media */
+    Error = LoadSetupInf(&SetupInf, &USetupData);
+    if (Error != ERROR_SUCCESS)
     {
-        MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
+        MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
         return QUIT_PAGE;
     }
 
-    /* Get the 'FreeSysPartDiskSpace' value */
-    if (!SetupGetIntField(&Context, 1, &IntValue))
-    {
-        MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    RequiredPartitionDiskSpace = (ULONG)IntValue;
-
     /* Start the PnP thread */
     if (hPnpThread != NULL)
     {
@@ -944,7 +635,7 @@ SetupStartPage(PINPUT_RECORD Ir)
         hPnpThread = NULL;
     }
 
-    CheckUnattendedSetup();
+    CheckUnattendedSetup(&USetupData);
 
     if (IsUnattendedSetup)
     {
@@ -952,18 +643,21 @@ SetupStartPage(PINPUT_RECORD Ir)
         ComputerList = CreateComputerTypeList(SetupInf);
         DisplayList = CreateDisplayDriverList(SetupInf);
         KeyboardList = CreateKeyboardDriverList(SetupInf);
-        LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
+
         LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
 
         /* new part */
-        wcscpy(SelectedLanguageId, LocaleID);
-        LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
+        SelectedLanguageId = DefaultLanguage;
+        wcscpy(SelectedLanguageId, USetupData.LocaleID);
+        USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
+
+        LayoutList = CreateKeyboardLayoutList(SetupInf, SelectedLanguageId, DefaultKBLayout);
 
         /* first we hack LanguageList */
         ListEntry = GetFirstListEntry(LanguageList);
         while (ListEntry != NULL)
         {
-            if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
+            if (!wcsicmp(USetupData.LocaleID, GetListEntryUserData(ListEntry)))
             {
                 DPRINT("found %S in LanguageList\n",GetListEntryUserData(ListEntry));
                 SetCurrentListEntry(LanguageList, ListEntry);
@@ -977,7 +671,7 @@ SetupStartPage(PINPUT_RECORD Ir)
         ListEntry = GetFirstListEntry(LayoutList);
         while (ListEntry != NULL)
         {
-            if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
+            if (!wcsicmp(USetupData.LocaleID, GetListEntryUserData(ListEntry)))
             {
                 DPRINT("found %S in LayoutList\n",GetListEntryUserData(ListEntry));
                 SetCurrentListEntry(LayoutList, ListEntry);
@@ -1021,7 +715,7 @@ WelcomePage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -1199,7 +893,7 @@ UpgradeRepairPage(PINPUT_RECORD Ir)
                 break;
             case VK_F3:     /* F3 */
             {
-                if (ConfirmQuit(Ir) == TRUE)
+                if (ConfirmQuit(Ir))
                     return QUIT_PAGE;
                 else
                     RedrawGenericList(&ListUi);
@@ -1286,7 +980,7 @@ InstallIntroPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -1323,7 +1017,7 @@ ScsiControllerPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -1355,7 +1049,7 @@ OemDriverPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
         {
-            if (ConfirmQuit(Ir) == TRUE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -1396,6 +1090,7 @@ static PAGE_NUMBER
 DeviceSettingsPage(PINPUT_RECORD Ir)
 {
     static ULONG Line = 16;
+    CHAR CurrentItemText[256];
 
     /* Initialize the computer settings list */
     if (ComputerList == NULL)
@@ -1433,7 +1128,7 @@ DeviceSettingsPage(PINPUT_RECORD Ir)
     /* Initialize the keyboard layout list */
     if (LayoutList == NULL)
     {
-        LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
+        LayoutList = CreateKeyboardLayoutList(SetupInf, SelectedLanguageId, DefaultKBLayout);
         if (LayoutList == NULL)
         {
             /* FIXME: report error */
@@ -1450,10 +1145,14 @@ DeviceSettingsPage(PINPUT_RECORD Ir)
 
     MUIDisplayPage(DEVICE_SETTINGS_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)));
+    sprintf(CurrentItemText, "%S", GetListEntryText(GetCurrentListEntry(ComputerList)));
+    CONSOLE_SetTextXY(25, 11, CurrentItemText);
+    sprintf(CurrentItemText, "%S", GetListEntryText(GetCurrentListEntry(DisplayList)));
+    CONSOLE_SetTextXY(25, 12, CurrentItemText);
+    sprintf(CurrentItemText, "%S", GetListEntryText(GetCurrentListEntry(KeyboardList)));
+    CONSOLE_SetTextXY(25, 13, CurrentItemText);
+    sprintf(CurrentItemText, "%S", GetListEntryText(GetCurrentListEntry(LayoutList)));
+    CONSOLE_SetTextXY(25, 14, CurrentItemText);
 
     CONSOLE_InvertTextXY(24, Line, 48, 1);
 
@@ -1492,7 +1191,7 @@ DeviceSettingsPage(PINPUT_RECORD Ir)
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -1556,7 +1255,7 @@ HandleGenericList(PGENERIC_LIST_UI ListUi,
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
             else
                 RedrawGenericList(ListUi);
@@ -1704,10 +1403,10 @@ IsDiskSizeValid(PPARTENTRY PartEntry)
     size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
     size = (size + (512 * KB)) / MB;  /* in MBytes */
 
-    if (size < RequiredPartitionDiskSpace)
+    if (size < USetupData.RequiredPartitionDiskSpace)
     {
         /* 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);
+        DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, USetupData.RequiredPartitionDiskSpace);
         return FALSE;
     }
     else
@@ -1786,9 +1485,11 @@ SelectPartitionPage(PINPUT_RECORD Ir)
 
     if (IsUnattendedSetup)
     {
-        if (!SelectPartition(PartitionList, UnattendDestinationDiskNumber, UnattendDestinationPartitionNumber))
+        if (!SelectPartition(PartitionList,
+                             USetupData.DestinationDiskNumber,
+                             USetupData.DestinationPartitionNumber))
         {
-            if (AutoPartition)
+            if (USetupData.AutoPartition)
             {
                 if (PartitionList->CurrentPartition->LogicalPartition)
                 {
@@ -1807,7 +1508,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
                 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
                 {
                     MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
-                                    RequiredPartitionDiskSpace);
+                                    USetupData.RequiredPartitionDiskSpace);
                     return SELECT_PARTITION_PAGE; /* let the user select another partition */
                 }
 
@@ -1822,7 +1523,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
             if (!IsDiskSizeValid(PartitionList->CurrentPartition))
             {
                 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
-                                RequiredPartitionDiskSpace);
+                                USetupData.RequiredPartitionDiskSpace);
                 return SELECT_PARTITION_PAGE; /* let the user select another partition */
             }
 
@@ -1872,7 +1573,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
             {
                 DestroyPartitionList(PartitionList);
                 PartitionList = NULL;
@@ -1916,7 +1617,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
             if (!IsDiskSizeValid(PartitionList->CurrentPartition))
             {
                 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
-                                RequiredPartitionDiskSpace);
+                                USetupData.RequiredPartitionDiskSpace);
                 return SELECT_PARTITION_PAGE; /* let the user select another partition */
             }
 
@@ -1952,7 +1653,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
         }
         else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L')  /* L */
         {
-            if (PartitionList->CurrentPartition->LogicalPartition != FALSE)
+            if (PartitionList->CurrentPartition->LogicalPartition)
             {
                 Error = LogicalPartitionCreationChecks(PartitionList);
                 if (Error != NOT_AN_ERROR)
@@ -1966,12 +1667,34 @@ SelectPartitionPage(PINPUT_RECORD Ir)
         }
         else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D')  /* D */
         {
+            WCHAR PathBuffer[MAX_PATH];
+            UNICODE_STRING CurrentPartition;
+
             if (PartitionList->CurrentPartition->IsPartitioned == FALSE)
             {
                 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
                 return SELECT_PARTITION_PAGE;
             }
 
+            RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+                    L"\\Device\\Harddisk%lu\\Partition%lu\\",
+                    PartitionList->CurrentDisk->DiskNumber,
+                    PartitionList->CurrentPartition->PartitionNumber);
+            RtlInitUnicodeString(&CurrentPartition, PathBuffer);
+
+            /*
+             * Check whether the user attempts to delete the partition on which
+             * the installation source is present. If so, fail with an error.
+             */
+            // &USetupData.SourceRootPath
+            if (RtlPrefixUnicodeString(&CurrentPartition, &USetupData.SourcePath, TRUE))
+            {
+                PopupError("You cannot delete the partition containing the installation source!",
+                           MUIGetString(STRING_CONTINUE),
+                           Ir, POPUP_WAIT_ENTER);
+                return SELECT_PARTITION_PAGE;
+            }
+
             if (PartitionList->CurrentPartition->BootIndicator ||
                 PartitionList->CurrentPartition == PartitionList->SystemPartition)
             {
@@ -2276,14 +1999,14 @@ CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
         ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
                                   MaxSize, InputBuffer, &Quit, &Cancel);
 
-        if (Quit != FALSE)
+        if (Quit)
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
         }
-        else if (Cancel != FALSE)
+        else if (Cancel)
         {
             return SELECT_PARTITION_PAGE;
         }
@@ -2435,14 +2158,14 @@ CreateExtendedPartitionPage(PINPUT_RECORD Ir)
         ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
                                   MaxSize, InputBuffer, &Quit, &Cancel);
 
-        if (Quit != FALSE)
+        if (Quit)
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
         }
-        else if (Cancel != FALSE)
+        else if (Cancel)
         {
             return SELECT_PARTITION_PAGE;
         }
@@ -2593,14 +2316,14 @@ CreateLogicalPartitionPage(PINPUT_RECORD Ir)
         ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
                                   MaxSize, InputBuffer, &Quit, &Cancel);
 
-        if (Quit != FALSE)
+        if (Quit)
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
         }
-        else if (Cancel != FALSE)
+        else if (Cancel)
         {
             return SELECT_PARTITION_PAGE;
         }
@@ -2672,7 +2395,7 @@ ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) == TRUE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -2819,7 +2542,7 @@ DeletePartitionPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -2845,8 +2568,8 @@ DeletePartitionPage(PINPUT_RECORD Ir)
  *
  * Next pages:
  *  CheckFileSystemPage (At once if RepairUpdate is selected)
- *  CheckFileSystemPage (At once if Unattended and not UnattendFormatPartition)
- *  FormatPartitionPage (At once if Unattended and UnattendFormatPartition)
+ *  CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
+ *  FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
  *  SelectPartitionPage (If the user aborts)
  *  FormatPartitionPage (Default)
  *  QuitPage
@@ -3009,7 +2732,9 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
                                        PartTypeString,
                                        ARRAYSIZE(PartTypeString));
 
-    if (PartEntry->AutoCreate != FALSE)
+    MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
+
+    if (PartEntry->AutoCreate)
     {
         CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
 
@@ -3035,7 +2760,7 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
 
         PartEntry->AutoCreate = FALSE;
     }
-    else if (PartEntry->New != FALSE)
+    else if (PartEntry->New)
     {
         switch (FormatState)
         {
@@ -3093,8 +2818,6 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
                             DiskEntry->NoMbr ? "GPT" : "MBR");
     }
 
-    MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
-
     if (FileSystemList == NULL)
     {
         /* Create the file system list, and by default select the "FAT" file system */
@@ -3114,7 +2837,7 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
 
     if (IsUnattendedSetup)
     {
-        if (UnattendFormatPartition)
+        if (USetupData.FormatPartition)
         {
             /*
              * We use whatever currently selected file system we have
@@ -3138,7 +2861,7 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -3184,7 +2907,7 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
  *
  * SIDEEFFECTS
  *  Sets PartitionList->CurrentPartition->FormatState
- *  Sets DestinationRootPath
+ *  Sets USetupData.DestinationRootPath
  *
  * RETURNS
  *   Number of the next page.
@@ -3230,7 +2953,7 @@ FormatPartitionPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -3281,7 +3004,7 @@ FormatPartitionPage(PINPUT_RECORD Ir)
             }
 
             /* Set PartitionRootPath */
-            StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+            RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
                     L"\\Device\\Harddisk%lu\\Partition%lu",
                     DiskEntry->DiskNumber,
                     PartEntry->PartitionNumber);
@@ -3354,7 +3077,7 @@ CheckFileSystemPage(PINPUT_RECORD Ir)
     }
 
     /* Set PartitionRootPath */
-    StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+    RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
             L"\\Device\\Harddisk%lu\\Partition%lu",
             DiskEntry->DiskNumber,
             PartEntry->PartitionNumber);
@@ -3443,31 +3166,31 @@ BuildInstallPaths(PWSTR InstallDir,
     RtlFreeUnicodeString(&InstallPath);
     RtlCreateUnicodeString(&InstallPath, InstallDir);
 
-    /* Create 'DestinationRootPath' string */
-    RtlFreeUnicodeString(&DestinationRootPath);
-    StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+    /* Create 'USetupData.DestinationRootPath' string */
+    RtlFreeUnicodeString(&USetupData.DestinationRootPath);
+    RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
             L"\\Device\\Harddisk%lu\\Partition%lu\\",
             DiskEntry->DiskNumber,
             PartEntry->PartitionNumber);
-    RtlCreateUnicodeString(&DestinationRootPath, PathBuffer);
-    DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath);
+    RtlCreateUnicodeString(&USetupData.DestinationRootPath, PathBuffer);
+    DPRINT("DestinationRootPath: %wZ\n", &USetupData.DestinationRootPath);
 
 /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
-    /* Create 'DestinationPath' string */
-    RtlFreeUnicodeString(&DestinationPath);
+    /* Create 'USetupData.DestinationPath' string */
+    RtlFreeUnicodeString(&USetupData.DestinationPath);
     CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                 DestinationRootPath.Buffer, InstallDir);
-    RtlCreateUnicodeString(&DestinationPath, PathBuffer);
+                 USetupData.DestinationRootPath.Buffer, InstallDir);
+    RtlCreateUnicodeString(&USetupData.DestinationPath, PathBuffer);
 
 /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
-    /* Create 'DestinationArcPath' */
-    RtlFreeUnicodeString(&DestinationArcPath);
-    StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+    /* Create 'USetupData.DestinationArcPath' */
+    RtlFreeUnicodeString(&USetupData.DestinationArcPath);
+    RtlStringCchPrintfW(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);
+    RtlCreateUnicodeString(&USetupData.DestinationArcPath, PathBuffer);
 
     /* Initialize DestinationDriveLetter */
     DestinationDriveLetter = (WCHAR)PartEntry->DriveLetter;
@@ -3489,7 +3212,7 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
 {
     PDISKENTRY DiskEntry;
     PPARTENTRY PartEntry;
-    WCHAR InstallDir[51];
+    WCHAR InstallDir[MAX_PATH];
     WCHAR c;
     ULONG Length, Pos;
 
@@ -3511,10 +3234,11 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
     DiskEntry = PartitionList->CurrentDisk;
     PartEntry = PartitionList->CurrentPartition;
 
-    if (IsUnattendedSetup)
-        wcscpy(InstallDir, UnattendInstallationDirectory);
-    else if (RepairUpdateFlag)
+    // if (IsUnattendedSetup)
+    if (RepairUpdateFlag)
         wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath
+    else if (USetupData.InstallationDirectory[0])
+        wcscpy(InstallDir, USetupData.InstallationDirectory);
     else
         wcscpy(InstallDir, L"\\ReactOS");
 
@@ -3531,6 +3255,19 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
                           DiskEntry,
                           PartEntry);
 
+        /*
+         * Check whether the user attempts to install ReactOS within the
+         * installation source directory, or in a subdirectory thereof.
+         * If so, fail with an error.
+         */
+        if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
+        {
+            PopupError("You cannot install ReactOS within the installation source directory!",
+                       MUIGetString(STRING_CONTINUE),
+                       Ir, POPUP_WAIT_ENTER);
+            return INSTALL_DIRECTORY_PAGE;
+        }
+
         return PREPARE_COPY_PAGE;
     }
 
@@ -3551,7 +3288,7 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
         {
             CONSOLE_SetCursorType(TRUE, FALSE);
 
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             CONSOLE_SetCursorType(TRUE, TRUE);
@@ -3620,6 +3357,19 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
                               DiskEntry,
                               PartEntry);
 
+            /*
+             * Check whether the user attempts to install ReactOS within the
+             * installation source directory, or in a subdirectory thereof.
+             * If so, fail with an error.
+             */
+            if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
+            {
+                PopupError("You cannot install ReactOS within the installation source directory!",
+                           MUIGetString(STRING_CONTINUE),
+                           Ir, POPUP_WAIT_ENTER);
+                return INSTALL_DIRECTORY_PAGE;
+            }
+
             return PREPARE_COPY_PAGE;
         }
         else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
@@ -3737,8 +3487,8 @@ AddSectionToCopyQueueCab(HINF InfFile,
 
         if (!SetupQueueCopy(SetupFileQueue,
                             SourceCabinet,
-                            SourceRootPath.Buffer,
-                            SourceRootDir.Buffer,
+                            USetupData.SourceRootPath.Buffer,
+                            USetupData.SourceRootDir.Buffer,
                             FileKeyName,
                             DirKeyValue,
                             TargetFileName))
@@ -3845,8 +3595,8 @@ AddSectionToCopyQueue(HINF InfFile,
             /* Installation path */
             DPRINT("InstallationPath: '%S'\n", DirKeyValue);
 
-            StringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
-                           SourceRootDir.Buffer);
+            RtlStringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
+                              USetupData.SourceRootDir.Buffer);
 
             DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName);
         }
@@ -3855,8 +3605,8 @@ AddSectionToCopyQueue(HINF InfFile,
             /* Absolute path */
             DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
 
-            StringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
-                           DirKeyValue);
+            RtlStringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
+                              DirKeyValue);
 
             DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName);
         }
@@ -3866,14 +3616,14 @@ AddSectionToCopyQueue(HINF InfFile,
             DPRINT("RelativePath: '%S'\n", DirKeyValue);
 
             CombinePaths(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName), 2,
-                         SourceRootDir.Buffer, DirKeyValue);
+                         USetupData.SourceRootDir.Buffer, DirKeyValue);
 
             DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
         }
 
         if (!SetupQueueCopy(SetupFileQueue,
                             SourceCabinet,
-                            SourceRootPath.Buffer,
+                            USetupData.SourceRootPath.Buffer,
                             CompleteOrigDirName,
                             FileKeyName,
                             DirKeyValue,
@@ -3904,7 +3654,7 @@ PrepareCopyPageInfFile(HINF InfFile,
     WCHAR PathBuffer[MAX_PATH];
 
     /* Add common files */
-    if (!AddSectionToCopyQueue(InfFile, L"SourceDisksFiles", SourceCabinet, &DestinationPath, Ir))
+    if (!AddSectionToCopyQueue(InfFile, L"SourceDisksFiles", SourceCabinet, &USetupData.DestinationPath, Ir))
         return FALSE;
 
     /* Add specific files depending of computer type */
@@ -3915,7 +3665,7 @@ PrepareCopyPageInfFile(HINF InfFile,
 
         if (AdditionalSectionName)
         {
-            if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &DestinationPath, Ir))
+            if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &USetupData.DestinationPath, Ir))
                 return FALSE;
         }
     }
@@ -3924,14 +3674,14 @@ PrepareCopyPageInfFile(HINF InfFile,
 
     /*
      * FIXME:
-     * Copying files to DestinationRootPath should be done from within
+     * Copying files to USetupData.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 '\' .
+     * For installing to USetupData.DestinationPath specify just '\' .
      */
 
     /* Get destination path */
-    StringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), DestinationPath.Buffer);
+    RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), USetupData.DestinationPath.Buffer);
 
     DPRINT("FullPath(1): '%S'\n", PathBuffer);
 
@@ -3973,8 +3723,8 @@ PrepareCopyPageInfFile(HINF InfFile,
             /* Installation path */
             DPRINT("InstallationPath: '%S'\n", DirKeyValue);
 
-            StringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
-                           DestinationPath.Buffer);
+            RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
+                              USetupData.DestinationPath.Buffer);
 
             DPRINT("InstallationPath(2): '%S'\n", PathBuffer);
         }
@@ -3984,7 +3734,7 @@ PrepareCopyPageInfFile(HINF InfFile,
             DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
 
             CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                         DestinationRootPath.Buffer, DirKeyValue);
+                         USetupData.DestinationRootPath.Buffer, DirKeyValue);
 
             DPRINT("AbsolutePath(2): '%S'\n", PathBuffer);
 
@@ -4003,7 +3753,7 @@ PrepareCopyPageInfFile(HINF InfFile,
             DPRINT("RelativePath: '%S'\n", DirKeyValue);
 
             CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                         DestinationPath.Buffer, DirKeyValue);
+                         USetupData.DestinationPath.Buffer, DirKeyValue);
 
             DPRINT("RelativePath(2): '%S'\n", PathBuffer);
 
@@ -4081,7 +3831,7 @@ PrepareCopyPage(PINPUT_RECORD Ir)
             break;
 
         CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                     SourcePath.Buffer, KeyValue);
+                     USetupData.SourcePath.Buffer, KeyValue);
 
         CabinetInitialize();
         CabinetSetEventHandlers(NULL, NULL, NULL);
@@ -4109,7 +3859,7 @@ PrepareCopyPage(PINPUT_RECORD Ir)
                                           InfFileSize,
                                           NULL,
                                           INF_STYLE_WIN4,
-                                          LanguageId,
+                                          USetupData.LanguageId,
                                           &ErrorLine);
 
         if (InfHandle == INVALID_HANDLE_VALUE)
@@ -4224,7 +3974,7 @@ FileCopyPage(PINPUT_RECORD Ir)
     MUIDisplayPage(FILE_COPY_PAGE);
 
     /* Create context for the copy process */
-    CopyContext.DestinationRootPath = DestinationRootPath.Buffer;
+    CopyContext.DestinationRootPath = USetupData.DestinationRootPath.Buffer;
     CopyContext.InstallPath = InstallPath.Buffer;
     CopyContext.TotalOperations = 0;
     CopyContext.CompletedOperations = 0;
@@ -4286,6 +4036,9 @@ FileCopyPage(PINPUT_RECORD Ir)
     DestroyProgressBar(CopyContext.MemoryBars[1]);
     DestroyProgressBar(CopyContext.MemoryBars[2]);
 
+    /* Create the $winnt$.inf file */
+    InstallSetupInfFile(&USetupData);
+
     /* Go display the next page */
     return REGISTRY_PAGE;
 }
@@ -4327,7 +4080,7 @@ RegistryPage(PINPUT_RECORD Ir)
         DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n");
 
         /* Verify the registry hives and check whether we need to update or repair any of them */
-        Status = VerifyRegistryHives(&DestinationPath, &ShouldRepairRegistry);
+        Status = VerifyRegistryHives(&USetupData.DestinationPath, &ShouldRepairRegistry);
         if (!NT_SUCCESS(Status))
         {
             DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status);
@@ -4342,7 +4095,7 @@ DoUpdate:
     CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE));
 
     /* Initialize the registry and setup the registry hives */
-    Status = RegInitializeRegistry(&DestinationPath);
+    Status = RegInitializeRegistry(&USetupData.DestinationPath);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("RegInitializeRegistry() failed\n");
@@ -4431,7 +4184,7 @@ DoUpdate:
 
         CONSOLE_SetStatusText(MUIGetString(STRING_IMPORTFILE), File);
 
-        if (!ImportRegistryFile(SourcePath.Buffer, File, Section, LanguageId, Delete))
+        if (!ImportRegistryFile(USetupData.SourcePath.Buffer, File, Section, USetupData.LanguageId, Delete))
         {
             DPRINT1("Importing %S failed\n", File);
             INF_FreeData(File);
@@ -4446,7 +4199,7 @@ DoUpdate:
         /* See the explanation for this test above */
 
         /* Update display registry settings */
-        CONSOLE_SetStatusText(MUIGetString(STRING_DISPLAYETTINGSUPDATE));
+        CONSOLE_SetStatusText(MUIGetString(STRING_DISPLAYSETTINGSUPDATE));
         if (!ProcessDisplayRegistry(SetupInf, DisplayList))
         {
             MUIDisplayError(ERROR_UPDATE_DISPLAY_SETTINGS, Ir, POPUP_WAIT_ENTER);
@@ -4463,14 +4216,14 @@ DoUpdate:
 
         /* Add keyboard layouts */
         CONSOLE_SetStatusText(MUIGetString(STRING_ADDKBLAYOUTS));
-        if (!AddKeyboardLayouts())
+        if (!AddKeyboardLayouts(SelectedLanguageId))
         {
             MUIDisplayError(ERROR_ADDING_KBLAYOUTS, Ir, POPUP_WAIT_ENTER);
             goto Cleanup;
         }
 
         /* Set GeoID */
-        if (!SetGeoID(MUIGetGeoID()))
+        if (!SetGeoID(MUIGetGeoID(SelectedLanguageId)))
         {
             MUIDisplayError(ERROR_UPDATE_GEOID, Ir, POPUP_WAIT_ENTER);
             goto Cleanup;
@@ -4480,7 +4233,7 @@ DoUpdate:
         {
             /* Update keyboard layout settings */
             CONSOLE_SetStatusText(MUIGetString(STRING_KEYBOARDSETTINGSUPDATE));
-            if (!ProcessKeyboardLayoutRegistry(LayoutList))
+            if (!ProcessKeyboardLayoutRegistry(LayoutList, SelectedLanguageId))
             {
                 MUIDisplayError(ERROR_UPDATE_KBSETTINGS, Ir, POPUP_WAIT_ENTER);
                 goto Cleanup;
@@ -4489,7 +4242,7 @@ DoUpdate:
 
         /* Add codepage information to registry */
         CONSOLE_SetStatusText(MUIGetString(STRING_CODEPAGEINFOUPDATE));
-        if (!AddCodePage())
+        if (!AddCodePage(SelectedLanguageId))
         {
             MUIDisplayError(ERROR_ADDING_CODEPAGE, Ir, POPUP_WAIT_ENTER);
             goto Cleanup;
@@ -4508,7 +4261,7 @@ Cleanup:
     // TODO: Unload all the registry stuff, perform cleanup,
     // and copy the created hive files into .sav files.
     //
-    RegCleanupRegistry(&DestinationPath);
+    RegCleanupRegistry(&USetupData.DestinationPath);
 
     /*
      * Check whether we were in update/repair mode but we were actually
@@ -4564,28 +4317,30 @@ BootLoaderPage(PINPUT_RECORD Ir)
 
     CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
 
-    RtlFreeUnicodeString(&SystemRootPath);
-    StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+    RtlFreeUnicodeString(&USetupData.SystemRootPath);
+    RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
             L"\\Device\\Harddisk%lu\\Partition%lu\\",
             PartitionList->SystemPartition->DiskEntry->DiskNumber,
             PartitionList->SystemPartition->PartitionNumber);
-    RtlCreateUnicodeString(&SystemRootPath, PathBuffer);
-    DPRINT1("SystemRootPath: %wZ\n", &SystemRootPath);
+    RtlCreateUnicodeString(&USetupData.SystemRootPath, PathBuffer);
+    DPRINT1("SystemRootPath: %wZ\n", &USetupData.SystemRootPath);
 
     PartitionType = PartitionList->SystemPartition->PartitionType;
 
+    /* For unattended setup, skip MBR installation or install on floppy if needed */
     if (IsUnattendedSetup)
     {
-        if (UnattendMBRInstallType == 0) /* skip MBR installation */
+        if ((USetupData.MBRInstallType == 0) ||
+            (USetupData.MBRInstallType == 1))
         {
-            return SUCCESS_PAGE;
-        }
-        else if (UnattendMBRInstallType == 1) /* install on floppy */
-        {
-            return BOOT_LOADER_FLOPPY_PAGE;
+            goto Quit;
         }
     }
 
+    /*
+     * We may install an MBR or VBR, but before that, check whether
+     * we need to actually install the VBR on floppy.
+     */
     if (PartitionType == PARTITION_ENTRY_UNUSED)
     {
         DPRINT("Error: system partition invalid (unused)\n");
@@ -4628,15 +4383,21 @@ BootLoaderPage(PINPUT_RECORD Ir)
         InstallOnFloppy = TRUE;
     }
 
-    if (InstallOnFloppy != FALSE)
+    /* We should install on floppy */
+    if (InstallOnFloppy)
     {
-        return BOOT_LOADER_FLOPPY_PAGE;
+        USetupData.MBRInstallType = 1;
+        goto Quit;
     }
 
-    /* Unattended install on hdd? */
-    if (IsUnattendedSetup && UnattendMBRInstallType == 2)
+    /* Is it an unattended install on hdd? */
+    if (IsUnattendedSetup)
     {
-        return BOOT_LOADER_HARDDISK_MBR_PAGE;
+        if ((USetupData.MBRInstallType == 2) ||
+            (USetupData.MBRInstallType == 3))
+        {
+            goto Quit;
+        }
     }
 
     MUIDisplayPage(BOOT_LOADER_PAGE);
@@ -4677,7 +4438,7 @@ BootLoaderPage(PINPUT_RECORD Ir)
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -4686,25 +4447,53 @@ BootLoaderPage(PINPUT_RECORD Ir)
         {
             if (Line == 12)
             {
-                return BOOT_LOADER_HARDDISK_MBR_PAGE;
+                /* Install on both MBR and VBR */
+                USetupData.MBRInstallType = 2;
+                break;
             }
             else if (Line == 13)
             {
-                return BOOT_LOADER_HARDDISK_VBR_PAGE;
+                /* Install on VBR only */
+                USetupData.MBRInstallType = 3;
+                break;
             }
             else if (Line == 14)
             {
-                return BOOT_LOADER_FLOPPY_PAGE;
+                /* Install on floppy */
+                USetupData.MBRInstallType = 1;
+                break;
             }
             else if (Line == 15)
             {
-                return SUCCESS_PAGE;
+                /* Skip MBR installation */
+                USetupData.MBRInstallType = 0;
+                break;
             }
 
             return BOOT_LOADER_PAGE;
         }
     }
 
+Quit:
+    switch (USetupData.MBRInstallType)
+    {
+        /* Skip MBR installation */
+        case 0:
+            return SUCCESS_PAGE;
+
+        /* Install on floppy */
+        case 1:
+            return BOOT_LOADER_FLOPPY_PAGE;
+
+        /* Install on both MBR and VBR */
+        case 2:
+            return BOOT_LOADER_HARDDISK_MBR_PAGE;
+
+        /* Install on VBR only */
+        case 3:
+            return BOOT_LOADER_HARDDISK_VBR_PAGE;
+    }
+
     return BOOT_LOADER_PAGE;
 }
 
@@ -4738,23 +4527,21 @@ BootLoaderFloppyPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
         }
         else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)    /* ENTER */
         {
-            if (DoesPathExist(NULL, L"\\Device\\Floppy0\\") == FALSE)
-            {
-                MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER);
-                return BOOT_LOADER_FLOPPY_PAGE;
-            }
-
-            Status = InstallFatBootcodeToFloppy(&SourceRootPath, &DestinationArcPath);
+            Status = InstallFatBootcodeToFloppy(&USetupData.SourceRootPath,
+                                                &USetupData.DestinationArcPath);
             if (!NT_SUCCESS(Status))
             {
-                /* Print error message */
+                if (Status == STATUS_DEVICE_NOT_READY)
+                    MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER);
+
+                /* TODO: Print error message */
                 return BOOT_LOADER_FLOPPY_PAGE;
             }
 
@@ -4784,9 +4571,9 @@ BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
 {
     NTSTATUS Status;
 
-    Status = InstallVBRToPartition(&SystemRootPath,
-                                   &SourceRootPath,
-                                   &DestinationArcPath,
+    Status = InstallVBRToPartition(&USetupData.SystemRootPath,
+                                   &USetupData.SourceRootPath,
+                                   &USetupData.DestinationArcPath,
                                    PartitionList->SystemPartition->PartitionType);
     if (!NT_SUCCESS(Status))
     {
@@ -4817,13 +4604,11 @@ BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
 {
     NTSTATUS Status;
     WCHAR DestinationDevicePathBuffer[MAX_PATH];
-    WCHAR SourceMbrPathBuffer[MAX_PATH];
-    WCHAR DstPath[MAX_PATH];
 
     /* Step 1: Write the VBR */
-    Status = InstallVBRToPartition(&SystemRootPath,
-                                   &SourceRootPath,
-                                   &DestinationArcPath,
+    Status = InstallVBRToPartition(&USetupData.SystemRootPath,
+                                   &USetupData.SourceRootPath,
+                                   &USetupData.DestinationArcPath,
                                    PartitionList->SystemPartition->PartitionType);
     if (!NT_SUCCESS(Status))
     {
@@ -4832,34 +4617,15 @@ BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
     }
 
     /* Step 2: Write the MBR */
-    StringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
+    RtlStringCchPrintfW(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");
-
-        DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath);
-        Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR));
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
-            // Don't care if we succeeded or not saving the old MBR, just go ahead.
-        }
-    }
-
-    DPRINT1("Install MBR bootcode: %S ==> %S\n",
-            SourceMbrPathBuffer, DestinationDevicePathBuffer);
-    Status = InstallMbrBootCodeToDisk(SourceMbrPathBuffer,
+    Status = InstallMbrBootCodeToDisk(&USetupData.SystemRootPath,
+                                      &USetupData.SourceRootPath,
                                       DestinationDevicePathBuffer);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
-                Status);
+        DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status);
         MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER);
         return QUIT_PAGE;
     }
@@ -5236,14 +5002,14 @@ RunUSetup(VOID)
     }
 
     /* Initialize global unicode strings */
-    RtlInitUnicodeString(&SourcePath, NULL);
-    RtlInitUnicodeString(&SourceRootPath, NULL);
-    RtlInitUnicodeString(&SourceRootDir, NULL);
+    RtlInitUnicodeString(&USetupData.SourcePath, NULL);
+    RtlInitUnicodeString(&USetupData.SourceRootPath, NULL);
+    RtlInitUnicodeString(&USetupData.SourceRootDir, NULL);
     RtlInitUnicodeString(&InstallPath, NULL);
-    RtlInitUnicodeString(&DestinationPath, NULL);
-    RtlInitUnicodeString(&DestinationArcPath, NULL);
-    RtlInitUnicodeString(&DestinationRootPath, NULL);
-    RtlInitUnicodeString(&SystemRootPath, NULL);
+    RtlInitUnicodeString(&USetupData.DestinationPath, NULL);
+    RtlInitUnicodeString(&USetupData.DestinationArcPath, NULL);
+    RtlInitUnicodeString(&USetupData.DestinationRootPath, NULL);
+    RtlInitUnicodeString(&USetupData.SystemRootPath, NULL);
 
     /* Hide the cursor */
     CONSOLE_SetCursorType(TRUE, FALSE);
@@ -5408,6 +5174,8 @@ RunUSetup(VOID)
         }
     }
 
+    SetupCloseInfFile(SetupInf);
+
     if (Page == RECOVERY_PAGE)
         RecoveryConsole();