mirror of
https://github.com/reactos/reactos.git
synced 2024-09-28 13:34:53 +00:00
843 lines
28 KiB
C
843 lines
28 KiB
C
/*
|
|
* ReactOS applications
|
|
* Copyright (C) 2004-2008 ReactOS Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS GUI first stage setup application
|
|
* FILE: base/setup/reactos/drivepage.c
|
|
* PROGRAMMERS: Matthias Kupfer
|
|
* Dmitry Chapyshev (dmitry@reactos.org)
|
|
*/
|
|
|
|
#include "reactos.h"
|
|
#include <shlwapi.h>
|
|
|
|
// #include <ntdddisk.h>
|
|
#include <ntddstor.h>
|
|
#include <ntddscsi.h>
|
|
|
|
#include "resource.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* GLOBALS ******************************************************************/
|
|
|
|
#define IDS_LIST_COLUMN_FIRST IDS_PARTITION_NAME
|
|
#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, 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 ****************************************************************/
|
|
|
|
static INT_PTR CALLBACK
|
|
MoreOptDlgProc(HWND hwndDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
PSETUPDATA pSetupData;
|
|
|
|
/* Retrieve pointer to the global setup data */
|
|
pSetupData = (PSETUPDATA)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
/* Save pointer to the global setup data */
|
|
pSetupData = (PSETUPDATA)lParam;
|
|
SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pSetupData);
|
|
|
|
CheckDlgButton(hwndDlg, IDC_INSTFREELDR, BST_CHECKED);
|
|
SetDlgItemTextW(hwndDlg, IDC_PATH,
|
|
pSetupData->USetupData.InstallationDirectory);
|
|
break;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
{
|
|
GetDlgItemTextW(hwndDlg, IDC_PATH,
|
|
pSetupData->USetupData.InstallationDirectory,
|
|
ARRAYSIZE(pSetupData->USetupData.InstallationDirectory));
|
|
EndDialog(hwndDlg, IDOK);
|
|
return TRUE;
|
|
}
|
|
|
|
case IDCANCEL:
|
|
EndDialog(hwndDlg, IDCANCEL);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static INT_PTR CALLBACK
|
|
PartitionDlgProc(HWND hwndDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
EndDialog(hwndDlg, IDOK);
|
|
return TRUE;
|
|
case IDCANCEL:
|
|
EndDialog(hwndDlg, IDCANCEL);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CreateTreeListColumns(
|
|
IN HINSTANCE hInstance,
|
|
IN HWND hWndTreeList,
|
|
IN const UINT* pIDs,
|
|
IN const INT* pColsWidth,
|
|
IN const INT* pColsAlign,
|
|
IN UINT nNumOfColumns)
|
|
{
|
|
UINT i;
|
|
TLCOLUMN tlC;
|
|
WCHAR szText[50];
|
|
|
|
/* Create the columns */
|
|
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++)
|
|
{
|
|
tlC.iSubItem = i;
|
|
tlC.cx = pColsWidth[i];
|
|
tlC.fmt = pColsAlign[i];
|
|
|
|
LoadStringW(hInstance, pIDs[i], szText, ARRAYSIZE(szText));
|
|
|
|
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
|
|
GetPartitionTypeString(
|
|
IN PPARTENTRY PartEntry,
|
|
OUT PSTR strBuffer,
|
|
IN ULONG cchBuffer)
|
|
{
|
|
if (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED)
|
|
{
|
|
StringCchCopyA(strBuffer, cchBuffer,
|
|
"Unused" /* MUIGetString(STRING_FORMATUNUSED) */);
|
|
}
|
|
else if (IsContainerPartition(PartEntry->PartitionType))
|
|
{
|
|
StringCchCopyA(strBuffer, cchBuffer,
|
|
"Extended Partition" /* MUIGetString(STRING_EXTENDED_PARTITION) */);
|
|
}
|
|
else
|
|
{
|
|
UINT i;
|
|
|
|
/* Do the table lookup */
|
|
if (PartEntry->DiskEntry->DiskStyle == PARTITION_STYLE_MBR)
|
|
{
|
|
for (i = 0; i < ARRAYSIZE(MbrPartitionTypes); ++i)
|
|
{
|
|
if (PartEntry->PartitionType == MbrPartitionTypes[i].Type)
|
|
{
|
|
StringCchCopyA(strBuffer, cchBuffer,
|
|
MbrPartitionTypes[i].Description);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#if 0 // TODO: GPT support!
|
|
else if (PartEntry->DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
|
|
{
|
|
for (i = 0; i < ARRAYSIZE(GptPartitionTypes); ++i)
|
|
{
|
|
if (IsEqualPartitionType(PartEntry->PartitionType,
|
|
GptPartitionTypes[i].Guid))
|
|
{
|
|
StringCchCopyA(strBuffer, cchBuffer,
|
|
GptPartitionTypes[i].Description);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* We are here because the partition type is unknown */
|
|
if (cchBuffer > 0) *strBuffer = '\0';
|
|
}
|
|
|
|
if ((cchBuffer > 0) && (*strBuffer == '\0'))
|
|
{
|
|
StringCchPrintfA(strBuffer, cchBuffer,
|
|
// MUIGetString(STRING_PARTTYPE),
|
|
"Type 0x%02x",
|
|
PartEntry->PartitionType);
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
GetPartitionTypeString(PartEntry,
|
|
PartTypeString,
|
|
ARRAYSIZE(PartTypeString));
|
|
PartType = PartTypeString;
|
|
}
|
|
|
|
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_HDDINFO_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_HDDINFO_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_HDDINFO_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_HDDINFO_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, GPT or RAW (Uninitialized) */
|
|
TreeList_SetItemText(hWndList, htiDisk, 1,
|
|
DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? L"MBR" :
|
|
DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? L"GPT" :
|
|
L"RAW");
|
|
|
|
/* 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
|
|
DriveDlgProc(
|
|
HWND hwndDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
PSETUPDATA pSetupData;
|
|
HWND hList;
|
|
HIMAGELIST hSmall;
|
|
|
|
/* Retrieve pointer to the global setup data */
|
|
pSetupData = (PSETUPDATA)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
/* Save pointer to the global setup data */
|
|
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 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);
|
|
|
|
/* 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;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_PARTMOREOPTS:
|
|
DialogBoxParamW(pSetupData->hInstance,
|
|
MAKEINTRESOURCEW(IDD_BOOTOPTIONS),
|
|
hwndDlg,
|
|
MoreOptDlgProc,
|
|
(LPARAM)pSetupData);
|
|
break;
|
|
|
|
case IDC_PARTCREATE:
|
|
DialogBoxW(pSetupData->hInstance,
|
|
MAKEINTRESOURCEW(IDD_PARTITION),
|
|
hwndDlg,
|
|
PartitionDlgProc);
|
|
break;
|
|
|
|
case IDC_PARTDELETE:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_NOTIFY:
|
|
{
|
|
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:
|
|
{
|
|
/*
|
|
* 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:
|
|
{
|
|
if (MessageBoxW(GetParent(hwndDlg),
|
|
pSetupData->szAbortMessage,
|
|
pSetupData->szAbortTitle,
|
|
MB_YESNO | MB_ICONQUESTION) == IDYES)
|
|
{
|
|
/* Go to the Terminate page */
|
|
PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_RESTARTPAGE);
|
|
}
|
|
|
|
/* Do not close the wizard too soon */
|
|
SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, TRUE);
|
|
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.HwDiskNumber = 0;
|
|
DiskEntry.HwFixedDiskNumber = 0;
|
|
PartEntry.DiskEntry = &DiskEntry;
|
|
PartEntry.PartitionNumber = 1; // 4;
|
|
/****/
|
|
|
|
Status = InitDestinationPaths(&pSetupData->USetupData,
|
|
NULL, // pSetupData->USetupData.InstallationDirectory,
|
|
&PartEntry);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("InitDestinationPaths() failed with status 0x%08lx\n", Status);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* EOF */
|