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