[SYSSETUP] Add Lunar theme option to 2nd setup stage
[reactos.git] / dll / win32 / syssetup / wizard.c
index f1caf2a..45f1394 100644 (file)
@@ -5,17 +5,23 @@
  * PURPOSE:         GUI controls
  * PROGRAMMERS:     Eric Kohl
  *                  Pierre Schweitzer <heis_spiter@hotmail.com>
+ *                  Ismael Ferreras Morezuelas <swyterzone+ros@gmail.com>
  */
 
 /* INCLUDES *****************************************************************/
 
 #include "precomp.h"
 
+#include <stdlib.h>
+#include <time.h>
+#include <winnls.h>
+#include <windowsx.h>
+#include <wincon.h>
+#include <shlobj.h>
+
 #define NDEBUG
 #include <debug.h>
 
-#define VMWINST
-
 #define PM_REGISTRATION_NOTIFY (WM_APP + 1)
 /* Private Message used to communicate progress from the background
    registration thread to the main thread.
@@ -39,56 +45,11 @@ typedef struct _REGISTRATIONDATA
     PVOID DefaultContext;
 } REGISTRATIONDATA, *PREGISTRATIONDATA;
 
-/* GLOBALS ******************************************************************/
-
-SETUPDATA SetupData;
-
 
 /* FUNCTIONS ****************************************************************/
-BOOL
-GetRosInstallCD(WCHAR *pwszPath, DWORD cchPathMax);
-
-#ifdef VMWINST
-static BOOL
-RunVMWInstall(HWND hWnd)
-{
-    PROCESS_INFORMATION ProcInfo;
-    MSG msg;
-    DWORD ret;
-    STARTUPINFOW si;
-    WCHAR InstallName[] = L"vmwinst.exe";
-
-    ZeroMemory(&si, sizeof(si));
-    si.cb = sizeof(si);
-
-    if(CreateProcessW(NULL, InstallName, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS,
-                      NULL, NULL, &si, &ProcInfo))
-    {
-        EnableWindow(hWnd, FALSE);
-        for (;;)
-        {
-            while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
-            {
-                if (msg.message == WM_QUIT)
-                    goto done;
-                TranslateMessage(&msg);
-                DispatchMessage(&msg);
-            }
 
-            ret = MsgWaitForMultipleObjects(1, &ProcInfo.hProcess, FALSE, INFINITE, QS_ALLEVENTS | QS_ALLINPUT);
-            if (ret == WAIT_OBJECT_0)
-                break;
-        }
-done:
-        EnableWindow(hWnd, TRUE);
+extern void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow);
 
-        CloseHandle(ProcInfo.hThread);
-        CloseHandle(ProcInfo.hProcess);
-        return TRUE;
-    }
-    return FALSE;
-}
-#endif
 
 static VOID
 CenterWindow(HWND hWnd)
@@ -117,29 +78,45 @@ CenterWindow(HWND hWnd)
 static HFONT
 CreateTitleFont(VOID)
 {
-    NONCLIENTMETRICSW ncm;
-    LOGFONTW LogFont;
+    LOGFONTW LogFont = {0};
     HDC hdc;
-    INT FontSize;
     HFONT hFont;
 
-    ncm.cbSize = sizeof(NONCLIENTMETRICSW);
-    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
-
-    LogFont = ncm.lfMessageFont;
-    LogFont.lfWeight = FW_BOLD;
+    LogFont.lfWeight = FW_HEAVY;
     wcscpy(LogFont.lfFaceName, L"MS Shell Dlg");
 
     hdc = GetDC(NULL);
-    FontSize = 12;
-    LogFont.lfHeight = 0 - GetDeviceCaps(hdc, LOGPIXELSY) * FontSize / 72;
+    LogFont.lfHeight = -MulDiv(12, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+
     hFont = CreateFontIndirectW(&LogFont);
+
     ReleaseDC(NULL, hdc);
 
     return hFont;
 }
 
 
+static HFONT
+CreateBoldFont(VOID)
+{
+    LOGFONTW tmpFont = {0};
+    HFONT hBoldFont;
+    HDC hDc;
+
+    /* Grabs the Drawing Context */
+    hDc = GetDC(NULL);
+
+    tmpFont.lfHeight = -MulDiv(8, GetDeviceCaps(hDc, LOGPIXELSY), 72);
+    tmpFont.lfWeight = FW_HEAVY;
+    wcscpy(tmpFont.lfFaceName, L"MS Shell Dlg");
+
+    hBoldFont = CreateFontIndirectW(&tmpFont);
+
+    ReleaseDC(NULL, hDc);
+
+    return hBoldFont;
+}
+
 static INT_PTR CALLBACK
 GplDlgProc(HWND hwndDlg,
            UINT uMsg,
@@ -215,16 +192,20 @@ WelcomeDlgProc(HWND hwndDlg,
                WPARAM wParam,
                LPARAM lParam)
 {
+    PSETUPDATA pSetupData;
+
+    pSetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
+
     switch (uMsg)
     {
         case WM_INITDIALOG:
         {
-            PSETUPDATA SetupData;
             HWND hwndControl;
             DWORD dwStyle;
 
             /* Get pointer to the global setup data */
-            SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
+            pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
+            SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pSetupData);
 
             hwndControl = GetParent(hwndDlg);
 
@@ -244,7 +225,7 @@ WelcomeDlgProc(HWND hwndDlg,
             SendDlgItemMessage(hwndDlg,
                                IDC_WELCOMETITLE,
                                WM_SETFONT,
-                               (WPARAM)SetupData->hTitleFont,
+                               (WPARAM)pSetupData->hTitleFont,
                                (LPARAM)TRUE);
         }
         break;
@@ -257,17 +238,22 @@ WelcomeDlgProc(HWND hwndDlg,
             switch (lpnm->code)
             {
                 case PSN_SETACTIVE:
+                    LogItem(L"BEGIN", L"WelcomePage");
                     /* Enable the Next button */
                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
-                    if (SetupData.UnattendSetup)
+                    if (pSetupData->UnattendSetup)
                     {
-                        SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, IDD_ACKPAGE);
+                        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_ACKPAGE);
                         return TRUE;
                     }
                     break;
 
+                case PSN_WIZNEXT:
+                    LogItem(L"END", L"WelcomePage");
+                    break;
+
                 case PSN_WIZBACK:
-                    SetupData.UnattendSetup = FALSE;
+                    pSetupData->UnattendSetup = FALSE;
                     break;
 
                 default:
@@ -294,14 +280,20 @@ AckPageDlgProc(HWND hwndDlg,
     PWCHAR Projects;
     PWCHAR End, CurrentProject;
     INT ProjectsSize, ProjectsCount;
+    PSETUPDATA pSetupData;
+
+    pSetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
 
     switch (uMsg)
     {
         case WM_INITDIALOG:
         {
+            pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
+            SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pSetupData);
+
             Projects = NULL;
             ProjectsSize = 256;
-            do
+            while (TRUE)
             {
                 Projects = HeapAlloc(GetProcessHeap(), 0, ProjectsSize * sizeof(WCHAR));
                 if (NULL == Projects)
@@ -321,9 +313,9 @@ AckPageDlgProc(HWND hwndDlg,
                 HeapFree(GetProcessHeap(), 0, Projects);
                 ProjectsSize *= 2;
             }
-            while (1);
+
             CurrentProject = Projects;
-            while (L'\0' != *CurrentProject)
+            while (*CurrentProject != L'\0')
             {
                 End = wcschr(CurrentProject, L'\n');
                 if (NULL != End)
@@ -361,15 +353,15 @@ AckPageDlgProc(HWND hwndDlg,
                 case PSN_SETACTIVE:
                     /* Enable the Back and Next buttons */
                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
-                    if (SetupData.UnattendSetup)
+                    if (pSetupData->UnattendSetup)
                     {
-                        SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, IDD_OWNERPAGE);
+                        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_LOCALEPAGE);
                         return TRUE;
                     }
                     break;
 
                 case PSN_WIZBACK:
-                    SetupData.UnattendSetup = FALSE;
+                    pSetupData->UnattendSetup = FALSE;
                     break;
 
                 default:
@@ -393,8 +385,6 @@ WriteOwnerSettings(WCHAR * OwnerName,
     HKEY hKey;
     LONG res;
 
-
-
     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
                         L"Software\\Microsoft\\Windows NT\\CurrentVersion",
                         0,
@@ -441,16 +431,31 @@ OwnerPageDlgProc(HWND hwndDlg,
     WCHAR Title[64];
     WCHAR ErrorName[256];
     LPNMHDR lpnm;
+    PSETUPDATA pSetupData;
+
+    pSetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
 
     switch (uMsg)
     {
         case WM_INITDIALOG:
         {
+            pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
+            SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pSetupData);
+
+            /* set a localized ('Owner') placeholder string as default */
+            if (LoadStringW(hDllInstance, IDS_MACHINE_OWNER_NAME, OwnerName, _countof(OwnerName)))
+            {
+                SendDlgItemMessage(hwndDlg, IDC_OWNERNAME, WM_SETTEXT, 0, (LPARAM)OwnerName);
+            }
+
             SendDlgItemMessage(hwndDlg, IDC_OWNERNAME, EM_LIMITTEXT, 50, 0);
             SendDlgItemMessage(hwndDlg, IDC_OWNERORGANIZATION, EM_LIMITTEXT, 50, 0);
 
             /* Set focus to owner name */
             SetFocus(GetDlgItem(hwndDlg, IDC_OWNERNAME));
+
+            /* Select the default text to quickly overwrite it by typing */
+            SendDlgItemMessage(hwndDlg, IDC_OWNERNAME, EM_SETSEL, 0, -1);
         }
         break;
 
@@ -464,13 +469,13 @@ OwnerPageDlgProc(HWND hwndDlg,
                 case PSN_SETACTIVE:
                     /* Enable the Back and Next buttons */
                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
-                    if (SetupData.UnattendSetup)
+                    if (pSetupData->UnattendSetup)
                     {
-                        SendMessage(GetDlgItem(hwndDlg, IDC_OWNERNAME), WM_SETTEXT, 0, (LPARAM)SetupData.OwnerName);
-                        SendMessage(GetDlgItem(hwndDlg, IDC_OWNERORGANIZATION), WM_SETTEXT, 0, (LPARAM)SetupData.OwnerOrganization);
-                        if (WriteOwnerSettings(SetupData.OwnerName, SetupData.OwnerOrganization))
+                        SendMessage(GetDlgItem(hwndDlg, IDC_OWNERNAME), WM_SETTEXT, 0, (LPARAM)pSetupData->OwnerName);
+                        SendMessage(GetDlgItem(hwndDlg, IDC_OWNERORGANIZATION), WM_SETTEXT, 0, (LPARAM)pSetupData->OwnerOrganization);
+                        if (WriteOwnerSettings(pSetupData->OwnerName, pSetupData->OwnerOrganization))
                         {
-                            SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, IDD_COMPUTERPAGE);
+                            SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_COMPUTERPAGE);
                             return TRUE;
                         }
                     }
@@ -480,18 +485,18 @@ OwnerPageDlgProc(HWND hwndDlg,
                     OwnerName[0] = 0;
                     if (GetDlgItemTextW(hwndDlg, IDC_OWNERNAME, OwnerName, 50) == 0)
                     {
-                        if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP, Title, sizeof(Title) / sizeof(Title[0])))
+                        if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP, Title, ARRAYSIZE(Title)))
                         {
                             wcscpy(Title, L"ReactOS Setup");
                         }
-                        if (0 == LoadStringW(hDllInstance, IDS_WZD_NAME, ErrorName, sizeof(ErrorName) / sizeof(ErrorName[0])))
+                        if (0 == LoadStringW(hDllInstance, IDS_WZD_NAME, ErrorName, ARRAYSIZE(ErrorName)))
                         {
                             wcscpy(ErrorName, L"Setup cannot continue until you enter your name.");
                         }
                         MessageBoxW(hwndDlg, ErrorName, Title, MB_ICONERROR | MB_OK);
 
                         SetFocus(GetDlgItem(hwndDlg, IDC_OWNERNAME));
-                        SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, -1);
+                        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
 
                         return TRUE;
                     }
@@ -502,12 +507,12 @@ OwnerPageDlgProc(HWND hwndDlg,
                     if (!WriteOwnerSettings(OwnerName, OwnerOrganization))
                     {
                         SetFocus(GetDlgItem(hwndDlg, IDC_OWNERNAME));
-                        SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, -1);
+                        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
                         return TRUE;
                     }
 
                 case PSN_WIZBACK:
-                    SetupData.UnattendSetup = FALSE;
+                    pSetupData->UnattendSetup = FALSE;
                     break;
 
                 default:
@@ -529,18 +534,22 @@ WriteComputerSettings(WCHAR * ComputerName, HWND hwndDlg)
 {
     WCHAR Title[64];
     WCHAR ErrorComputerName[256];
+
     if (!SetComputerNameW(ComputerName))
     {
-        if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP, Title, sizeof(Title) / sizeof(Title[0])))
+        if (hwndDlg != NULL)
         {
-            wcscpy(Title, L"ReactOS Setup");
-        }
-        if (0 == LoadStringW(hDllInstance, IDS_WZD_SETCOMPUTERNAME, ErrorComputerName,
-                             sizeof(ErrorComputerName) / sizeof(ErrorComputerName[0])))
-        {
-            wcscpy(ErrorComputerName, L"Setup failed to set the computer name.");
+            if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP, Title, ARRAYSIZE(Title)))
+            {
+                wcscpy(Title, L"ReactOS Setup");
+            }
+            if (0 == LoadStringW(hDllInstance, IDS_WZD_SETCOMPUTERNAME, ErrorComputerName,
+                                 ARRAYSIZE(ErrorComputerName)))
+            {
+                wcscpy(ErrorComputerName, L"Setup failed to set the computer name.");
+            }
+            MessageBoxW(hwndDlg, ErrorComputerName, Title, MB_ICONERROR | MB_OK);
         }
-        MessageBoxW(hwndDlg, ErrorComputerName, Title, MB_ICONERROR | MB_OK);
 
         return FALSE;
     }
@@ -548,12 +557,65 @@ WriteComputerSettings(WCHAR * ComputerName, HWND hwndDlg)
     /* Try to also set DNS hostname */
     SetComputerNameExW(ComputerNamePhysicalDnsHostname, ComputerName);
 
-    /* Set the account domain name */
-    SetAccountDomain(ComputerName, NULL);
+    /* Set the accounts domain name */
+    SetAccountsDomainSid(NULL, ComputerName);
+
+    return TRUE;
+}
+
+
+static
+BOOL
+WriteDefaultLogonData(LPWSTR Domain)
+{
+    WCHAR szAdministratorName[256];
+    HKEY hKey = NULL;
+    LONG lError;
+
+    if (LoadStringW(hDllInstance,
+                    IDS_ADMINISTRATOR_NAME,
+                    szAdministratorName,
+                    ARRAYSIZE(szAdministratorName)) == 0)
+    {
+        wcscpy(szAdministratorName, L"Administrator");
+    }
+
+    lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                           L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
+                           0,
+                           KEY_SET_VALUE,
+                           &hKey);
+    if (lError != ERROR_SUCCESS)
+        return FALSE;
+
+    lError = RegSetValueEx(hKey,
+                           L"DefaultDomainName",
+                           0,
+                           REG_SZ,
+                           (LPBYTE)Domain,
+                           (wcslen(Domain)+ 1) * sizeof(WCHAR));
+    if (lError != ERROR_SUCCESS)
+    {
+        DPRINT1("RegSetValueEx(\"DefaultDomainName\") failed!\n");
+    }
+
+    lError = RegSetValueEx(hKey,
+                           L"DefaultUserName",
+                           0,
+                           REG_SZ,
+                           (LPBYTE)szAdministratorName,
+                           (wcslen(szAdministratorName)+ 1) * sizeof(WCHAR));
+    if (lError != ERROR_SUCCESS)
+    {
+        DPRINT1("RegSetValueEx(\"DefaultUserName\") failed!\n");
+    }
+
+    RegCloseKey(hKey);
 
     return TRUE;
 }
 
+
 /* lpBuffer will be filled with a 15-char string (plus the null terminator) */
 static void
 GenerateComputerName(LPWSTR lpBuffer)
@@ -580,14 +642,17 @@ ComputerPageDlgProc(HWND hwndDlg,
                     LPARAM lParam)
 {
     WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
-    WCHAR Password1[15];
-    WCHAR Password2[15];
+    WCHAR Password1[128];
+    WCHAR Password2[128];
     PWCHAR Password;
     WCHAR Title[64];
     WCHAR EmptyComputerName[256], NotMatchPassword[256], WrongPassword[256];
     LPNMHDR lpnm;
+    PSETUPDATA pSetupData;
+
+    pSetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
 
-    if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP, Title, sizeof(Title) / sizeof(Title[0])))
+    if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP, Title, ARRAYSIZE(Title)))
     {
         wcscpy(Title, L"ReactOS Setup");
     }
@@ -595,7 +660,9 @@ ComputerPageDlgProc(HWND hwndDlg,
     switch (uMsg)
     {
         case WM_INITDIALOG:
-        {
+            pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
+            SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pSetupData);
+
             /* Generate a new pseudo-random computer name */
             GenerateComputerName(ComputerName);
 
@@ -604,20 +671,23 @@ ComputerPageDlgProc(HWND hwndDlg,
 
             /* Set text limits */
             SendDlgItemMessage(hwndDlg, IDC_COMPUTERNAME, EM_LIMITTEXT, MAX_COMPUTERNAME_LENGTH, 0);
-            SendDlgItemMessage(hwndDlg, IDC_ADMINPASSWORD1, EM_LIMITTEXT, 14, 0);
-            SendDlgItemMessage(hwndDlg, IDC_ADMINPASSWORD2, EM_LIMITTEXT, 14, 0);
+            SendDlgItemMessage(hwndDlg, IDC_ADMINPASSWORD1, EM_LIMITTEXT, 127, 0);
+            SendDlgItemMessage(hwndDlg, IDC_ADMINPASSWORD2, EM_LIMITTEXT, 127, 0);
 
             /* Set focus to computer name */
             SetFocus(GetDlgItem(hwndDlg, IDC_COMPUTERNAME));
-            if (SetupData.UnattendSetup)
+            if (pSetupData->UnattendSetup)
             {
-                SendMessage(GetDlgItem(hwndDlg, IDC_COMPUTERNAME), WM_SETTEXT, 0, (LPARAM)SetupData.ComputerName);
-                SendMessage(GetDlgItem(hwndDlg, IDC_ADMINPASSWORD1), WM_SETTEXT, 0, (LPARAM)SetupData.AdminPassword);
-                SendMessage(GetDlgItem(hwndDlg, IDC_ADMINPASSWORD2), WM_SETTEXT, 0, (LPARAM)SetupData.AdminPassword);
+                SendMessage(GetDlgItem(hwndDlg, IDC_COMPUTERNAME), WM_SETTEXT, 0, (LPARAM)pSetupData->ComputerName);
+                SendMessage(GetDlgItem(hwndDlg, IDC_ADMINPASSWORD1), WM_SETTEXT, 0, (LPARAM)pSetupData->AdminPassword);
+                SendMessage(GetDlgItem(hwndDlg, IDC_ADMINPASSWORD2), WM_SETTEXT, 0, (LPARAM)pSetupData->AdminPassword);
+                WriteComputerSettings(pSetupData->ComputerName, NULL);
+                SetAdministratorPassword(pSetupData->AdminPassword);
             }
 
-        }
-        break;
+            /* Store the administrator account name as the default user name */
+            WriteDefaultLogonData(pSetupData->ComputerName);
+            break;
 
 
         case WM_NOTIFY:
@@ -629,9 +699,9 @@ ComputerPageDlgProc(HWND hwndDlg,
                 case PSN_SETACTIVE:
                     /* Enable the Back and Next buttons */
                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
-                    if (SetupData.UnattendSetup && WriteComputerSettings(SetupData.ComputerName, hwndDlg))
+                    if (pSetupData->UnattendSetup && WriteComputerSettings(pSetupData->ComputerName, hwndDlg))
                     {
-                        SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, IDD_LOCALEPAGE);
+                        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_THEMEPAGE);
                         return TRUE;
                     }
                     break;
@@ -640,13 +710,13 @@ ComputerPageDlgProc(HWND hwndDlg,
                     if (0 == GetDlgItemTextW(hwndDlg, IDC_COMPUTERNAME, ComputerName, MAX_COMPUTERNAME_LENGTH + 1))
                     {
                         if (0 == LoadStringW(hDllInstance, IDS_WZD_COMPUTERNAME, EmptyComputerName,
-                                             sizeof(EmptyComputerName) / sizeof(EmptyComputerName[0])))
+                                             ARRAYSIZE(EmptyComputerName)))
                         {
                             wcscpy(EmptyComputerName, L"Setup cannot continue until you enter the name of your computer.");
                         }
                         MessageBoxW(hwndDlg, EmptyComputerName, Title, MB_ICONERROR | MB_OK);
                         SetFocus(GetDlgItem(hwndDlg, IDC_COMPUTERNAME));
-                        SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, -1);
+                        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
                         return TRUE;
                     }
 
@@ -656,38 +726,38 @@ ComputerPageDlgProc(HWND hwndDlg,
                     if (!WriteComputerSettings(ComputerName, hwndDlg))
                     {
                         SetFocus(GetDlgItem(hwndDlg, IDC_COMPUTERNAME));
-                        SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, -1);
+                        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
                         return TRUE;
                     }
 
 #if 0
                     /* Check if admin passwords have been entered */
-                    if ((GetDlgItemText(hwndDlg, IDC_ADMINPASSWORD1, Password1, 15) == 0) ||
-                            (GetDlgItemText(hwndDlg, IDC_ADMINPASSWORD2, Password2, 15) == 0))
+                    if ((GetDlgItemText(hwndDlg, IDC_ADMINPASSWORD1, Password1, 128) == 0) ||
+                        (GetDlgItemText(hwndDlg, IDC_ADMINPASSWORD2, Password2, 128) == 0))
                     {
                         if (0 == LoadStringW(hDllInstance, IDS_WZD_PASSWORDEMPTY, EmptyPassword,
-                                             sizeof(EmptyPassword) / sizeof(EmptyPassword[0])))
+                                             ARRAYSIZE(EmptyPassword)))
                         {
                             wcscpy(EmptyPassword, L"You must enter a password !");
                         }
                         MessageBoxW(hwndDlg, EmptyPassword, Title, MB_ICONERROR | MB_OK);
-                        SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, -1);
+                        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
                         return TRUE;
                     }
 #else
-                    GetDlgItemTextW(hwndDlg, IDC_ADMINPASSWORD1, Password1, 15);
-                    GetDlgItemTextW(hwndDlg, IDC_ADMINPASSWORD2, Password2, 15);
+                    GetDlgItemTextW(hwndDlg, IDC_ADMINPASSWORD1, Password1, 128);
+                    GetDlgItemTextW(hwndDlg, IDC_ADMINPASSWORD2, Password2, 128);
 #endif
                     /* Check if passwords match */
                     if (wcscmp(Password1, Password2))
                     {
                         if (0 == LoadStringW(hDllInstance, IDS_WZD_PASSWORDMATCH, NotMatchPassword,
-                                             sizeof(NotMatchPassword) / sizeof(NotMatchPassword[0])))
+                                             ARRAYSIZE(NotMatchPassword)))
                         {
                             wcscpy(NotMatchPassword, L"The passwords you entered do not match. Please enter the desired password again.");
                         }
                         MessageBoxW(hwndDlg, NotMatchPassword, Title, MB_ICONERROR | MB_OK);
-                        SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, -1);
+                        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
                         return TRUE;
                     }
 
@@ -698,22 +768,23 @@ ComputerPageDlgProc(HWND hwndDlg,
                         if (!isprint(*Password))
                         {
                             if (0 == LoadStringW(hDllInstance, IDS_WZD_PASSWORDCHAR, WrongPassword,
-                                                 sizeof(WrongPassword) / sizeof(WrongPassword[0])))
+                                                 ARRAYSIZE(WrongPassword)))
                             {
                                 wcscpy(WrongPassword, L"The password you entered contains invalid characters. Please enter a cleaned password.");
                             }
                             MessageBoxW(hwndDlg, WrongPassword, Title, MB_ICONERROR | MB_OK);
-                            SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, -1);
+                            SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
                             return TRUE;
                         }
                         Password++;
                     }
 
-                    /* FIXME: Set admin password */
+                    /* Set admin password */
+                    SetAdministratorPassword(Password1);
                     break;
 
                 case PSN_WIZBACK:
-                    SetupData.UnattendSetup = FALSE;
+                    pSetupData->UnattendSetup = FALSE;
                     break;
 
                 default:
@@ -790,43 +861,50 @@ SetKeyboardLayoutName(HWND hwnd)
 static BOOL
 RunControlPanelApplet(HWND hwnd, PCWSTR pwszCPLParameters)
 {
-    if (pwszCPLParameters)
+    MSG msg;
+    STARTUPINFOW StartupInfo;
+    PROCESS_INFORMATION ProcessInformation;
+    WCHAR CmdLine[MAX_PATH] = L"rundll32.exe shell32.dll,Control_RunDLL ";
+
+    if (!pwszCPLParameters)
     {
-        STARTUPINFOW StartupInfo;
-        PROCESS_INFORMATION ProcessInformation;
-        WCHAR CmdLine[MAX_PATH] = L"rundll32.exe shell32.dll,Control_RunDLL ";
+        MessageBoxW(hwnd, L"Error: Failed to launch the Control Panel Applet.", NULL, MB_ICONERROR);
+        return FALSE;
+    }
 
-        ZeroMemory(&StartupInfo, sizeof(StartupInfo));
-        StartupInfo.cb = sizeof(StartupInfo);
+    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
+    StartupInfo.cb = sizeof(StartupInfo);
+    ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
 
-        ASSERT(_countof(CmdLine) > wcslen(CmdLine) + wcslen(pwszCPLParameters));
-        wcscat(CmdLine, pwszCPLParameters);
+    ASSERT(_countof(CmdLine) > wcslen(CmdLine) + wcslen(pwszCPLParameters));
+    wcscat(CmdLine, pwszCPLParameters);
 
-        if (!CreateProcessW(NULL,
-                            CmdLine,
-                            NULL,
-                            NULL,
-                            FALSE,
-                            0,
-                            NULL,
-                            NULL,
-                            &StartupInfo,
-                            &ProcessInformation))
-        {
-            MessageBoxW(hwnd, L"Error: Failed to launch the Control Panel Applet.", NULL, MB_ICONERROR);
-            return FALSE;
-        }
-
-        WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
-        CloseHandle(ProcessInformation.hThread);
-        CloseHandle(ProcessInformation.hProcess);
-        return TRUE;
-    }
-    else
+    if (!CreateProcessW(NULL,
+                        CmdLine,
+                        NULL,
+                        NULL,
+                        FALSE,
+                        0,
+                        NULL,
+                        NULL,
+                        &StartupInfo,
+                        &ProcessInformation))
     {
         MessageBoxW(hwnd, L"Error: Failed to launch the Control Panel Applet.", NULL, MB_ICONERROR);
         return FALSE;
     }
+
+    while ((MsgWaitForMultipleObjects(1, &ProcessInformation.hProcess, FALSE, INFINITE, QS_ALLINPUT|QS_ALLPOSTMESSAGE )) != WAIT_OBJECT_0)
+    { 
+       while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
+       {
+           TranslateMessage(&msg);
+           DispatchMessageW(&msg);
+       }
+    }
+    CloseHandle(ProcessInformation.hThread);
+    CloseHandle(ProcessInformation.hProcess);
+    return TRUE;
 }
 
 static VOID
@@ -838,7 +916,7 @@ WriteUserLocale(VOID)
 
     lcid = GetSystemDefaultLCID();
 
-    if (GetLocaleInfoW(MAKELCID(lcid, SORT_DEFAULT), LOCALE_ILANGUAGE, Locale, sizeof(Locale) / sizeof(Locale[0])) != 0)
+    if (GetLocaleInfoW(MAKELCID(lcid, SORT_DEFAULT), LOCALE_ILANGUAGE, Locale, ARRAYSIZE(Locale)) != 0)
     {
         if (RegCreateKeyExW(HKEY_CURRENT_USER, L"Control Panel\\International",
                             0, NULL, REG_OPTION_NON_VOLATILE,
@@ -859,7 +937,7 @@ LocalePageDlgProc(HWND hwndDlg,
     PSETUPDATA SetupData;
 
     /* Retrieve pointer to the global setup data */
-    SetupData = (PSETUPDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
+    SetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 
     switch (uMsg)
     {
@@ -867,7 +945,7 @@ LocalePageDlgProc(HWND hwndDlg,
         {
             /* Save pointer to the global setup data */
             SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
-            SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)SetupData);
+            SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)SetupData);
             WriteUserLocale();
 
             SetKeyboardLayoutName(GetDlgItem(hwndDlg, IDC_LAYOUTTEXT));
@@ -902,19 +980,12 @@ LocalePageDlgProc(HWND hwndDlg,
                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
                     if (SetupData->UnattendSetup)
                     {
-                        WCHAR wszPath[MAX_PATH];
-                        if (GetRosInstallCD(wszPath, _countof(wszPath)))
-                        {
-                            WCHAR wszParams[1024];
-                            swprintf(wszParams, L"intl.cpl,,/f:\"%sreactos\\unattend.inf\"", wszPath);
-                            RunControlPanelApplet(hwndDlg, wszParams);
-                        }
-                        else
+                        // if (!*SetupData->SourcePath)
                         {
-                            RunControlPanelApplet(hwndDlg, L"intl.cpl,,/f:\"unattend.inf\"");
+                            RunControlPanelApplet(hwndDlg, L"intl.cpl,,/f:\"$winnt$.inf\""); // Should be in System32
                         }
 
-                        SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, IDD_DATETIMEPAGE);
+                        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_OWNERPAGE);
                         return TRUE;
                     }
                     break;
@@ -1151,27 +1222,36 @@ GetTimeZoneListIndex(LPDWORD lpIndex)
     BOOL bFound = FALSE;
     unsigned long iLanguageID;
 
-    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
-                      L"SYSTEM\\CurrentControlSet\\Control\\NLS\\Language",
-                      0,
-                      KEY_ALL_ACCESS,
-                      &hKey))
-        return FALSE;
-
-    dwValueSize = 9 * sizeof(WCHAR);
-    if (RegQueryValueExW(hKey,
-                         L"Default",
-                         NULL,
-                         NULL,
-                         (LPBYTE)szLanguageIdString,
-                         &dwValueSize))
+    if (*lpIndex == -1)
     {
+        *lpIndex = 85; /* fallback to GMT time zone */
+
+        if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                          L"SYSTEM\\CurrentControlSet\\Control\\NLS\\Language",
+                          0,
+                          KEY_ALL_ACCESS,
+                          &hKey))
+            return FALSE;
+
+        dwValueSize = 9 * sizeof(WCHAR);
+        if (RegQueryValueExW(hKey,
+                             L"Default",
+                             NULL,
+                             NULL,
+                             (LPBYTE)szLanguageIdString,
+                             &dwValueSize))
+        {
+            RegCloseKey(hKey);
+            return FALSE;
+        }
+
+        iLanguageID = wcstoul(szLanguageIdString, NULL, 16);
         RegCloseKey(hKey);
-        return FALSE;
     }
-
-    iLanguageID = wcstoul(szLanguageIdString, NULL, 16);
-    RegCloseKey(hKey);
+    else
+    {
+        iLanguageID = *lpIndex;
+    }
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
                       L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
@@ -1374,79 +1454,48 @@ SetAutoDaylightInfo(HWND hwnd)
 static BOOL
 SetSystemLocalTime(HWND hwnd, PSETUPDATA SetupData)
 {
-    HANDLE hToken;
-    DWORD PrevSize;
-    TOKEN_PRIVILEGES priv, previouspriv;
     BOOL Ret = FALSE;
 
     /*
-     * enable the SeSystemtimePrivilege privilege
+     * Call SetLocalTime twice to ensure correct results
      */
+    Ret = SetLocalTime(&SetupData->SystemTime) &&
+          SetLocalTime(&SetupData->SystemTime);
 
-    if(OpenProcessToken(GetCurrentProcess(),
-                        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
-                        &hToken))
-    {
-        priv.PrivilegeCount = 1;
-        priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+    return Ret;
+}
 
-        if(LookupPrivilegeValue(NULL,
-                                SE_SYSTEMTIME_NAME,
-                                &priv.Privileges[0].Luid))
-        {
-            if(AdjustTokenPrivileges(hToken,
-                                     FALSE,
-                                     &priv,
-                                     sizeof(previouspriv),
-                                     &previouspriv,
-                                     &PrevSize) &&
-                    GetLastError() == ERROR_SUCCESS)
-            {
-                /*
-                 * We successfully enabled it, we're permitted to change the system time
-                 * Call SetLocalTime twice to ensure correct results
-                 */
-                Ret = SetLocalTime(&SetupData->SystemTime) &&
-                      SetLocalTime(&SetupData->SystemTime);
-
-                /*
-                 * for the sake of security, restore the previous status again
-                 */
-                if(previouspriv.PrivilegeCount > 0)
-                {
-                    AdjustTokenPrivileges(hToken,
-                                          FALSE,
-                                          &previouspriv,
-                                          0,
-                                          NULL,
-                                          0);
-                }
-            }
-        }
-        CloseHandle(hToken);
-    }
 
-    return Ret;
+static VOID
+UpdateLocalSystemTime(HWND hwnd)
+{
+    SYSTEMTIME LocalTime;
+
+    GetLocalTime(&LocalTime);
+    DateTime_SetSystemtime(GetDlgItem(hwnd, IDC_DATEPICKER), GDT_VALID, &LocalTime);
+    DateTime_SetSystemtime(GetDlgItem(hwnd, IDC_TIMEPICKER), GDT_VALID, &LocalTime);
 }
 
+
 static BOOL
 WriteDateTimeSettings(HWND hwndDlg, PSETUPDATA SetupData)
 {
     WCHAR Title[64];
     WCHAR ErrorLocalTime[256];
+
     GetLocalSystemTime(hwndDlg, SetupData);
     SetLocalTimeZone(GetDlgItem(hwndDlg, IDC_TIMEZONELIST),
                      SetupData);
 
     SetAutoDaylightInfo(GetDlgItem(hwndDlg, IDC_AUTODAYLIGHT));
-    if(!SetSystemLocalTime(hwndDlg, SetupData))
+    if (!SetSystemLocalTime(hwndDlg, SetupData))
     {
-        if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP, Title, sizeof(Title) / sizeof(Title[0])))
+        if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP, Title, ARRAYSIZE(Title)))
         {
             wcscpy(Title, L"ReactOS Setup");
         }
         if (0 == LoadStringW(hDllInstance, IDS_WZD_LOCALTIME, ErrorLocalTime,
-                             sizeof(ErrorLocalTime) / sizeof(ErrorLocalTime[0])))
+                             ARRAYSIZE(ErrorLocalTime)))
         {
             wcscpy(ErrorLocalTime, L"Setup was unable to set the local time.");
         }
@@ -1457,6 +1506,7 @@ WriteDateTimeSettings(HWND hwndDlg, PSETUPDATA SetupData)
     return TRUE;
 }
 
+
 static INT_PTR CALLBACK
 DateTimePageDlgProc(HWND hwndDlg,
                     UINT uMsg,
@@ -1466,15 +1516,14 @@ DateTimePageDlgProc(HWND hwndDlg,
     PSETUPDATA SetupData;
 
     /* Retrieve pointer to the global setup data */
-    SetupData = (PSETUPDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
+    SetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 
     switch (uMsg)
     {
         case WM_INITDIALOG:
-        {
             /* Save pointer to the global setup data */
             SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
-            SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)SetupData);
+            SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)SetupData);
 
             CreateTimeZoneList(SetupData);
 
@@ -1491,36 +1540,38 @@ DateTimePageDlgProc(HWND hwndDlg,
             else
             {
                 ShowTimeZoneList(GetDlgItem(hwndDlg, IDC_TIMEZONELIST),
-                                 SetupData, 85 /* GMT time zone */);
+                                 SetupData, -1);
 
                 SendDlgItemMessage(hwndDlg, IDC_AUTODAYLIGHT, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
             }
+            break;
 
-        }
-        break;
-
+        case WM_TIMER:
+            UpdateLocalSystemTime(hwndDlg);
+            break;
 
         case WM_NOTIFY:
-        {
-            LPNMHDR lpnm = (LPNMHDR)lParam;
-
-            switch (lpnm->code)
+            switch (((LPNMHDR)lParam)->code)
             {
                 case PSN_SETACTIVE:
                     /* Enable the Back and Next buttons */
                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
                     if (SetupData->UnattendSetup && WriteDateTimeSettings(hwndDlg, SetupData))
                     {
-                        SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, IDD_PROCESSPAGE);
+                        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, SetupData->uFirstNetworkWizardPage);
                         return TRUE;
                     }
+                    SetTimer(hwndDlg, 1, 1000, NULL);
+                    break;
+
+                case PSN_KILLACTIVE:
+                case DTN_DATETIMECHANGE:
+                    KillTimer(hwndDlg, 1);
                     break;
 
                 case PSN_WIZNEXT:
-                {
                     WriteDateTimeSettings(hwndDlg, SetupData);
-                }
-                break;
+                    break;
 
                 case PSN_WIZBACK:
                     SetupData->UnattendSetup = FALSE;
@@ -1529,8 +1580,7 @@ DateTimePageDlgProc(HWND hwndDlg,
                 default:
                     break;
             }
-        }
-        break;
+            break;
 
         case WM_DESTROY:
             DestroyTimeZoneList(SetupData);
@@ -1543,6 +1593,131 @@ DateTimePageDlgProc(HWND hwndDlg,
     return FALSE;
 }
 
+static struct ThemeInfo
+{
+    LPCWSTR PreviewBitmap;
+    UINT DisplayName;
+    LPCWSTR ThemeFile;
+
+} Themes[] = {
+    { MAKEINTRESOURCE(IDB_CLASSIC), IDS_CLASSIC, NULL },
+    { MAKEINTRESOURCE(IDB_LAUTUS), IDS_LAUTUS, L"themes\\lautus\\lautus.msstyles" },
+    { MAKEINTRESOURCE(IDB_LUNAR), IDS_LUNAR, L"themes\\lunar\\lunar.msstyles" },
+};
+
+static INT_PTR CALLBACK
+ThemePageDlgProc(HWND hwndDlg,
+                    UINT uMsg,
+                    WPARAM wParam,
+                    LPARAM lParam)
+{
+    PSETUPDATA SetupData;
+    LPNMLISTVIEW pnmv;
+
+    /* Retrieve pointer to the global setup data */
+    SetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+    switch (uMsg)
+    {
+        case WM_INITDIALOG:
+        {
+            HWND hListView;
+            HIMAGELIST himl;
+            DWORD n;
+            LVITEM lvi = {0};
+
+            /* Save pointer to the global setup data */
+            SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
+            SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)SetupData);
+
+            hListView = GetDlgItem(hwndDlg, IDC_THEMEPICKER);
+
+            /* Common */
+            himl = ImageList_Create(180, 163, ILC_COLOR32 | ILC_MASK, ARRAYSIZE(Themes), 1);
+            lvi.mask = LVIF_TEXT | LVIF_IMAGE |LVIF_STATE;
+
+            for (n = 0; n < ARRAYSIZE(Themes); ++n)
+            {
+                WCHAR DisplayName[100] = {0};
+                /* Load the bitmap */
+                HANDLE image = LoadImageW(hDllInstance, Themes[n].PreviewBitmap, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
+                ImageList_AddMasked(himl, image, RGB(255,0,255));
+
+                /* Load the string */
+                LoadStringW(hDllInstance, Themes[n].DisplayName, DisplayName, ARRAYSIZE(DisplayName));
+                DisplayName[ARRAYSIZE(DisplayName)-1] = UNICODE_NULL;
+
+                /* Add the listview item */
+                lvi.iItem  = n;
+                lvi.iImage = n;
+                lvi.pszText = DisplayName;
+                ListView_InsertItem(hListView, &lvi);
+            }
+
+            /* Register the imagelist */
+            ListView_SetImageList(hListView, himl, LVSIL_NORMAL);
+            /* Transparant background */
+            ListView_SetBkColor(hListView, CLR_NONE);
+            ListView_SetTextBkColor(hListView, CLR_NONE);
+            /* Reduce the size between the items */
+            ListView_SetIconSpacing(hListView, 190, 173);
+            break;
+        }
+        case WM_NOTIFY:
+            switch (((LPNMHDR)lParam)->code)
+            {
+                //case LVN_ITEMCHANGING:
+                case LVN_ITEMCHANGED:
+                    pnmv = (LPNMLISTVIEW)lParam;
+                    if ((pnmv->uChanged & LVIF_STATE) && (pnmv->uNewState & LVIS_SELECTED))
+                    {
+                        int iTheme = pnmv->iItem;
+                        DPRINT1("Selected theme: %S\n", Themes[iTheme].DisplayName);
+
+                        if (Themes[iTheme].ThemeFile)
+                        {
+                            WCHAR wszParams[1024];
+                            WCHAR wszTheme[MAX_PATH];
+                            WCHAR* format = L"desk.cpl desk,@Appearance /Action:ActivateMSTheme /file:\"%s\"";
+
+                            SHGetFolderPathAndSubDirW(0, CSIDL_RESOURCES, NULL, SHGFP_TYPE_DEFAULT, Themes[iTheme].ThemeFile, wszTheme);
+                            swprintf(wszParams, format, wszTheme);
+                            RunControlPanelApplet(hwndDlg, wszParams);
+                        }
+                        else
+                        {
+                            RunControlPanelApplet(hwndDlg, L"desk.cpl desk,@Appearance /Action:ActivateMSTheme");
+                        }
+                    }
+                    break;
+                case PSN_SETACTIVE:
+                    /* Enable the Back and Next buttons */
+                    PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+                    if (SetupData->UnattendSetup)
+                    {
+                        SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, SetupData->uFirstNetworkWizardPage);
+                        return TRUE;
+                    }
+                    break;
+
+                case PSN_WIZNEXT:
+                    break;
+
+                case PSN_WIZBACK:
+                    SetupData->UnattendSetup = FALSE;
+                    break;
+
+                default:
+                    break;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    return FALSE;
+}
 
 static UINT CALLBACK
 RegistrationNotificationProc(PVOID Context,
@@ -1610,8 +1785,7 @@ RegistrationNotificationProc(PVOID Context,
                 }
                 if (0 == LoadStringW(hDllInstance, MessageID,
                                      ErrorMessage,
-                                     sizeof(ErrorMessage) /
-                                     sizeof(ErrorMessage[0])))
+                                     ARRAYSIZE(ErrorMessage)))
                 {
                     ErrorMessage[0] = L'\0';
                 }
@@ -1620,8 +1794,8 @@ RegistrationNotificationProc(PVOID Context,
                     FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
                                    StatusInfo->Win32Error, 0,
                                    ErrorMessage + wcslen(ErrorMessage),
-                                   sizeof(ErrorMessage) / sizeof(ErrorMessage[0]) -
-                                   wcslen(ErrorMessage), NULL);
+                                   ARRAYSIZE(ErrorMessage) - wcslen(ErrorMessage),
+                                   NULL);
                 }
                 RegistrationNotify.ErrorMessage = ErrorMessage;
             }
@@ -1704,8 +1878,7 @@ RegistrationProc(LPVOID Parameter)
         {
             if (0 == LoadStringW(hDllInstance, IDS_UNKNOWN_ERROR,
                                  UnknownError,
-                                 sizeof(UnknownError) / sizeof(UnknownError[0]) -
-                                 20))
+                                 ARRAYSIZE(UnknownError) - 20))
             {
                 wcscpy(UnknownError, L"Unknown error");
             }
@@ -1729,6 +1902,8 @@ RegistrationProc(LPVOID Parameter)
     SetupTermDefaultQueueCallback(RegistrationData->DefaultContext);
     HeapFree(GetProcessHeap(), 0, RegistrationData);
 
+    RegisterTypeLibraries(hSysSetupInf, L"TypeLibraries");
+
     // FIXME: Move this call to a separate cleanup page!
     RtlCreateBootStatusDataFile();
 
@@ -1746,15 +1921,15 @@ StartComponentRegistration(HWND hwndDlg, PULONG MaxProgress)
     PREGISTRATIONDATA RegistrationData;
 
     DllCount = -1;
-    if (! SetupFindFirstLineW(hSysSetupInf, L"RegistrationPhase2",
-                              L"RegisterDlls", &Context))
+    if (!SetupFindFirstLineW(hSysSetupInf, L"RegistrationPhase2",
+                             L"RegisterDlls", &Context))
     {
         DPRINT1("No RegistrationPhase2 section found\n");
         return FALSE;
     }
-    if (! SetupGetStringFieldW(&Context, 1, SectionName,
-                               sizeof(SectionName) / sizeof(SectionName[0]),
-                               NULL))
+    if (!SetupGetStringFieldW(&Context, 1, SectionName,
+                              ARRAYSIZE(SectionName),
+                              NULL))
     {
         DPRINT1("Unable to retrieve section name\n");
         return FALSE;
@@ -1781,7 +1956,7 @@ StartComponentRegistration(HWND hwndDlg, PULONG MaxProgress)
         RegistrationData->hwndDlg = hwndDlg;
         RegistrationData->DllCount = DllCount;
         RegistrationThread = CreateThread(NULL, 0, RegistrationProc,
-                                          (LPVOID) RegistrationData, 0, NULL);
+                                          RegistrationData, 0, NULL);
         if (RegistrationThread != NULL)
         {
             CloseHandle(RegistrationThread);
@@ -1815,7 +1990,7 @@ ProcessPageDlgProc(HWND hwndDlg,
     WCHAR Title[64];
 
     /* Retrieve pointer to the global setup data */
-    SetupData = (PSETUPDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
+    SetupData = (PSETUPDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 
     switch (uMsg)
     {
@@ -1823,7 +1998,7 @@ ProcessPageDlgProc(HWND hwndDlg,
         {
             /* Save pointer to the global setup data */
             SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
-            SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)SetupData);
+            SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)SetupData);
         }
         break;
 
@@ -1868,7 +2043,7 @@ ProcessPageDlgProc(HWND hwndDlg,
             {
                 if (0 != LoadStringW(hDllInstance, RegistrationNotify->ActivityID,
                                      Activity,
-                                     sizeof(Activity) / sizeof(Activity[0])))
+                                     ARRAYSIZE(Activity)))
                 {
                     SendDlgItemMessageW(hwndDlg, IDC_ACTIVITY, WM_SETTEXT,
                                         0, (LPARAM) Activity);
@@ -1883,7 +2058,7 @@ ProcessPageDlgProc(HWND hwndDlg,
             if (NULL != RegistrationNotify->ErrorMessage)
             {
                 if (0 == LoadStringW(hDllInstance, IDS_REACTOS_SETUP,
-                                     Title, sizeof(Title) / sizeof(Title[0])))
+                                     Title, ARRAYSIZE(Title)))
                 {
                     wcscpy(Title, L"ReactOS Setup");
                 }
@@ -1894,11 +2069,6 @@ ProcessPageDlgProc(HWND hwndDlg,
 
             if (wParam)
             {
-#ifdef VMWINST
-                if(!SetupData->UnattendSetup && !SetupData->DisableVmwInst)
-                    RunVMWInstall(GetParent(hwndDlg));
-#endif
-
                 /* Enable the Back and Next buttons */
                 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
                 PropSheet_PressButton(GetParent(hwndDlg), PSBTN_NEXT);
@@ -1943,7 +2113,6 @@ SetInstallationCompleted(VOID)
     }
 }
 
-
 static INT_PTR CALLBACK
 FinishDlgProc(HWND hwndDlg,
               UINT uMsg,
@@ -1955,10 +2124,14 @@ FinishDlgProc(HWND hwndDlg,
     {
         case WM_INITDIALOG:
         {
-            PSETUPDATA SetupData;
-
             /* Get pointer to the global setup data */
-            SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
+            PSETUPDATA SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
+
+            if (!SetupData->UnattendSetup || !SetupData->DisableGeckoInst)
+            {
+                /* Run the Wine Gecko prompt */
+                Control_RunDLLW(hwndDlg, 0, L"appwiz.cpl install_gecko", SW_SHOW);
+            }
 
             /* Set title font */
             SendDlgItemMessage(hwndDlg,
@@ -2035,8 +2208,70 @@ FinishDlgProc(HWND hwndDlg,
 }
 
 
-BOOL
-ProcessUnattendInf(HINF hUnattendedInf)
+/*
+ * GetInstallSourceWin32 retrieves the path to the ReactOS installation medium
+ * in Win32 format, for later use by syssetup and storage in the registry.
+ */
+static BOOL
+GetInstallSourceWin32(
+    OUT PWSTR pwszPath,
+    IN DWORD cchPathMax,
+    IN PCWSTR pwszNTPath)
+{
+    WCHAR wszDrives[512];
+    WCHAR wszNTPath[512]; // MAX_PATH ?
+    DWORD cchDrives;
+    PWCHAR pwszDrive;
+
+    *pwszPath = UNICODE_NULL;
+
+    cchDrives = GetLogicalDriveStringsW(_countof(wszDrives) - 1, wszDrives);
+    if (cchDrives == 0 || cchDrives >= _countof(wszDrives))
+    {
+        /* Buffer too small or failure */
+        LogItem(NULL, L"GetLogicalDriveStringsW failed");
+        return FALSE;
+    }
+
+    for (pwszDrive = wszDrives; *pwszDrive; pwszDrive += wcslen(pwszDrive) + 1)
+    {
+        WCHAR wszBuf[MAX_PATH];
+
+        /* Retrieve the NT path corresponding to the current Win32 DOS path */
+        pwszDrive[2] = UNICODE_NULL; // Temporarily remove the backslash
+        QueryDosDeviceW(pwszDrive, wszNTPath, _countof(wszNTPath));
+        pwszDrive[2] = L'\\';        // Restore the backslash
+
+        wcscat(wszNTPath, L"\\");    // Concat a backslash
+
+        /* Logging */
+        wsprintf(wszBuf, L"Testing '%s' --> '%s' %s a CD",
+                 pwszDrive, wszNTPath,
+                 (GetDriveTypeW(pwszDrive) == DRIVE_CDROM) ? L"is" : L"is not");
+        LogItem(NULL, wszBuf);
+
+        /* Check whether the NT path corresponds to the NT installation source path */
+        if (!_wcsicmp(wszNTPath, pwszNTPath))
+        {
+            /* Found it! */
+            wcscpy(pwszPath, pwszDrive); // cchPathMax
+
+            /* Logging */
+            wsprintf(wszBuf, L"GetInstallSourceWin32: %s", pwszPath);
+            LogItem(NULL, wszBuf);
+            wcscat(wszBuf, L"\n");
+            OutputDebugStringW(wszBuf);
+
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+VOID
+ProcessUnattendSection(
+    IN OUT PSETUPDATA pSetupData)
 {
     INFCONTEXT InfContext;
     WCHAR szName[256];
@@ -2044,109 +2279,172 @@ ProcessUnattendInf(HINF hUnattendedInf)
     DWORD LineLength;
     HKEY hKey;
 
-    if (!SetupFindFirstLineW(hUnattendedInf,
+    if (!SetupFindFirstLineW(pSetupData->hSetupInf,
                              L"Unattend",
                              L"UnattendSetupEnabled",
                              &InfContext))
     {
-        DPRINT1("Error: Cant find UnattendSetupEnabled Key! %d\n", GetLastError());
-        return FALSE;
+        DPRINT1("Error: Cannot find UnattendSetupEnabled Key! %d\n", GetLastError());
+        return;
     }
 
     if (!SetupGetStringFieldW(&InfContext,
                               1,
                               szValue,
-                              sizeof(szValue) / sizeof(WCHAR),
+                              ARRAYSIZE(szValue),
                               &LineLength))
     {
         DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
-        return FALSE;
+        return;
     }
 
-    if (wcscmp(szValue, L"yes") != 0)
+    if (_wcsicmp(szValue, L"yes") != 0)
     {
         DPRINT("Unattend setup was disabled by UnattendSetupEnabled key.\n");
-        return FALSE;
+        return;
     }
 
-    if (!SetupFindFirstLineW(hUnattendedInf,
+    pSetupData->UnattendSetup = TRUE;
+
+    if (!SetupFindFirstLineW(pSetupData->hSetupInf,
                              L"Unattend",
                              NULL,
                              &InfContext))
     {
         DPRINT1("Error: SetupFindFirstLine failed %d\n", GetLastError());
-        return FALSE;
+        return;
     }
 
-
     do
     {
         if (!SetupGetStringFieldW(&InfContext,
                                   0,
                                   szName,
-                                  sizeof(szName) / sizeof(WCHAR),
+                                  ARRAYSIZE(szName),
                                   &LineLength))
         {
             DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
-            return FALSE;
+            return;
         }
 
         if (!SetupGetStringFieldW(&InfContext,
                                   1,
                                   szValue,
-                                  sizeof(szValue) / sizeof(WCHAR),
+                                  ARRAYSIZE(szValue),
                                   &LineLength))
         {
             DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
-            return FALSE;
+            return;
         }
         DPRINT1("Name %S Value %S\n", szName, szValue);
-        if (!wcscmp(szName, L"FullName"))
+        if (!_wcsicmp(szName, L"FullName"))
         {
-            if ((sizeof(SetupData.OwnerName) / sizeof(TCHAR)) > LineLength)
+            if (ARRAYSIZE(pSetupData->OwnerName) > LineLength)
             {
-                wcscpy(SetupData.OwnerName, szValue);
+                wcscpy(pSetupData->OwnerName, szValue);
             }
         }
-        else if (!wcscmp(szName, L"OrgName"))
+        else if (!_wcsicmp(szName, L"OrgName"))
         {
-            if ((sizeof(SetupData.OwnerOrganization) / sizeof(WCHAR)) > LineLength)
+            if (ARRAYSIZE(pSetupData->OwnerOrganization) > LineLength)
             {
-                wcscpy(SetupData.OwnerOrganization, szValue);
+                wcscpy(pSetupData->OwnerOrganization, szValue);
             }
         }
-        else if (!wcscmp(szName, L"ComputerName"))
+        else if (!_wcsicmp(szName, L"ComputerName"))
         {
-            if ((sizeof(SetupData.ComputerName) / sizeof(WCHAR)) > LineLength)
+            if (ARRAYSIZE(pSetupData->ComputerName) > LineLength)
             {
-                wcscpy(SetupData.ComputerName, szValue);
+                wcscpy(pSetupData->ComputerName, szValue);
             }
         }
-        else if (!wcscmp(szName, L"AdminPassword"))
+        else if (!_wcsicmp(szName, L"AdminPassword"))
         {
-            if ((sizeof(SetupData.AdminPassword) / sizeof(WCHAR)) > LineLength)
+            if (ARRAYSIZE(pSetupData->AdminPassword) > LineLength)
             {
-                wcscpy(SetupData.AdminPassword, szValue);
+                wcscpy(pSetupData->AdminPassword, szValue);
             }
         }
-        else if (!wcscmp(szName, L"TimeZoneIndex"))
+        else if (!_wcsicmp(szName, L"TimeZoneIndex"))
         {
-            SetupData.TimeZoneIndex = _wtoi(szValue);
+            pSetupData->TimeZoneIndex = _wtoi(szValue);
         }
-        else if (!wcscmp(szName, L"DisableAutoDaylightTimeSet"))
+        else if (!_wcsicmp(szName, L"DisableAutoDaylightTimeSet"))
         {
-            SetupData.DisableAutoDaylightTimeSet = _wtoi(szValue);
+            pSetupData->DisableAutoDaylightTimeSet = _wtoi(szValue);
         }
-        else if (!wcscmp(szName, L"DisableVmwInst"))
+        else if (!_wcsicmp(szName, L"DisableGeckoInst"))
         {
-            if(!wcscmp(szValue, L"yes"))
-                SetupData.DisableVmwInst = 1;
+            if (!_wcsicmp(szValue, L"yes"))
+                pSetupData->DisableGeckoInst = TRUE;
             else
-                SetupData.DisableVmwInst = 0;
+                pSetupData->DisableGeckoInst = FALSE;
         }
 
+    } while (SetupFindNextLine(&InfContext, &InfContext));
+
+    if (SetupFindFirstLineW(pSetupData->hSetupInf,
+                            L"Display",
+                            NULL,
+                            &InfContext))
+    {
+        DEVMODEW dm = { { 0 } };
+        dm.dmSize = sizeof(dm);
+        if (EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &dm))
+        {
+            do
+            {
+                int iValue;
+                if (!SetupGetStringFieldW(&InfContext,
+                                          0,
+                                          szName,
+                                          ARRAYSIZE(szName),
+                                          &LineLength))
+                {
+                    DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
+                    return;
+                }
+
+                if (!SetupGetStringFieldW(&InfContext,
+                                          1,
+                                          szValue,
+                                          ARRAYSIZE(szValue),
+                                          &LineLength))
+                {
+                    DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
+                    return;
+                }
+                iValue = _wtoi(szValue);
+                DPRINT1("Name %S Value %i\n", szName, iValue);
+
+                if (!iValue)
+                    continue;
+
+                if (!_wcsicmp(szName, L"BitsPerPel"))
+                {
+                    dm.dmFields |= DM_BITSPERPEL;
+                    dm.dmBitsPerPel = iValue;
+                }
+                else if (!_wcsicmp(szName, L"XResolution"))
+                {
+                    dm.dmFields |= DM_PELSWIDTH;
+                    dm.dmPelsWidth = iValue;
+                }
+                else if (!_wcsicmp(szName, L"YResolution"))
+                {
+                    dm.dmFields |= DM_PELSHEIGHT;
+                    dm.dmPelsHeight = iValue;
+                }
+                else if (!_wcsicmp(szName, L"VRefresh"))
+                {
+                    dm.dmFields |= DM_DISPLAYFREQUENCY;
+                    dm.dmDisplayFrequency = iValue;
+                }
+            } while (SetupFindNextLine(&InfContext, &InfContext));
+
+            ChangeDisplaySettingsW(&dm, CDS_UPDATEREGISTRY);
+        }
     }
-    while (SetupFindNextLine(&InfContext, &InfContext));
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
                       L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
@@ -2155,24 +2453,22 @@ ProcessUnattendInf(HINF hUnattendedInf)
                       &hKey) != ERROR_SUCCESS)
     {
         DPRINT1("Error: failed to open HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce\n");
-        return TRUE;
+        return;
     }
 
-
-    if (SetupFindFirstLineW(hUnattendedInf,
+    if (SetupFindFirstLineW(pSetupData->hSetupInf,
                             L"GuiRunOnce",
                             NULL,
                             &InfContext))
     {
-
         int i = 0;
         do
         {
-            if(SetupGetStringFieldW(&InfContext,
-                                    0,
-                                    szValue,
-                                    sizeof(szValue) / sizeof(WCHAR),
-                                    NULL))
+            if (SetupGetStringFieldW(&InfContext,
+                                     0,
+                                     szValue,
+                                     ARRAYSIZE(szValue),
+                                     NULL))
             {
                 WCHAR szPath[MAX_PATH];
                 swprintf(szName, L"%d", i);
@@ -2192,119 +2488,215 @@ ProcessUnattendInf(HINF hUnattendedInf)
                     }
                 }
             }
-        } while(SetupFindNextLine(&InfContext, &InfContext));
+        } while (SetupFindNextLine(&InfContext, &InfContext));
     }
 
     RegCloseKey(hKey);
-    return TRUE;
 }
 
-/*
- * GetRosInstallCD should find the path to ros installation medium
- * BUG 1
- * If there are more than one CDDrive in it containing a ReactOS
- * installation cd, then it will pick the first one regardless if
- * it is really the installation cd
- *
- * The best way to implement this is to set the key
- * HKLM\Software\Microsoft\Windows NT\CurrentVersion\SourcePath (REG_SZ)
- */
-
-BOOL
-GetRosInstallCD(WCHAR *pwszPath, DWORD cchPathMax)
+VOID
+ProcessSetupInf(
+    IN OUT PSETUPDATA pSetupData)
 {
-    WCHAR wszDrives[512];
-    DWORD cchDrives;
-    WCHAR *pwszDrive;
+    WCHAR szPath[MAX_PATH];
+    WCHAR szValue[MAX_PATH];
+    INFCONTEXT InfContext;
+    DWORD LineLength;
+    HKEY hKey;
+    LONG res;
 
-    cchDrives = GetLogicalDriveStringsW(_countof(wszDrives) - 1, wszDrives);
-    if (cchDrives == 0 || cchDrives >= _countof(wszDrives))
+    pSetupData->hSetupInf = INVALID_HANDLE_VALUE;
+
+    /* Retrieve the path of the setup INF */
+    GetSystemDirectoryW(szPath, _countof(szPath));
+    wcscat(szPath, L"\\$winnt$.inf");
+
+    /* Open the setup INF */
+    pSetupData->hSetupInf = SetupOpenInfFileW(szPath,
+                                              NULL,
+                                              INF_STYLE_OLDNT,
+                                              NULL);
+    if (pSetupData->hSetupInf == INVALID_HANDLE_VALUE)
     {
-        /* buffer too small or failure */
-        LogItem(SYSSETUP_SEVERITY_INFORMATION, L"GetLogicalDriveStringsW failed");
-        return FALSE;
+        DPRINT1("Error: Cannot open the setup information file %S with error %d\n", szPath, GetLastError());
+        return;
     }
 
-    for (pwszDrive = wszDrives; pwszDrive[0]; pwszDrive += wcslen(pwszDrive) + 1)
+
+    /* Retrieve the NT source path from which the 1st-stage installer was run */
+    if (!SetupFindFirstLineW(pSetupData->hSetupInf,
+                             L"data",
+                             L"sourcepath",
+                             &InfContext))
     {
-        if (GetDriveTypeW(pwszDrive) == DRIVE_CDROM)
-        {
-            WCHAR wszBuf[MAX_PATH];
-            wsprintf(wszBuf, L"%sreactos\\system32\\ntoskrnl.exe", pwszDrive);
-            LogItem(SYSSETUP_SEVERITY_INFORMATION, wszBuf);
-            if (GetFileAttributesW(wszBuf) != INVALID_FILE_ATTRIBUTES)
-            {
-                /* the file exists, so this is the right drive */
-                wcsncpy(pwszPath, pwszDrive, cchPathMax);
-                OutputDebugStringW(L"GetRosInstallCD: ");OutputDebugStringW(pwszPath);OutputDebugStringW(L"\n");
-                return TRUE;
-            }
-        }
+        DPRINT1("Error: Cannot find sourcepath Key! %d\n", GetLastError());
+        return;
     }
-    return FALSE;
-}
 
+    if (!SetupGetStringFieldW(&InfContext,
+                              1,
+                              szValue,
+                              ARRAYSIZE(szValue),
+                              &LineLength))
+    {
+        DPRINT1("Error: SetupGetStringField failed with %d\n", GetLastError());
+        return;
+    }
+
+    *pSetupData->SourcePath = UNICODE_NULL;
+
+    /* Close the setup INF as we are going to modify it manually */
+    if (pSetupData->hSetupInf != INVALID_HANDLE_VALUE)
+        SetupCloseInfFile(pSetupData->hSetupInf);
 
-VOID
-ProcessUnattendSetup(VOID)
-{
-    WCHAR szPath[MAX_PATH];
-    HINF hUnattendedInf;
-    DWORD dwLength;
 
-    if (!GetRosInstallCD(szPath, MAX_PATH))
+    /* Find the installation source path in Win32 format */
+    if (!GetInstallSourceWin32(pSetupData->SourcePath,
+                               _countof(pSetupData->SourcePath),
+                               szValue))
     {
-        /* no cd drive found */
-        return;
+        *pSetupData->SourcePath = UNICODE_NULL;
     }
 
-    dwLength = wcslen(szPath);
-    if (dwLength + 21 > MAX_PATH)
+    /* Save the path in Win32 format in the setup INF */
+    swprintf(szValue, L"\"%s\"", pSetupData->SourcePath);
+    WritePrivateProfileStringW(L"data", L"dospath", szValue, szPath);
+
+    /*
+     * Save it also in the registry, in the following keys:
+     * - HKLM\Software\Microsoft\Windows\CurrentVersion\Setup ,
+     *   values "SourcePath" and "ServicePackSourcePath" (REG_SZ);
+     * - HKLM\Software\Microsoft\Windows NT\CurrentVersion ,
+     *   value "SourcePath" (REG_SZ); set to the full path (e.g. D:\I386).
+     */
+#if 0
+    res = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                        L"Software\\Microsoft\\Windows NT\\CurrentVersion",
+                        0,
+                        KEY_ALL_ACCESS,
+                        &hKey);
+
+    if (res != ERROR_SUCCESS)
     {
-        /* FIXME
-         * allocate bigger buffer
-         */
-        return;
+        return FALSE;
     }
+#endif
 
-    wcscat(szPath, L"reactos\\unattend.inf");
+    res = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
+                          L"Software\\Microsoft\\Windows\\CurrentVersion\\Setup",
+                          0, NULL,
+                          REG_OPTION_NON_VOLATILE,
+                          KEY_ALL_ACCESS, // KEY_WRITE
+                          NULL,
+                          &hKey,
+                          NULL);
+    if (res == ERROR_SUCCESS)
+    {
+        res = RegSetValueExW(hKey,
+                             L"SourcePath",
+                             0,
+                             REG_SZ,
+                             (LPBYTE)pSetupData->SourcePath,
+                             (wcslen(pSetupData->SourcePath) + 1) * sizeof(WCHAR));
+
+        res = RegSetValueExW(hKey,
+                             L"ServicePackSourcePath",
+                             0,
+                             REG_SZ,
+                             (LPBYTE)pSetupData->SourcePath,
+                             (wcslen(pSetupData->SourcePath) + 1) * sizeof(WCHAR));
+
+        RegCloseKey(hKey);
+    }
 
-    hUnattendedInf = SetupOpenInfFileW(szPath,
-                                       NULL,
-                                       INF_STYLE_OLDNT,
-                                       NULL);
 
-    if (hUnattendedInf != INVALID_HANDLE_VALUE)
+    /* Now, re-open the setup INF (this must succeed) */
+    pSetupData->hSetupInf = SetupOpenInfFileW(szPath,
+                                              NULL,
+                                              INF_STYLE_OLDNT,
+                                              NULL);
+    if (pSetupData->hSetupInf == INVALID_HANDLE_VALUE)
     {
-        SetupData.UnattendSetup = ProcessUnattendInf(hUnattendedInf);
-        SetupCloseInfFile(hUnattendedInf);
+        DPRINT1("Error: Cannot open the setup information file %S with error %d\n", szPath, GetLastError());
+        return;
     }
+
+    /* Process the unattended section of the setup file */
+    ProcessUnattendSection(pSetupData);
 }
 
+typedef DWORD(WINAPI *PFNREQUESTWIZARDPAGES)(PDWORD, HPROPSHEETPAGE *, PSETUPDATA);
 
 VOID
 InstallWizard(VOID)
 {
     PROPSHEETHEADER psh;
-    HPROPSHEETPAGE ahpsp[8];
+    HPROPSHEETPAGE *phpage = NULL;
     PROPSHEETPAGE psp = {0};
     UINT nPages = 0;
     HWND hWnd;
     MSG msg;
+    PSETUPDATA pSetupData = NULL;
+    HMODULE hNetShell = NULL;
+    PFNREQUESTWIZARDPAGES pfn = NULL;
+    DWORD dwPageCount = 9, dwNetworkPageCount = 0;
+
+    LogItem(L"BEGIN_SECTION", L"InstallWizard");
+
+    /* Allocate setup data */
+    pSetupData = HeapAlloc(GetProcessHeap(),
+                           HEAP_ZERO_MEMORY,
+                           sizeof(SETUPDATA));
+    if (pSetupData == NULL)
+    {
+        LogItem(NULL, L"SetupData allocation failed!");
+        MessageBoxW(NULL,
+                    L"Setup failed to allocate global data!",
+                    L"ReactOS Setup",
+                    MB_ICONERROR | MB_OK);
+        goto done;
+    }
+
+    hNetShell = LoadLibraryW(L"netshell.dll");
+    if (hNetShell != NULL)
+    {
+        DPRINT("Netshell.dll loaded!\n");
+
+        pfn = (PFNREQUESTWIZARDPAGES)GetProcAddress(hNetShell,
+                                                    "NetSetupRequestWizardPages");
+        if (pfn != NULL)
+        {
+            pfn(&dwNetworkPageCount, NULL, NULL);
+            dwPageCount += dwNetworkPageCount;
+        }
+    }
 
-    /* Clear setup data */
-    ZeroMemory(&SetupData, sizeof(SETUPDATA));
+    DPRINT("PageCount: %lu\n", dwPageCount);
 
-    ProcessUnattendSetup();
+    phpage = HeapAlloc(GetProcessHeap(),
+                       HEAP_ZERO_MEMORY,
+                       dwPageCount * sizeof(HPROPSHEETPAGE));
+    if (phpage == NULL)
+    {
+        LogItem(NULL, L"Page array allocation failed!");
+        MessageBoxW(NULL,
+                    L"Setup failed to allocate page array!",
+                    L"ReactOS Setup",
+                    MB_ICONERROR | MB_OK);
+        goto done;
+    }
+
+    /* Process the $winnt$.inf setup file */
+    ProcessSetupInf(pSetupData);
 
     /* Create the Welcome page */
     psp.dwSize = sizeof(PROPSHEETPAGE);
     psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
     psp.hInstance = hDllInstance;
-    psp.lParam = (LPARAM)&SetupData;
+    psp.lParam = (LPARAM)pSetupData;
     psp.pfnDlgProc = WelcomeDlgProc;
     psp.pszTemplate = MAKEINTRESOURCE(IDD_WELCOMEPAGE);
-    ahpsp[nPages++] = CreatePropertySheetPage(&psp);
+    phpage[nPages++] = CreatePropertySheetPage(&psp);
 
     /* Create the Acknowledgements page */
     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
@@ -2312,7 +2704,15 @@ InstallWizard(VOID)
     psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_ACKSUBTITLE);
     psp.pszTemplate = MAKEINTRESOURCE(IDD_ACKPAGE);
     psp.pfnDlgProc = AckPageDlgProc;
-    ahpsp[nPages++] = CreatePropertySheetPage(&psp);
+    phpage[nPages++] = CreatePropertySheetPage(&psp);
+
+    /* Create the Locale page */
+    psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+    psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_LOCALETITLE);
+    psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_LOCALESUBTITLE);
+    psp.pfnDlgProc = LocalePageDlgProc;
+    psp.pszTemplate = MAKEINTRESOURCE(IDD_LOCALEPAGE);
+    phpage[nPages++] = CreatePropertySheetPage(&psp);
 
     /* Create the Owner page */
     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
@@ -2320,7 +2720,7 @@ InstallWizard(VOID)
     psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_OWNERSUBTITLE);
     psp.pszTemplate = MAKEINTRESOURCE(IDD_OWNERPAGE);
     psp.pfnDlgProc = OwnerPageDlgProc;
-    ahpsp[nPages++] = CreatePropertySheetPage(&psp);
+    phpage[nPages++] = CreatePropertySheetPage(&psp);
 
     /* Create the Computer page */
     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
@@ -2328,17 +2728,7 @@ InstallWizard(VOID)
     psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_COMPUTERSUBTITLE);
     psp.pfnDlgProc = ComputerPageDlgProc;
     psp.pszTemplate = MAKEINTRESOURCE(IDD_COMPUTERPAGE);
-    ahpsp[nPages++] = CreatePropertySheetPage(&psp);
-
-
-    /* Create the Locale page */
-    psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
-    psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_LOCALETITLE);
-    psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_LOCALESUBTITLE);
-    psp.pfnDlgProc = LocalePageDlgProc;
-    psp.pszTemplate = MAKEINTRESOURCE(IDD_LOCALEPAGE);
-    ahpsp[nPages++] = CreatePropertySheetPage(&psp);
-
+    phpage[nPages++] = CreatePropertySheetPage(&psp);
 
     /* Create the DateTime page */
     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
@@ -2346,8 +2736,24 @@ InstallWizard(VOID)
     psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_DATETIMESUBTITLE);
     psp.pfnDlgProc = DateTimePageDlgProc;
     psp.pszTemplate = MAKEINTRESOURCE(IDD_DATETIMEPAGE);
-    ahpsp[nPages++] = CreatePropertySheetPage(&psp);
+    phpage[nPages++] = CreatePropertySheetPage(&psp);
 
+    /* Create the theme selection page */
+    psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+    psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_THEMESELECTIONTITLE);
+    psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_THEMESELECTIONSUBTITLE);
+    psp.pfnDlgProc = ThemePageDlgProc;
+    psp.pszTemplate = MAKEINTRESOURCE(IDD_THEMEPAGE);
+    phpage[nPages++] = CreatePropertySheetPage(&psp);
+
+    pSetupData->uFirstNetworkWizardPage = IDD_PROCESSPAGE;
+    pSetupData->uPostNetworkWizardPage = IDD_PROCESSPAGE;
+
+    if (pfn)
+    {
+        pfn(&dwNetworkPageCount, &phpage[nPages], pSetupData);
+        nPages += dwNetworkPageCount;
+    }
 
     /* Create the Process page */
     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
@@ -2355,14 +2761,15 @@ InstallWizard(VOID)
     psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_PROCESSSUBTITLE);
     psp.pfnDlgProc = ProcessPageDlgProc;
     psp.pszTemplate = MAKEINTRESOURCE(IDD_PROCESSPAGE);
-    ahpsp[nPages++] = CreatePropertySheetPage(&psp);
-
+    phpage[nPages++] = CreatePropertySheetPage(&psp);
 
     /* Create the Finish page */
     psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
     psp.pfnDlgProc = FinishDlgProc;
     psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHPAGE);
-    ahpsp[nPages++] = CreatePropertySheetPage(&psp);
+    phpage[nPages++] = CreatePropertySheetPage(&psp);
+
+    ASSERT(nPages == dwPageCount);
 
     /* Create the property sheet */
     psh.dwSize = sizeof(PROPSHEETHEADER);
@@ -2371,12 +2778,13 @@ InstallWizard(VOID)
     psh.hwndParent = NULL;
     psh.nPages = nPages;
     psh.nStartPage = 0;
-    psh.phpage = ahpsp;
+    psh.phpage = phpage;
     psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
     psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER);
 
     /* Create title font */
-    SetupData.hTitleFont = CreateTitleFont();
+    pSetupData->hTitleFont = CreateTitleFont();
+    pSetupData->hBoldFont  = CreateBoldFont();
 
     /* Display the wizard */
     hWnd = (HWND)PropertySheet(&psh);
@@ -2384,14 +2792,30 @@ InstallWizard(VOID)
 
     while (GetMessage(&msg, NULL, 0, 0))
     {
-        if(!IsDialogMessage(hWnd, &msg))
+        if (!IsDialogMessage(hWnd, &msg))
         {
             TranslateMessage(&msg);
             DispatchMessage(&msg);
         }
     }
 
-    DeleteObject(SetupData.hTitleFont);
+    DeleteObject(pSetupData->hBoldFont);
+    DeleteObject(pSetupData->hTitleFont);
+
+    if (pSetupData->hSetupInf != INVALID_HANDLE_VALUE)
+        SetupCloseInfFile(pSetupData->hSetupInf);
+
+done:
+    if (phpage != NULL)
+        HeapFree(GetProcessHeap(), 0, phpage);
+
+    if (hNetShell != NULL)
+        FreeLibrary(hNetShell);
+
+    if (pSetupData != NULL)
+        HeapFree(GetProcessHeap(), 0, pSetupData);
+
+    LogItem(L"END_SECTION", L"InstallWizard");
 }
 
 /* EOF */