Offer an explanation why AllocConsole() might have failed
[reactos.git] / reactos / subsys / system / usetup / usetup.c
index cb29772..474c311 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ReactOS kernel
- *  Copyright (C) 2002 ReactOS Team
+ *  Copyright (C) 2002, 2003, 2004 ReactOS Team
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  * FILE:            subsys/system/usetup/usetup.c
  * PURPOSE:         Text-mode setup
  * PROGRAMMER:      Eric Kohl
+ *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
  */
 
-#include <ddk/ntddk.h>
-#include <ntdll/rtl.h>
-
-#include <ntos/minmax.h>
-#include <reactos/resource.h>
-
-#include "usetup.h"
-#include "console.h"
-#include "partlist.h"
-#include "inicache.h"
-#include "infcache.h"
-#include "filequeue.h"
-#include "progress.h"
-#include "bootsup.h"
-#include "registry.h"
+#include <usetup.h>
 
+#define NDEBUG
+#include <debug.h>
 
 typedef enum _PAGE_NUMBER
 {
   START_PAGE,
   INTRO_PAGE,
+  LICENSE_PAGE,
+  WARNING_PAGE,
   INSTALL_INTRO_PAGE,
 
+//  SCSI_CONTROLLER_PAGE,
+
+  DEVICE_SETTINGS_PAGE,
+  COMPUTER_SETTINGS_PAGE,
+  DISPLAY_SETTINGS_PAGE,
+  KEYBOARD_SETTINGS_PAGE,
+  LAYOUT_SETTINGS_PAGE,
+
   SELECT_PARTITION_PAGE,
+  CREATE_PARTITION_PAGE,
+  DELETE_PARTITION_PAGE,
+
   SELECT_FILE_SYSTEM_PAGE,
+  FORMAT_PARTITION_PAGE,
   CHECK_FILE_SYSTEM_PAGE,
+
   PREPARE_COPY_PAGE,
   INSTALL_DIRECTORY_PAGE,
   FILE_COPY_PAGE,
   REGISTRY_PAGE,
   BOOT_LOADER_PAGE,
+  BOOT_LOADER_FLOPPY_PAGE,
+  BOOT_LOADER_HARDDISK_PAGE,
 
   REPAIR_INTRO_PAGE,
 
   SUCCESS_PAGE,
   QUIT_PAGE,
+  FLUSH_PAGE,
   REBOOT_PAGE,                 /* virtual page */
 } PAGE_NUMBER, *PPAGE_NUMBER;
 
@@ -67,33 +74,48 @@ typedef struct _COPYCONTEXT
 {
   ULONG TotalOperations;
   ULONG CompletedOperations;
-  PPROGRESS ProgressBar;
+  PPROGRESSBAR ProgressBar;
 } COPYCONTEXT, *PCOPYCONTEXT;
 
 
 /* GLOBALS ******************************************************************/
 
 HANDLE ProcessHeap;
+UNICODE_STRING SourceRootPath;
+BOOLEAN IsUnattendedSetup;
+LONG UnattendDestinationDiskNumber;
+LONG UnattendDestinationPartitionNumber;
+WCHAR UnattendInstallationDirectory[MAX_PATH];
 
-BOOLEAN PartDataValid;
-PARTDATA PartData;
+/* LOCALS *******************************************************************/
 
-BOOLEAN ActivePartitionValid;
-PARTDATA ActivePartition;
+static PPARTLIST PartitionList = NULL;
 
-UNICODE_STRING SourcePath;
-UNICODE_STRING SourceRootPath;
+static PFILE_SYSTEM_LIST FileSystemList = NULL;
 
-UNICODE_STRING InstallPath;
-UNICODE_STRING DestinationPath;
-UNICODE_STRING DestinationArcPath;
-UNICODE_STRING DestinationRootPath;
 
-UNICODE_STRING SystemRootPath; /* Path to the active partition */
+static UNICODE_STRING SourcePath;
 
-HINF SetupInf;
+static UNICODE_STRING InstallPath;
 
-HSPFILEQ SetupFileQueue = NULL;
+/* Path to the install directory */
+static UNICODE_STRING DestinationPath;
+static UNICODE_STRING DestinationArcPath;
+static UNICODE_STRING DestinationRootPath;
+
+/* Path to the active partition (boot manager) */
+static UNICODE_STRING SystemRootPath;
+
+static HINF SetupInf;
+
+static HSPFILEQ SetupFileQueue = NULL;
+
+static BOOLEAN WarnLinuxPartitions = TRUE;
+
+static PGENERIC_LIST ComputerList = NULL;
+static PGENERIC_LIST DisplayList = NULL;
+static PGENERIC_LIST KeyboardList = NULL;
+static PGENERIC_LIST LayoutList = NULL;
 
 
 /* FUNCTIONS ****************************************************************/
@@ -322,7 +344,7 @@ PopupError(PCHAR Text,
       coPos.Y++;
       coPos.X = xLeft + 2;
       WriteConsoleOutputCharacters(Status,
-                                  min(strlen(Status), Width - 4),
+                                  min(strlen(Status), (SIZE_T)Width - 4),
                                   coPos);
     }
 }
@@ -343,8 +365,8 @@ ConfirmQuit(PINPUT_RECORD Ir)
             "computer. If you quit Setup now, you will need to\n"
             "run Setup again to install ReactOS.\n"
             "\n"
-            "  * Press ENTER to continue Setup.\n"
-            "  * Press F3 to quit Setup.",
+            "  \x07  Press ENTER to continue Setup.\n"
+            "  \x07  Press F3 to quit Setup.",
             "F3= Quit  ENTER = Continue");
 
   while(TRUE)
@@ -364,10 +386,134 @@ ConfirmQuit(PINPUT_RECORD Ir)
        }
     }
 
-  return(Result);
+  return Result;
 }
 
 
+VOID
+CheckUnattendedSetup(VOID)
+{
+  WCHAR UnattendInfPath[MAX_PATH];
+  UNICODE_STRING FileName;
+  PINFCONTEXT Context;
+  HINF UnattendInf;
+  ULONG ErrorLine;
+  NTSTATUS Status;
+  LONG IntValue;
+  PWCHAR Value;
+
+  if (DoesFileExist(SourcePath.Buffer, L"unattend.inf") == FALSE)
+    {
+      DPRINT("Does not exist: %S\\%S\n", SourcePath.Buffer, L"unattend.inf");
+      IsUnattendedSetup = FALSE;
+      return;
+    }
+
+  wcscpy(UnattendInfPath, SourcePath.Buffer);
+  wcscat(UnattendInfPath, L"\\unattend.inf");
+
+  RtlInitUnicodeString(&FileName,
+                      UnattendInfPath);
+
+  /* Load 'unattend.inf' from install media. */
+  Status = InfOpenFile(&UnattendInf,
+                      &FileName,
+                      &ErrorLine);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("InfOpenFile() failed with status 0x%x\n", Status);
+      return;
+    }
+
+  /* Open 'Unattend' section */
+  if (!InfFindFirstLine(UnattendInf, L"Unattend", L"Signature", &Context))
+    {
+      DPRINT("InfFindFirstLine() failed for section 'Unattend'\n");
+      InfFreeContext(Context);
+      InfCloseFile(UnattendInf);
+      return;
+    }
+
+  /* Get pointer 'Signature' key */
+  if (!InfGetData(Context, NULL, &Value))
+    {
+      DPRINT("InfGetData() failed for key 'Signature'\n");
+      InfFreeContext(Context);
+      InfCloseFile(UnattendInf);
+      return;
+    }
+
+  /* Check 'Signature' string */
+  if (_wcsicmp(Value, L"$ReactOS$") != 0)
+    {
+      DPRINT("Signature not $ReactOS$\n");
+      InfFreeContext(Context);
+      InfCloseFile(UnattendInf);
+      return;
+    }
+
+  /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
+  if (!InfFindFirstLine(UnattendInf, L"Unattend", L"DestinationDiskNumber", &Context))
+    {
+      DPRINT("InfFindFirstLine() failed for key 'DestinationDiskNumber'\n");
+      InfFreeContext(Context);
+      InfCloseFile(UnattendInf);
+      return;
+    }
+  if (!InfGetIntField(Context, 0, &IntValue))
+    {
+      DPRINT("InfGetIntField() failed for key 'DestinationDiskNumber'\n");
+      InfFreeContext(Context);
+      InfCloseFile(UnattendInf);
+      return;
+    }
+  UnattendDestinationDiskNumber = IntValue;
+  InfFreeContext(Context);
+
+  /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
+  if (!InfFindFirstLine(UnattendInf, L"Unattend", L"DestinationPartitionNumber", &Context))
+    {
+      DPRINT("InfFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
+      InfFreeContext(Context);
+      InfCloseFile(UnattendInf);
+      return;
+    }
+  if (!InfGetIntField(Context, 0, &IntValue))
+    {
+      DPRINT("InfGetIntField() failed for key 'DestinationPartitionNumber'\n");
+      InfFreeContext(Context);
+      InfCloseFile(UnattendInf);
+      return;
+    }
+  UnattendDestinationPartitionNumber = IntValue;
+  InfFreeContext(Context);
+
+  /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
+  if (!InfFindFirstLine(UnattendInf, L"Unattend", L"DestinationPartitionNumber", &Context))
+    {
+      DPRINT("InfFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
+      InfCloseFile(UnattendInf);
+      return;
+    }
+
+  /* Get pointer 'InstallationDirectory' key */
+  if (!InfGetData(Context, NULL, &Value))
+    {
+      DPRINT("InfGetData() failed for key 'InstallationDirectory'\n");
+      InfFreeContext(Context);
+      InfCloseFile(UnattendInf);
+      return;
+    }
+  wcscpy(UnattendInstallationDirectory, Value);
+
+  InfFreeContext(Context);
+  InfCloseFile(UnattendInf);
+
+  IsUnattendedSetup = TRUE;
+
+  DPRINT("Running unattended setup\n");
+}
+
 
 /*
  * Start page
@@ -375,35 +521,85 @@ ConfirmQuit(PINPUT_RECORD Ir)
  *     Number of the next page.
  */
 static PAGE_NUMBER
-StartPage(PINPUT_RECORD Ir)
+SetupStartPage(PINPUT_RECORD Ir)
 {
+  SYSTEM_DEVICE_INFORMATION Sdi;
   NTSTATUS Status;
   WCHAR FileNameBuffer[MAX_PATH];
   UNICODE_STRING FileName;
-
-  INFCONTEXT Context;
+  PINFCONTEXT Context;
   PWCHAR Value;
   ULONG ErrorLine;
-
+  ULONG ReturnSize;
 
   SetStatusText("   Please wait...");
 
+
+  /* Check whether a harddisk is available */
+  Status = NtQuerySystemInformation (SystemDeviceInformation,
+                                    &Sdi,
+                                    sizeof(SYSTEM_DEVICE_INFORMATION),
+                                    &ReturnSize);
+  if (!NT_SUCCESS (Status))
+    {
+      PrintTextXY(6, 15, "NtQuerySystemInformation() failed (Status 0x%08lx)", Status);
+      PopupError("Setup could not retrieve system drive information.\n",
+                "ENTER = Reboot computer");
+      while(TRUE)
+       {
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return QUIT_PAGE;
+           }
+       }
+    }
+
+  if (Sdi.NumberOfDisks == 0)
+    {
+      PopupError("Setup could not find a harddisk.\n",
+                "ENTER = Reboot computer");
+      while(TRUE)
+       {
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return QUIT_PAGE;
+           }
+       }
+    }
+
+  /* Get the source path and source root path */
   Status = GetSourcePaths(&SourcePath,
                          &SourceRootPath);
   if (!NT_SUCCESS(Status))
     {
       PrintTextXY(6, 15, "GetSourcePath() failed (Status 0x%08lx)", Status);
+      PopupError("Setup could not find its source drive.\n",
+                "ENTER = Reboot computer");
+      while(TRUE)
+       {
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return QUIT_PAGE;
+           }
+       }
     }
+#if 0
   else
     {
       PrintTextXY(6, 15, "SourcePath: '%wZ'", &SourcePath);
       PrintTextXY(6, 16, "SourceRootPath: '%wZ'", &SourceRootPath);
     }
-
+#endif
 
   /* Load txtsetup.sif from install media. */
   wcscpy(FileNameBuffer, SourceRootPath.Buffer);
-  wcscat(FileNameBuffer, L"\\install\\txtsetup.sif");
+  wcscat(FileNameBuffer, L"\\reactos\\txtsetup.sif");
   RtlInitUnicodeString(&FileName,
                       FileNameBuffer);
 
@@ -421,7 +617,7 @@ StartPage(PINPUT_RECORD Ir)
 
          if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
            {
-             return(QUIT_PAGE);
+             return QUIT_PAGE;
            }
        }
     }
@@ -438,15 +634,16 @@ StartPage(PINPUT_RECORD Ir)
 
          if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
            {
-             return(QUIT_PAGE);
+             return QUIT_PAGE;
            }
        }
     }
 
 
   /* Get pointer 'Signature' key */
-  if (!InfGetData (&Context, NULL, &Value))
+  if (!InfGetData (Context, NULL, &Value))
     {
+      InfFreeContext(Context);
       PopupError("Setup found a corrupt TXTSETUP.SIF.\n",
                 "ENTER = Reboot computer");
 
@@ -456,7 +653,7 @@ StartPage(PINPUT_RECORD Ir)
 
          if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
            {
-             return(QUIT_PAGE);
+             return QUIT_PAGE;
            }
        }
     }
@@ -464,6 +661,7 @@ StartPage(PINPUT_RECORD Ir)
   /* Check 'Signature' string */
   if (_wcsicmp(Value, L"$ReactOS$") != 0)
     {
+      InfFreeContext(Context);
       PopupError("Setup found an invalid signature in TXTSETUP.SIF.\n",
                 "ENTER = Reboot computer");
 
@@ -473,126 +671,224 @@ StartPage(PINPUT_RECORD Ir)
 
          if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
            {
-             return(QUIT_PAGE);
+             return QUIT_PAGE;
            }
        }
     }
+  InfFreeContext(Context);
 
-  return(INTRO_PAGE);
-}
+  CheckUnattendedSetup();
 
+  return INTRO_PAGE;
+}
 
 
+/*
+ * First setup page
+ * RETURNS
+ *     Next page number.
+ */
 static PAGE_NUMBER
-RepairIntroPage(PINPUT_RECORD Ir)
+IntroPage(PINPUT_RECORD Ir)
 {
-  SetTextXY(6, 8, "ReactOS Setup is in an early development phase. It does not yet");
-  SetTextXY(6, 9, "support all the functions of a fully usable setup application.");
+  SetHighlightedTextXY(6, 8, "Welcome to ReactOS Setup");
 
-  SetTextXY(6, 12, "The repair functions are not implemented yet.");
+  SetTextXY(6, 11, "This part of the setup copies the ReactOS Operating System to your");
+  SetTextXY(6, 12, "computer and prepares the second part of the setup.");
 
-  SetTextXY(8, 15, "\xfa  Press ESC to return to the main page.");
+  SetTextXY(8, 15, "\x07  Press ENTER to install ReactOS.");
+  SetTextXY(8, 17, "\x07  Press R to repair ReactOS.");
+  SetTextXY(8, 19, "\x07  Press L to view the ReactOS Licensing Terms and Conditions");
+  SetTextXY(8, 21, "\x07  Press F3 to quit without installing ReactOS.");
 
-  SetTextXY(8, 17, "\xfa  Press ENTER to reboot your computer.");
+  SetStatusText("   ENTER = Continue  R = Repair F3 = Quit");
 
-  SetStatusText("   ESC = Main page  ENTER = Reboot");
+  if (IsUnattendedSetup)
+    {
+      return INSTALL_INTRO_PAGE;
+    }
 
-  while(TRUE)
+  while (TRUE)
     {
       ConInKey(Ir);
 
-      if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+      if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
        {
-         return(REBOOT_PAGE);
+         if (ConfirmQuit(Ir) == TRUE)
+           return QUIT_PAGE;
+         break;
        }
-      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
+      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+       {
+         return WARNING_PAGE;
+      break;
+       }
+      else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
        {
-         return(INTRO_PAGE);
+         return REPAIR_INTRO_PAGE;
+      break;
        }
+      else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* R */
+       {
+         return LICENSE_PAGE;
+      break;
+       }   
     }
 
-  return(REPAIR_INTRO_PAGE);
+  return INTRO_PAGE;
 }
 
-
 /*
- * First setup page
+ * License Page
  * RETURNS
- *     TRUE: setup/repair completed successfully
- *     FALSE: setup/repair terminated by user
+ *     Back to main setup page.
  */
 static PAGE_NUMBER
-IntroPage(PINPUT_RECORD Ir)
+LicensePage(PINPUT_RECORD Ir)
 {
-  SetHighlightedTextXY(6, 8, "Welcome to ReactOS Setup");
+  SetHighlightedTextXY(6, 8, "Licensing:");
 
-  SetTextXY(6, 11, "This part of the setup copies the ReactOS Operating System to your");
-  SetTextXY(6, 12, "computer and prepares the second part of the setup.");
+  SetTextXY(8, 11, "The ReactOS System is licensed under the terms of the");
+  SetTextXY(8, 12, "GNU GPL with parts containing code from other compatible");
+  SetTextXY(8, 13, "licenses such as the X11 or BSD and GNU LGPL licenses.");
+  SetTextXY(8, 14, "All software that is part of the ReactOS system is");
+  SetTextXY(8, 15, "therefore released under the GNU GPL as well as maintaining");
+  SetTextXY(8, 16, "the original license.");
+
+  SetTextXY(8, 18, "This software comes with NO WARRANTY or restrictions on usage");
+  SetTextXY(8, 19, "save applicable local and international law. The licensing of");
+  SetTextXY(8, 20, "ReactOS only covers distribution to third parties.");
 
-  SetTextXY(8, 15, "\xfa  Press ENTER to install ReactOS.");
+  SetTextXY(8, 22, "If for some reason you did not receive a copy of the");
+  SetTextXY(8, 23, "GNU General Public License with ReactOS please visit");
+  SetHighlightedTextXY(8, 25, "http://www.gnu.org/licenses/licenses.html");
 
-  SetTextXY(8, 17, "\xfa  Press E to start the emergency repair console.");
+  SetStatusText("   ENTER = Return");
 
-  SetTextXY(8, 19, "\xfa  Press R to repair ReactOS.");
+  while (TRUE)
+    {
+      ConInKey(Ir);
+
+      if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+      {
+          return INTRO_PAGE;
+          break;
+      }
+    }
 
-  SetTextXY(8, 21, "\xfa  Press F3 to quit without installing ReactOS.");
+  return LICENSE_PAGE;
+}
 
+/*
+ * Warning Page
+ * RETURNS
+ *     Continues to setup
+ */
+static PAGE_NUMBER
+WarningPage(PINPUT_RECORD Ir)
+{
+  SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Warranty Statement");
+  SetHighlightedTextXY(6, 8, "Warranty:");
 
-  SetStatusText("   ENTER = Continue   F3 = Quit");
+  SetTextXY(8, 11, "This is free software; see the source for copying conditions.");
+  SetTextXY(8, 12, "There is NO warranty; not even for MERCHANTABILITY or");
+  SetTextXY(8, 13, "FITNESS FOR A PARTICULAR PURPOSE");
 
-  while(TRUE)
+  SetTextXY(8, 15, "For more information on ReactOS, please visit:");
+  SetHighlightedTextXY(8, 16, "http://www.reactos.org");
+
+  SetStatusText("   F8 = Continue   ESC = Exit");
+
+  while (TRUE)
     {
       ConInKey(Ir);
 
       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F8)) /* F8 */
        {
-         if (ConfirmQuit(Ir) == TRUE)
-           return(QUIT_PAGE);
+           return INSTALL_INTRO_PAGE;
          break;
        }
-      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
        {
-         return(INSTALL_INTRO_PAGE);
+         return QUIT_PAGE;
        }
-#if 0
-      else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'E') /* E */
+    }
+
+  return LICENSE_PAGE;
+}
+
+static PAGE_NUMBER
+RepairIntroPage(PINPUT_RECORD Ir)
+{
+  SetTextXY(6, 8, "ReactOS Setup is in an early development phase. It does not yet");
+  SetTextXY(6, 9, "support all the functions of a fully usable setup application.");
+
+  SetTextXY(6, 12, "The repair functions are not implemented yet.");
+
+  SetTextXY(8, 15, "\x07  Press R for the Recovery Console.");
+  
+  SetTextXY(8, 17, "\x07  Press ESC to return to the main page.");
+
+  SetTextXY(8, 19, "\x07  Press ENTER to reboot your computer.");
+
+  SetStatusText("   ESC = Main page  ENTER = Reboot");
+
+  while(TRUE)
+    {
+      ConInKey(Ir);
+
+      if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
        {
-         return(RepairConsole());
+         return REBOOT_PAGE;
        }
-#endif
-      else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
+    else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
+       {
+         return INTRO_PAGE;
+       }
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
        {
-         return(REPAIR_INTRO_PAGE);
+         return INTRO_PAGE;
        }
     }
 
-  return(INTRO_PAGE);
+  return REPAIR_INTRO_PAGE;
 }
 
 
 static PAGE_NUMBER
 InstallIntroPage(PINPUT_RECORD Ir)
 {
+  SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
+
   SetTextXY(6, 8, "ReactOS Setup is in an early development phase. It does not yet");
   SetTextXY(6, 9, "support all the functions of a fully usable setup application.");
 
-  SetTextXY(6, 12, "The following functions are missing:");
-  SetTextXY(8, 13, "- Creating and deleting harddisk partitions.");
-  SetTextXY(8, 14, "- Formatting partitions.");
-  SetTextXY(8, 15, "- Support for non-FAT file systems.");
-  SetTextXY(8, 16, "- Checking file systems.");
+  SetTextXY(6, 12, "The following limitations apply:");
+  SetTextXY(8, 13, "- Setup can not handle more than one primary partition per disk.");
+  SetTextXY(8, 14, "- Setup can not delete a primary partition from a disk");
+  SetTextXY(8, 15, "  as long as extended partitions exist on this disk.");
+  SetTextXY(8, 16, "- Setup can not delete the first extended partition from a disk");
+  SetTextXY(8, 17, "  as long as other extended partitions exist on this disk.");
+  SetTextXY(8, 18, "- Setup supports FAT file systems only.");
+  SetTextXY(8, 19, "- File system checks are not implemented yet.");
 
 
+  SetTextXY(8, 23, "\x07  Press ENTER to install ReactOS.");
 
-  SetTextXY(8, 21, "\xfa  Press ENTER to install ReactOS.");
-
-  SetTextXY(8, 23, "\xfa  Press F3 to quit without installing ReactOS.");
+  SetTextXY(8, 25, "\x07  Press F3 to quit without installing ReactOS.");
 
 
   SetStatusText("   ENTER = Continue   F3 = Quit");
 
+  if (IsUnattendedSetup)
+    {
+      return SELECT_PARTITION_PAGE;
+    }
+
   while(TRUE)
     {
       ConInKey(Ir);
@@ -601,48 +897,31 @@ InstallIntroPage(PINPUT_RECORD Ir)
          (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
        {
          if (ConfirmQuit(Ir) == TRUE)
-           return(QUIT_PAGE);
+           return QUIT_PAGE;
          break;
        }
       else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
        {
-         return(SELECT_PARTITION_PAGE);
+         return DEVICE_SETTINGS_PAGE;
+//       return SCSI_CONTROLLER_PAGE;
        }
     }
 
-  return(INSTALL_INTRO_PAGE);
+  return INSTALL_INTRO_PAGE;
 }
 
 
+#if 0
 static PAGE_NUMBER
-SelectPartitionPage(PINPUT_RECORD Ir)
+ScsiControllerPage(PINPUT_RECORD Ir)
 {
-  WCHAR PathBuffer[MAX_PATH];
-  PPARTLIST PartList;
-  SHORT xScreen;
-  SHORT yScreen;
+  SetTextXY(6, 8, "Setup detected the following mass storage devices:");
 
-  SetTextXY(6, 8, "The list below shows existing partitions and unused disk");
-  SetTextXY(6, 9, "space for new partitions.");
-
-  SetTextXY(8, 11, "\xfa  Press UP or DOWN to select a list entry.");
-  SetTextXY(8, 13, "\xfa  Press ENTER to install ReactOS onto the selected partition.");
-  SetTextXY(8, 15, "\xfa  Press C to create a new partition.");
-  SetTextXY(8, 17, "\xfa  Press D to delete an existing partition.");
-
-  SetStatusText("   Please wait...");
-
-  RtlFreeUnicodeString(&DestinationPath);
-  RtlFreeUnicodeString(&DestinationRootPath);
-
-  GetScreenSize(&xScreen, &yScreen);
+  /* FIXME: print loaded mass storage driver descriptions */
+#if 0
+  SetTextXY(8, 10, "TEST device");
+#endif
 
-  PartList = CreatePartitionList(2, 19, xScreen - 3, yScreen - 3);
-  if (PartList == NULL)
-    {
-      /* FIXME: show an error dialog */
-      return(QUIT_PAGE);
-    }
 
   SetStatusText("   ENTER = Continue   F3 = Quit");
 
@@ -654,149 +933,1312 @@ SelectPartitionPage(PINPUT_RECORD Ir)
          (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
        {
          if (ConfirmQuit(Ir) == TRUE)
-           {
-             DestroyPartitionList(PartList);
-             return(QUIT_PAGE);
-           }
+           return QUIT_PAGE;
          break;
        }
-      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
-       {
-         ScrollDownPartitionList(PartList);
-       }
-      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
-       {
-         ScrollUpPartitionList(PartList);
-       }
       else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
        {
-         PartDataValid = GetSelectedPartition(PartList,
-                                              &PartData);
-         ActivePartitionValid = GetActiveBootPartition(PartList,
-                                                       &ActivePartition);
-         DestroyPartitionList(PartList);
-
-         RtlFreeUnicodeString(&DestinationRootPath);
-         swprintf(PathBuffer,
-                  L"\\Device\\Harddisk%lu\\Partition%lu",
-                  PartData.DiskNumber,
-                  PartData.PartNumber);
-         RtlCreateUnicodeString(&DestinationRootPath,
-                                PathBuffer);
-
-         RtlFreeUnicodeString(&SystemRootPath);
-         swprintf(PathBuffer,
-                  L"\\Device\\Harddisk%lu\\Partition%lu",
-                  ActivePartition.DiskNumber,
-                  ActivePartition.PartNumber);
-         RtlCreateUnicodeString(&SystemRootPath,
-                                PathBuffer);
-
-         return(SELECT_FILE_SYSTEM_PAGE);
+         return DEVICE_SETTINGS_PAGE;
        }
-
-      /* FIXME: Update status text */
-
     }
 
-  DestroyPartitionList(PartList);
-
-  return(SELECT_PARTITION_PAGE);
+  return SCSI_CONTROLLER_PAGE;
 }
+#endif
 
 
 static PAGE_NUMBER
-SelectFileSystemPage(PINPUT_RECORD Ir)
+DeviceSettingsPage(PINPUT_RECORD Ir)
 {
-  ULONGLONG DiskSize;
-  ULONGLONG PartSize;
-  PCHAR DiskUnit;
-  PCHAR PartUnit;
-  PCHAR PartType;
+  static ULONG Line = 16;
 
-  if (PartDataValid == FALSE)
+  /* Initialize the computer settings list */
+  if (ComputerList == NULL)
     {
-      /* FIXME: show an error dialog */
-      return(QUIT_PAGE);
+      ComputerList = CreateComputerTypeList(SetupInf);
+      if (ComputerList == NULL)
+       {
+         /* FIXME: report error */
+       }
     }
 
-  /* adjust disk size */
-  if (PartData.DiskSize >= 0x280000000ULL) /* 10 GB */
-    {
-      DiskSize = (PartData.DiskSize + (1 << 29)) >> 30;
-      DiskUnit = "GB";
-    }
-  else
+  /* Initialize the display settings list */
+  if (DisplayList == NULL)
     {
-      DiskSize = (PartData.DiskSize + (1 << 19)) >> 20;
-      DiskUnit = "MB";
+      DisplayList = CreateDisplayDriverList(SetupInf);
+      if (DisplayList == NULL)
+       {
+         /* FIXME: report error */
+       }
+    }
+
+  /* Initialize the keyboard settings list */
+  if (KeyboardList == NULL)
+    {
+      KeyboardList = CreateKeyboardDriverList(SetupInf);
+      if (KeyboardList == NULL)
+       {
+         /* FIXME: report error */
+       }
+    }
+
+  /* Initialize the keyboard layout list */
+  if (LayoutList == NULL)
+    {
+      LayoutList = CreateKeyboardLayoutList(SetupInf);
+      if (LayoutList == NULL)
+       {
+         /* FIXME: report error */
+         PopupError("Setup failed to load the keyboard layout list.\n",
+                    "ENTER = Reboot computer");
+
+         while (TRUE)
+           {
+             ConInKey(Ir);
+
+             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
+               {
+                 return QUIT_PAGE;
+               }
+           }
+       }
+    }
+
+  SetTextXY(6, 8, "The list below shows the current device settings.");
+
+  SetTextXY(8, 11, "       Computer:");
+  SetTextXY(8, 12, "        Display:");
+  SetTextXY(8, 13, "       Keyboard:");
+  SetTextXY(8, 14, "Keyboard layout:");
+
+  SetTextXY(8, 16, "         Accept:");
+
+  SetTextXY(25, 11, GetGenericListEntry(ComputerList)->Text);
+  SetTextXY(25, 12, GetGenericListEntry(DisplayList)->Text);
+  SetTextXY(25, 13, GetGenericListEntry(KeyboardList)->Text);
+  SetTextXY(25, 14, GetGenericListEntry(LayoutList)->Text);
+
+  SetTextXY(25, 16, "Accept these device settings");
+  InvertTextXY (24, Line, 48, 1);
+
+
+  SetTextXY(6, 19, "You can change the hardware settings by pressing the UP or DOWN keys");
+  SetTextXY(6, 20, "to select an entry. Then press the ENTER key to select alternative");
+  SetTextXY(6, 21, "settings.");
+
+  SetTextXY(6, 23, "When all settings are correct, select \"Accept these device settings\"");
+  SetTextXY(6, 24, "and press ENTER.");
+
+  SetStatusText("   ENTER = Continue   F3 = Quit");
+
+  while(TRUE)
+    {
+      ConInKey(Ir);
+
+      if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
+       {
+         NormalTextXY (24, Line, 48, 1);
+         if (Line == 14)
+           Line = 16;
+         else if (Line == 16)
+           Line = 11;
+         else
+           Line++;
+         InvertTextXY (24, Line, 48, 1);
+       }
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
+       {
+         NormalTextXY (24, Line, 48, 1);
+         if (Line == 11)
+           Line = 16;
+         else if (Line == 16)
+           Line = 14;
+         else
+           Line--;
+         InvertTextXY (24, Line, 48, 1);
+       }
+      else 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 */
+       {
+         if (Line == 11)
+           return COMPUTER_SETTINGS_PAGE;
+         else if (Line == 12)
+           return DISPLAY_SETTINGS_PAGE;
+         else if (Line == 13)
+           return KEYBOARD_SETTINGS_PAGE;
+         else if (Line == 14)
+           return LAYOUT_SETTINGS_PAGE;
+         else if (Line == 16)
+           return SELECT_PARTITION_PAGE;
+       }
+    }
+
+  return DEVICE_SETTINGS_PAGE;
+}
+
+
+static PAGE_NUMBER
+ComputerSettingsPage(PINPUT_RECORD Ir)
+{
+  SHORT xScreen;
+  SHORT yScreen;
+
+  SetTextXY(6, 8, "You want to change the type of computer to be installed.");
+
+  SetTextXY(8, 10, "\x07  Press the UP or DOWN key to select the desired computer type.");
+  SetTextXY(8, 11, "   Then press ENTER.");
+
+  SetTextXY(8, 13, "\x07  Press the ESC key to return to the previous page without changing");
+  SetTextXY(8, 14, "   the computer type.");
+
+  GetScreenSize(&xScreen, &yScreen);
+
+  DrawGenericList(ComputerList,
+                 2,
+                 18,
+                 xScreen - 3,
+                 yScreen - 3);
+
+  SetStatusText("   ENTER = Continue   ESC = Cancel   F3 = Quit");
+
+  SaveGenericListState(ComputerList);
+
+  while(TRUE)
+    {
+      ConInKey(Ir);
+
+      if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
+       {
+         ScrollDownGenericList (ComputerList);
+       }
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
+       {
+         ScrollUpGenericList (ComputerList);
+       }
+      else 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 == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
+       {
+         RestoreGenericListState(ComputerList);
+         return DEVICE_SETTINGS_PAGE;
+       }
+      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+       {
+         return DEVICE_SETTINGS_PAGE;
+       }
+    }
+
+  return COMPUTER_SETTINGS_PAGE;
+}
+
+
+static PAGE_NUMBER
+DisplaySettingsPage(PINPUT_RECORD Ir)
+{
+  SHORT xScreen;
+  SHORT yScreen;
+
+  SetTextXY(6, 8, "You want to change the type of display to be installed.");
+
+  SetTextXY(8, 10, "\x07  Press the UP or DOWN key to select the desired display type.");
+  SetTextXY(8, 11, "   Then press ENTER.");
+
+  SetTextXY(8, 13, "\x07  Press the ESC key to return to the previous page without changing");
+  SetTextXY(8, 14, "   the display type.");
+
+  GetScreenSize(&xScreen, &yScreen);
+
+  DrawGenericList(DisplayList,
+                 2,
+                 18,
+                 xScreen - 3,
+                 yScreen - 3);
+
+  SetStatusText("   ENTER = Continue   ESC = Cancel   F3 = Quit");
+
+  SaveGenericListState(DisplayList);
+
+  while(TRUE)
+    {
+      ConInKey(Ir);
+
+      if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
+       {
+         ScrollDownGenericList (DisplayList);
+       }
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
+       {
+         ScrollUpGenericList (DisplayList);
+       }
+      else 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 == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
+       {
+         RestoreGenericListState(DisplayList);
+         return DEVICE_SETTINGS_PAGE;
+       }
+      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+       {
+         return DEVICE_SETTINGS_PAGE;
+       }
+    }
+
+  return DISPLAY_SETTINGS_PAGE;
+}
+
+
+static PAGE_NUMBER
+KeyboardSettingsPage(PINPUT_RECORD Ir)
+{
+  SHORT xScreen;
+  SHORT yScreen;
+
+  SetTextXY(6, 8, "You want to change the type of keyboard to be installed.");
+
+  SetTextXY(8, 10, "\x07  Press the UP or DOWN key to select the desired keyboard type.");
+  SetTextXY(8, 11, "   Then press ENTER.");
+
+  SetTextXY(8, 13, "\x07  Press the ESC key to return to the previous page without changing");
+  SetTextXY(8, 14, "   the keyboard type.");
+
+  GetScreenSize(&xScreen, &yScreen);
+
+  DrawGenericList(KeyboardList,
+                 2,
+                 18,
+                 xScreen - 3,
+                 yScreen - 3);
+
+  SetStatusText("   ENTER = Continue   ESC = Cancel   F3 = Quit");
+
+  SaveGenericListState(KeyboardList);
+
+  while(TRUE)
+    {
+      ConInKey(Ir);
+
+      if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
+       {
+         ScrollDownGenericList (KeyboardList);
+       }
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
+       {
+         ScrollUpGenericList (KeyboardList);
+       }
+      else 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 == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
+       {
+         RestoreGenericListState(KeyboardList);
+         return DEVICE_SETTINGS_PAGE;
+       }
+      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+       {
+         return DEVICE_SETTINGS_PAGE;
+       }
+    }
+
+  return DISPLAY_SETTINGS_PAGE;
+}
+
+
+static PAGE_NUMBER
+LayoutSettingsPage(PINPUT_RECORD Ir)
+{
+  SHORT xScreen;
+  SHORT yScreen;
+
+  SetTextXY(6, 8, "You want to change the keyboard layout to be installed.");
+
+  SetTextXY(8, 10, "\x07  Press the UP or DOWN key to select the desired keyboard");
+  SetTextXY(8, 11, "    layout. Then press ENTER.");
+
+  SetTextXY(8, 13, "\x07  Press the ESC key to return to the previous page without changing");
+  SetTextXY(8, 14, "   the keyboard layout.");
+
+  GetScreenSize(&xScreen, &yScreen);
+
+  DrawGenericList(LayoutList,
+                 2,
+                 18,
+                 xScreen - 3,
+                 yScreen - 3);
+
+  SetStatusText("   ENTER = Continue   ESC = Cancel   F3 = Quit");
+
+  SaveGenericListState(LayoutList);
+
+  while(TRUE)
+    {
+      ConInKey(Ir);
+
+      if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
+       {
+         ScrollDownGenericList (LayoutList);
+       }
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
+       {
+         ScrollUpGenericList (LayoutList);
+       }
+      else 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 == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
+       {
+         RestoreGenericListState(LayoutList);
+         return DEVICE_SETTINGS_PAGE;
+       }
+      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+       {
+         return DEVICE_SETTINGS_PAGE;
+       }
+    }
+
+  return DISPLAY_SETTINGS_PAGE;
+}
+
+
+static PAGE_NUMBER
+SelectPartitionPage(PINPUT_RECORD Ir)
+{
+  SHORT xScreen;
+  SHORT yScreen;
+
+  SetTextXY(6, 8, "The list below shows existing partitions and unused disk");
+  SetTextXY(6, 9, "space for new partitions.");
+
+  SetTextXY(8, 11, "\x07  Press UP or DOWN to select a list entry.");
+  SetTextXY(8, 13, "\x07  Press ENTER to install ReactOS onto the selected partition.");
+  SetTextXY(8, 15, "\x07  Press C to create a new partition.");
+  SetTextXY(8, 17, "\x07  Press D to delete an existing partition.");
+
+  SetStatusText("   Please wait...");
+
+  GetScreenSize(&xScreen, &yScreen);
+
+  if (PartitionList == NULL)
+    {
+      PartitionList = CreatePartitionList (2,
+                                          19,
+                                          xScreen - 3,
+                                          yScreen - 3);
+      if (PartitionList == NULL)
+       {
+         /* FIXME: show an error dialog */
+         return QUIT_PAGE;
+       }
+    }
+
+  CheckActiveBootPartition (PartitionList);
+
+  DrawPartitionList (PartitionList);
+
+  /* Warn about partitions created by Linux Fdisk */
+  if (WarnLinuxPartitions == TRUE &&
+      CheckForLinuxFdiskPartitions (PartitionList) == TRUE)
+    {
+      PopupError ("Setup found that at least one harddisk contains an incompatible\n"
+                 "partition table that can not be handled properly!\n"
+                 "\n"
+                 "Creating or deleting partitions can destroy the partiton table.\n"
+                 "\n"
+                 "  \x07  Press F3 to quit Setup."
+                 "  \x07  Press ENTER to continue.",
+                 "F3= Quit  ENTER = Continue");
+      while (TRUE)
+       {
+         ConInKey (Ir);
+
+         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
+           {
+             return QUIT_PAGE;
+           }
+         else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
+           {
+             WarnLinuxPartitions = FALSE;
+             return SELECT_PARTITION_PAGE;
+           }
+       }
+    }
+
+  if (IsUnattendedSetup)
+    {
+      SelectPartition(PartitionList,
+        UnattendDestinationDiskNumber,
+        UnattendDestinationPartitionNumber);
+      return(SELECT_FILE_SYSTEM_PAGE);
+    }
+
+  while(TRUE)
+    {
+      /* Update status text */
+      if (PartitionList->CurrentPartition == NULL ||
+         PartitionList->CurrentPartition->Unpartitioned == TRUE)
+       {
+         SetStatusText ("   ENTER = Install   C = Create Partition   F3 = Quit");
+       }
+      else
+       {
+         SetStatusText ("   ENTER = Install   D = Delete Partition   F3 = Quit");
+       }
+
+      ConInKey(Ir);
+
+      if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
+       {
+         if (ConfirmQuit(Ir) == TRUE)
+           {
+             DestroyPartitionList (PartitionList);
+             PartitionList = NULL;
+             return QUIT_PAGE;
+           }
+         break;
+       }
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
+       {
+         ScrollDownPartitionList (PartitionList);
+       }
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
+       {
+         ScrollUpPartitionList (PartitionList);
+       }
+      else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
+       {
+         if (PartitionList->CurrentPartition == NULL ||
+             PartitionList->CurrentPartition->Unpartitioned == TRUE)
+           {
+             CreateNewPartition (PartitionList,
+                                 0ULL,
+                                 TRUE);
+           }
+
+         return SELECT_FILE_SYSTEM_PAGE;
+       }
+      else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'C') /* C */
+       {
+         if (PartitionList->CurrentPartition->Unpartitioned == FALSE)
+           {
+             PopupError ("You can not create a new Partition inside\n"
+                         "of an already existing Partition!\n"
+                         "\n"
+                         "  * Press any key to continue.",
+                         NULL);
+             ConInKey (Ir);
+
+             return SELECT_PARTITION_PAGE;
+           }
+
+         return CREATE_PARTITION_PAGE;
+       }
+      else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
+       {
+         if (PartitionList->CurrentPartition->Unpartitioned == TRUE)
+           {
+             PopupError ("You can not delete unpartitioned disk space!\n"
+                         "\n"
+                         "  * Press any key to continue.",
+                         NULL);
+             ConInKey (Ir);
+
+             return SELECT_PARTITION_PAGE;
+           }
+
+         return DELETE_PARTITION_PAGE;
+       }
+    }
+
+  return SELECT_PARTITION_PAGE;
+}
+
+
+static VOID
+DrawInputField(ULONG FieldLength,
+  SHORT Left,
+  SHORT Top,
+  PCHAR FieldContent)
+{
+  CHAR buf[100];
+  COORD coPos;
+
+  coPos.X = Left;
+  coPos.Y = Top;
+  memset(buf, '_', sizeof(buf));
+  buf[FieldLength - strlen(FieldContent)] = 0;
+  strcat(buf, FieldContent);
+
+  WriteConsoleOutputCharacters (buf,
+                               strlen (buf),
+                               coPos);
+}
+
+
+#define PARTITION_SIZE_INPUT_FIELD_LENGTH 6
+
+static VOID
+ShowPartitionSizeInputBox(SHORT Left,
+                         SHORT Top,
+                         SHORT Right,
+                         SHORT Bottom,
+                         ULONG MaxSize,
+                         PCHAR InputBuffer,
+                         PBOOLEAN Quit,
+                         PBOOLEAN Cancel)
+{
+  INPUT_RECORD Ir;
+  COORD coPos;
+  ULONG Written;
+  SHORT i;
+  CHAR Buffer[100];
+  ULONG Index;
+  CHAR ch;
+  SHORT iLeft;
+  SHORT iTop;
+
+  if (Quit != NULL)
+    *Quit = FALSE;
+
+  if (Cancel != NULL)
+    *Cancel = FALSE;
+
+  /* draw upper left corner */
+  coPos.X = Left;
+  coPos.Y = Top;
+  FillConsoleOutputCharacter(0xDA, // '+',
+                            1,
+                            coPos,
+                            &Written);
+
+  /* draw upper edge */
+  coPos.X = Left + 1;
+  coPos.Y = Top;
+  FillConsoleOutputCharacter(0xC4, // '-',
+                            Right - Left - 1,
+                            coPos,
+                            &Written);
+
+  /* draw upper right corner */
+  coPos.X = Right;
+  coPos.Y = Top;
+  FillConsoleOutputCharacter(0xBF, // '+',
+                            1,
+                            coPos,
+                            &Written);
+
+  /* draw left and right edge */
+  for (i = Top + 1; i < Bottom; i++)
+    {
+      coPos.X = Left;
+      coPos.Y = i;
+      FillConsoleOutputCharacter(0xB3, // '|',
+                                1,
+                                coPos,
+                                &Written);
+
+      coPos.X = Right;
+      FillConsoleOutputCharacter(0xB3, //'|',
+                                1,
+                                coPos,
+                                &Written);
+    }
+
+  /* draw lower left corner */
+  coPos.X = Left;
+  coPos.Y = Bottom;
+  FillConsoleOutputCharacter(0xC0, // '+',
+                            1,
+                            coPos,
+                            &Written);
+
+  /* draw lower edge */
+  coPos.X = Left + 1;
+  coPos.Y = Bottom;
+  FillConsoleOutputCharacter(0xC4, // '-',
+                            Right - Left - 1,
+                            coPos,
+                            &Written);
+
+  /* draw lower right corner */
+  coPos.X = Right;
+  coPos.Y = Bottom;
+  FillConsoleOutputCharacter(0xD9, // '+',
+                            1,
+                            coPos,
+                            &Written);
+
+  /* Print message */
+  coPos.X = Left + 2;
+  coPos.Y = Top + 2;
+  strcpy (Buffer, "Size of new partition:");
+  iLeft = coPos.X + strlen (Buffer) + 1;
+  iTop = coPos.Y;
+  WriteConsoleOutputCharacters (Buffer,
+                                strlen (Buffer),
+                                coPos);
+
+  sprintf (Buffer, "MB (max. %lu MB)", MaxSize);
+  coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
+  coPos.Y = iTop;
+  WriteConsoleOutputCharacters (Buffer,
+                               strlen (Buffer),
+                               coPos);
+
+  sprintf(Buffer, "%lu", MaxSize);
+  Index = strlen(Buffer);
+  DrawInputField (PARTITION_SIZE_INPUT_FIELD_LENGTH,
+                 iLeft,
+                 iTop,
+                 Buffer);
+
+  while (TRUE)
+    {
+      ConInKey (&Ir);
+
+      if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
+       {
+         if (Quit != NULL)
+           *Quit = TRUE;
+         Buffer[0] = 0;
+         break;
+       }
+      else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
+       {
+         break;
+       }
+      else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */
+       {
+         if (Cancel != NULL)
+           *Cancel = TRUE;
+         Buffer[0] = 0;
+         break;
+       }
+      else if ((Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) &&  /* BACKSPACE */
+              (Index > 0))
+       {
+         Index--;
+         Buffer[Index] = 0;
+         DrawInputField (PARTITION_SIZE_INPUT_FIELD_LENGTH,
+                         iLeft,
+                         iTop,
+                         Buffer);
+       }
+      else if ((Ir.Event.KeyEvent.uChar.AsciiChar != 0x00) &&
+              (Index < PARTITION_SIZE_INPUT_FIELD_LENGTH))
+       {
+         ch = Ir.Event.KeyEvent.uChar.AsciiChar;
+         if ((ch >= '0') && (ch <= '9'))
+           {
+             Buffer[Index] = ch;
+             Index++;
+             Buffer[Index] = 0;
+             DrawInputField (PARTITION_SIZE_INPUT_FIELD_LENGTH,
+                             iLeft,
+                             iTop,
+                             Buffer);
+           }
+       }
+    }
+
+  strcpy (InputBuffer,
+         Buffer);
+}
+
+
+static PAGE_NUMBER
+CreatePartitionPage (PINPUT_RECORD Ir)
+{
+  PDISKENTRY DiskEntry;
+  PPARTENTRY PartEntry;
+  SHORT xScreen;
+  SHORT yScreen;
+  BOOLEAN Quit;
+  BOOLEAN Cancel;
+  CHAR InputBuffer[50];
+  ULONG MaxSize;
+  ULONGLONG PartSize;
+  ULONGLONG DiskSize;
+  PCHAR Unit;
+
+  if (PartitionList == NULL ||
+      PartitionList->CurrentDisk == NULL ||
+      PartitionList->CurrentPartition == NULL)
+    {
+      /* FIXME: show an error dialog */
+      return QUIT_PAGE;
+    }
+
+  DiskEntry = PartitionList->CurrentDisk;
+  PartEntry = PartitionList->CurrentPartition;
+
+  SetStatusText ("   Please wait...");
+
+  GetScreenSize (&xScreen, &yScreen);
+
+  SetTextXY (6, 8, "You have chosen to create a new partition on");
+
+#if 0
+  if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
+    {
+      DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
+      Unit = "GB";
+    }
+  else
+#endif
+    {
+      DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
+      if (DiskSize == 0)
+       DiskSize = 1;
+      Unit = "MB";
+    }
+
+  if (DiskEntry->DriverName.Length > 0)
+    {
+      PrintTextXY (6, 10,
+                  "%I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu) on %wZ.",
+                  DiskSize,
+                  Unit,
+                  DiskEntry->DiskNumber,
+                  DiskEntry->Port,
+                  DiskEntry->Bus,
+                  DiskEntry->Id,
+                  &DiskEntry->DriverName);
+    }
+  else
+    {
+      PrintTextXY (6, 10,
+                  "%I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu).",
+                  DiskSize,
+                  Unit,
+                  DiskEntry->DiskNumber,
+                  DiskEntry->Port,
+                  DiskEntry->Bus,
+                  DiskEntry->Id);
+    }
+
+
+  SetTextXY (6, 12, "Please enter the size of the new partition in megabytes.");
+
+#if 0
+  PrintTextXY (8, 10, "Maximum size of the new partition is %I64u MB",
+              PartitionList->CurrentPartition->UnpartitionedLength / (1024*1024));
+#endif
+
+  SetStatusText ("   ENTER = Create Partition   ESC = Cancel   F3 = Quit");
+
+  PartEntry = PartitionList->CurrentPartition;
+  while (TRUE)
+    {
+      MaxSize = (PartEntry->UnpartitionedLength + (1 << 19)) >> 20;  /* in MBytes (rounded) */
+      ShowPartitionSizeInputBox (12, 14, xScreen - 12, 17, /* left, top, right, bottom */
+                                MaxSize, InputBuffer, &Quit, &Cancel);
+      if (Quit == TRUE)
+       {
+         if (ConfirmQuit (Ir) == TRUE)
+           {
+             return QUIT_PAGE;
+           }
+       }
+      else if (Cancel == TRUE)
+       {
+         return SELECT_PARTITION_PAGE;
+       }
+      else
+       {
+         PartSize = atoi (InputBuffer);
+         if (PartSize < 1)
+           {
+             /* Too small */
+             continue;
+           }
+
+         if (PartSize > MaxSize)
+           {
+             /* Too large */
+             continue;
+           }
+
+         /* Convert to bytes */
+         if (PartSize == MaxSize)
+           {
+             /* Use all of the unpartitioned disk space */
+             PartSize = PartEntry->UnpartitionedLength;
+           }
+         else
+           {
+             /* Round-up by cylinder size */
+             PartSize = ROUND_UP (PartSize * 1024 * 1024,
+                                  DiskEntry->CylinderSize);
+
+             /* But never get larger than the unpartitioned disk space */
+             if (PartSize > PartEntry->UnpartitionedLength)
+               PartSize = PartEntry->UnpartitionedLength;
+           }
+
+         DPRINT ("Partition size: %I64u bytes\n", PartSize);
+
+         CreateNewPartition (PartitionList,
+                             PartSize,
+                             FALSE);
+
+         return SELECT_PARTITION_PAGE;
+       }
+    }
+
+  return CREATE_PARTITION_PAGE;
+}
+
+
+static PAGE_NUMBER
+DeletePartitionPage (PINPUT_RECORD Ir)
+{
+  PDISKENTRY DiskEntry;
+  PPARTENTRY PartEntry;
+  ULONGLONG DiskSize;
+  ULONGLONG PartSize;
+  PCHAR Unit;
+  PCHAR PartType;
+
+  if (PartitionList == NULL ||
+      PartitionList->CurrentDisk == NULL ||
+      PartitionList->CurrentPartition == NULL)
+    {
+      /* FIXME: show an error dialog */
+      return QUIT_PAGE;
+    }
+
+  DiskEntry = PartitionList->CurrentDisk;
+  PartEntry = PartitionList->CurrentPartition;
+
+  SetTextXY (6, 8, "You have chosen to delete the partition");
+
+  /* Determine partition type */
+  PartType = NULL;
+  if (PartEntry->New == TRUE)
+    {
+      PartType = "New (Unformatted)";
+    }
+  else if (PartEntry->Unpartitioned == FALSE)
+    {
+      if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
+         (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
+         (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
+         (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13))
+       {
+         PartType = "FAT";
+       }
+      else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
+              (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
+       {
+         PartType = "FAT32";
+       }
+      else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
+       {
+         PartType = "NTFS"; /* FIXME: Not quite correct! */
+       }
+    }
+
+#if 0
+  if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0x280000000LL) /* 10 GB */
+    {
+      PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 29)) >> 30;
+      Unit = "GB";
+    }
+  else
+#endif
+  if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0xA00000LL) /* 10 MB */
+    {
+      PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 19)) >> 20;
+      Unit = "MB";
+    }
+  else
+    {
+      PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 9)) >> 10;
+      Unit = "KB";
+    }
+
+  if (PartType == NULL)
+    {
+      PrintTextXY (6, 10,
+                  "   %c%c  Type %lu    %I64u %s",
+                  (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
+                  (PartEntry->DriveLetter == 0) ? '-' : ':',
+                  PartEntry->PartInfo[0].PartitionType,
+                  PartSize,
+                  Unit);
+    }
+  else
+    {
+      PrintTextXY (6, 10,
+                  "   %c%c  %s    %I64u %s",
+                  (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
+                  (PartEntry->DriveLetter == 0) ? '-' : ':',
+                  PartType,
+                  PartSize,
+                  Unit);
+    }
+
+#if 0
+  if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
+    {
+      DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
+      Unit = "GB";
+    }
+  else
+#endif
+    {
+      DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
+      if (DiskSize == 0)
+       DiskSize = 1;
+      Unit = "MB";
+    }
+
+  if (DiskEntry->DriverName.Length > 0)
+    {
+      PrintTextXY (6, 12,
+                  "on %I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu) on %wZ.",
+                  DiskSize,
+                  Unit,
+                  DiskEntry->DiskNumber,
+                  DiskEntry->Port,
+                  DiskEntry->Bus,
+                  DiskEntry->Id,
+                  &DiskEntry->DriverName);
+    }
+  else
+    {
+      PrintTextXY (6, 12,
+                  "on %I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu).",
+                  DiskSize,
+                  Unit,
+                  DiskEntry->DiskNumber,
+                  DiskEntry->Port,
+                  DiskEntry->Bus,
+                  DiskEntry->Id);
+    }
+
+  SetTextXY (8, 18, "\x07  Press D to delete the partition.");
+  SetTextXY (11, 19, "WARNING: All data on this partition will be lost!");
+
+  SetTextXY (8, 21, "\x07  Press ESC to cancel.");
+
+  SetStatusText ("   D = Delete Partition   ESC = Cancel   F3 = Quit");
+
+  while (TRUE)
+    {
+      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.wVirtualKeyCode == VK_ESCAPE)  /* ESC */
+       {
+         return SELECT_PARTITION_PAGE;
+       }
+      else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
+       {
+         DeleteCurrentPartition (PartitionList);
+
+         return SELECT_PARTITION_PAGE;
+       }
+    }
+
+  return DELETE_PARTITION_PAGE;
+}
+
+
+static PAGE_NUMBER
+SelectFileSystemPage (PINPUT_RECORD Ir)
+{
+  PDISKENTRY DiskEntry;
+  PPARTENTRY PartEntry;
+  ULONGLONG DiskSize;
+  ULONGLONG PartSize;
+  PCHAR DiskUnit;
+  PCHAR PartUnit;
+  PCHAR PartType;
+
+  if (PartitionList == NULL ||
+      PartitionList->CurrentDisk == NULL ||
+      PartitionList->CurrentPartition == NULL)
+    {
+      /* FIXME: show an error dialog */
+      return QUIT_PAGE;
+    }
+
+  DiskEntry = PartitionList->CurrentDisk;
+  PartEntry = PartitionList->CurrentPartition;
+
+  /* adjust disk size */
+  if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
+    {
+      DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
+      DiskUnit = "GB";
+    }
+  else
+    {
+      DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
+      DiskUnit = "MB";
     }
 
   /* adjust partition size */
-  if (PartData.PartSize >= 0x280000000ULL) /* 10 GB */
+  if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0x280000000LL) /* 10 GB */
     {
-      PartSize = (PartData.PartSize + (1 << 29)) >> 30;
+      PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 29)) >> 30;
       PartUnit = "GB";
     }
   else
     {
-      PartSize = (PartData.PartSize + (1 << 19)) >> 20;
+      PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 19)) >> 20;
       PartUnit = "MB";
     }
 
   /* adjust partition type */
-  if ((PartData.PartType == PARTITION_FAT_12) ||
-      (PartData.PartType == PARTITION_FAT_16) ||
-      (PartData.PartType == PARTITION_HUGE) ||
-      (PartData.PartType == PARTITION_XINT13))
+  if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
+      (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
+      (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
+      (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13))
     {
       PartType = "FAT";
     }
-  else if ((PartData.PartType == PARTITION_FAT32) ||
-          (PartData.PartType == PARTITION_FAT32_XINT13))
+  else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
+          (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
     {
       PartType = "FAT32";
     }
-  else if (PartData.PartType == PARTITION_IFS)
+  else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
     {
       PartType = "NTFS"; /* FIXME: Not quite correct! */
     }
+  else if (PartEntry->PartInfo[0].PartitionType == PARTITION_ENTRY_UNUSED)
+    {
+      PartType = "Unused";
+    }
+  else
+    {
+      PartType = "Unknown";
+    }
+
+  if (PartEntry->AutoCreate == TRUE)
+    {
+      SetTextXY(6, 8, "Setup created a new partition on");
+
+#if 0
+  PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
+             PartEntry->PartInfo[0].PartitionNumber,
+             PartSize,
+             PartUnit,
+             PartType);
+#endif
+
+  PrintTextXY(8, 10, "Harddisk %lu (%I64u %s), Port=%hu, Bus=%hu, Id=%hu (%wZ).",
+             DiskEntry->DiskNumber,
+             DiskSize,
+             DiskUnit,
+             DiskEntry->Port,
+             DiskEntry->Bus,
+             DiskEntry->Id,
+             &DiskEntry->DriverName);
+
+      SetTextXY(6, 12, "This Partition will be formatted next.");
+
+
+      PartEntry->AutoCreate = FALSE;
+    }
+  else if (PartEntry->New == TRUE)
+    {
+      SetTextXY(6, 8, "You chose to install ReactOS on a new or unformatted Partition.");
+      SetTextXY(6, 10, "This Partition will be formatted next.");
+    }
   else
     {
-      PartType = "Unknown";
+      SetTextXY(6, 8, "Setup install ReactOS onto Partition");
+
+      if (PartType == NULL)
+       {
+         PrintTextXY (8, 10,
+                      "%c%c  Type %lu    %I64u %s",
+                      (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
+                      (PartEntry->DriveLetter == 0) ? '-' : ':',
+                      PartEntry->PartInfo[0].PartitionType,
+                      PartSize,
+                      PartUnit);
+       }
+      else
+       {
+         PrintTextXY (8, 10,
+                      "%c%c  %s    %I64u %s",
+                      (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
+                      (PartEntry->DriveLetter == 0) ? '-' : ':',
+                      PartType,
+                      PartSize,
+                      PartUnit);
+       }
+
+      PrintTextXY(6, 12, "on Harddisk %lu (%I64u %s), Port=%hu, Bus=%hu, Id=%hu (%wZ).",
+                 DiskEntry->DiskNumber,
+                 DiskSize,
+                 DiskUnit,
+                 DiskEntry->Port,
+                 DiskEntry->Bus,
+                 DiskEntry->Id,
+                 &DiskEntry->DriverName);
+    }
+
+
+  SetTextXY(6, 17, "Select a file system from the list below.");
+
+  SetTextXY(8, 19, "\x07  Press UP or DOWN to select a file system.");
+  SetTextXY(8, 21, "\x07  Press ENTER to format the partition.");
+  SetTextXY(8, 23, "\x07  Press ESC to select another partition.");
+
+  if (FileSystemList == NULL)
+    {
+      FileSystemList = CreateFileSystemList (6, 26, PartEntry->New, FsFat);
+      if (FileSystemList == NULL)
+       {
+         /* FIXME: show an error dialog */
+         return QUIT_PAGE;
+       }
+
+      /* FIXME: Add file systems to list */
+    }
+  DrawFileSystemList (FileSystemList);
+
+  SetStatusText ("   ENTER = Continue   ESC = Cancel   F3 = Quit");
+
+  if (IsUnattendedSetup)
+    {
+      return(CHECK_FILE_SYSTEM_PAGE);
+    }
+
+  while (TRUE)
+    {
+      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 == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
+       {
+         return SELECT_PARTITION_PAGE;
+       }
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
+       {
+         ScrollDownFileSystemList (FileSystemList);
+       }
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
+       {
+         ScrollUpFileSystemList (FileSystemList);
+       }
+      else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
+       {
+         if (FileSystemList->CurrentFileSystem == FsKeep)
+           {
+             return CHECK_FILE_SYSTEM_PAGE;
+           }
+         else
+           {
+             return FORMAT_PARTITION_PAGE;
+           }
+       }
     }
 
-  SetTextXY(6, 8, "Setup will install ReactOS on");
+  return SELECT_FILE_SYSTEM_PAGE;
+}
 
-  PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
-             PartData.PartNumber,
-             PartSize,
-             PartUnit,
-             PartType);
 
-  PrintTextXY(8, 12, "Harddisk %lu (%I64u %s), Port=%hu, Bus=%hu, Id=%hu (%wZ).",
-             PartData.DiskNumber,
-             DiskSize,
-             DiskUnit,
-             PartData.Port,
-             PartData.Bus,
-             PartData.Id,
-             &PartData.DriverName);
+static ULONG
+FormatPartitionPage (PINPUT_RECORD Ir)
+{
+  WCHAR PathBuffer[MAX_PATH];
+  PDISKENTRY DiskEntry;
+  PPARTENTRY PartEntry;
+  NTSTATUS Status;
+
+#ifndef NDEBUG
+  ULONG Line;
+  ULONG i;
+  PLIST_ENTRY Entry;
+#endif
 
 
-  SetTextXY(6, 17, "Select a file system for the partition from the list below.");
+  SetTextXY(6, 8, "Format partition");
 
-  SetTextXY(8, 19, "\xfa  Press UP or DOWN to select a file system.");
-  SetTextXY(8, 21, "\xfa  Press ENTER to format the partition.");
-  SetTextXY(8, 23, "\xfa  Press ESC to select another partition.");
+  SetTextXY(6, 10, "Setup will now format the partition. Press ENTER to continue.");
 
-  /* FIXME: use a real list later */
-  SetInvertedTextXY(6, 26, " Keep current file system (no changes) ");
+  SetStatusText("   ENTER = Continue   F3 = Quit");
 
 
-  SetStatusText("   ENTER = Continue   ESC = Cancel   F3 = Quit");
+  if (PartitionList == NULL ||
+      PartitionList->CurrentDisk == NULL ||
+      PartitionList->CurrentPartition == NULL)
+    {
+      /* FIXME: show an error dialog */
+      return QUIT_PAGE;
+    }
+
+  DiskEntry = PartitionList->CurrentDisk;
+  PartEntry = PartitionList->CurrentPartition;
 
   while(TRUE)
     {
@@ -805,28 +2247,236 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
          (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
        {
-         if (ConfirmQuit(Ir) == TRUE)
-           return(QUIT_PAGE);
+         if (ConfirmQuit (Ir) == TRUE)
+           {
+             return QUIT_PAGE;
+           }
          break;
        }
-      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
-       {
-         return(SELECT_PARTITION_PAGE);
-       }
-      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+      else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
        {
-         return(CHECK_FILE_SYSTEM_PAGE);
+         SetStatusText ("   Please wait ...");
+
+         if (PartEntry->PartInfo[0].PartitionType == PARTITION_ENTRY_UNUSED)
+           {
+             switch (FileSystemList->CurrentFileSystem)
+               {
+                 case FsFat:
+                   if (PartEntry->PartInfo[0].PartitionLength.QuadPart < (4200LL * 1024LL))
+                     {
+                       /* FAT12 CHS partition (disk is smaller than 4.1MB) */
+                       PartEntry->PartInfo[0].PartitionType = PARTITION_FAT_12;
+                     }
+                   else if (PartEntry->PartInfo[0].StartingOffset.QuadPart < (1024LL * 255LL * 63LL * 512LL))
+                     {
+                       /* Partition starts below the 8.4GB boundary ==> CHS partition */
+
+                       if (PartEntry->PartInfo[0].PartitionLength.QuadPart < (32LL * 1024LL * 1024LL))
+                         {
+                           /* FAT16 CHS partition (partiton size < 32MB) */
+                           PartEntry->PartInfo[0].PartitionType = PARTITION_FAT_16;
+                         }
+                       else if (PartEntry->PartInfo[0].PartitionLength.QuadPart < (512LL * 1024LL * 1024LL))
+                         {
+                           /* FAT16 CHS partition (partition size < 512MB) */
+                           PartEntry->PartInfo[0].PartitionType = PARTITION_HUGE;
+                         }
+                       else
+                         {
+                           /* FAT32 CHS partition (partition size >= 512MB) */
+                           PartEntry->PartInfo[0].PartitionType = PARTITION_FAT32;
+                         }
+                     }
+                   else
+                     {
+                       /* Partition starts above the 8.4GB boundary ==> LBA partition */
+
+                       if (PartEntry->PartInfo[0].PartitionLength.QuadPart < (512LL * 1024LL * 1024LL))
+                         {
+                           /* FAT16 LBA partition (partition size < 512MB) */
+                           PartEntry->PartInfo[0].PartitionType = PARTITION_XINT13;
+                         }
+                       else
+                         {
+                           /* FAT32 LBA partition (partition size >= 512MB) */
+                           PartEntry->PartInfo[0].PartitionType = PARTITION_FAT32_XINT13;
+                         }
+                     }
+                   break;
+
+                 case FsKeep:
+                   break;
+
+                 default:
+                   return QUIT_PAGE;
+               }
+           }
+
+         CheckActiveBootPartition (PartitionList);
+
+#ifndef NDEBUG
+         PrintTextXY (6, 12,
+                      "Disk: %I64u  Cylinder: %I64u  Track: %I64u",
+                      DiskEntry->DiskSize,
+                      DiskEntry->CylinderSize,
+                      DiskEntry->TrackSize);
+
+         Line = 13;
+         DiskEntry = PartitionList->CurrentDisk;
+         Entry = DiskEntry->PartListHead.Flink;
+         while (Entry != &DiskEntry->PartListHead)
+           {
+             PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
+
+             if (PartEntry->Unpartitioned == FALSE)
+               {
+
+                 for (i = 0; i < 4; i++)
+                   {
+                     PrintTextXY (6, Line,
+                                  "%2u:  %2u  %c  %12I64u  %12I64u  %2u  %c",
+                                  i,
+                                  PartEntry->PartInfo[i].PartitionNumber,
+                                  PartEntry->PartInfo[i].BootIndicator ? 'A' : '-',
+                                  PartEntry->PartInfo[i].StartingOffset.QuadPart,
+                                  PartEntry->PartInfo[i].PartitionLength.QuadPart,
+                                  PartEntry->PartInfo[i].PartitionType,
+                                  PartEntry->PartInfo[i].RewritePartition ? '*' : ' ');
+
+                     Line++;
+                   }
+
+                 Line++;
+               }
+
+             Entry = Entry->Flink;
+           }
+
+         /* Restore the old entry */
+         PartEntry = PartitionList->CurrentPartition;
+#endif
+
+         if (WritePartitionsToDisk (PartitionList) == FALSE)
+           {
+             DPRINT ("WritePartitionsToDisk() failed\n");
+
+             PopupError ("Setup failed to write partition tables.\n",
+                         "ENTER = Reboot computer");
+
+             while (TRUE)
+               {
+                 ConInKey (Ir);
+
+                 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+                   {
+                     return QUIT_PAGE;
+                   }
+               }
+           }
+
+         /* Set DestinationRootPath */
+         RtlFreeUnicodeString (&DestinationRootPath);
+         swprintf (PathBuffer,
+                   L"\\Device\\Harddisk%lu\\Partition%lu",
+                   PartitionList->CurrentDisk->DiskNumber,
+                   PartitionList->CurrentPartition->PartInfo[0].PartitionNumber);
+         RtlCreateUnicodeString (&DestinationRootPath,
+                                 PathBuffer);
+         DPRINT ("DestinationRootPath: %wZ\n", &DestinationRootPath);
+
+
+         /* Set SystemRootPath */
+         RtlFreeUnicodeString (&SystemRootPath);
+         swprintf (PathBuffer,
+                   L"\\Device\\Harddisk%lu\\Partition%lu",
+                   PartitionList->ActiveBootDisk->DiskNumber,
+                   PartitionList->ActiveBootPartition->PartInfo[0].PartitionNumber);
+         RtlCreateUnicodeString (&SystemRootPath,
+                                 PathBuffer);
+         DPRINT ("SystemRootPath: %wZ\n", &SystemRootPath);
+
+
+         switch (FileSystemList->CurrentFileSystem)
+           {
+             case FsFat:
+               Status = FormatPartition (&DestinationRootPath);
+               if (!NT_SUCCESS (Status))
+                 {
+                   DPRINT1 ("FormatPartition() failed with status 0x%.08x\n", Status);
+                   /* FIXME: show an error dialog */
+                   return QUIT_PAGE;
+                 }
+
+               PartEntry->New = FALSE;
+               if (FileSystemList != NULL)
+                 {
+                   DestroyFileSystemList (FileSystemList);
+                   FileSystemList = NULL;
+                 }
+
+               CheckActiveBootPartition (PartitionList);
+
+               /* FIXME: Install boot code. This is a hack! */
+               if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13) ||
+                   (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32))
+                 {
+                   wcscpy (PathBuffer, SourceRootPath.Buffer);
+                   wcscat (PathBuffer, L"\\loader\\fat32.bin");
+
+                   DPRINT ("Install FAT32 bootcode: %S ==> %S\n", PathBuffer,
+                           DestinationRootPath.Buffer);
+                   Status = InstallFat32BootCodeToDisk (PathBuffer,
+                                                        DestinationRootPath.Buffer);
+                   if (!NT_SUCCESS (Status))
+                     {
+                       DPRINT1 ("InstallFat32BootCodeToDisk() failed with status 0x%.08x\n", Status);
+                       /* FIXME: show an error dialog */
+                       return QUIT_PAGE;
+                     }
+                 }
+               else
+                 {
+                   wcscpy (PathBuffer, SourceRootPath.Buffer);
+                   wcscat (PathBuffer, L"\\loader\\fat.bin");
+
+                   DPRINT ("Install FAT bootcode: %S ==> %S\n", PathBuffer,
+                           DestinationRootPath.Buffer);
+                   Status = InstallFat16BootCodeToDisk (PathBuffer,
+                                                        DestinationRootPath.Buffer);
+                   if (!NT_SUCCESS (Status))
+                     {
+                       DPRINT1 ("InstallFat16BootCodeToDisk() failed with status 0x%.08x\n", Status);
+                       /* FIXME: show an error dialog */
+                       return QUIT_PAGE;
+                     }
+                 }
+               break;
+
+             case FsKeep:
+               break;
+
+             default:
+               return QUIT_PAGE;
+           }
+
+#ifndef NDEBUG
+         SetStatusText ("   Done.  Press any key ...");
+         ConInKey(Ir);
+#endif
+
+         return INSTALL_DIRECTORY_PAGE;
        }
     }
 
-  return(SELECT_FILE_SYSTEM_PAGE);
+  return FORMAT_PARTITION_PAGE;
 }
 
 
 static ULONG
 CheckFileSystemPage(PINPUT_RECORD Ir)
 {
+  WCHAR PathBuffer[MAX_PATH];
+
   SetTextXY(6, 8, "Check file system");
 
   SetTextXY(6, 10, "At present, ReactOS can not check file systems.");
@@ -836,6 +2486,33 @@ CheckFileSystemPage(PINPUT_RECORD Ir)
 
   SetStatusText("   ENTER = Continue   F3 = Quit");
 
+
+  /* Set DestinationRootPath */
+  RtlFreeUnicodeString (&DestinationRootPath);
+  swprintf (PathBuffer,
+           L"\\Device\\Harddisk%lu\\Partition%lu",
+           PartitionList->CurrentDisk->DiskNumber,
+           PartitionList->CurrentPartition->PartInfo[0].PartitionNumber);
+  RtlCreateUnicodeString (&DestinationRootPath,
+                         PathBuffer);
+  DPRINT ("DestinationRootPath: %wZ\n", &DestinationRootPath);
+
+  /* Set SystemRootPath */
+  RtlFreeUnicodeString (&SystemRootPath);
+  swprintf (PathBuffer,
+           L"\\Device\\Harddisk%lu\\Partition%lu",
+           PartitionList->ActiveBootDisk->DiskNumber,
+           PartitionList->ActiveBootPartition->PartInfo[0].PartitionNumber);
+  RtlCreateUnicodeString (&SystemRootPath,
+                         PathBuffer);
+  DPRINT ("SystemRootPath: %wZ\n", &SystemRootPath);
+
+
+  if (IsUnattendedSetup)
+    {
+      return(INSTALL_DIRECTORY_PAGE);
+    }
+
   while(TRUE)
     {
       ConInKey(Ir);
@@ -858,14 +2535,63 @@ CheckFileSystemPage(PINPUT_RECORD Ir)
 
 
 static PAGE_NUMBER
-InstallDirectoryPage(PINPUT_RECORD Ir)
+InstallDirectoryPage1(PWCHAR InstallDir, PDISKENTRY DiskEntry, PPARTENTRY PartEntry)
 {
   WCHAR PathBuffer[MAX_PATH];
+
+  /* Create 'InstallPath' string */
+  RtlFreeUnicodeString(&InstallPath);
+  RtlCreateUnicodeString(&InstallPath,
+                        InstallDir);
+
+  /* Create 'DestinationPath' string */
+  RtlFreeUnicodeString(&DestinationPath);
+  wcscpy(PathBuffer,
+        DestinationRootPath.Buffer);
+  if (InstallDir[0] != L'\\')
+    wcscat(PathBuffer,
+          L"\\");
+  wcscat(PathBuffer, InstallDir);
+  RtlCreateUnicodeString(&DestinationPath,
+                        PathBuffer);
+
+  /* Create 'DestinationArcPath' */
+  RtlFreeUnicodeString(&DestinationArcPath);
+  swprintf(PathBuffer,
+          L"multi(0)disk(0)rdisk(%lu)partition(%lu)",
+          DiskEntry->BiosDiskNumber,
+          PartEntry->PartInfo[0].PartitionNumber);
+  if (InstallDir[0] != L'\\')
+    wcscat(PathBuffer,
+          L"\\");
+  wcscat(PathBuffer, InstallDir);
+  RtlCreateUnicodeString(&DestinationArcPath,
+                        PathBuffer);
+
+  return(PREPARE_COPY_PAGE);
+}
+
+
+static PAGE_NUMBER
+InstallDirectoryPage(PINPUT_RECORD Ir)
+{
+  PDISKENTRY DiskEntry;
+  PPARTENTRY PartEntry;
   WCHAR InstallDir[51];
   PWCHAR DefaultPath;
-  INFCONTEXT Context;
+  PINFCONTEXT Context;
   ULONG Length;
-  NTSTATUS Status;
+
+  if (PartitionList == NULL ||
+      PartitionList->CurrentDisk == NULL ||
+      PartitionList->CurrentPartition == NULL)
+    {
+      /* FIXME: show an error dialog */
+      return QUIT_PAGE;
+    }
+
+  DiskEntry = PartitionList->CurrentDisk;
+  PartEntry = PartitionList->CurrentPartition;
 
   /* Search for 'DefaultPath' in the 'SetupData' section */
   if (!InfFindFirstLine (SetupInf, L"SetupData", L"DefaultPath", &Context))
@@ -874,19 +2600,19 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
                 "in TXTSETUP.SIF.\n",
                 "ENTER = Reboot computer");
 
-      while(TRUE)
+      while (TRUE)
        {
-         ConInKey(Ir);
+         ConInKey (Ir);
 
          if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
            {
-             return(QUIT_PAGE);
+             return QUIT_PAGE;
            }
        }
     }
 
   /* Read the 'DefaultPath' data */
-  if (InfGetData (&Context, NULL, &DefaultPath))
+  if (InfGetData (Context, NULL, &DefaultPath))
     {
       wcscpy(InstallDir, DefaultPath);
     }
@@ -894,6 +2620,7 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
     {
       wcscpy(InstallDir, L"\\ReactOS");
     }
+  InfFreeContext(Context);
   Length = wcslen(InstallDir);
 
   SetTextXY(6, 8, "Setup installs ReactOS files onto the selected partition. Choose a");
@@ -907,6 +2634,11 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
 
   SetStatusText("   ENTER = Continue   F3 = Quit");
 
+  if (IsUnattendedSetup)
+    {
+      return(InstallDirectoryPage1 (InstallDir, DiskEntry, PartEntry));
+    }
+
   while(TRUE)
     {
       ConInKey(Ir);
@@ -920,36 +2652,7 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
        }
       else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
        {
-         /* Create 'InstallPath' string */
-         RtlFreeUnicodeString(&InstallPath);
-         RtlCreateUnicodeString(&InstallPath,
-                                InstallDir);
-
-         /* Create 'DestinationPath' string */
-         RtlFreeUnicodeString(&DestinationPath);
-         wcscpy(PathBuffer,
-                DestinationRootPath.Buffer);
-         if (InstallDir[0] != L'\\')
-           wcscat(PathBuffer,
-                  L"\\");
-         wcscat(PathBuffer, InstallDir);
-         RtlCreateUnicodeString(&DestinationPath,
-                                PathBuffer);
-
-         /* Create 'DestinationArcPath' */
-         RtlFreeUnicodeString(&DestinationArcPath);
-         swprintf(PathBuffer,
-                  L"multi(0)disk(0)rdisk(%lu)partition(%lu)",
-                  PartData.DiskNumber,
-                  PartData.PartNumber);
-         if (InstallDir[0] != L'\\')
-           wcscat(PathBuffer,
-                  L"\\");
-         wcscat(PathBuffer, InstallDir);
-         RtlCreateUnicodeString(&DestinationArcPath,
-                                PathBuffer);
-
-         return(PREPARE_COPY_PAGE);
+         return (InstallDirectoryPage1 (InstallDir, DiskEntry, PartEntry));
        }
       else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
        {
@@ -976,45 +2679,144 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
 }
 
 
-static PAGE_NUMBER
-PrepareCopyPage(PINPUT_RECORD Ir)
+static BOOLEAN
+AddSectionToCopyQueue(HINF InfFile,
+                      PWCHAR SectionName,
+                      PWCHAR SourceCabinet,
+                      PINPUT_RECORD Ir)
 {
-  WCHAR PathBuffer[MAX_PATH];
-  INFCONTEXT FilesContext;
-  INFCONTEXT DirContext;
-  PWCHAR KeyName;
-  PWCHAR KeyValue;
-  ULONG Length;
-  NTSTATUS Status;
-
+  PINFCONTEXT FilesContext;
+  PINFCONTEXT DirContext;
   PWCHAR FileKeyName;
   PWCHAR FileKeyValue;
-  PWCHAR DirKeyName;
   PWCHAR DirKeyValue;
+  PWCHAR TargetFileName;
 
-  SetTextXY(6, 8, "Setup prepares your computer for copying the ReactOS files. ");
+  /* Search for the SectionName section */
+  if (!InfFindFirstLine (InfFile, SectionName, NULL, &FilesContext))
+    {
+      char Buffer[128];
+      sprintf(Buffer, "Setup failed to find the '%S' section\nin TXTSETUP.SIF.\n", SectionName);
+      PopupError(Buffer, "ENTER = Reboot computer");
+
+      while(TRUE)
+       {
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(FALSE);
+           }
+       }
+    }
+
+  /*
+   * Enumerate the files in the section
+   * and add them to the file queue.
+   */
+  do
+    {
+      /* Get source file name and target directory id */
+      if (!InfGetData (FilesContext, &FileKeyName, &FileKeyValue))
+       {
+         /* FIXME: Handle error! */
+         DPRINT1("InfGetData() failed\n");
+         break;
+       }
 
+      /* Get optional target file name */
+      if (!InfGetDataField (FilesContext, 2, &TargetFileName))
+       TargetFileName = NULL;
 
-//  SetTextXY(8, 12, "Build file copy list");
+      DPRINT ("FileKeyName: '%S'  FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
 
-//  SetTextXY(8, 14, "Create directories");
+      /* Lookup target directory */
+      if (!InfFindFirstLine (InfFile, L"Directories", FileKeyValue, &DirContext))
+       {
+         /* FIXME: Handle error! */
+         DPRINT1("InfFindFirstLine() failed\n");
+         break;
+       }
 
-//  SetStatusText("   Please wait...");
+      if (!InfGetData (DirContext, NULL, &DirKeyValue))
+       {
+         /* FIXME: Handle error! */
+          InfFreeContext(DirContext);
+         DPRINT1("InfGetData() failed\n");
+         break;
+       }
+
+      if (!SetupQueueCopy(SetupFileQueue,
+                         SourceCabinet,
+                         SourceRootPath.Buffer,
+                         L"\\reactos",
+                         FileKeyName,
+                         DirKeyValue,
+                         TargetFileName))
+       {
+         /* FIXME: Handle error! */
+         DPRINT1("SetupQueueCopy() failed\n");
+       }
+      InfFreeContext(DirContext);
+    }
+  while (InfFindNextLine(FilesContext, FilesContext));
+
+  InfFreeContext(FilesContext);
+
+  return TRUE;
+}
+
+static BOOLEAN
+PrepareCopyPageInfFile(HINF InfFile,
+                      PWCHAR SourceCabinet,
+                      PINPUT_RECORD Ir)
+{
+  WCHAR PathBuffer[MAX_PATH];
+  PINFCONTEXT DirContext;
+  PWCHAR AdditionalSectionName = NULL;
+  PWCHAR KeyValue;
+  ULONG Length;
+  NTSTATUS Status;
+
+  /* Add common files */
+  if (!AddSectionToCopyQueue(InfFile, L"SourceFiles", SourceCabinet, Ir))
+    return FALSE;
+
+  /* Add specific files depending of computer type */
+  if (SourceCabinet == NULL)
+  {
+    if (!ProcessComputerFiles(InfFile, ComputerList, &AdditionalSectionName))
+      return FALSE;
+    if (AdditionalSectionName)
+    {
+      if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, Ir))
+        return FALSE;
+    }
+  }
 
+  /* Create directories */
 
   /*
-   * Build the file copy list
+   * FIXME:
+   * Install directories like '\reactos\test' are not handled yet.
    */
-  SetStatusText("   Building the file copy list...");
-//  SetInvertedTextXY(8, 12, "Build file copy list");
 
+  /* Get destination path */
+  wcscpy(PathBuffer, DestinationPath.Buffer);
 
+  /* Remove trailing backslash */
+  Length = wcslen(PathBuffer);
+  if ((Length > 0) && (PathBuffer[Length - 1] == '\\'))
+    {
+      PathBuffer[Length - 1] = 0;
+    }
 
-  /* Search for the 'SourceFiles' section */
-  if (!InfFindFirstLine (SetupInf, L"SourceFiles", NULL, &FilesContext))
+  /* Create the install directory */
+  Status = SetupCreateDirectory(PathBuffer);
+  if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
     {
-      PopupError("Setup failed to find the 'SourceFiles' section\n"
-                "in TXTSETUP.SIF.\n",
+      DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
+      PopupError("Setup could not create the install directory.",
                 "ENTER = Reboot computer");
 
       while(TRUE)
@@ -1023,18 +2825,25 @@ PrepareCopyPage(PINPUT_RECORD Ir)
 
          if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
            {
-             return(QUIT_PAGE);
+             return(FALSE);
            }
        }
     }
 
 
-  /* Create the file queue */
-  SetupFileQueue = SetupOpenFileQueue();
-  if (SetupFileQueue == NULL)
+  /* Search for the 'Directories' section */
+  if (!InfFindFirstLine(InfFile, L"Directories", NULL, &DirContext))
     {
-      PopupError("Setup failed to open the copy file queue.\n",
-                "ENTER = Reboot computer");
+      if (SourceCabinet)
+       {
+         PopupError("Setup failed to find the 'Directories' section\n"
+                    "in the cabinet.\n", "ENTER = Reboot computer");
+       }
+      else
+       {
+         PopupError("Setup failed to find the 'Directories' section\n"
+                    "in TXTSETUP.SIF.\n", "ENTER = Reboot computer");
+        }
 
       while(TRUE)
        {
@@ -1042,75 +2851,86 @@ PrepareCopyPage(PINPUT_RECORD Ir)
 
          if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
            {
-             return(QUIT_PAGE);
+             return(FALSE);
            }
        }
     }
 
-  /*
-   * Enumerate the files in the 'SourceFiles' section
-   * and add them to the file queue.
-   */
+  /* Enumerate the directory values and create the subdirectories */
   do
     {
-      if (!InfGetData (&FilesContext, &FileKeyName, &FileKeyValue))
-       break;
-
-      DPRINT1("FileKeyName: '%S'  FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
-
-      /* Lookup target directory */
-      if (!InfFindFirstLine (SetupInf, L"Directories", FileKeyValue, &DirContext))
+      if (!InfGetData (DirContext, NULL, &KeyValue))
        {
-         /* FIXME: Handle error! */
-         DPRINT1("InfFindFirstLine() failed\n");
+         DPRINT1("break\n");
          break;
        }
 
-      if (!InfGetData (&DirContext, NULL, &DirKeyValue))
+      if (KeyValue[0] == L'\\' && KeyValue[1] != 0)
        {
-         /* FIXME: Handle error! */
-         DPRINT1("InfGetData() failed\n");
-         break;
-       }
+         DPRINT("Absolute Path: '%S'\n", KeyValue);
 
-      if (!SetupQueueCopy(SetupFileQueue,
-                         SourceRootPath.Buffer,
-                         L"\\install",
-                         FileKeyName,
-                         DirKeyValue,
-                         NULL))
+         wcscpy(PathBuffer, DestinationRootPath.Buffer);
+         wcscat(PathBuffer, KeyValue);
+
+         DPRINT("FullPath: '%S'\n", PathBuffer);
+       }
+      else if (KeyValue[0] != L'\\')
        {
-         /* FIXME: Handle error! */
-         DPRINT1("SetupQueueCopy() failed\n");
+         DPRINT("RelativePath: '%S'\n", KeyValue);
+         wcscpy(PathBuffer, DestinationPath.Buffer);
+         wcscat(PathBuffer, L"\\");
+         wcscat(PathBuffer, KeyValue);
+
+         DPRINT("FullPath: '%S'\n", PathBuffer);
+
+         Status = SetupCreateDirectory(PathBuffer);
+         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
+           {
+             DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
+             PopupError("Setup could not create install directories.",
+                        "ENTER = Reboot computer");
+
+             while (TRUE)
+               {
+                 ConInKey(Ir);
+
+                 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+                   {
+                     return(FALSE);
+                   }
+               }
+           }
        }
     }
-  while (InfFindNextLine(&FilesContext, &FilesContext));
+  while (InfFindNextLine (DirContext, DirContext));
 
+  InfFreeContext(DirContext);
 
-  /* Create directories */
-  SetStatusText("   Creating directories...");
+  return(TRUE);
+}
 
-  /*
-   * FIXME:
-   * Install directories like '\reactos\test' are not handled yet.
-   */
 
-  /* Get destination path */
-  wcscpy(PathBuffer, DestinationPath.Buffer);
+static PAGE_NUMBER
+PrepareCopyPage(PINPUT_RECORD Ir)
+{
+  HINF InfHandle;
+  WCHAR PathBuffer[MAX_PATH];
+  PINFCONTEXT CabinetsContext;
+  ULONG InfFileSize;
+  PWCHAR KeyValue;
+  NTSTATUS Status;
+  ULONG ErrorLine;
+  PVOID InfFileData;
 
-  /* Remove trailing backslash */
-  Length = wcslen(PathBuffer);
-  if ((Length > 0) && (PathBuffer[Length - 1] == '\\'))
-    {
-      PathBuffer[Length - 1] = 0;
-    }
+  SetTextXY(6, 8, "Setup prepares your computer for copying the ReactOS files. ");
 
-  /* Create the install directory */
-  Status = CreateDirectory(PathBuffer);
-  if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
+  SetStatusText("   Building the file copy list...");
+
+  /* Create the file queue */
+  SetupFileQueue = SetupOpenFileQueue();
+  if (SetupFileQueue == NULL)
     {
-      DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
-      PopupError("Setup could not create the install directory.",
+      PopupError("Setup failed to open the copy file queue.\n",
                 "ENTER = Reboot computer");
 
       while(TRUE)
@@ -1124,71 +2944,105 @@ PrepareCopyPage(PINPUT_RECORD Ir)
        }
     }
 
-
-  /* Search for the 'Directories' section */
-  if (!InfFindFirstLine(SetupInf, L"Directories", NULL, &DirContext))
+  if (!PrepareCopyPageInfFile(SetupInf, NULL, Ir))
     {
-      PopupError("Setup failed to find the 'Directories' section\n"
-                "in TXTSETUP.SIF.\n",
-                "ENTER = Reboot computer");
-
-      while(TRUE)
-       {
-         ConInKey(Ir);
+      return QUIT_PAGE;
+    }
 
-         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
-           {
-             return(QUIT_PAGE);
-           }
-       }
+  /* Search for the 'Cabinets' section */
+  if (!InfFindFirstLine (SetupInf, L"Cabinets", NULL, &CabinetsContext))
+    {
+      return FILE_COPY_PAGE;
     }
 
-  /* Enumerate the directory values and create the subdirectories */
+  /*
+   * Enumerate the directory values in the 'Cabinets'
+   * section and parse their inf files.
+   */
   do
     {
-      if (!InfGetData (&DirContext, NULL, &KeyValue))
+      if (!InfGetData (CabinetsContext, NULL, &KeyValue))
        break;
 
-      if (KeyValue[0] == L'\\' && KeyValue[1] != 0)
-       {
-             DPRINT("Absolute Path: '%S'\n", KeyValue);
+      wcscpy(PathBuffer, SourcePath.Buffer);
+      wcscat(PathBuffer, L"\\");
+      wcscat(PathBuffer, KeyValue);
 
-             wcscpy(PathBuffer, DestinationRootPath.Buffer);
-             wcscat(PathBuffer, KeyValue);
+      CabinetInitialize();
+      CabinetSetEventHandlers(NULL, NULL, NULL);
+      CabinetSetCabinetName(PathBuffer);
 
-             DPRINT("FullPath: '%S'\n", PathBuffer);
-       }
-      else if (KeyValue[0] != L'\\')
+      if (CabinetOpen() == CAB_STATUS_SUCCESS)
        {
-         DPRINT("RelativePath: '%S'\n", KeyValue);
-         wcscpy(PathBuffer, DestinationPath.Buffer);
-         wcscat(PathBuffer, L"\\");
-         wcscat(PathBuffer, KeyValue);
-
-         DPRINT("FullPath: '%S'\n", PathBuffer);
+         DPRINT("Cabinet %S\n", CabinetGetCabinetName());
 
-         Status = CreateDirectory(PathBuffer);
-         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
+         InfFileData = CabinetGetCabinetReservedArea(&InfFileSize);
+         if (InfFileData == NULL)
            {
-             DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
-             PopupError("Setup could not create install directories.",
+             PopupError("Cabinet has no setup script.\n",
                         "ENTER = Reboot computer");
 
-             while (TRUE)
+             while(TRUE)
                {
                  ConInKey(Ir);
 
                  if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
                    {
-                     return(QUIT_PAGE);
+                     return QUIT_PAGE;
                    }
                }
            }
        }
+      else
+       {
+         DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
+
+         PopupError("Cabinet not found.\n",
+                    "ENTER = Reboot computer");
+
+         while(TRUE)
+           {
+             ConInKey(Ir);
+
+             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
+               {
+                 return QUIT_PAGE;
+               }
+           }
+       }
+
+      Status = InfOpenBufferedFile(&InfHandle,
+                                  InfFileData,
+                                  InfFileSize,
+                                  &ErrorLine);
+      if (!NT_SUCCESS(Status))
+       {
+         PopupError("Cabinet has no valid inf file.\n",
+                    "ENTER = Reboot computer");
+
+         while(TRUE)
+           {
+             ConInKey(Ir);
+
+             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
+               {
+                 return QUIT_PAGE;
+               }
+           }
+       }
+
+      CabinetCleanup();
+
+      if (!PrepareCopyPageInfFile(InfHandle, KeyValue, Ir))
+        {
+          return QUIT_PAGE;
+        }
     }
-  while (InfFindNextLine (&DirContext, &DirContext));
+  while (InfFindNextLine (CabinetsContext, CabinetsContext));
 
-  return(FILE_COPY_PAGE);
+  InfFreeContext(CabinetsContext);
+
+  return FILE_COPY_PAGE;
 }
 
 
@@ -1212,11 +3066,7 @@ FileCopyCallback(PVOID Context,
 
       case SPFILENOTIFY_STARTCOPY:
        /* Display copy message */
-       PrintTextXYN(6, 16, 60, "Copying file: %S", (PWSTR)Param1);
-
-       PrintTextXYN(6, 18, 60, "File %lu of %lu",
-                    CopyContext->CompletedOperations + 1,
-                    CopyContext->TotalOperations);
+    SetStatusText("                                                   \xB3 Copying file: %S", (PWSTR)Param1);
        break;
 
       case SPFILENOTIFY_ENDCOPY:
@@ -1225,7 +3075,7 @@ FileCopyCallback(PVOID Context,
        break;
     }
 
-  return(0);
+  return 0;
 }
 
 
@@ -1236,18 +3086,20 @@ FileCopyPage(PINPUT_RECORD Ir)
   SHORT xScreen;
   SHORT yScreen;
 
-  SetStatusText("   Please wait...");
-
-  SetTextXY(6, 8, "Copying files");
+  SetStatusText("                                                           \xB3 Please wait...    ");
 
-  GetScreenSize(&xScreen, &yScreen);
+  SetTextXY(11, 12, "Please wait while ReactOS Setup copies files to your ReactOS");
+  SetTextXY(30, 13, "installation folder.");
+  SetTextXY(20, 14, "This may take several minutes to complete.");
 
+  GetScreenSize(&xScreen, &yScreen);  
   CopyContext.TotalOperations = 0;
   CopyContext.CompletedOperations = 0;
-  CopyContext.ProgressBar = CreateProgressBar(6,
-                                             yScreen - 14,
-                                             xScreen - 7,
-                                             yScreen - 10);
+  CopyContext.ProgressBar = CreateProgressBar(13,
+                                             26,
+                                             xScreen - 13,
+                                             yScreen - 20,
+                          "Setup is copying files...");
 
   SetupCommitFileQueue(SetupFileQueue,
                       DestinationRootPath.Buffer,
@@ -1259,21 +3111,19 @@ FileCopyPage(PINPUT_RECORD Ir)
 
   DestroyProgressBar(CopyContext.ProgressBar);
 
-  return(REGISTRY_PAGE);
+  return REGISTRY_PAGE;
 }
 
 
 static PAGE_NUMBER
 RegistryPage(PINPUT_RECORD Ir)
 {
-  INFCONTEXT InfContext;
-  NTSTATUS Status;
-
+  PINFCONTEXT InfContext;
   PWSTR Action;
   PWSTR File;
   PWSTR Section;
   BOOLEAN Delete;
-
+  NTSTATUS Status;
 
   SetTextXY(6, 8, "Setup is updating the system configuration");
 
@@ -1291,7 +3141,7 @@ RegistryPage(PINPUT_RECORD Ir)
 
          if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
            {
-             return(QUIT_PAGE);
+             return QUIT_PAGE;
            }
        }
     }
@@ -1310,7 +3160,7 @@ RegistryPage(PINPUT_RECORD Ir)
 
          if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
            {
-             return(QUIT_PAGE);
+             return QUIT_PAGE;
            }
        }
     }
@@ -1330,18 +3180,18 @@ RegistryPage(PINPUT_RECORD Ir)
 
          if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
            {
-             return(QUIT_PAGE);
+             return QUIT_PAGE;
            }
        }
     }
 
   do
     {
-      InfGetDataField (&InfContext, 0, &Action);
-      InfGetDataField (&InfContext, 1, &File);
-      InfGetDataField (&InfContext, 2, &Section);
+      InfGetDataField (InfContext, 0, &Action);
+      InfGetDataField (InfContext, 1, &File);
+      InfGetDataField (InfContext, 2, &Section);
 
-      DPRINT1("Action: %S  File: %S  Section %S\n", Action, File, Section);
+      DPRINT("Action: %S  File: %S  Section %S\n", Action, File, Section);
 
       if (!_wcsicmp (Action, L"AddReg"))
        {
@@ -1360,7 +3210,7 @@ RegistryPage(PINPUT_RECORD Ir)
 
       if (!ImportRegistryFile(File, Section, Delete))
        {
-         DPRINT1("Importing %S failed\n", File);
+         DPRINT("Importing %S failed\n", File);
 
          PopupError("Setup failed to import a hive file.",
                     "ENTER = Reboot computer");
@@ -1371,108 +3221,20 @@ RegistryPage(PINPUT_RECORD Ir)
 
              if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
                {
-                 return(QUIT_PAGE);
+                 return QUIT_PAGE;
                }
            }
        }
     }
-  while (InfFindNextLine (&InfContext, &InfContext));
-
-  SetStatusText("   Done...");
-
-  return(BOOT_LOADER_PAGE);
-}
-
-
-static PAGE_NUMBER
-BootLoaderPage(PINPUT_RECORD Ir)
-{
-  WCHAR SrcPath[MAX_PATH];
-  WCHAR DstPath[MAX_PATH];
-  PINICACHE IniCache;
-  PINICACHESECTION IniSection;
-  NTSTATUS Status;
-
-  SetTextXY(6, 8, "Installing the boot loader");
-
-  SetStatusText("   Please wait...");
-
-  if (ActivePartitionValid == FALSE)
-    {
-      DPRINT1("Error: no active partition found\n");
-      PopupError("Setup could not find an active partiton\n",
-                "ENTER = Reboot computer");
-
-      while(TRUE)
-       {
-         ConInKey(Ir);
-
-         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
-           {
-             return(QUIT_PAGE);
-           }
-       }
-    }
-
-  if (ActivePartition.PartType == PARTITION_ENTRY_UNUSED)
-    {
-      DPRINT1("Error: active partition invalid (unused)\n");
-      PopupError("The active partition is unused (invalid).\n",
-                "ENTER = Reboot computer");
-
-      while(TRUE)
-       {
-         ConInKey(Ir);
-
-         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
-           {
-             return(QUIT_PAGE);
-           }
-       }
-    }
-
-  if (ActivePartition.PartType == 0x0A)
-    {
-      /* OS/2 boot manager partition */
-      DPRINT1("Found OS/2 boot manager partition\n");
-      PopupError("Setup found an OS/2 boot manager partiton.\n"
-                "The OS/2 boot manager is not supported yet!",
-                "ENTER = Reboot computer");
-
-      while(TRUE)
-       {
-         ConInKey(Ir);
-
-         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
-           {
-             return(QUIT_PAGE);
-           }
-       }
-    }
-  else if (ActivePartition.PartType == 0x83)
-    {
-      /* Linux ext2 partition */
-      DPRINT1("Found Linux ext2 partition\n");
-      PopupError("Setup found a Linux ext2 partiton.\n"
-                "Linux ext2 partitions are not supported yet!",
-                "ENTER = Reboot computer");
+  while (InfFindNextLine (InfContext, InfContext));
 
-      while(TRUE)
-       {
-         ConInKey(Ir);
+  InfFreeContext(InfContext);
 
-         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
-           {
-             return(QUIT_PAGE);
-           }
-       }
-    }
-  else if (ActivePartition.PartType == PARTITION_IFS)
+  /* Update display registry settings */
+  SetStatusText("   Updating display registry settings...");
+  if (!ProcessDisplayRegistry(SetupInf, DisplayList))
     {
-      /* NTFS partition */
-      DPRINT1("Found NTFS partition\n");
-      PopupError("Setup found an NTFS partiton.\n"
-                "NTFS partitions are not supported yet!",
+      PopupError("Setup failed to update display registry settings.",
                 "ENTER = Reboot computer");
 
       while(TRUE)
@@ -1481,521 +3243,261 @@ BootLoaderPage(PINPUT_RECORD Ir)
 
          if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
            {
-             return(QUIT_PAGE);
-           }
-       }
-    }
-  else if ((ActivePartition.PartType == PARTITION_FAT_12) ||
-          (ActivePartition.PartType == PARTITION_FAT_16) ||
-          (ActivePartition.PartType == PARTITION_HUGE) ||
-          (ActivePartition.PartType == PARTITION_XINT13) ||
-          (ActivePartition.PartType == PARTITION_FAT32) ||
-          (ActivePartition.PartType == PARTITION_FAT32_XINT13))
-  {
-    /* FAT or FAT32 partition */
-    DPRINT1("System path: '%wZ'\n", &SystemRootPath);
-
-    if (DoesFileExist(SystemRootPath.Buffer, L"ntldr") == TRUE ||
-       DoesFileExist(SystemRootPath.Buffer, L"boot.ini") == TRUE)
-    {
-      /* Search root directory for 'ntldr' and 'boot.ini'. */
-      DPRINT1("Found Microsoft Windows NT/2000/XP boot loader\n");
-
-      /* Copy FreeLoader to the boot partition */
-      wcscpy(SrcPath, SourceRootPath.Buffer);
-      wcscat(SrcPath, L"\\loader\\freeldr.sys");
-      wcscpy(DstPath, SystemRootPath.Buffer);
-      wcscat(DstPath, L"\\freeldr.sys");
-
-      DPRINT1("Copy: %S ==> %S\n", SrcPath, DstPath);
-      Status = SetupCopyFile(SrcPath, DstPath);
-      if (!NT_SUCCESS(Status))
-      {
-       DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
-       PopupError("Setup failed to copy 'freeldr.sys'.",
-                  "ENTER = Reboot computer");
-
-       while(TRUE)
-       {
-         ConInKey(Ir);
-
-         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
-         {
-           return(QUIT_PAGE);
-         }
-       }
-      }
-
-      /* Create or update freeldr.ini */
-      if (DoesFileExist(SystemRootPath.Buffer, L"freeldr.ini") == FALSE)
-      {
-       /* Create new 'freeldr.ini' */
-       DPRINT1("Create new 'freeldr.ini'\n");
-       wcscpy(DstPath, SystemRootPath.Buffer);
-       wcscat(DstPath, L"\\freeldr.ini");
-
-       Status = CreateFreeLoaderIniForReactos(DstPath,
-                                              DestinationArcPath.Buffer);
-       if (!NT_SUCCESS(Status))
-       {
-         DPRINT1("CreateFreeLoaderIniForReactos() failed (Status %lx)\n", Status);
-         PopupError("Setup failed to create 'freeldr.ini'.",
-                    "ENTER = Reboot computer");
-
-         while(TRUE)
-         {
-           ConInKey(Ir);
-
-           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
-           {
-             return(QUIT_PAGE);
-           }
-         }
-       }
-
-       /* Install new bootcode */
-       if ((ActivePartition.PartType == PARTITION_FAT32) ||
-           (ActivePartition.PartType == PARTITION_FAT32_XINT13))
-       {
-         /* Install FAT32 bootcode */
-         wcscpy(SrcPath, SourceRootPath.Buffer);
-         wcscat(SrcPath, L"\\loader\\fat32.bin");
-         wcscpy(DstPath, SystemRootPath.Buffer);
-         wcscat(DstPath, L"\\bootsect.ros");
-
-         DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, DstPath);
-         Status = InstallFat32BootCodeToFile(SrcPath,
-                                             DstPath,
-                                             SystemRootPath.Buffer);
-         if (!NT_SUCCESS(Status))
-         {
-           DPRINT1("InstallFat32BootCodeToFile() failed (Status %lx)\n", Status);
-           PopupError("Setup failed to install the FAT32 bootcode.",
-                      "ENTER = Reboot computer");
-
-           while(TRUE)
-           {
-             ConInKey(Ir);
-
-             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
-             {
-               return(QUIT_PAGE);
-             }
-           }
-         }
-       }
-       else
-       {
-         /* Install FAT16 bootcode */
-         wcscpy(SrcPath, SourceRootPath.Buffer);
-         wcscat(SrcPath, L"\\loader\\fat.bin");
-         wcscpy(DstPath, SystemRootPath.Buffer);
-         wcscat(DstPath, L"\\bootsect.ros");
-
-         DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, DstPath);
-         Status = InstallFat16BootCodeToFile(SrcPath,
-                                             DstPath,
-                                             SystemRootPath.Buffer);
-         if (!NT_SUCCESS(Status))
-         {
-           DPRINT1("InstallFat16BootCodeToFile() failed (Status %lx)\n", Status);
-           PopupError("Setup failed to install the FAT bootcode.",
-                      "ENTER = Reboot computer");
-
-           while(TRUE)
-           {
-             ConInKey(Ir);
-
-             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
-             {
-               return(QUIT_PAGE);
-             }
-           }
-         }
-       }
-
-       /* Update 'boot.ini' */
-       wcscpy(DstPath, SystemRootPath.Buffer);
-       wcscat(DstPath, L"\\boot.ini");
-
-       DPRINT1("Update 'boot.ini': %S\n", DstPath);
-       Status = UpdateBootIni(DstPath,
-                              L"C:\\bootsect.ros",
-                              L"\"ReactOS\"");
-       if (!NT_SUCCESS(Status))
-       {
-         DPRINT1("UpdateBootIni() failed (Status %lx)\n", Status);
-         PopupError("Setup failed to update \'boot.ini\'.",
-                    "ENTER = Reboot computer");
-
-         while(TRUE)
-         {
-           ConInKey(Ir);
-
-           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
-           {
-             return(QUIT_PAGE);
-           }
-         }
-       }
-      }
-      else
-      {
-       /* Update existing 'freeldr.ini' */
-       DPRINT1("Update existing 'freeldr.ini'\n");
-       wcscpy(DstPath, SystemRootPath.Buffer);
-       wcscat(DstPath, L"\\freeldr.ini");
-
-       Status = UpdateFreeLoaderIni(DstPath,
-                                    DestinationArcPath.Buffer);
-       if (!NT_SUCCESS(Status))
-       {
-         DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
-         PopupError("Setup failed to update 'freeldr.ini'.",
-                    "ENTER = Reboot computer");
-
-         while(TRUE)
-         {
-           ConInKey(Ir);
-
-           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
-           {
-             return(QUIT_PAGE);
+             return QUIT_PAGE;
            }
-         }
        }
-      }
     }
-    else if (DoesFileExist(SystemRootPath.Buffer, L"io.sys") == TRUE ||
-            DoesFileExist(SystemRootPath.Buffer, L"msdos.sys") == TRUE)
-    {
-      /* Search for root directory for 'io.sys' and 'msdos.sys'. */
-      DPRINT1("Found Microsoft DOS or Windows 9x boot loader\n");
-
-      /* Copy FreeLoader to the boot partition */
-      wcscpy(SrcPath, SourceRootPath.Buffer);
-      wcscat(SrcPath, L"\\loader\\freeldr.sys");
-      wcscpy(DstPath, SystemRootPath.Buffer);
-      wcscat(DstPath, L"\\freeldr.sys");
 
-      DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
-      Status = SetupCopyFile(SrcPath, DstPath);
-      if (!NT_SUCCESS(Status))
-      {
-       DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
-       PopupError("Setup failed to copy 'freeldr.sys'.",
-                  "ENTER = Reboot computer");
+  /* Update keyboard layout settings */
+  SetStatusText("   Updating keyboard layout settings...");
+  if (!ProcessKeyboardLayoutRegistry(LayoutList))
+    {
+      PopupError("Setup failed to update keyboard layout settings.",
+                "ENTER = Reboot computer");
 
-       while(TRUE)
+      while(TRUE)
        {
          ConInKey(Ir);
 
          if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
-         {
-           return(QUIT_PAGE);
-         }
+           {
+             return QUIT_PAGE;
+           }
        }
-      }
+    }
 
-      /* Create or update 'freeldr.ini' */
-      if (DoesFileExist(SystemRootPath.Buffer, L"freeldr.ini") == FALSE)
-      {
-       /* Create new 'freeldr.ini' */
-       DPRINT1("Create new 'freeldr.ini'\n");
-       wcscpy(DstPath, SystemRootPath.Buffer);
-       wcscat(DstPath, L"\\freeldr.ini");
+  /* Update the mounted devices list */
+  SetMountedDeviceValues(PartitionList);
 
-       Status = CreateFreeLoaderIniForDos(DstPath,
-                                          DestinationArcPath.Buffer);
-       if (!NT_SUCCESS(Status))
-       {
-         DPRINT1("CreateFreeLoaderIniForDos() failed (Status %lx)\n", Status);
-         PopupError("Setup failed to create 'freeldr.ini'.",
-                    "ENTER = Reboot computer");
+  SetStatusText("   Done...");
 
-         while(TRUE)
-         {
-           ConInKey(Ir);
+  return BOOT_LOADER_PAGE;
+}
 
-           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
-           {
-             return(QUIT_PAGE);
-           }
-         }
-       }
 
-       /* Save current bootsector as 'BOOTSECT.DOS' */
-       wcscpy(SrcPath, SystemRootPath.Buffer);
-       wcscpy(DstPath, SystemRootPath.Buffer);
-       wcscat(DstPath, L"\\bootsect.dos");
+static PAGE_NUMBER
+BootLoaderPage(PINPUT_RECORD Ir)
+{
+  UCHAR PartitionType;
+  BOOLEAN InstallOnFloppy;
+  USHORT Line = 12;
 
-       DPRINT1("Save bootsector: %S ==> %S\n", SrcPath, DstPath);
-       Status = SaveCurrentBootSector(SrcPath,
-                                      DstPath);
-       if (!NT_SUCCESS(Status))
-       {
-         DPRINT1("SaveCurrentBootSector() failed (Status %lx)\n", Status);
-         PopupError("Setup failed to save the current bootsector.",
-                    "ENTER = Reboot computer");
+  SetStatusText("   Please wait...");
 
-         while(TRUE)
-         {
-           ConInKey(Ir);
+  PartitionType = PartitionList->ActiveBootPartition->PartInfo[0].PartitionType;
 
-           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
-           {
-             return(QUIT_PAGE);
-           }
-         }
-       }
+  if (PartitionType == PARTITION_ENTRY_UNUSED)
+    {
+      DPRINT("Error: active partition invalid (unused)\n");
+      InstallOnFloppy = TRUE;
+    }
+  else if (PartitionType == 0x0A)
+    {
+      /* OS/2 boot manager partition */
+      DPRINT("Found OS/2 boot manager partition\n");
+      InstallOnFloppy = TRUE;
+    }
+  else if (PartitionType == 0x83)
+    {
+      /* Linux ext2 partition */
+      DPRINT("Found Linux ext2 partition\n");
+      InstallOnFloppy = TRUE;
+    }
+  else if (PartitionType == PARTITION_IFS)
+    {
+      /* NTFS partition */
+      DPRINT("Found NTFS partition\n");
+      InstallOnFloppy = TRUE;
+    }
+  else if ((PartitionType == PARTITION_FAT_12) ||
+          (PartitionType == PARTITION_FAT_16) ||
+          (PartitionType == PARTITION_HUGE) ||
+          (PartitionType == PARTITION_XINT13) ||
+          (PartitionType == PARTITION_FAT32) ||
+          (PartitionType == PARTITION_FAT32_XINT13))
+    {
+      DPRINT("Found FAT partition\n");
+      InstallOnFloppy = FALSE;
+    }
+  else
+    {
+      /* Unknown partition */
+      DPRINT("Unknown partition found\n");
+      InstallOnFloppy = TRUE;
+    }
 
-       /* Install new bootsector */
-       if ((ActivePartition.PartType == PARTITION_FAT32) ||
-           (ActivePartition.PartType == PARTITION_FAT32_XINT13))
-       {
-         wcscpy(SrcPath, SourceRootPath.Buffer);
-         wcscat(SrcPath, L"\\loader\\fat32.bin");
+  if (InstallOnFloppy == TRUE)
+    {
+      return BOOT_LOADER_FLOPPY_PAGE;
+    }
 
-         DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath.Buffer);
-         Status = InstallFat32BootCodeToDisk(SrcPath,
-                                             SystemRootPath.Buffer);
-         if (!NT_SUCCESS(Status))
-         {
-           DPRINT1("InstallFat32BootCodeToDisk() failed (Status %lx)\n", Status);
-           PopupError("Setup failed to install the FAT32 bootcode.",
-                      "ENTER = Reboot computer");
+  SetTextXY(6, 8, "Setup is installing the boot loader");
 
-           while(TRUE)
-           {
-             ConInKey(Ir);
+  SetTextXY(8, 12, "Install bootloader on the harddisk (MBR).");
+  SetTextXY(8, 13, "Install bootloader on a floppy disk.");
+  SetTextXY(8, 14, "Skip install bootloader.");
+  InvertTextXY (8, Line, 48, 1);
 
-             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
-             {
-               return(QUIT_PAGE);
-             }
-           }
-         }
-       }
-       else
-       {
-         wcscpy(SrcPath, SourceRootPath.Buffer);
-         wcscat(SrcPath, L"\\loader\\fat.bin");
+  SetStatusText("   ENTER = Continue   F3 = Quit");
 
-         DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, SystemRootPath.Buffer);
-         Status = InstallFat16BootCodeToDisk(SrcPath,
-                                             SystemRootPath.Buffer);
-         if (!NT_SUCCESS(Status))
-         {
-           DPRINT1("InstallFat16BootCodeToDisk() failed (Status %lx)\n", Status);
-           PopupError("Setup failed to install the FAT bootcode.",
-                      "ENTER = Reboot computer");
+  while(TRUE)
+    {
+      ConInKey(Ir);
 
-           while(TRUE)
-           {
-             ConInKey(Ir);
+      if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
+       {
+         NormalTextXY (8, Line, 48, 1);
+         
+         Line++;
+      if (Line<12) Line=14;
+      if (Line>14) Line=12;
+        
+       
 
-             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
-             {
-               return(QUIT_PAGE);
-             }
-           }
-         }
+         InvertTextXY (8, Line, 48, 1);
        }
-      }
-      else
-      {
-       /* Update existing 'freeldr.ini' */
-       wcscpy(DstPath, SystemRootPath.Buffer);
-       wcscat(DstPath, L"\\freeldr.ini");
-
-       Status = UpdateFreeLoaderIni(DstPath,
-                                    DestinationArcPath.Buffer);
-       if (!NT_SUCCESS(Status))
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
        {
-         DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
-         PopupError("Setup failed to update 'freeldr.ini'.",
-                    "ENTER = Reboot computer");
+         NormalTextXY (8, Line, 48, 1);
+         
+         Line--;
+      if (Line<12) Line=14;
+      if (Line>14) Line=12;
 
-         while(TRUE)
-         {
-           ConInKey(Ir);
 
-           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
+         InvertTextXY (8, Line, 48, 1);
+       }
+      else 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 */
+       {
+         if (Line == 12)
            {
-             return(QUIT_PAGE);
+             return BOOT_LOADER_HARDDISK_PAGE;
+           }
+         else if (Line == 13)
+           {
+             return BOOT_LOADER_FLOPPY_PAGE;
            }
-         }
+      else if (Line == 14)
+           {
+              return SUCCESS_PAGE;;
+           }
+
+         return BOOT_LOADER_PAGE;
        }
-      }
-    }
-    else
-    {
-      /* No or unknown boot loader */
-      DPRINT1("No or unknown boot loader found\n");
 
-      /* Copy FreeLoader to the boot partition */
-      wcscpy(SrcPath, SourceRootPath.Buffer);
-      wcscat(SrcPath, L"\\loader\\freeldr.sys");
-      wcscpy(DstPath, SystemRootPath.Buffer);
-      wcscat(DstPath, L"\\freeldr.sys");
+    }
 
-      DPRINT1("Copy: %S ==> %S\n", SrcPath, DstPath);
-      Status = SetupCopyFile(SrcPath, DstPath);
-      if (!NT_SUCCESS(Status))
-      {
-       DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
-       PopupError("Setup failed to copy 'freeldr.sys'.",
-                  "ENTER = Reboot computer");
+  return BOOT_LOADER_PAGE;
+}
 
-       while(TRUE)
-       {
-         ConInKey(Ir);
 
-         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
-         {
-           return(QUIT_PAGE);
-         }
-       }
-      }
+static PAGE_NUMBER
+BootLoaderFloppyPage(PINPUT_RECORD Ir)
+{
+  NTSTATUS Status;
 
-      /* Create or update 'freeldr.ini' */
-      if (DoesFileExist(SystemRootPath.Buffer, L"freeldr.ini") == FALSE)
-      {
-       /* Create new freeldr.ini */
-       wcscpy(DstPath, SystemRootPath.Buffer);
-       wcscat(DstPath, L"\\freeldr.ini");
+  SetTextXY(6, 8, "Setup cannot install the bootloader on your computers");
+  SetTextXY(6, 9, "harddisk");
 
-       DPRINT1("Copy: %S ==> %S\n", SrcPath, DstPath);
-       Status = CreateFreeLoaderIniForReactos(DstPath,
-                                              DestinationArcPath.Buffer);
-       if (!NT_SUCCESS(Status))
-       {
-         DPRINT1("CreateFreeLoaderIniForReactos() failed (Status %lx)\n", Status);
-         PopupError("Setup failed to create \'freeldr.ini\'.",
-                    "ENTER = Reboot computer");
+  SetTextXY(6, 13, "Please insert a formatted floppy disk in drive A: and");
+  SetTextXY(6, 14, "press ENTER.");
 
-         while(TRUE)
-         {
-           ConInKey(Ir);
 
-           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
-           {
-             return(QUIT_PAGE);
-           }
-         }
-       }
+  SetStatusText("   ENTER = Continue   F3 = Quit");
+//  SetStatusText("   Please wait...");
 
-       /* Save current bootsector as 'BOOTSECT.OLD' */
-       wcscpy(SrcPath, SystemRootPath.Buffer);
-       wcscpy(DstPath, SystemRootPath.Buffer);
-       wcscat(DstPath, L"\\bootsect.old");
+  while(TRUE)
+    {
+      ConInKey(Ir);
 
-       DPRINT1("Save bootsector: %S ==> %S\n", SrcPath, DstPath);
-       Status = SaveCurrentBootSector(SrcPath,
-                                      DstPath);
-       if (!NT_SUCCESS(Status))
+      if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
        {
-         DPRINT1("SaveCurrentBootSector() failed (Status %lx)\n", Status);
-         PopupError("Setup failed save the current bootsector.",
-                    "ENTER = Reboot computer");
+         if (ConfirmQuit(Ir) == TRUE)
+           return QUIT_PAGE;
+         break;
+       }
+      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
+       {
+         if (DoesFileExist(L"\\Device\\Floppy0", L"\\") == FALSE)
+           {
+             PopupError("No disk in drive A:.",
+                        "ENTER = Continue");
+             while(TRUE)
+               {
+                 ConInKey(Ir);
 
-         while(TRUE)
-         {
-           ConInKey(Ir);
+                 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+                   break;
+               }
 
-           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
-           {
-             return(QUIT_PAGE);
+             return BOOT_LOADER_FLOPPY_PAGE;
            }
-         }
-       }
-
-       /* Install new bootsector */
-       if ((ActivePartition.PartType == PARTITION_FAT32) ||
-           (ActivePartition.PartType == PARTITION_FAT32_XINT13))
-       {
-         wcscpy(SrcPath, SourceRootPath.Buffer);
-         wcscat(SrcPath, L"\\loader\\fat32.bin");
 
-         DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath.Buffer);
-         Status = InstallFat32BootCodeToDisk(SrcPath,
-                                             SystemRootPath.Buffer);
+         Status = InstallFatBootcodeToFloppy(&SourceRootPath,
+                                             &DestinationArcPath);
          if (!NT_SUCCESS(Status))
-         {
-           DPRINT1("InstallFat32BootCodeToDisk() failed (Status %lx)\n", Status);
-           PopupError("Setup failed to install the FAT32 bootcode.",
-                      "ENTER = Reboot computer");
-
-           while(TRUE)
            {
-             ConInKey(Ir);
-
-             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
-             {
-               return(QUIT_PAGE);
-             }
+             /* Print error message */
+             return BOOT_LOADER_FLOPPY_PAGE;
            }
-         }
+
+         return SUCCESS_PAGE;
        }
-       else
-       {
-         wcscpy(SrcPath, SourceRootPath.Buffer);
-         wcscat(SrcPath, L"\\loader\\fat.bin");
+    }
 
-         DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, SystemRootPath.Buffer);
-         Status = InstallFat16BootCodeToDisk(SrcPath,
-                                             SystemRootPath.Buffer);
-         if (!NT_SUCCESS(Status))
-         {
-           DPRINT1("InstallFat16BootCodeToDisk() failed (Status %lx)\n", Status);
-           PopupError("Setup failed to install the FAT bootcode.",
-                      "ENTER = Reboot computer");
+  return BOOT_LOADER_FLOPPY_PAGE;
+}
 
-           while(TRUE)
-           {
-             ConInKey(Ir);
 
-             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
-             {
-               return(QUIT_PAGE);
-             }
-           }
-         }
-       }
-      }
-      else
-      {
-       /* Update existing 'freeldr.ini' */
-       wcscpy(DstPath, SystemRootPath.Buffer);
-       wcscat(DstPath, L"\\freeldr.ini");
+static PAGE_NUMBER
+BootLoaderHarddiskPage(PINPUT_RECORD Ir)
+{
+  UCHAR PartitionType;
+  NTSTATUS Status;
 
-       Status = UpdateFreeLoaderIni(DstPath,
-                                    DestinationArcPath.Buffer);
-       if (!NT_SUCCESS(Status))
+  PartitionType = PartitionList->ActiveBootPartition->PartInfo[0].PartitionType;
+  if ((PartitionType == PARTITION_FAT_12) ||
+      (PartitionType == PARTITION_FAT_16) ||
+      (PartitionType == PARTITION_HUGE) ||
+      (PartitionType == PARTITION_XINT13) ||
+      (PartitionType == PARTITION_FAT32) ||
+      (PartitionType == PARTITION_FAT32_XINT13))
+    {
+      Status = InstallFatBootcodeToPartition(&SystemRootPath,
+                                            &SourceRootPath,
+                                            &DestinationArcPath,
+                                            PartitionType);
+      if (!NT_SUCCESS(Status))
        {
-         DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
-         PopupError("Setup failed to update 'freeldr.ini'.",
+         PopupError("Setup failed to install the FAT bootcode on the system partition.",
                     "ENTER = Reboot computer");
 
          while(TRUE)
-         {
-           ConInKey(Ir);
-
-           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
            {
-             return(QUIT_PAGE);
+             ConInKey(Ir);
+
+             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
+               {
+                 return QUIT_PAGE;
+               }
            }
-         }
        }
-      }
+
+      return SUCCESS_PAGE;
     }
-  }
   else
     {
-      /* Unknown partition */
-      DPRINT1("Unknown partition found\n");
-      PopupError("Setup found an unknown partiton type.\n"
-                "This partition type is not supported!",
+      PopupError("failed to install FAT bootcode on the system partition.",
                 "ENTER = Reboot computer");
 
       while(TRUE)
@@ -2004,16 +3506,15 @@ BootLoaderPage(PINPUT_RECORD Ir)
 
          if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
            {
-             return(QUIT_PAGE);
+             return QUIT_PAGE;
            }
        }
     }
 
-  return(SUCCESS_PAGE);
+  return BOOT_LOADER_HARDDISK_PAGE;
 }
 
 
-
 static PAGE_NUMBER
 QuitPage(PINPUT_RECORD Ir)
 {
@@ -2024,6 +3525,50 @@ QuitPage(PINPUT_RECORD Ir)
 
   SetTextXY(10, 11, "Press ENTER to reboot your computer.");
 
+  SetStatusText("   Please wait ...");
+
+  /* Destroy partition list */
+  if (PartitionList != NULL)
+    {
+      DestroyPartitionList (PartitionList);
+      PartitionList = NULL;
+    }
+
+  /* Destroy filesystem list */
+  if (FileSystemList != NULL)
+    {
+      DestroyFileSystemList (FileSystemList);
+      FileSystemList = NULL;
+    }
+
+  /* Destroy computer settings list */
+  if (ComputerList != NULL)
+    {
+      DestroyGenericList(ComputerList, TRUE);
+      ComputerList = NULL;
+    }
+
+  /* Destroy display settings list */
+  if (DisplayList != NULL)
+    {
+      DestroyGenericList(DisplayList, TRUE);
+      DisplayList = NULL;
+    }
+
+  /* Destroy keyboard settings list */
+  if (KeyboardList != NULL)
+    {
+      DestroyGenericList(KeyboardList, TRUE);
+      KeyboardList = NULL;
+    }
+
+  /* Destroy keyboard layout list */
+  if (LayoutList != NULL)
+    {
+      DestroyGenericList(LayoutList, TRUE);
+      LayoutList = NULL;
+    }
+
   SetStatusText("   ENTER = Reboot computer");
 
   while(TRUE)
@@ -2032,7 +3577,7 @@ QuitPage(PINPUT_RECORD Ir)
 
       if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
        {
-         return(REBOOT_PAGE);
+         return FLUSH_PAGE;
        }
     }
 }
@@ -2050,18 +3595,73 @@ SuccessPage(PINPUT_RECORD Ir)
 
   SetStatusText("   ENTER = Reboot computer");
 
+  if (IsUnattendedSetup)
+    {
+      return FLUSH_PAGE;
+    }
+
   while(TRUE)
     {
       ConInKey(Ir);
 
       if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
        {
-         return(REBOOT_PAGE);
+         return FLUSH_PAGE;
        }
     }
 }
 
 
+static PAGE_NUMBER
+FlushPage(PINPUT_RECORD Ir)
+{
+  SetTextXY(10, 6, "The system is now making sure all data is stored on your disk");
+
+  SetTextXY(10, 8, "This may take a minute");
+  SetTextXY(10, 9, "When finished, your computer will reboot automatically");
+
+  SetStatusText("   Flushing cache");
+
+  return REBOOT_PAGE;
+}
+
+
+static VOID
+SignalInitEvent()
+{
+  NTSTATUS Status;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  UNICODE_STRING UnicodeString = RTL_CONSTANT_STRING(L"\\ReactOSInitDone");
+  HANDLE ReactOSInitEvent;
+
+  InitializeObjectAttributes(&ObjectAttributes,
+    &UnicodeString,
+    0,
+    0,
+    NULL);
+  Status = NtOpenEvent(&ReactOSInitEvent,
+    EVENT_ALL_ACCESS,
+    &ObjectAttributes);
+  if (NT_SUCCESS(Status))
+    {
+      LARGE_INTEGER Timeout;
+      /* This will cause the boot screen image to go away (if displayed) */
+      NtPulseEvent(ReactOSInitEvent, NULL);
+
+      /* Wait for the display mode to be changed (if in graphics mode) */
+      Timeout.QuadPart = -50000000LL;  /* 5 second timeout */
+      NtWaitForSingleObject(ReactOSInitEvent, FALSE, &Timeout);
+
+      NtClose(ReactOSInitEvent);
+    }
+  else
+    {
+      /* We don't really care if this fails */
+      DPRINT1("USETUP: Failed to open ReactOS init notification event\n");
+    }
+}
+
+
 VOID STDCALL
 NtProcessStartup(PPEB Peb)
 {
@@ -2072,18 +3672,22 @@ NtProcessStartup(PPEB Peb)
   RtlNormalizeProcessParams(Peb->ProcessParameters);
 
   ProcessHeap = Peb->ProcessHeap;
+  InfSetHeap(ProcessHeap);
+
+  SignalInitEvent();
 
   Status = AllocConsole();
   if (!NT_SUCCESS(Status))
     {
-      PrintString("AllocConsole() failed (Status = 0x%08lx)\n", Status);
+      PrintString("Unable to open the console (Status = 0x%08lx)\n\n", Status);
+      PrintString("The most common cause of this is using an USB keyboard\n");
+      PrintString("USB keyboards are not fully supported yet\n");
 
       /* Raise a hard error (crash the system/BSOD) */
       NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
                       0,0,0,0,0);
     }
 
-  PartDataValid = FALSE;
 
   /* Initialize global unicode strings */
   RtlInitUnicodeString(&SourcePath, NULL);
@@ -2094,6 +3698,8 @@ NtProcessStartup(PPEB Peb)
   RtlInitUnicodeString(&DestinationRootPath, NULL);
   RtlInitUnicodeString(&SystemRootPath, NULL);
 
+  /* Hide the cursor */
+  SetCursorType(TRUE, FALSE);
 
   Page = START_PAGE;
   while (Page != REBOOT_PAGE)
@@ -2106,7 +3712,17 @@ NtProcessStartup(PPEB Peb)
        {
          /* Start page */
          case START_PAGE:
-           Page = StartPage(&Ir);
+           Page = SetupStartPage(&Ir);
+           break;
+
+         /* License page */
+         case LICENSE_PAGE:
+           Page = LicensePage(&Ir);
+           break;
+        
+         /* Warning page */
+         case WARNING_PAGE:
+           Page = WarningPage(&Ir);
            break;
 
          /* Intro page */
@@ -2119,24 +3735,58 @@ NtProcessStartup(PPEB Peb)
            Page = InstallIntroPage(&Ir);
            break;
 
+#if 0
+         case SCSI_CONTROLLER_PAGE:
+           Page = ScsiControllerPage(&Ir);
+           break;
+#endif
+
 #if 0
          case OEM_DRIVER_PAGE:
            Page = OemDriverPage(&Ir);
            break;
 #endif
 
-#if 0
          case DEVICE_SETTINGS_PAGE:
-#endif
+           Page = DeviceSettingsPage(&Ir);
+           break;
+
+         case COMPUTER_SETTINGS_PAGE:
+           Page = ComputerSettingsPage(&Ir);
+           break;
+
+         case DISPLAY_SETTINGS_PAGE:
+           Page = DisplaySettingsPage(&Ir);
+           break;
+
+         case KEYBOARD_SETTINGS_PAGE:
+           Page = KeyboardSettingsPage(&Ir);
+           break;
+
+         case LAYOUT_SETTINGS_PAGE:
+           Page = LayoutSettingsPage(&Ir);
+           break;
 
          case SELECT_PARTITION_PAGE:
            Page = SelectPartitionPage(&Ir);
            break;
 
+         case CREATE_PARTITION_PAGE:
+           Page = CreatePartitionPage(&Ir);
+           break;
+
+         case DELETE_PARTITION_PAGE:
+           Page = DeletePartitionPage(&Ir);
+           break;
+
          case SELECT_FILE_SYSTEM_PAGE:
            Page = SelectFileSystemPage(&Ir);
            break;
 
+         case FORMAT_PARTITION_PAGE:
+           Page = FormatPartitionPage(&Ir);
+           break;
+
          case CHECK_FILE_SYSTEM_PAGE:
            Page = CheckFileSystemPage(&Ir);
            break;
@@ -2161,26 +3811,41 @@ NtProcessStartup(PPEB Peb)
            Page = BootLoaderPage(&Ir);
            break;
 
+         case BOOT_LOADER_FLOPPY_PAGE:
+           Page = BootLoaderFloppyPage(&Ir);
+           break;
+
+         case BOOT_LOADER_HARDDISK_PAGE:
+           Page = BootLoaderHarddiskPage(&Ir);
+           break;
+
 
          /* Repair pages */
          case REPAIR_INTRO_PAGE:
            Page = RepairIntroPage(&Ir);
            break;
 
-
          case SUCCESS_PAGE:
            Page = SuccessPage(&Ir);
            break;
 
+         case FLUSH_PAGE:
+           Page = FlushPage(&Ir);
+           break;
+
          case QUIT_PAGE:
            Page = QuitPage(&Ir);
            break;
+
+         case REBOOT_PAGE:
+           break;
        }
     }
 
   /* Reboot */
   FreeConsole();
   NtShutdownSystem(ShutdownReboot);
+  NtTerminateProcess(NtCurrentProcess(), 0);
 }
 
 /* EOF */