[REACTOS] Add features/usability additions.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 28 Jan 2018 22:47:25 +0000 (23:47 +0100)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 5 Nov 2018 23:09:16 +0000 (00:09 +0100)
- Interface the TreeList code and populate it with the list of
  discovered disks and partitions. Code is adapted from USETUP.
  Also display the names of the disks.

- Display some installation settings summary, before doing the
  installation proper.

- Force the user to select a checkbox when (s)he acknowledges that
  ReactOS is alpha-quality software and may break on his/her computer
  or corrupt his/her data.

- Improve wizard pages transitions and buttons enabling/disabling.

- Press Shift-F10 to start a command-line (as in the 2nd-stage setup
  in syssetup.dll).

- Use some explicit UNICODE functions/macros.

base/setup/reactos/CMakeLists.txt
base/setup/reactos/drivepage.c
base/setup/reactos/reactos.c
base/setup/reactos/reactos.h

index 8c58f9e..75418ed 100644 (file)
@@ -20,5 +20,5 @@ add_executable(reactos ${SOURCE} reactos.rc)
 set_module_type(reactos win32gui UNICODE)
 add_pch(reactos reactos.h SOURCE)
 target_link_libraries(reactos uuid setuplib ext2lib vfatlib btrfslib)
-add_importlibs(reactos advapi32 gdi32 user32 comctl32 setupapi msvcrt kernel32 ntdll)
+add_importlibs(reactos advapi32 gdi32 user32 comctl32 shlwapi setupapi msvcrt kernel32 ntdll)
 add_cd_file(TARGET reactos DESTINATION reactos NO_CAB FOR bootcd)
index cf79aa3..1da5771 100644 (file)
  */
 
 #include "reactos.h"
+#include <shlwapi.h>
+
+// #include <ntdddisk.h>
+#include <ntddstor.h>
+#include <ntddscsi.h>
+
 #include "resource.h"
 
 /* GLOBALS ******************************************************************/
 
 #define IDS_LIST_COLUMN_FIRST IDS_PARTITION_NAME
-#define IDS_LIST_COLUMN_LAST  IDS_PARTITION_TYPE
+#define IDS_LIST_COLUMN_LAST  IDS_PARTITION_STATUS
 
 #define MAX_LIST_COLUMNS (IDS_LIST_COLUMN_LAST - IDS_LIST_COLUMN_FIRST + 1)
-static const UINT column_ids[MAX_LIST_COLUMNS] = {IDS_LIST_COLUMN_FIRST, IDS_LIST_COLUMN_FIRST + 1, IDS_LIST_COLUMN_FIRST + 2};
-static const INT  column_widths[MAX_LIST_COLUMNS] = {200, 150, 150};
-static const INT  column_alignment[MAX_LIST_COLUMNS] = {LVCFMT_LEFT, LVCFMT_LEFT, LVCFMT_LEFT};
+static const UINT column_ids[MAX_LIST_COLUMNS] = {IDS_LIST_COLUMN_FIRST, IDS_LIST_COLUMN_FIRST + 1, IDS_LIST_COLUMN_FIRST + 2, IDS_LIST_COLUMN_FIRST + 3};
+static const INT  column_widths[MAX_LIST_COLUMNS] = {200, 90, 60, 60};
+static const INT  column_alignment[MAX_LIST_COLUMNS] = {LVCFMT_LEFT, LVCFMT_LEFT, LVCFMT_RIGHT, LVCFMT_RIGHT};
 
 /* FUNCTIONS ****************************************************************/
 
@@ -59,23 +65,19 @@ MoreOptDlgProc(HWND hwndDlg,
             SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pSetupData);
 
             CheckDlgButton(hwndDlg, IDC_INSTFREELDR, BST_CHECKED);
-            SendMessageW(GetDlgItem(hwndDlg, IDC_PATH),
-                         WM_SETTEXT,
-                         (WPARAM)0,
-                         (LPARAM)pSetupData->USetupData.InstallationDirectory);
+            SetDlgItemTextW(hwndDlg, IDC_PATH,
+                            pSetupData->USetupData.InstallationDirectory);
             break;
         }
 
         case WM_COMMAND:
-            switch(LOWORD(wParam))
+            switch (LOWORD(wParam))
             {
                 case IDOK:
                 {
-                    SendMessageW(GetDlgItem(hwndDlg, IDC_PATH),
-                                 WM_GETTEXT,
-                                 (WPARAM)ARRAYSIZE(pSetupData->USetupData.InstallationDirectory),
-                                 (LPARAM)pSetupData->USetupData.InstallationDirectory);
-
+                    GetDlgItemTextW(hwndDlg, IDC_PATH,
+                                    pSetupData->USetupData.InstallationDirectory,
+                                    ARRAYSIZE(pSetupData->USetupData.InstallationDirectory));
                     EndDialog(hwndDlg, IDOK);
                     return TRUE;
                 }
@@ -100,9 +102,10 @@ PartitionDlgProc(HWND hwndDlg,
     {
         case WM_INITDIALOG:
             break;
+
         case WM_COMMAND:
         {
-            switch(LOWORD(wParam))
+            switch (LOWORD(wParam))
             {
                 case IDOK:
                     EndDialog(hwndDlg, IDOK);
@@ -118,38 +121,469 @@ PartitionDlgProc(HWND hwndDlg,
 
 
 BOOL
-CreateListViewColumns(
+CreateTreeListColumns(
     IN HINSTANCE hInstance,
-    IN HWND hWndListView,
+    IN HWND hWndTreeList,
     IN const UINT* pIDs,
     IN const INT* pColsWidth,
     IN const INT* pColsAlign,
     IN UINT nNumOfColumns)
 {
     UINT i;
-    LVCOLUMN lvC;
+    TLCOLUMN tlC;
     WCHAR szText[50];
 
     /* Create the columns */
-    lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
-    lvC.pszText = szText;
+    tlC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
+    tlC.pszText = szText;
 
     /* Load the column labels from the resource file */
     for (i = 0; i < nNumOfColumns; i++)
     {
-        lvC.iSubItem = i;
-        lvC.cx = pColsWidth[i];
-        lvC.fmt = pColsAlign[i];
+        tlC.iSubItem = i;
+        tlC.cx = pColsWidth[i];
+        tlC.fmt = pColsAlign[i];
 
         LoadStringW(hInstance, pIDs[i], szText, ARRAYSIZE(szText));
 
-        if (ListView_InsertColumn(hWndListView, i, &lvC) == -1)
+        if (TreeList_InsertColumn(hWndTreeList, i, &tlC) == -1)
             return FALSE;
     }
 
     return TRUE;
 }
 
+// unused
+VOID
+DisplayStuffUsingWin32Setup(HWND hwndDlg)
+{
+    HDEVINFO h;
+    HWND hList;
+    SP_DEVINFO_DATA DevInfoData;
+    DWORD i;
+
+    h = SetupDiGetClassDevs(&GUID_DEVCLASS_DISKDRIVE, NULL, NULL, DIGCF_PRESENT);
+    if (h == INVALID_HANDLE_VALUE)
+        return;
+
+    hList = GetDlgItem(hwndDlg, IDC_PARTITION);
+    DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+    for (i=0; SetupDiEnumDeviceInfo(h, i, &DevInfoData); i++)
+    {
+        DWORD DataT;
+        LPTSTR buffer = NULL;
+        DWORD buffersize = 0;
+
+        while (!SetupDiGetDeviceRegistryProperty(h,
+                                                 &DevInfoData,
+                                                 SPDRP_DEVICEDESC,
+                                                 &DataT,
+                                                 (PBYTE)buffer,
+                                                 buffersize,
+                                                 &buffersize))
+        {
+            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+            {
+                if (buffer) LocalFree(buffer);
+                buffer = LocalAlloc(LPTR, buffersize * 2);
+            }
+            else
+            {
+                return;
+            }
+        }
+        if (buffer)
+        {
+            SendMessageW(hList, LB_ADDSTRING, (WPARAM)0, (LPARAM)buffer);
+            LocalFree(buffer);
+        }
+    }
+    SetupDiDestroyDeviceInfoList(h);
+}
+
+
+HTLITEM
+TreeListAddItem(IN HWND hTreeList,
+                IN HTLITEM hParent,
+                IN LPWSTR lpText,
+                IN INT iImage,
+                IN INT iSelectedImage,
+                IN LPARAM lParam)
+{
+    TL_INSERTSTRUCTW Insert;
+
+    ZeroMemory(&Insert, sizeof(Insert));
+
+    Insert.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+    Insert.hInsertAfter = TVI_LAST;
+    Insert.hParent = hParent;
+    Insert.item.pszText = lpText;
+    Insert.item.iImage = iImage;
+    Insert.item.iSelectedImage = iSelectedImage;
+    Insert.item.lParam = lParam;
+
+    // Insert.item.mask |= TVIF_STATE;
+    // Insert.item.stateMask = TVIS_OVERLAYMASK;
+    // Insert.item.state = INDEXTOOVERLAYMASK(1);
+
+    return TreeList_InsertItem(hTreeList, &Insert);
+}
+
+
+VOID
+GetPartTypeStringFromPartitionType(
+    IN UCHAR partitionType,
+    OUT PCHAR strPartType,
+    IN ULONG cchPartType)
+{
+    /* Determine partition type */
+
+    if (IsContainerPartition(partitionType))
+    {
+        StringCchCopyA(strPartType, cchPartType, "Extended Partition" /* MUIGetString(STRING_EXTENDED_PARTITION) */);
+    }
+    else if (partitionType == PARTITION_ENTRY_UNUSED)
+    {
+        StringCchCopyA(strPartType, cchPartType, "Unused" /* MUIGetString(STRING_FORMATUNUSED) */);
+    }
+    else
+    {
+        UINT i;
+
+        /* Do the table lookup */
+        for (i = 0; i < ARRAYSIZE(PartitionTypes); i++)
+        {
+            if (partitionType == PartitionTypes[i].Type)
+            {
+                StringCchCopyA(strPartType, cchPartType, PartitionTypes[i].Description);
+                return;
+            }
+        }
+
+        /* We are here because the partition type is unknown */
+        StringCchCopyA(strPartType, cchPartType, "Unknown" /* MUIGetString(STRING_FORMATUNKNOWN) */);
+    }
+}
+
+static
+HTLITEM
+PrintPartitionData(
+    IN HWND hWndList,
+    IN PPARTLIST List,
+    IN HTLITEM htiParent,
+    IN PDISKENTRY DiskEntry,
+    IN PPARTENTRY PartEntry)
+{
+    LARGE_INTEGER PartSize;
+    HTLITEM htiPart;
+    CHAR PartTypeString[32];
+    PCHAR PartType = PartTypeString;
+    WCHAR LineBuffer[128];
+
+    /* Volume name */
+    if (PartEntry->IsPartitioned == FALSE)
+    {
+        StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
+                         // MUIGetString(STRING_UNPSPACE),
+                         L"Unpartitioned space");
+    }
+    else
+    {
+        StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
+                         // MUIGetString(STRING_HDDINFOUNK5),
+                         L"%s (%c%c)",
+                         *PartEntry->VolumeLabel ? PartEntry->VolumeLabel : L"Partition",
+                         (PartEntry->DriveLetter == 0) ? L'-' : PartEntry->DriveLetter,
+                         (PartEntry->DriveLetter == 0) ? L'-' : L':');
+    }
+
+    htiPart = TreeListAddItem(hWndList, htiParent, LineBuffer,
+                              1, 1,
+                              (LPARAM)PartEntry);
+
+    /* Determine partition type */
+    *LineBuffer = 0;
+    if (PartEntry->IsPartitioned)
+    {
+        PartTypeString[0] = '\0';
+        if (PartEntry->New == TRUE)
+        {
+            PartType = "New (Unformatted)"; // MUIGetString(STRING_UNFORMATTED);
+        }
+        else if (PartEntry->IsPartitioned == TRUE)
+        {
+           GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
+                                              PartTypeString,
+                                              ARRAYSIZE(PartTypeString));
+           PartType = PartTypeString;
+        }
+
+        if (strcmp(PartType, "Unknown" /* MUIGetString(STRING_FORMATUNKNOWN) */) == 0)
+        {
+            StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
+                             // MUIGetString(STRING_HDDINFOUNK5),
+                             L"Type 0x%02x",
+                             PartEntry->PartitionType);
+        }
+        else
+        {
+            StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
+                             L"%S",
+                             PartType);
+        }
+    }
+    TreeList_SetItemText(hWndList, htiPart, 1, LineBuffer);
+
+    /* Format the disk size in KBs, MBs, etc... */
+    PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
+    if (StrFormatByteSizeW(PartSize.QuadPart, LineBuffer, ARRAYSIZE(LineBuffer)) == NULL)
+    {
+        /* We failed for whatever reason, do the hardcoded way */
+        PWCHAR Unit;
+
+#if 0
+        if (PartSize.QuadPart >= 10 * GB) /* 10 GB */
+        {
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, GB);
+            // Unit = MUIGetString(STRING_GB);
+            Unit = L"GB";
+        }
+        else
+#endif
+        if (PartSize.QuadPart >= 10 * MB) /* 10 MB */
+        {
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, MB);
+            // Unit = MUIGetString(STRING_MB);
+            Unit = L"MB";
+        }
+        else
+        {
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, KB);
+            // Unit = MUIGetString(STRING_KB);
+            Unit = L"KB";
+        }
+
+        StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
+                         L"%6lu %s",
+                         PartSize.u.LowPart,
+                         Unit);
+    }
+    TreeList_SetItemText(hWndList, htiPart, 2, LineBuffer);
+
+    /* Volume status */
+    *LineBuffer = 0;
+    if (PartEntry->IsPartitioned)
+    {
+        StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
+                         // MUIGetString(STRING_HDDINFOUNK5),
+                         PartEntry->BootIndicator ? L"Active" : L"");
+    }
+    TreeList_SetItemText(hWndList, htiPart, 3, LineBuffer);
+
+    return htiPart;
+}
+
+static
+VOID
+PrintDiskData(
+    IN HWND hWndList,
+    IN PPARTLIST List,
+    IN PDISKENTRY DiskEntry)
+{
+    BOOL Success;
+    HANDLE hDevice;
+    PCHAR DiskName = NULL;
+    ULONG Length = 0;
+    PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
+    PLIST_ENTRY PrimaryEntry, LogicalEntry;
+    ULARGE_INTEGER DiskSize;
+    HTLITEM htiDisk, htiPart;
+    WCHAR LineBuffer[128];
+    UCHAR outBuf[512];
+
+    StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
+                     // L"\\Device\\Harddisk%lu\\Partition%lu",
+                     L"\\\\.\\PhysicalDrive%lu",
+                     DiskEntry->DiskNumber);
+
+    hDevice = CreateFileW(
+                LineBuffer,                         // device interface name
+                GENERIC_READ /*| GENERIC_WRITE*/,   // dwDesiredAccess
+                FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
+                NULL,                               // lpSecurityAttributes
+                OPEN_EXISTING,                      // dwCreationDistribution
+                0,                                  // dwFlagsAndAttributes
+                NULL                                // hTemplateFile
+                );
+    if (hDevice != INVALID_HANDLE_VALUE)
+    {
+        STORAGE_PROPERTY_QUERY Query;
+
+        Query.PropertyId = StorageDeviceProperty;
+        Query.QueryType  = PropertyStandardQuery;
+
+        Success = DeviceIoControl(hDevice,
+                                  IOCTL_STORAGE_QUERY_PROPERTY,
+                                  &Query,
+                                  sizeof(Query),
+                                  &outBuf,
+                                  sizeof(outBuf),
+                                  &Length,
+                                  NULL);
+        if (Success)
+        {
+            PSTORAGE_DEVICE_DESCRIPTOR devDesc = (PSTORAGE_DEVICE_DESCRIPTOR)outBuf;
+            if (devDesc->ProductIdOffset)
+            {
+                DiskName = (PCHAR)&outBuf[devDesc->ProductIdOffset];
+                Length -= devDesc->ProductIdOffset;
+                DiskName[min(Length, strlen(DiskName))] = 0;
+                // ( i = devDesc->ProductIdOffset; p[i] != 0 && i < Length; i++ )
+            }
+        }
+
+        CloseHandle(hDevice);
+    }
+
+    if (DiskName && *DiskName)
+    {
+        if (DiskEntry->DriverName.Length > 0)
+        {
+            StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
+                             // MUIGetString(STRING_HDINFOPARTSELECT_1),
+                             L"Harddisk %lu (%S) (Port=%hu, Bus=%hu, Id=%hu) on %wZ",
+                             DiskEntry->DiskNumber,
+                             DiskName,
+                             DiskEntry->Port,
+                             DiskEntry->Bus,
+                             DiskEntry->Id,
+                             &DiskEntry->DriverName);
+        }
+        else
+        {
+            StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
+                             // MUIGetString(STRING_HDINFOPARTSELECT_2),
+                             L"Harddisk %lu (%S) (Port=%hu, Bus=%hu, Id=%hu)",
+                             DiskEntry->DiskNumber,
+                             DiskName,
+                             DiskEntry->Port,
+                             DiskEntry->Bus,
+                             DiskEntry->Id);
+        }
+    }
+    else
+    {
+        if (DiskEntry->DriverName.Length > 0)
+        {
+            StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
+                             // MUIGetString(STRING_HDINFOPARTSELECT_1),
+                             L"Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu) on %wZ",
+                             DiskEntry->DiskNumber,
+                             DiskEntry->Port,
+                             DiskEntry->Bus,
+                             DiskEntry->Id,
+                             &DiskEntry->DriverName);
+        }
+        else
+        {
+            StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
+                             // MUIGetString(STRING_HDINFOPARTSELECT_2),
+                             L"Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)",
+                             DiskEntry->DiskNumber,
+                             DiskEntry->Port,
+                             DiskEntry->Bus,
+                             DiskEntry->Id);
+        }
+    }
+
+    htiDisk = TreeListAddItem(hWndList, NULL, LineBuffer,
+                              0, 0,
+                              (LPARAM)DiskEntry);
+
+    /* Disk type (MBR or GPT) */
+    TreeList_SetItemText(hWndList, htiDisk, 1, DiskEntry->NoMbr ? L"GPT" : L"MBR");
+
+    /* Format the disk size in KBs, MBs, etc... */
+    DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
+    if (StrFormatByteSizeW(DiskSize.QuadPart, LineBuffer, ARRAYSIZE(LineBuffer)) == NULL)
+    {
+        /* We failed for whatever reason, do the hardcoded way */
+        PWCHAR Unit;
+
+        if (DiskSize.QuadPart >= 10 * GB) /* 10 GB */
+        {
+            DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, GB);
+            // Unit = MUIGetString(STRING_GB);
+            Unit = L"GB";
+        }
+        else
+        {
+            DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, MB);
+            if (DiskSize.QuadPart == 0)
+                DiskSize.QuadPart = 1;
+            // Unit = MUIGetString(STRING_MB);
+            Unit = L"MB";
+        }
+
+        StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
+                         L"%6lu %s",
+                         DiskSize.u.LowPart,
+                         Unit);
+    }
+    TreeList_SetItemText(hWndList, htiDisk, 2, LineBuffer);
+
+
+    /* Print partition lines */
+    for (PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
+         PrimaryEntry != &DiskEntry->PrimaryPartListHead;
+         PrimaryEntry = PrimaryEntry->Flink)
+    {
+        PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
+
+        htiPart = PrintPartitionData(hWndList, List, htiDisk,
+                                     DiskEntry, PrimaryPartEntry);
+
+        if (IsContainerPartition(PrimaryPartEntry->PartitionType))
+        {
+            for (LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
+                 LogicalEntry != &DiskEntry->LogicalPartListHead;
+                 LogicalEntry = LogicalEntry->Flink)
+            {
+                LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
+
+                PrintPartitionData(hWndList, List, htiPart,
+                                   DiskEntry, LogicalPartEntry);
+            }
+
+            /* Expand the extended partition node */
+            TreeList_Expand(hWndList, htiPart, TVE_EXPAND);
+        }
+    }
+
+    /* Expand the disk node */
+    TreeList_Expand(hWndList, htiDisk, TVE_EXPAND);
+}
+
+VOID
+DrawPartitionList(
+    IN HWND hWndList,
+    IN PPARTLIST List)
+{
+    PLIST_ENTRY Entry;
+    PDISKENTRY DiskEntry;
+
+    for (Entry = List->DiskListHead.Flink;
+         Entry != &List->DiskListHead;
+         Entry = Entry->Flink)
+    {
+        DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
+
+        /* Print disk entry */
+        PrintDiskData(hWndList, List, DiskEntry);
+    }
+}
+
+
 
 INT_PTR
 CALLBACK
@@ -160,12 +594,8 @@ DriveDlgProc(
     LPARAM lParam)
 {
     PSETUPDATA pSetupData;
-#if 1
-    HDEVINFO h;
     HWND hList;
-    SP_DEVINFO_DATA DevInfoData;
-    DWORD i;
-#endif
+    HIMAGELIST hSmall;
 
     /* Retrieve pointer to the global setup data */
     pSetupData = (PSETUPDATA)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
@@ -178,70 +608,70 @@ DriveDlgProc(
             pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
             SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pSetupData);
 
-            CreateListViewColumns(pSetupData->hInstance,
-                                  GetDlgItem(hwndDlg, IDC_PARTITION),
+            /*
+             * Keep the "Next" button disabled. It will be enabled only
+             * when the user selects a valid partition.
+             */
+            PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
+
+            hList = GetDlgItem(hwndDlg, IDC_PARTITION);
+
+            TreeList_SetExtendedStyleEx(hList, TVS_EX_FULLROWMARK, TVS_EX_FULLROWMARK);
+            // TreeList_SetExtendedStyleEx(hList, TVS_EX_FULLROWITEMS, TVS_EX_FULLROWITEMS);
+
+            CreateTreeListColumns(pSetupData->hInstance,
+                                  hList,
                                   column_ids,
                                   column_widths,
                                   column_alignment,
                                   MAX_LIST_COLUMNS);
 
-#if 1
-            h = SetupDiGetClassDevs(&GUID_DEVCLASS_DISKDRIVE, NULL, NULL, DIGCF_PRESENT);
-            if (h != INVALID_HANDLE_VALUE)
-            {
-                hList =GetDlgItem(hwndDlg, IDC_PARTITION); 
-                DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
-                for (i=0; SetupDiEnumDeviceInfo(h, i, &DevInfoData); i++)
-                {
-                    DWORD DataT;
-                    LPTSTR buffer = NULL;
-                    DWORD buffersize = 0;
-
-                    while (!SetupDiGetDeviceRegistryProperty(h,
-                                                             &DevInfoData,
-                                                             SPDRP_DEVICEDESC,
-                                                             &DataT,
-                                                             (PBYTE)buffer,
-                                                             buffersize,
-                                                             &buffersize))
-                    {
-                        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-                        {
-                            if (buffer) LocalFree(buffer);
-                            buffer = LocalAlloc(LPTR, buffersize * 2);
-                        }
-                        else
-                            break;
-                    }
-                    if (buffer)
-                    {
-                        SendMessageW(hList, LB_ADDSTRING, (WPARAM) 0, (LPARAM) buffer);
-                        LocalFree(buffer);
-                    }
-                }
-                SetupDiDestroyDeviceInfoList(h);
-            }
-#endif
+            /* Create the ImageList */
+            hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
+                                      GetSystemMetrics(SM_CYSMICON),
+                                      ILC_COLOR32 | ILC_MASK, // ILC_COLOR24
+                                      1, 1);
+
+            /* Add event type icons to the ImageList */
+            ImageList_AddIcon(hSmall, LoadIconW(pSetupData->hInstance, MAKEINTRESOURCEW(IDI_DISKDRIVE)));
+            ImageList_AddIcon(hSmall, LoadIconW(pSetupData->hInstance, MAKEINTRESOURCEW(IDI_PARTITION)));
+
+            /* Assign the ImageList to the List View */
+            TreeList_SetImageList(hList, hSmall, TVSIL_NORMAL);
+
+            // DisplayStuffUsingWin32Setup(hwndDlg);
+            DrawPartitionList(hList, pSetupData->PartitionList);
+            break;
+        }
+
+        case WM_DESTROY:
+        {
+            hList = GetDlgItem(hwndDlg, IDC_PARTITION);
+            hSmall = TreeList_GetImageList(hList, TVSIL_NORMAL);
+            TreeList_SetImageList(hList, NULL, TVSIL_NORMAL);
+            ImageList_Destroy(hSmall);
+            return TRUE;
         }
-        break;
 
         case WM_COMMAND:
         {
-            switch(LOWORD(wParam))
+            switch (LOWORD(wParam))
             {
                 case IDC_PARTMOREOPTS:
-                    DialogBoxParam(pSetupData->hInstance,
-                                   MAKEINTRESOURCE(IDD_BOOTOPTIONS),
-                                   hwndDlg,
-                                   MoreOptDlgProc,
-                                   (LPARAM)pSetupData);
+                    DialogBoxParamW(pSetupData->hInstance,
+                                    MAKEINTRESOURCEW(IDD_BOOTOPTIONS),
+                                    hwndDlg,
+                                    MoreOptDlgProc,
+                                    (LPARAM)pSetupData);
                     break;
+
                 case IDC_PARTCREATE:
-                    DialogBox(pSetupData->hInstance,
-                              MAKEINTRESOURCE(IDD_PARTITION),
-                              hwndDlg,
-                              PartitionDlgProc);
+                    DialogBoxW(pSetupData->hInstance,
+                               MAKEINTRESOURCEW(IDD_PARTITION),
+                               hwndDlg,
+                               PartitionDlgProc);
                     break;
+
                 case IDC_PARTDELETE:
                     break;
             }
@@ -252,11 +682,83 @@ DriveDlgProc(
         {
             LPNMHDR lpnm = (LPNMHDR)lParam;
 
+            // On Vista+ we can use TVN_ITEMCHANGED instead, with  NMTVITEMCHANGE* pointer
+            if (lpnm->idFrom == IDC_PARTITION && lpnm->code == TVN_SELCHANGED)
+            {
+                LPNMTREEVIEW pnmv = (LPNMTREEVIEW)lParam;
+
+                // if (pnmv->uChanged & TVIF_STATE) /* The state has changed */
+                if (pnmv->itemNew.mask & TVIF_STATE)
+                {
+                    /* The item has been (de)selected */
+                    // if (pnmv->uNewState & TVIS_SELECTED)
+                    if (pnmv->itemNew.state & TVIS_SELECTED)
+                    {
+                        HTLITEM hParentItem = TreeList_GetParent(lpnm->hwndFrom, pnmv->itemNew.hItem);
+                        /* May or may not be a PPARTENTRY: this is a PPARTENTRY only when hParentItem != NULL */
+                        PPARTENTRY PartEntry = (PPARTENTRY)pnmv->itemNew.lParam;
+
+                        if (!hParentItem || !PartEntry)
+                        {
+                            EnableWindow(GetDlgItem(hwndDlg, IDC_PARTCREATE), TRUE);
+                            EnableWindow(GetDlgItem(hwndDlg, IDC_PARTDELETE), FALSE);
+                            goto DisableWizNext;
+                        }
+                        else // if (hParentItem && PartEntry)
+                        {
+                            EnableWindow(GetDlgItem(hwndDlg, IDC_PARTCREATE), !PartEntry->IsPartitioned);
+                            EnableWindow(GetDlgItem(hwndDlg, IDC_PARTDELETE),  PartEntry->IsPartitioned);
+
+                            if (PartEntry->IsPartitioned &&
+                                !IsContainerPartition(PartEntry->PartitionType) /* alternatively: PartEntry->PartitionNumber != 0 */ &&
+                                // !PartEntry->New &&
+                                (PartEntry->FormatState == Preformatted /* || PartEntry->FormatState == Formatted */))
+                            {
+                                PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+                            }
+                            else
+                            {
+                                goto DisableWizNext;
+                            }
+                        }
+                    }
+                    else
+                    {
+DisableWizNext:
+                        /*
+                         * Keep the "Next" button disabled. It will be enabled only
+                         * when the user selects a valid partition.
+                         */
+                        PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
+                    }
+                }
+
+                break;
+            }
+
             switch (lpnm->code)
-            {        
+            {
+#if 0
                 case PSN_SETACTIVE:
-                    PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+                {
+                    /*
+                     * Keep the "Next" button disabled. It will be enabled only
+                     * when the user selects a valid partition.
+                     */
+                    PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
                     break;
+                }
+#endif
+
+                case PSN_QUERYINITIALFOCUS:
+                {
+                    /* Give the focus on and select the first item */
+                    hList = GetDlgItem(hwndDlg, IDC_PARTITION);
+                    // TreeList_SetFocusItem(hList, 1, 1);
+                    TreeList_SelectItem(hList, 1);
+                    SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)hList);
+                    return TRUE;
+                }
 
                 case PSN_QUERYCANCEL:
                 {
@@ -274,6 +776,28 @@ DriveDlgProc(
                     return TRUE;
                 }
 
+                case PSN_WIZNEXT: /* Set the selected data */
+                {
+                    NTSTATUS Status;
+
+                    /****/
+                    // FIXME: This is my test disk encoding!
+                    DISKENTRY DiskEntry;
+                    PARTENTRY PartEntry;
+                    DiskEntry.DiskNumber = 0;
+                    DiskEntry.BiosDiskNumber = 0;
+                    PartEntry.PartitionNumber = 1; // 4;
+                    /****/
+
+                    Status = InitDestinationPaths(&pSetupData->USetupData,
+                                                  NULL, // pSetupData->USetupData.InstallationDirectory,
+                                                  &DiskEntry, &PartEntry);
+                    // TODO: Check Status
+                    UNREFERENCED_PARAMETER(Status);
+
+                    break;
+                }
+
                 default:
                     break;
             }
@@ -282,7 +806,6 @@ DriveDlgProc(
 
         default:
             break;
-
     }
 
     return FALSE;
index 230eafa..55b18a2 100644 (file)
@@ -124,15 +124,15 @@ StartDlgProc(
             pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
             SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pSetupData);
 
-            /* Center the wizard window */
-            CenterWindow(GetParent(hwndDlg));
-
             /* Set title font */
             SendDlgItemMessage(hwndDlg,
                                IDC_STARTTITLE,
                                WM_SETFONT,
                                (WPARAM)pSetupData->hTitleFont,
                                (LPARAM)TRUE);
+
+            /* Center the wizard window */
+            CenterWindow(GetParent(hwndDlg));
             break;
         }
 
@@ -212,6 +212,13 @@ TypeDlgProc(
                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
                     break;
 
+                case PSN_QUERYINITIALFOCUS:
+                {
+                    /* Focus on "Install ReactOS" */
+                    SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_INSTALL));
+                    return TRUE;
+                }
+
                 case PSN_QUERYCANCEL:
                 {
                     if (MessageBoxW(GetParent(hwndDlg),
@@ -230,23 +237,40 @@ TypeDlgProc(
 
                 case PSN_WIZNEXT: /* Set the selected data */
                 {
-                    pSetupData->RepairUpdateFlag =
-                        !(SendMessageW(GetDlgItem(hwndDlg, IDC_INSTALL),
-                                       BM_GETCHECK,
-                                       0, 0) == BST_CHECKED);
-
                     /*
-                     * Display the existing NT installations page only
-                     * if we have more than one available NT installations.
+                     * Go update only if we have available NT installations
+                     * and we choose to do so.
                      */
                     if (pSetupData->NtOsInstallsList &&
-                        GetNumberOfListEntries(pSetupData->NtOsInstallsList) > 1)
+                        GetNumberOfListEntries(pSetupData->NtOsInstallsList) != 0 &&
+                        IsDlgButtonChecked(hwndDlg, IDC_UPDATE) == BST_CHECKED)
                     {
-                        /* Actually the best would be to dynamically insert the page only when needed */
-                        SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, IDD_UPDATEREPAIRPAGE);
+                        pSetupData->RepairUpdateFlag = TRUE;
+
+                        /*
+                         * Display the existing NT installations page only
+                         * if we have more than one available NT installations.
+                         */
+                        if (GetNumberOfListEntries(pSetupData->NtOsInstallsList) > 1)
+                        {
+                            /* pSetupData->CurrentInstallation will be set from within IDD_UPDATEREPAIRPAGE */
+
+                            /* Actually the best would be to dynamically insert the page only when needed */
+                            SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, IDD_UPDATEREPAIRPAGE);
+                        }
+                        else
+                        {
+                            /* Retrieve the current installation */
+                            pSetupData->CurrentInstallation =
+                                (PNTOS_INSTALLATION)GetListEntryData(GetCurrentListEntry(pSetupData->NtOsInstallsList));
+
+                            SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, IDD_DEVICEPAGE);
+                        }
                     }
                     else
                     {
+                        pSetupData->CurrentInstallation = NULL;
+                        pSetupData->RepairUpdateFlag = FALSE;
                         SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, IDD_DEVICEPAGE);
                     }
 
@@ -268,6 +292,39 @@ TypeDlgProc(
 
 
 
+BOOL
+CreateListViewColumns(
+    IN HINSTANCE hInstance,
+    IN HWND hWndListView,
+    IN const UINT* pIDs,
+    IN const INT* pColsWidth,
+    IN const INT* pColsAlign,
+    IN UINT nNumOfColumns)
+{
+    UINT i;
+    LVCOLUMN lvC;
+    WCHAR szText[50];
+
+    /* Create the columns */
+    lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
+    lvC.pszText = szText;
+
+    /* Load the column labels from the resource file */
+    for (i = 0; i < nNumOfColumns; i++)
+    {
+        lvC.iSubItem = i;
+        lvC.cx = pColsWidth[i];
+        lvC.fmt = pColsAlign[i];
+
+        LoadStringW(hInstance, pIDs[i], szText, ARRAYSIZE(szText));
+
+        if (ListView_InsertColumn(hWndListView, i, &lvC) == -1)
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
 typedef VOID
 (NTAPI *PGET_ENTRY_DESCRIPTION)(
     IN PGENERIC_LIST_ENTRY Entry,
@@ -312,19 +369,17 @@ InitGenericComboList(
     SendMessageW(hWndList, CB_SETCURSEL, CurrentEntryIndex, 0);
 }
 
-INT
+PVOID
 GetSelectedComboListItem(
     IN HWND hWndList)
 {
-    LRESULT Index;
+    INT Index;
 
-    Index = SendMessageW(hWndList, CB_GETCURSEL, 0, 0);
+    Index = ComboBox_GetCurSel(hWndList);
     if (Index == CB_ERR)
-        return CB_ERR;
+        return NULL;
 
-    // TODO: Update List->CurrentEntry?
-    // return SendMessageW(hWndList, CB_GETITEMDATA, (WPARAM)Index, 0);
-    return Index;
+    return (PVOID)ComboBox_GetItemData(hWndList, Index);
 }
 
 typedef VOID
@@ -366,9 +421,28 @@ InitGenericListView(
             CurrentEntryIndex = lvItem.iItem;
     }
 
-    SendMessageW(hWndList, LVM_ENSUREVISIBLE, CurrentEntryIndex, FALSE);
-    ListView_SetItemState(hWndList, CurrentEntryIndex, LVIS_SELECTED, LVIS_SELECTED);
-    ListView_SetItemState(hWndList, CurrentEntryIndex, LVIS_FOCUSED, LVIS_FOCUSED);
+    ListView_EnsureVisible(hWndList, CurrentEntryIndex, FALSE);
+    ListView_SetItemState(hWndList, CurrentEntryIndex,
+                          LVIS_FOCUSED | LVIS_SELECTED,
+                          LVIS_FOCUSED | LVIS_SELECTED);
+}
+
+PVOID
+GetSelectedListViewItem(
+    IN HWND hWndList)
+{
+    INT Index;
+    LVITEM item;
+
+    Index = ListView_GetSelectionMark(hWndList);
+    if (Index == LB_ERR)
+        return NULL;
+
+    item.mask = LVIF_PARAM;
+    item.iItem = Index;
+    ListView_GetItem(hWndList, &item);
+
+    return (PVOID)item.lParam;
 }
 
 
@@ -399,7 +473,7 @@ AddNTOSInstallationItem(
     {
         /* We have retrieved a partition that is mounted */
         StringCchPrintfW(Buffer, cchBufferSize,
-                         L"%C:%s",
+                         L"%c:%s",
                          PartEntry->DriveLetter,
                          NtOsInstall->PathComponent);
     }
@@ -471,8 +545,16 @@ UpgradeRepairDlgProc(
             pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
             SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pSetupData);
 
+            /*
+             * Keep the "Next" button disabled. It will be enabled only
+             * when the user selects an installation to upgrade.
+             */
+            PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
+
             hList = GetDlgItem(hwndDlg, IDC_NTOSLIST);
 
+            ListView_SetExtendedListViewStyleEx(hList, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
+
             CreateListViewColumns(pSetupData->hInstance,
                                   hList,
                                   column_ids,
@@ -494,7 +576,6 @@ UpgradeRepairDlgProc(
             ListView_SetImageList(hList, hSmall, LVSIL_SMALL);
 
             InitGenericListView(hList, pSetupData->NtOsInstallsList, AddNTOSInstallationItem);
-
             break;
         }
 
@@ -507,15 +588,70 @@ UpgradeRepairDlgProc(
             return TRUE;
         }
 
+        case WM_COMMAND:
+            switch (LOWORD(wParam))
+            {
+                case IDC_SKIPUPGRADE:
+                {
+                    /* Skip the upgrade and do the usual new-installation workflow */
+                    pSetupData->CurrentInstallation = NULL;
+                    pSetupData->RepairUpdateFlag = FALSE;
+                    PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_DEVICEPAGE);
+                    return TRUE;
+                }
+            }
+            break;
+
         case WM_NOTIFY:
         {
             LPNMHDR lpnm = (LPNMHDR)lParam;
 
+            if (lpnm->idFrom == IDC_NTOSLIST && lpnm->code == LVN_ITEMCHANGED)
+            {
+                LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
+
+                if (pnmv->uChanged & LVIF_STATE) /* The state has changed */
+                {
+                    /* The item has been (de)selected */
+                    if (pnmv->uNewState & (LVIS_FOCUSED | LVIS_SELECTED))
+                    {
+                        PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+                    }
+                    else
+                    {
+                        /*
+                         * Keep the "Next" button disabled. It will be enabled only
+                         * when the user selects an installation to upgrade.
+                         */
+                        PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
+                    }
+                }
+
+                break;
+            }
+
             switch (lpnm->code)
             {
+#if 0
                 case PSN_SETACTIVE:
-                    PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+                {
+                    /*
+                     * Keep the "Next" button disabled. It will be enabled only
+                     * when the user selects an installation to upgrade.
+                     */
+                    PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
                     break;
+                }
+#endif
+
+                case PSN_QUERYINITIALFOCUS:
+                {
+                    /* Give the focus on and select the first item */
+                    hList = GetDlgItem(hwndDlg, IDC_NTOSLIST);
+                    ListView_SetItemState(hList, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
+                    SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)hList);
+                    return TRUE;
+                }
 
                 case PSN_QUERYCANCEL:
                 {
@@ -534,11 +670,31 @@ UpgradeRepairDlgProc(
                 }
 
                 case PSN_WIZNEXT: /* Set the selected data */
-                    pSetupData->RepairUpdateFlag =
-                        !(SendMessageW(GetDlgItem(hwndDlg, IDC_INSTALL),
-                                       BM_GETCHECK,
-                                       0, 0) == BST_CHECKED);
+                {
+                    /*
+                     * Go update only if we have available NT installations
+                     * and we choose to do so.
+                     */
+                    if (!pSetupData->NtOsInstallsList ||
+                        GetNumberOfListEntries(pSetupData->NtOsInstallsList) == 0)
+                    {
+                        pSetupData->CurrentInstallation = NULL;
+                        pSetupData->RepairUpdateFlag = FALSE;
+                        break;
+                    }
+
+                    hList = GetDlgItem(hwndDlg, IDC_NTOSLIST);
+                    SetCurrentListEntry(pSetupData->NtOsInstallsList,
+                                        GetSelectedListViewItem(hList));
+
+                    /* Retrieve the current installation */
+                    pSetupData->CurrentInstallation =
+                        (PNTOS_INSTALLATION)GetListEntryData(GetCurrentListEntry(pSetupData->NtOsInstallsList));
+
+                    /* We perform an upgrade */
+                    pSetupData->RepairUpdateFlag = TRUE;
                     return TRUE;
+                }
 
                 default:
                     break;
@@ -599,6 +755,13 @@ DeviceDlgProc(
                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
                     break;
 
+                case PSN_QUERYINITIALFOCUS:
+                {
+                    /* Focus on "Computer" list */
+                    SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_COMPUTER));
+                    return TRUE;
+                }
+
                 case PSN_QUERYCANCEL:
                 {
                     if (MessageBoxW(GetParent(hwndDlg),
@@ -618,13 +781,20 @@ DeviceDlgProc(
                 case PSN_WIZNEXT: /* Set the selected data */
                 {
                     hList = GetDlgItem(hwndDlg, IDC_COMPUTER);
-                    pSetupData->SelectedComputer = GetSelectedComboListItem(hList);
+                    SetCurrentListEntry(pSetupData->USetupData.ComputerList,
+                                        GetSelectedComboListItem(hList));
 
                     hList = GetDlgItem(hwndDlg, IDC_DISPLAY);
-                    pSetupData->SelectedDisplay = GetSelectedComboListItem(hList);
+                    SetCurrentListEntry(pSetupData->USetupData.DisplayList,
+                                        GetSelectedComboListItem(hList));
 
                     hList = GetDlgItem(hwndDlg, IDC_KEYBOARD);
-                    pSetupData->SelectedKeyboard = GetSelectedComboListItem(hList);
+                    SetCurrentListEntry(pSetupData->USetupData.KeyboardList,
+                                        GetSelectedComboListItem(hList));
+
+                    // hList = GetDlgItem(hwndDlg, IDC_KEYBOARD_LAYOUT);
+                    // SetCurrentListEntry(pSetupData->USetupData.LayoutList,
+                    //                     GetSelectedComboListItem(hList));
 
                     return TRUE;
                 }
@@ -649,6 +819,8 @@ SummaryDlgProc(
     IN WPARAM wParam,
     IN LPARAM lParam)
 {
+    static WCHAR szOrgWizNextBtnText[260]; // TODO: Make it dynamic
+
     PSETUPDATA pSetupData;
 
     /* Retrieve pointer to the global setup data */
@@ -657,10 +829,24 @@ SummaryDlgProc(
     switch (uMsg)
     {
         case WM_INITDIALOG:
+        {
             /* Save pointer to the global setup data */
             pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
             SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pSetupData);
             break;
+        }
+
+        case WM_COMMAND:
+        {
+            if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_CONFIRM_INSTALL)
+            {
+                if (IsDlgButtonChecked(hwndDlg, IDC_CONFIRM_INSTALL) == BST_CHECKED)
+                    PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+                else
+                    PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
+            }
+            break;
+        }
 
         case WM_NOTIFY:
         {
@@ -669,8 +855,92 @@ SummaryDlgProc(
             switch (lpnm->code)
             {
                 case PSN_SETACTIVE:
-                    PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+                {
+                    WCHAR CurrentItemText[256];
+
+                    /* Show the current selected settings */
+
+                    // FIXME! Localize
+                    if (pSetupData->RepairUpdateFlag)
+                    {
+                        StringCchPrintfW(CurrentItemText, ARRAYSIZE(CurrentItemText),
+                                         L"Upgrading/Repairing \"%s\" from \"%s\"",
+                                         pSetupData->CurrentInstallation->InstallationName,
+                                         pSetupData->CurrentInstallation->VendorName);
+                    }
+                    else
+                    {
+                        StringCchCopyW(CurrentItemText, ARRAYSIZE(CurrentItemText),
+                                       L"New ReactOS installation");
+                    }
+                    SetDlgItemTextW(hwndDlg, IDC_INSTALLTYPE, CurrentItemText);
+
+                    SetDlgItemTextW(hwndDlg, IDC_INSTALLSOURCE, L"n/a");
+                    SetDlgItemTextW(hwndDlg, IDC_ARCHITECTURE, L"n/a");
+
+                    GetSettingDescription(GetCurrentListEntry(pSetupData->USetupData.ComputerList),
+                                          CurrentItemText,
+                                          ARRAYSIZE(CurrentItemText));
+                    SetDlgItemTextW(hwndDlg, IDC_COMPUTER, CurrentItemText);
+
+                    GetSettingDescription(GetCurrentListEntry(pSetupData->USetupData.DisplayList),
+                                          CurrentItemText,
+                                          ARRAYSIZE(CurrentItemText));
+                    SetDlgItemTextW(hwndDlg, IDC_DISPLAY, CurrentItemText);
+
+                    GetSettingDescription(GetCurrentListEntry(pSetupData->USetupData.KeyboardList),
+                                          CurrentItemText,
+                                          ARRAYSIZE(CurrentItemText));
+                    SetDlgItemTextW(hwndDlg, IDC_KEYBOARD, CurrentItemText);
+
+                    if (L'C') // FIXME!
+                    {
+                        StringCchPrintfW(CurrentItemText, ARRAYSIZE(CurrentItemText),
+                                         L"%c: \x2014 %wZ",
+                                         L'C', // FIXME!
+                                         &pSetupData->USetupData.DestinationRootPath);
+                    }
+                    else
+                    {
+                        StringCchPrintfW(CurrentItemText, ARRAYSIZE(CurrentItemText),
+                                         L"%wZ",
+                                         &pSetupData->USetupData.DestinationRootPath);
+                    }
+                    SetDlgItemTextW(hwndDlg, IDC_DESTDRIVE, CurrentItemText);
+
+                    SetDlgItemTextW(hwndDlg, IDC_PATH,
+                                    /*pSetupData->USetupData.InstallationDirectory*/
+                                    pSetupData->USetupData.InstallPath.Buffer);
+
+
+                    /* Change the "Next" button text to "Install" */
+                    // PropSheet_SetNextText(GetParent(hwndDlg), ...);
+                    GetDlgItemTextW(GetParent(hwndDlg), ID_WIZNEXT,
+                                    szOrgWizNextBtnText, ARRAYSIZE(szOrgWizNextBtnText));
+                    SetDlgItemTextW(GetParent(hwndDlg), ID_WIZNEXT, L"Install"); // FIXME: Localize!
+
+                    /*
+                     * Keep the "Next" button disabled. It will be enabled only
+                     * when the user clicks on the installation approval checkbox.
+                     */
+                    CheckDlgButton(hwndDlg, IDC_CONFIRM_INSTALL, BST_UNCHECKED);
+                    PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
                     break;
+                }
+
+                case PSN_QUERYINITIALFOCUS:
+                {
+                    /* Focus on the confirmation check-box */
+                    SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_CONFIRM_INSTALL));
+                    return TRUE;
+                }
+
+                case PSN_KILLACTIVE:
+                {
+                    /* Restore the original "Next" button text */
+                    SetDlgItemTextW(GetParent(hwndDlg), ID_WIZNEXT, szOrgWizNextBtnText);
+                    break;
+                }
 
                 case PSN_QUERYCANCEL:
                 {
@@ -691,8 +961,8 @@ SummaryDlgProc(
                 default:
                     break;
             }
+            break;
         }
-        break;
 
         default:
             break;
@@ -832,13 +1102,18 @@ PrepareAndDoCopyThread(
     /* Retrieve pointer to the global setup data */
     pSetupData = (PSETUPDATA)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
 
+    /* Get the progress handle */
+    hWndProgress = GetDlgItem(hwndDlg, IDC_PROCESSPROGRESS);
+
+
+    /*
+     * Preparation of the list of files to be copied
+     */
+
     /* Set status text */
     SetDlgItemTextW(hwndDlg, IDC_ACTIVITY, L"Preparing the list of files to be copied, please wait...");
     SetDlgItemTextW(hwndDlg, IDC_ITEM, L"");
 
-    /* Get the progress handle */
-    hWndProgress = GetDlgItem(hwndDlg, IDC_PROCESSPROGRESS);
-
     /* Set progress marquee style */
     dwStyle = GetWindowLongPtrW(hWndProgress, GWL_STYLE);
     SetWindowLongPtrW(hWndProgress, GWL_STYLE, dwStyle | PBS_MARQUEE);
@@ -876,8 +1151,14 @@ PrepareAndDoCopyThread(
     /* Restore progress style */
     SetWindowLongPtrW(hWndProgress, GWL_STYLE, dwStyle);
 
+
+    /*
+     * Perform the file copy
+     */
+
     /* Set status text */
     SetDlgItemTextW(hwndDlg, IDC_ACTIVITY, L"Copying the files...");
+    SetDlgItemTextW(hwndDlg, IDC_ITEM, L"");
 
     /* Create context for the copy process */
     CopyContext.pSetupData = pSetupData;
@@ -932,16 +1213,6 @@ ProcessDlgProc(
     {
         case WM_INITDIALOG:
         {
-            NTSTATUS Status;
-            /****/
-            // FIXME: This is my disk encoding!
-            DISKENTRY DiskEntry;
-            PARTENTRY PartEntry;
-            DiskEntry.DiskNumber = 1;
-            DiskEntry.BiosDiskNumber = 1;
-            PartEntry.PartitionNumber = 4;
-            /****/
-
             /* Save pointer to the global setup data */
             pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
             SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pSetupData);
@@ -950,10 +1221,6 @@ ProcessDlgProc(
             SetDlgItemTextW(hwndDlg, IDC_ACTIVITY, L"");
             SetDlgItemTextW(hwndDlg, IDC_ITEM, L"");
 
-            Status = InitDestinationPaths(&pSetupData->USetupData, NULL /*InstallDir*/, &DiskEntry, &PartEntry);
-            // TODO: Check Status
-            UNREFERENCED_PARAMETER(Status);
-
             break;
         }
 
@@ -1069,11 +1336,11 @@ RestartDlgProc(
             SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pSetupData);
 
             /* Set title font */
-            /*SendDlgItemMessage(hwndDlg,
-                                 IDC_STARTTITLE,
-                                 WM_SETFONT,
-                                 (WPARAM)hTitleFont,
-                                 (LPARAM)TRUE);*/
+            SendDlgItemMessage(hwndDlg,
+                               IDC_FINISHTITLE,
+                               WM_SETFONT,
+                               (WPARAM)pSetupData->hTitleFont,
+                               (LPARAM)TRUE);
             break;
 
         case WM_TIMER:
@@ -1104,12 +1371,18 @@ RestartDlgProc(
 
             switch (lpnm->code)
             {
-                case PSN_SETACTIVE: // Only "Finish" for closing the App
+                case PSN_SETACTIVE:
+                {
+                    /* Only "Finish" for closing the wizard */
+                    ShowWindow(GetDlgItem(GetParent(hwndDlg), IDCANCEL), SW_HIDE);
                     PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH);
+
+                    /* Set up the reboot progress bar */
                     SendDlgItemMessage(hwndDlg, IDC_RESTART_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, 300));
                     SendDlgItemMessage(hwndDlg, IDC_RESTART_PROGRESS, PBM_SETPOS, 0, 0);
                     SetTimer(hwndDlg, 1, 50, NULL);
                     break;
+                }
 
                 default:
                     break;
@@ -1509,6 +1782,55 @@ Quit:
     return Success;
 }
 
+/* Copied from HotkeyThread() in dll/win32/syssetup/install.c */
+static DWORD CALLBACK
+HotkeyThread(LPVOID Parameter)
+{
+    ATOM hotkey;
+    MSG msg;
+
+    DPRINT("HotkeyThread start\n");
+
+    hotkey = GlobalAddAtomW(L"Setup Shift+F10 Hotkey");
+
+    if (!RegisterHotKey(NULL, hotkey, MOD_SHIFT, VK_F10))
+        DPRINT1("RegisterHotKey failed with %lu\n", GetLastError());
+
+    while (GetMessageW(&msg, NULL, 0, 0))
+    {
+        if (msg.hwnd == NULL && msg.message == WM_HOTKEY && msg.wParam == hotkey)
+        {
+            STARTUPINFOW si = { sizeof(si) };
+            PROCESS_INFORMATION pi;
+
+            if (CreateProcessW(L"cmd.exe",
+                               NULL,
+                               NULL,
+                               NULL,
+                               FALSE,
+                               CREATE_NEW_CONSOLE,
+                               NULL,
+                               NULL,
+                               &si,
+                               &pi))
+            {
+                CloseHandle(pi.hProcess);
+                CloseHandle(pi.hThread);
+            }
+            else
+            {
+                DPRINT1("Failed to launch command prompt: %lu\n", GetLastError());
+            }
+        }
+    }
+
+    UnregisterHotKey(NULL, hotkey);
+    GlobalDeleteAtom(hotkey);
+
+    DPRINT("HotkeyThread terminate\n");
+    return 0;
+}
+
 int WINAPI
 _tWinMain(HINSTANCE hInst,
           HINSTANCE hPrevInstance,
@@ -1516,6 +1838,7 @@ _tWinMain(HINSTANCE hInst,
           int nCmdShow)
 {
     ULONG Error;
+    HANDLE hHotkeyThread;
     INITCOMMONCONTROLSEX iccx;
     PROPSHEETHEADER psh;
     HPROPSHEETPAGE ahpsp[8];
@@ -1556,6 +1879,8 @@ _tWinMain(HINSTANCE hInst,
     if (!LoadSetupData(&SetupData))
         goto Quit;
 
+    hHotkeyThread = CreateThread(NULL, 0, HotkeyThread, NULL, 0, NULL);
+
     CheckUnattendedSetup(&SetupData.USetupData);
     SetupData.bUnattend = IsUnattendedSetup; // FIXME :-)
 
@@ -1570,6 +1895,10 @@ _tWinMain(HINSTANCE hInst,
     iccx.dwICC = ICC_LISTVIEW_CLASSES | ICC_TREEVIEW_CLASSES | ICC_PROGRESS_CLASS;
     InitCommonControlsEx(&iccx);
 
+    /* Register the TreeList control */
+    // RegisterTreeListClass(hInst);
+    TreeListRegister(hInst);
+
     /* Create title font */
     SetupData.hTitleFont = CreateTitleFont();
 
@@ -1582,74 +1911,74 @@ _tWinMain(HINSTANCE hInst,
         psp.hInstance = hInst;
         psp.lParam = (LPARAM)&SetupData;
         psp.pfnDlgProc = StartDlgProc;
-        psp.pszTemplate = MAKEINTRESOURCE(IDD_STARTPAGE);
+        psp.pszTemplate = MAKEINTRESOURCEW(IDD_STARTPAGE);
         ahpsp[nPages++] = CreatePropertySheetPage(&psp);
 
         /* Create the install type selection page */
         psp.dwSize = sizeof(PROPSHEETPAGE);
         psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
-        psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_TYPETITLE);
-        psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_TYPESUBTITLE);
+        psp.pszHeaderTitle = MAKEINTRESOURCEW(IDS_TYPETITLE);
+        psp.pszHeaderSubTitle = MAKEINTRESOURCEW(IDS_TYPESUBTITLE);
         psp.hInstance = hInst;
         psp.lParam = (LPARAM)&SetupData;
         psp.pfnDlgProc = TypeDlgProc;
-        psp.pszTemplate = MAKEINTRESOURCE(IDD_TYPEPAGE);
+        psp.pszTemplate = MAKEINTRESOURCEW(IDD_TYPEPAGE);
         ahpsp[nPages++] = CreatePropertySheetPage(&psp);
 
         /* Create the upgrade/repair selection page */
         psp.dwSize = sizeof(PROPSHEETPAGE);
         psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
-        psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_TYPETITLE);
-        psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_TYPESUBTITLE);
+        psp.pszHeaderTitle = MAKEINTRESOURCEW(IDS_TYPETITLE);
+        psp.pszHeaderSubTitle = MAKEINTRESOURCEW(IDS_TYPESUBTITLE);
         psp.hInstance = hInst;
         psp.lParam = (LPARAM)&SetupData;
         psp.pfnDlgProc = UpgradeRepairDlgProc;
-        psp.pszTemplate = MAKEINTRESOURCE(IDD_UPDATEREPAIRPAGE);
+        psp.pszTemplate = MAKEINTRESOURCEW(IDD_UPDATEREPAIRPAGE);
         ahpsp[nPages++] = CreatePropertySheetPage(&psp);
 
         /* Create the device settings page */
         psp.dwSize = sizeof(PROPSHEETPAGE);
         psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
-        psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_DEVICETITLE);
-        psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_DEVICESUBTITLE);
+        psp.pszHeaderTitle = MAKEINTRESOURCEW(IDS_DEVICETITLE);
+        psp.pszHeaderSubTitle = MAKEINTRESOURCEW(IDS_DEVICESUBTITLE);
         psp.hInstance = hInst;
         psp.lParam = (LPARAM)&SetupData;
         psp.pfnDlgProc = DeviceDlgProc;
-        psp.pszTemplate = MAKEINTRESOURCE(IDD_DEVICEPAGE);
+        psp.pszTemplate = MAKEINTRESOURCEW(IDD_DEVICEPAGE);
         ahpsp[nPages++] = CreatePropertySheetPage(&psp);
 
         /* Create the install device settings page / boot method / install directory */
         psp.dwSize = sizeof(PROPSHEETPAGE);
         psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
-        psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_DRIVETITLE);
-        psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_DRIVESUBTITLE);
+        psp.pszHeaderTitle = MAKEINTRESOURCEW(IDS_DRIVETITLE);
+        psp.pszHeaderSubTitle = MAKEINTRESOURCEW(IDS_DRIVESUBTITLE);
         psp.hInstance = hInst;
         psp.lParam = (LPARAM)&SetupData;
         psp.pfnDlgProc = DriveDlgProc;
-        psp.pszTemplate = MAKEINTRESOURCE(IDD_DRIVEPAGE);
+        psp.pszTemplate = MAKEINTRESOURCEW(IDD_DRIVEPAGE);
         ahpsp[nPages++] = CreatePropertySheetPage(&psp);
 
         /* Create the summary page */
         psp.dwSize = sizeof(PROPSHEETPAGE);
         psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
-        psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_SUMMARYTITLE);
-        psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_SUMMARYSUBTITLE);
+        psp.pszHeaderTitle = MAKEINTRESOURCEW(IDS_SUMMARYTITLE);
+        psp.pszHeaderSubTitle = MAKEINTRESOURCEW(IDS_SUMMARYSUBTITLE);
         psp.hInstance = hInst;
         psp.lParam = (LPARAM)&SetupData;
         psp.pfnDlgProc = SummaryDlgProc;
-        psp.pszTemplate = MAKEINTRESOURCE(IDD_SUMMARYPAGE);
+        psp.pszTemplate = MAKEINTRESOURCEW(IDD_SUMMARYPAGE);
         ahpsp[nPages++] = CreatePropertySheetPage(&psp);
     }
 
     /* Create the installation progress page */
     psp.dwSize = sizeof(PROPSHEETPAGE);
     psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
-    psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_PROCESSTITLE);
-    psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_PROCESSSUBTITLE);
+    psp.pszHeaderTitle = MAKEINTRESOURCEW(IDS_PROCESSTITLE);
+    psp.pszHeaderSubTitle = MAKEINTRESOURCEW(IDS_PROCESSSUBTITLE);
     psp.hInstance = hInst;
     psp.lParam = (LPARAM)&SetupData;
     psp.pfnDlgProc = ProcessDlgProc;
-    psp.pszTemplate = MAKEINTRESOURCE(IDD_PROCESSPAGE);
+    psp.pszTemplate = MAKEINTRESOURCEW(IDD_PROCESSPAGE);
     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
 
     /* Create the finish-and-reboot page */
@@ -1658,7 +1987,7 @@ _tWinMain(HINSTANCE hInst,
     psp.hInstance = hInst;
     psp.lParam = (LPARAM)&SetupData;
     psp.pfnDlgProc = RestartDlgProc;
-    psp.pszTemplate = MAKEINTRESOURCE(IDD_RESTARTPAGE);
+    psp.pszTemplate = MAKEINTRESOURCEW(IDD_RESTARTPAGE);
     ahpsp[nPages++] = CreatePropertySheetPage(&psp);
 
     /* Create the property sheet */
@@ -1669,16 +1998,12 @@ _tWinMain(HINSTANCE hInst,
     psh.nPages = nPages;
     psh.nStartPage = 0;
     psh.phpage = ahpsp;
-    psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
-    psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER);
+    psh.pszbmWatermark = MAKEINTRESOURCEW(IDB_WATERMARK);
+    psh.pszbmHeader = MAKEINTRESOURCEW(IDB_HEADER);
 
     /* Display the wizard */
     PropertySheet(&psh);
 
-    if (SetupData.hTitleFont)
-        DeleteObject(SetupData.hTitleFont);
-
-Quit:
     /* Wait for any pending installation */
     WaitForSingleObject(SetupData.hInstallThread, INFINITE);
     CloseHandle(SetupData.hInstallThread);
@@ -1686,6 +2011,20 @@ Quit:
     CloseHandle(SetupData.hHaltInstallEvent);
     SetupData.hHaltInstallEvent = NULL;
 
+    if (SetupData.hTitleFont)
+        DeleteObject(SetupData.hTitleFont);
+
+    /* Unregister the TreeList control */
+    // UnregisterTreeListClass(hInst);
+    TreeListUnregister(hInst);
+
+    if (hHotkeyThread)
+    {
+        PostThreadMessageW(GetThreadId(hHotkeyThread), WM_QUIT, 0, 0);
+        CloseHandle(hHotkeyThread);
+    }
+
+Quit:
     /* Setup has finished */
     FinishSetup(&SetupData.USetupData);
 
index ded1d85..23e23af 100644 (file)
 #include <strsafe.h>
 
 #include <commctrl.h>
+#include <windowsx.h>
+
+/* These are public names and values determined from MFC, and compatible with Windows */
+// Property Sheet control id's (determined with Spy++)
+#define IDC_TAB_CONTROL                 0x3020
+#define ID_APPLY_NOW                    0x3021
+#define ID_WIZBACK                      0x3023
+#define ID_WIZNEXT                      0x3024
+#define ID_WIZFINISH                    0x3025
+
+
+#include "treelist.h"
+
 /**/#include <setupapi.h>/**/
 #include <devguid.h>
 
@@ -123,17 +136,13 @@ typedef struct _SETUPDATA
 
     /* Settings */
     LONG DestPartSize; // if partition doesn't exist, size of partition
-    LONG FSType; // file system type on partition 
-    LONG FormatPart; // type of format the partition
+    LONG FSType;       // file system type on partition
+    LONG FormatPart;   // type of format the partition
 
     LONG SelectedLangId; // selected language (table index)
-    LONG SelectedKBLayout; // selected keyboard layout (table index)
-    LONG SelectedComputer; // selected computer type (table index)
-    LONG SelectedDisplay; // selected display type (table index)
-    LONG SelectedKeyboard; // selected keyboard type (table index)
 
     /* txtsetup.sif data */
-    // LONG DefaultLang; // default language (table index)
+    // LONG DefaultLang;     // default language (table index)
     // LONG DefaultKBLayout; // default keyboard layout (table index)
     PCWSTR SelectedLanguageId;
     WCHAR DefaultLanguage[20];   // Copy of string inside LanguageList
@@ -147,14 +156,6 @@ extern BOOLEAN IsUnattendedSetup;
 extern SETUPDATA SetupData;
 
 
-typedef struct _IMGINFO
-{
-    HBITMAP hBitmap;
-    INT cxSource;
-    INT cySource;
-} IMGINFO, *PIMGINFO;
-
-
 /*
  * Attempts to convert a pure NT file path into a corresponding Win32 path.
  * Adapted from GetInstallSourceWin32() in dll/win32/syssetup/wizard.c