[USETUP][REACTOS] Check the status return value of InitDestinationPaths() (#1264)
[reactos.git] / base / setup / reactos / drivepage.c
1 /*
2 * ReactOS applications
3 * Copyright (C) 2004-2008 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS GUI first stage setup application
22 * FILE: base/setup/reactos/drivepage.c
23 * PROGRAMMERS: Matthias Kupfer
24 * Dmitry Chapyshev (dmitry@reactos.org)
25 */
26
27 #include "reactos.h"
28 #include <shlwapi.h>
29
30 // #include <ntdddisk.h>
31 #include <ntddstor.h>
32 #include <ntddscsi.h>
33
34 #include "resource.h"
35
36 #define NDEBUG
37 #include <debug.h>
38
39 /* GLOBALS ******************************************************************/
40
41 #define IDS_LIST_COLUMN_FIRST IDS_PARTITION_NAME
42 #define IDS_LIST_COLUMN_LAST IDS_PARTITION_STATUS
43
44 #define MAX_LIST_COLUMNS (IDS_LIST_COLUMN_LAST - IDS_LIST_COLUMN_FIRST + 1)
45 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};
46 static const INT column_widths[MAX_LIST_COLUMNS] = {200, 90, 60, 60};
47 static const INT column_alignment[MAX_LIST_COLUMNS] = {LVCFMT_LEFT, LVCFMT_LEFT, LVCFMT_RIGHT, LVCFMT_RIGHT};
48
49 /* FUNCTIONS ****************************************************************/
50
51 static INT_PTR CALLBACK
52 MoreOptDlgProc(HWND hwndDlg,
53 UINT uMsg,
54 WPARAM wParam,
55 LPARAM lParam)
56 {
57 PSETUPDATA pSetupData;
58
59 /* Retrieve pointer to the global setup data */
60 pSetupData = (PSETUPDATA)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
61
62 switch (uMsg)
63 {
64 case WM_INITDIALOG:
65 {
66 /* Save pointer to the global setup data */
67 pSetupData = (PSETUPDATA)lParam;
68 SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pSetupData);
69
70 CheckDlgButton(hwndDlg, IDC_INSTFREELDR, BST_CHECKED);
71 SetDlgItemTextW(hwndDlg, IDC_PATH,
72 pSetupData->USetupData.InstallationDirectory);
73 break;
74 }
75
76 case WM_COMMAND:
77 switch (LOWORD(wParam))
78 {
79 case IDOK:
80 {
81 GetDlgItemTextW(hwndDlg, IDC_PATH,
82 pSetupData->USetupData.InstallationDirectory,
83 ARRAYSIZE(pSetupData->USetupData.InstallationDirectory));
84 EndDialog(hwndDlg, IDOK);
85 return TRUE;
86 }
87
88 case IDCANCEL:
89 EndDialog(hwndDlg, IDCANCEL);
90 return TRUE;
91 }
92 break;
93 }
94
95 return FALSE;
96 }
97
98 static INT_PTR CALLBACK
99 PartitionDlgProc(HWND hwndDlg,
100 UINT uMsg,
101 WPARAM wParam,
102 LPARAM lParam)
103 {
104 switch (uMsg)
105 {
106 case WM_INITDIALOG:
107 break;
108
109 case WM_COMMAND:
110 {
111 switch (LOWORD(wParam))
112 {
113 case IDOK:
114 EndDialog(hwndDlg, IDOK);
115 return TRUE;
116 case IDCANCEL:
117 EndDialog(hwndDlg, IDCANCEL);
118 return TRUE;
119 }
120 }
121 }
122 return FALSE;
123 }
124
125
126 BOOL
127 CreateTreeListColumns(
128 IN HINSTANCE hInstance,
129 IN HWND hWndTreeList,
130 IN const UINT* pIDs,
131 IN const INT* pColsWidth,
132 IN const INT* pColsAlign,
133 IN UINT nNumOfColumns)
134 {
135 UINT i;
136 TLCOLUMN tlC;
137 WCHAR szText[50];
138
139 /* Create the columns */
140 tlC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
141 tlC.pszText = szText;
142
143 /* Load the column labels from the resource file */
144 for (i = 0; i < nNumOfColumns; i++)
145 {
146 tlC.iSubItem = i;
147 tlC.cx = pColsWidth[i];
148 tlC.fmt = pColsAlign[i];
149
150 LoadStringW(hInstance, pIDs[i], szText, ARRAYSIZE(szText));
151
152 if (TreeList_InsertColumn(hWndTreeList, i, &tlC) == -1)
153 return FALSE;
154 }
155
156 return TRUE;
157 }
158
159 // unused
160 VOID
161 DisplayStuffUsingWin32Setup(HWND hwndDlg)
162 {
163 HDEVINFO h;
164 HWND hList;
165 SP_DEVINFO_DATA DevInfoData;
166 DWORD i;
167
168 h = SetupDiGetClassDevs(&GUID_DEVCLASS_DISKDRIVE, NULL, NULL, DIGCF_PRESENT);
169 if (h == INVALID_HANDLE_VALUE)
170 return;
171
172 hList = GetDlgItem(hwndDlg, IDC_PARTITION);
173 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
174 for (i=0; SetupDiEnumDeviceInfo(h, i, &DevInfoData); i++)
175 {
176 DWORD DataT;
177 LPTSTR buffer = NULL;
178 DWORD buffersize = 0;
179
180 while (!SetupDiGetDeviceRegistryProperty(h,
181 &DevInfoData,
182 SPDRP_DEVICEDESC,
183 &DataT,
184 (PBYTE)buffer,
185 buffersize,
186 &buffersize))
187 {
188 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
189 {
190 if (buffer) LocalFree(buffer);
191 buffer = LocalAlloc(LPTR, buffersize * 2);
192 }
193 else
194 {
195 return;
196 }
197 }
198 if (buffer)
199 {
200 SendMessageW(hList, LB_ADDSTRING, (WPARAM)0, (LPARAM)buffer);
201 LocalFree(buffer);
202 }
203 }
204 SetupDiDestroyDeviceInfoList(h);
205 }
206
207
208 HTLITEM
209 TreeListAddItem(IN HWND hTreeList,
210 IN HTLITEM hParent,
211 IN LPWSTR lpText,
212 IN INT iImage,
213 IN INT iSelectedImage,
214 IN LPARAM lParam)
215 {
216 TL_INSERTSTRUCTW Insert;
217
218 ZeroMemory(&Insert, sizeof(Insert));
219
220 Insert.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
221 Insert.hInsertAfter = TVI_LAST;
222 Insert.hParent = hParent;
223 Insert.item.pszText = lpText;
224 Insert.item.iImage = iImage;
225 Insert.item.iSelectedImage = iSelectedImage;
226 Insert.item.lParam = lParam;
227
228 // Insert.item.mask |= TVIF_STATE;
229 // Insert.item.stateMask = TVIS_OVERLAYMASK;
230 // Insert.item.state = INDEXTOOVERLAYMASK(1);
231
232 return TreeList_InsertItem(hTreeList, &Insert);
233 }
234
235
236 VOID
237 GetPartTypeStringFromPartitionType(
238 IN UCHAR partitionType,
239 OUT PCHAR strPartType,
240 IN ULONG cchPartType)
241 {
242 /* Determine partition type */
243
244 if (IsContainerPartition(partitionType))
245 {
246 StringCchCopyA(strPartType, cchPartType, "Extended Partition" /* MUIGetString(STRING_EXTENDED_PARTITION) */);
247 }
248 else if (partitionType == PARTITION_ENTRY_UNUSED)
249 {
250 StringCchCopyA(strPartType, cchPartType, "Unused" /* MUIGetString(STRING_FORMATUNUSED) */);
251 }
252 else
253 {
254 UINT i;
255
256 /* Do the table lookup */
257 for (i = 0; i < ARRAYSIZE(PartitionTypes); i++)
258 {
259 if (partitionType == PartitionTypes[i].Type)
260 {
261 StringCchCopyA(strPartType, cchPartType, PartitionTypes[i].Description);
262 return;
263 }
264 }
265
266 /* We are here because the partition type is unknown */
267 StringCchCopyA(strPartType, cchPartType, "Unknown" /* MUIGetString(STRING_FORMATUNKNOWN) */);
268 }
269 }
270
271 static
272 HTLITEM
273 PrintPartitionData(
274 IN HWND hWndList,
275 IN PPARTLIST List,
276 IN HTLITEM htiParent,
277 IN PDISKENTRY DiskEntry,
278 IN PPARTENTRY PartEntry)
279 {
280 LARGE_INTEGER PartSize;
281 HTLITEM htiPart;
282 CHAR PartTypeString[32];
283 PCHAR PartType = PartTypeString;
284 WCHAR LineBuffer[128];
285
286 /* Volume name */
287 if (PartEntry->IsPartitioned == FALSE)
288 {
289 StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
290 // MUIGetString(STRING_UNPSPACE),
291 L"Unpartitioned space");
292 }
293 else
294 {
295 StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
296 // MUIGetString(STRING_HDDINFOUNK5),
297 L"%s (%c%c)",
298 *PartEntry->VolumeLabel ? PartEntry->VolumeLabel : L"Partition",
299 (PartEntry->DriveLetter == 0) ? L'-' : PartEntry->DriveLetter,
300 (PartEntry->DriveLetter == 0) ? L'-' : L':');
301 }
302
303 htiPart = TreeListAddItem(hWndList, htiParent, LineBuffer,
304 1, 1,
305 (LPARAM)PartEntry);
306
307 /* Determine partition type */
308 *LineBuffer = 0;
309 if (PartEntry->IsPartitioned)
310 {
311 PartTypeString[0] = '\0';
312 if (PartEntry->New == TRUE)
313 {
314 PartType = "New (Unformatted)"; // MUIGetString(STRING_UNFORMATTED);
315 }
316 else if (PartEntry->IsPartitioned == TRUE)
317 {
318 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
319 PartTypeString,
320 ARRAYSIZE(PartTypeString));
321 PartType = PartTypeString;
322 }
323
324 if (strcmp(PartType, "Unknown" /* MUIGetString(STRING_FORMATUNKNOWN) */) == 0)
325 {
326 StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
327 // MUIGetString(STRING_HDDINFOUNK5),
328 L"Type 0x%02x",
329 PartEntry->PartitionType);
330 }
331 else
332 {
333 StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
334 L"%S",
335 PartType);
336 }
337 }
338 TreeList_SetItemText(hWndList, htiPart, 1, LineBuffer);
339
340 /* Format the disk size in KBs, MBs, etc... */
341 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
342 if (StrFormatByteSizeW(PartSize.QuadPart, LineBuffer, ARRAYSIZE(LineBuffer)) == NULL)
343 {
344 /* We failed for whatever reason, do the hardcoded way */
345 PWCHAR Unit;
346
347 #if 0
348 if (PartSize.QuadPart >= 10 * GB) /* 10 GB */
349 {
350 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, GB);
351 // Unit = MUIGetString(STRING_GB);
352 Unit = L"GB";
353 }
354 else
355 #endif
356 if (PartSize.QuadPart >= 10 * MB) /* 10 MB */
357 {
358 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, MB);
359 // Unit = MUIGetString(STRING_MB);
360 Unit = L"MB";
361 }
362 else
363 {
364 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, KB);
365 // Unit = MUIGetString(STRING_KB);
366 Unit = L"KB";
367 }
368
369 StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
370 L"%6lu %s",
371 PartSize.u.LowPart,
372 Unit);
373 }
374 TreeList_SetItemText(hWndList, htiPart, 2, LineBuffer);
375
376 /* Volume status */
377 *LineBuffer = 0;
378 if (PartEntry->IsPartitioned)
379 {
380 StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
381 // MUIGetString(STRING_HDDINFOUNK5),
382 PartEntry->BootIndicator ? L"Active" : L"");
383 }
384 TreeList_SetItemText(hWndList, htiPart, 3, LineBuffer);
385
386 return htiPart;
387 }
388
389 static
390 VOID
391 PrintDiskData(
392 IN HWND hWndList,
393 IN PPARTLIST List,
394 IN PDISKENTRY DiskEntry)
395 {
396 BOOL Success;
397 HANDLE hDevice;
398 PCHAR DiskName = NULL;
399 ULONG Length = 0;
400 PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
401 PLIST_ENTRY PrimaryEntry, LogicalEntry;
402 ULARGE_INTEGER DiskSize;
403 HTLITEM htiDisk, htiPart;
404 WCHAR LineBuffer[128];
405 UCHAR outBuf[512];
406
407 StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
408 // L"\\Device\\Harddisk%lu\\Partition%lu",
409 L"\\\\.\\PhysicalDrive%lu",
410 DiskEntry->DiskNumber);
411
412 hDevice = CreateFileW(
413 LineBuffer, // device interface name
414 GENERIC_READ /*| GENERIC_WRITE*/, // dwDesiredAccess
415 FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
416 NULL, // lpSecurityAttributes
417 OPEN_EXISTING, // dwCreationDistribution
418 0, // dwFlagsAndAttributes
419 NULL // hTemplateFile
420 );
421 if (hDevice != INVALID_HANDLE_VALUE)
422 {
423 STORAGE_PROPERTY_QUERY Query;
424
425 Query.PropertyId = StorageDeviceProperty;
426 Query.QueryType = PropertyStandardQuery;
427
428 Success = DeviceIoControl(hDevice,
429 IOCTL_STORAGE_QUERY_PROPERTY,
430 &Query,
431 sizeof(Query),
432 &outBuf,
433 sizeof(outBuf),
434 &Length,
435 NULL);
436 if (Success)
437 {
438 PSTORAGE_DEVICE_DESCRIPTOR devDesc = (PSTORAGE_DEVICE_DESCRIPTOR)outBuf;
439 if (devDesc->ProductIdOffset)
440 {
441 DiskName = (PCHAR)&outBuf[devDesc->ProductIdOffset];
442 Length -= devDesc->ProductIdOffset;
443 DiskName[min(Length, strlen(DiskName))] = 0;
444 // ( i = devDesc->ProductIdOffset; p[i] != 0 && i < Length; i++ )
445 }
446 }
447
448 CloseHandle(hDevice);
449 }
450
451 if (DiskName && *DiskName)
452 {
453 if (DiskEntry->DriverName.Length > 0)
454 {
455 StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
456 // MUIGetString(STRING_HDINFOPARTSELECT_1),
457 L"Harddisk %lu (%S) (Port=%hu, Bus=%hu, Id=%hu) on %wZ",
458 DiskEntry->DiskNumber,
459 DiskName,
460 DiskEntry->Port,
461 DiskEntry->Bus,
462 DiskEntry->Id,
463 &DiskEntry->DriverName);
464 }
465 else
466 {
467 StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
468 // MUIGetString(STRING_HDINFOPARTSELECT_2),
469 L"Harddisk %lu (%S) (Port=%hu, Bus=%hu, Id=%hu)",
470 DiskEntry->DiskNumber,
471 DiskName,
472 DiskEntry->Port,
473 DiskEntry->Bus,
474 DiskEntry->Id);
475 }
476 }
477 else
478 {
479 if (DiskEntry->DriverName.Length > 0)
480 {
481 StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
482 // MUIGetString(STRING_HDINFOPARTSELECT_1),
483 L"Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu) on %wZ",
484 DiskEntry->DiskNumber,
485 DiskEntry->Port,
486 DiskEntry->Bus,
487 DiskEntry->Id,
488 &DiskEntry->DriverName);
489 }
490 else
491 {
492 StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
493 // MUIGetString(STRING_HDINFOPARTSELECT_2),
494 L"Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)",
495 DiskEntry->DiskNumber,
496 DiskEntry->Port,
497 DiskEntry->Bus,
498 DiskEntry->Id);
499 }
500 }
501
502 htiDisk = TreeListAddItem(hWndList, NULL, LineBuffer,
503 0, 0,
504 (LPARAM)DiskEntry);
505
506 /* Disk type: MBR, GPT or RAW (Uninitialized) */
507 TreeList_SetItemText(hWndList, htiDisk, 1,
508 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? L"MBR" :
509 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? L"GPT" :
510 L"RAW");
511
512 /* Format the disk size in KBs, MBs, etc... */
513 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
514 if (StrFormatByteSizeW(DiskSize.QuadPart, LineBuffer, ARRAYSIZE(LineBuffer)) == NULL)
515 {
516 /* We failed for whatever reason, do the hardcoded way */
517 PWCHAR Unit;
518
519 if (DiskSize.QuadPart >= 10 * GB) /* 10 GB */
520 {
521 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, GB);
522 // Unit = MUIGetString(STRING_GB);
523 Unit = L"GB";
524 }
525 else
526 {
527 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, MB);
528 if (DiskSize.QuadPart == 0)
529 DiskSize.QuadPart = 1;
530 // Unit = MUIGetString(STRING_MB);
531 Unit = L"MB";
532 }
533
534 StringCchPrintfW(LineBuffer, ARRAYSIZE(LineBuffer),
535 L"%6lu %s",
536 DiskSize.u.LowPart,
537 Unit);
538 }
539 TreeList_SetItemText(hWndList, htiDisk, 2, LineBuffer);
540
541
542 /* Print partition lines */
543 for (PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
544 PrimaryEntry != &DiskEntry->PrimaryPartListHead;
545 PrimaryEntry = PrimaryEntry->Flink)
546 {
547 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
548
549 htiPart = PrintPartitionData(hWndList, List, htiDisk,
550 DiskEntry, PrimaryPartEntry);
551
552 if (IsContainerPartition(PrimaryPartEntry->PartitionType))
553 {
554 for (LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
555 LogicalEntry != &DiskEntry->LogicalPartListHead;
556 LogicalEntry = LogicalEntry->Flink)
557 {
558 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
559
560 PrintPartitionData(hWndList, List, htiPart,
561 DiskEntry, LogicalPartEntry);
562 }
563
564 /* Expand the extended partition node */
565 TreeList_Expand(hWndList, htiPart, TVE_EXPAND);
566 }
567 }
568
569 /* Expand the disk node */
570 TreeList_Expand(hWndList, htiDisk, TVE_EXPAND);
571 }
572
573 VOID
574 DrawPartitionList(
575 IN HWND hWndList,
576 IN PPARTLIST List)
577 {
578 PLIST_ENTRY Entry;
579 PDISKENTRY DiskEntry;
580
581 for (Entry = List->DiskListHead.Flink;
582 Entry != &List->DiskListHead;
583 Entry = Entry->Flink)
584 {
585 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
586
587 /* Print disk entry */
588 PrintDiskData(hWndList, List, DiskEntry);
589 }
590 }
591
592
593
594 INT_PTR
595 CALLBACK
596 DriveDlgProc(
597 HWND hwndDlg,
598 UINT uMsg,
599 WPARAM wParam,
600 LPARAM lParam)
601 {
602 PSETUPDATA pSetupData;
603 HWND hList;
604 HIMAGELIST hSmall;
605
606 /* Retrieve pointer to the global setup data */
607 pSetupData = (PSETUPDATA)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
608
609 switch (uMsg)
610 {
611 case WM_INITDIALOG:
612 {
613 /* Save pointer to the global setup data */
614 pSetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
615 SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (DWORD_PTR)pSetupData);
616
617 /*
618 * Keep the "Next" button disabled. It will be enabled only
619 * when the user selects a valid partition.
620 */
621 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
622
623 hList = GetDlgItem(hwndDlg, IDC_PARTITION);
624
625 TreeList_SetExtendedStyleEx(hList, TVS_EX_FULLROWMARK, TVS_EX_FULLROWMARK);
626 // TreeList_SetExtendedStyleEx(hList, TVS_EX_FULLROWITEMS, TVS_EX_FULLROWITEMS);
627
628 CreateTreeListColumns(pSetupData->hInstance,
629 hList,
630 column_ids,
631 column_widths,
632 column_alignment,
633 MAX_LIST_COLUMNS);
634
635 /* Create the ImageList */
636 hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
637 GetSystemMetrics(SM_CYSMICON),
638 ILC_COLOR32 | ILC_MASK, // ILC_COLOR24
639 1, 1);
640
641 /* Add event type icons to the ImageList */
642 ImageList_AddIcon(hSmall, LoadIconW(pSetupData->hInstance, MAKEINTRESOURCEW(IDI_DISKDRIVE)));
643 ImageList_AddIcon(hSmall, LoadIconW(pSetupData->hInstance, MAKEINTRESOURCEW(IDI_PARTITION)));
644
645 /* Assign the ImageList to the List View */
646 TreeList_SetImageList(hList, hSmall, TVSIL_NORMAL);
647
648 // DisplayStuffUsingWin32Setup(hwndDlg);
649 DrawPartitionList(hList, pSetupData->PartitionList);
650 break;
651 }
652
653 case WM_DESTROY:
654 {
655 hList = GetDlgItem(hwndDlg, IDC_PARTITION);
656 hSmall = TreeList_GetImageList(hList, TVSIL_NORMAL);
657 TreeList_SetImageList(hList, NULL, TVSIL_NORMAL);
658 ImageList_Destroy(hSmall);
659 return TRUE;
660 }
661
662 case WM_COMMAND:
663 {
664 switch (LOWORD(wParam))
665 {
666 case IDC_PARTMOREOPTS:
667 DialogBoxParamW(pSetupData->hInstance,
668 MAKEINTRESOURCEW(IDD_BOOTOPTIONS),
669 hwndDlg,
670 MoreOptDlgProc,
671 (LPARAM)pSetupData);
672 break;
673
674 case IDC_PARTCREATE:
675 DialogBoxW(pSetupData->hInstance,
676 MAKEINTRESOURCEW(IDD_PARTITION),
677 hwndDlg,
678 PartitionDlgProc);
679 break;
680
681 case IDC_PARTDELETE:
682 break;
683 }
684 break;
685 }
686
687 case WM_NOTIFY:
688 {
689 LPNMHDR lpnm = (LPNMHDR)lParam;
690
691 // On Vista+ we can use TVN_ITEMCHANGED instead, with NMTVITEMCHANGE* pointer
692 if (lpnm->idFrom == IDC_PARTITION && lpnm->code == TVN_SELCHANGED)
693 {
694 LPNMTREEVIEW pnmv = (LPNMTREEVIEW)lParam;
695
696 // if (pnmv->uChanged & TVIF_STATE) /* The state has changed */
697 if (pnmv->itemNew.mask & TVIF_STATE)
698 {
699 /* The item has been (de)selected */
700 // if (pnmv->uNewState & TVIS_SELECTED)
701 if (pnmv->itemNew.state & TVIS_SELECTED)
702 {
703 HTLITEM hParentItem = TreeList_GetParent(lpnm->hwndFrom, pnmv->itemNew.hItem);
704 /* May or may not be a PPARTENTRY: this is a PPARTENTRY only when hParentItem != NULL */
705 PPARTENTRY PartEntry = (PPARTENTRY)pnmv->itemNew.lParam;
706
707 if (!hParentItem || !PartEntry)
708 {
709 EnableWindow(GetDlgItem(hwndDlg, IDC_PARTCREATE), TRUE);
710 EnableWindow(GetDlgItem(hwndDlg, IDC_PARTDELETE), FALSE);
711 goto DisableWizNext;
712 }
713 else // if (hParentItem && PartEntry)
714 {
715 EnableWindow(GetDlgItem(hwndDlg, IDC_PARTCREATE), !PartEntry->IsPartitioned);
716 EnableWindow(GetDlgItem(hwndDlg, IDC_PARTDELETE), PartEntry->IsPartitioned);
717
718 if (PartEntry->IsPartitioned &&
719 !IsContainerPartition(PartEntry->PartitionType) /* alternatively: PartEntry->PartitionNumber != 0 */ &&
720 // !PartEntry->New &&
721 (PartEntry->FormatState == Preformatted /* || PartEntry->FormatState == Formatted */))
722 {
723 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
724 }
725 else
726 {
727 goto DisableWizNext;
728 }
729 }
730 }
731 else
732 {
733 DisableWizNext:
734 /*
735 * Keep the "Next" button disabled. It will be enabled only
736 * when the user selects a valid partition.
737 */
738 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
739 }
740 }
741
742 break;
743 }
744
745 switch (lpnm->code)
746 {
747 #if 0
748 case PSN_SETACTIVE:
749 {
750 /*
751 * Keep the "Next" button disabled. It will be enabled only
752 * when the user selects a valid partition.
753 */
754 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
755 break;
756 }
757 #endif
758
759 case PSN_QUERYINITIALFOCUS:
760 {
761 /* Give the focus on and select the first item */
762 hList = GetDlgItem(hwndDlg, IDC_PARTITION);
763 // TreeList_SetFocusItem(hList, 1, 1);
764 TreeList_SelectItem(hList, 1);
765 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)hList);
766 return TRUE;
767 }
768
769 case PSN_QUERYCANCEL:
770 {
771 if (MessageBoxW(GetParent(hwndDlg),
772 pSetupData->szAbortMessage,
773 pSetupData->szAbortTitle,
774 MB_YESNO | MB_ICONQUESTION) == IDYES)
775 {
776 /* Go to the Terminate page */
777 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_RESTARTPAGE);
778 }
779
780 /* Do not close the wizard too soon */
781 SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, TRUE);
782 return TRUE;
783 }
784
785 case PSN_WIZNEXT: /* Set the selected data */
786 {
787 NTSTATUS Status;
788
789 /****/
790 // FIXME: This is my test disk encoding!
791 DISKENTRY DiskEntry;
792 PARTENTRY PartEntry;
793 DiskEntry.DiskNumber = 0;
794 DiskEntry.BiosDiskNumber = 0;
795 PartEntry.PartitionNumber = 1; // 4;
796 /****/
797
798 Status = InitDestinationPaths(&pSetupData->USetupData,
799 NULL, // pSetupData->USetupData.InstallationDirectory,
800 &DiskEntry, &PartEntry);
801
802 if (!NT_SUCCESS(Status))
803 {
804 DPRINT1("InitDestinationPaths() failed with status 0x%08lx\n", Status);
805 }
806
807 break;
808 }
809
810 default:
811 break;
812 }
813 }
814 break;
815
816 default:
817 break;
818 }
819
820 return FALSE;
821 }
822
823 /* EOF */