draw disk usage bar from "used" to "free" (left to right)
[reactos.git] / reactos / dll / win32 / shell32 / drive.c
1 /*
2 * Shell Library Functions
3 *
4 * Copyright 2005 Johannes Anderwald
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #define LARGEINT_PROTOS
22 #define LargeIntegerDivide RtlLargeIntegerDivide
23 #define ExtendedIntegerMultiply RtlExtendedIntegerMultiply
24 #define ConvertUlongToLargeInteger RtlConvertUlongToLargeInteger
25 #define LargeIntegerSubtract RtlLargeIntegerSubtract
26 #define MAX_PROPERTY_SHEET_PAGE 32
27
28 #define WIN32_NO_STATUS
29 #define NTOS_MODE_USER
30 #define UNICODE
31 #define _UNICODE
32 #define COBJMACROS
33 #include <windows.h>
34 #include <ndk/ntndk.h>
35 #include <fmifs/fmifs.h>
36 #include <largeint.h>
37
38 #include <precomp.h>
39
40 WINE_DEFAULT_DEBUG_CHANNEL(shell);
41
42 typedef enum
43 {
44 HWPD_STANDARDLIST = 0,
45 HWPD_LARGELIST,
46 HWPD_MAX = HWPD_LARGELIST
47 } HWPAGE_DISPLAYMODE, *PHWPAGE_DISPLAYMODE;
48
49 typedef
50 BOOLEAN
51 (NTAPI *INITIALIZE_FMIFS)(
52 IN PVOID hinstDll,
53 IN DWORD dwReason,
54 IN PVOID reserved
55 );
56 typedef
57 BOOLEAN
58 (NTAPI *QUERY_AVAILABLEFSFORMAT)(
59 IN DWORD Index,
60 IN OUT PWCHAR FileSystem,
61 OUT UCHAR* Major,
62 OUT UCHAR* Minor,
63 OUT BOOLEAN* LastestVersion
64 );
65 typedef
66 BOOLEAN
67 (NTAPI *ENABLEVOLUMECOMPRESSION)(
68 IN PWCHAR DriveRoot,
69 IN USHORT Compression
70 );
71
72 typedef
73 VOID
74 (NTAPI *FORMAT_EX)(
75 IN PWCHAR DriveRoot,
76 IN FMIFS_MEDIA_FLAG MediaFlag,
77 IN PWCHAR Format,
78 IN PWCHAR Label,
79 IN BOOLEAN QuickFormat,
80 IN ULONG ClusterSize,
81 IN PFMIFSCALLBACK Callback
82 );
83
84 typedef
85 VOID
86 (NTAPI *CHKDSK)(
87 IN PWCHAR DriveRoot,
88 IN PWCHAR Format,
89 IN BOOLEAN CorrectErrors,
90 IN BOOLEAN Verbose,
91 IN BOOLEAN CheckOnlyIfDirty,
92 IN BOOLEAN ScanDrive,
93 IN PVOID Unused2,
94 IN PVOID Unused3,
95 IN PFMIFSCALLBACK Callback
96 );
97
98
99 typedef struct
100 {
101 WCHAR Drive;
102 UINT Options;
103 HMODULE hLibrary;
104 QUERY_AVAILABLEFSFORMAT QueryAvailableFileSystemFormat;
105 FORMAT_EX FormatEx;
106 ENABLEVOLUMECOMPRESSION EnableVolumeCompression;
107 CHKDSK Chkdsk;
108 UINT Result;
109 }FORMAT_DRIVE_CONTEXT, *PFORMAT_DRIVE_CONTEXT;
110
111 BOOL InitializeFmifsLibrary(PFORMAT_DRIVE_CONTEXT pContext);
112 BOOL GetDefaultClusterSize(LPWSTR szFs, PDWORD pClusterSize, PULARGE_INTEGER TotalNumberOfBytes);
113 HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj);
114 HWND WINAPI
115 DeviceCreateHardwarePageEx(HWND hWndParent,
116 LPGUID lpGuids,
117 UINT uNumberOfGuids,
118 HWPAGE_DISPLAYMODE DisplayMode);
119
120 HPROPSHEETPAGE SH_CreatePropertySheetPage(LPSTR resname, DLGPROC dlgproc, LPARAM lParam, LPWSTR szTitle);
121
122 #define DRIVE_PROPERTY_PAGES (3)
123
124 static const GUID GUID_DEVCLASS_DISKDRIVE = {0x4d36e967L, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}};
125
126
127 VOID
128 GetDriveNameWithLetter(LPWSTR szText, UINT Length, WCHAR Drive)
129 {
130 WCHAR szDrive[] = {'C',':','\\', 0};
131 DWORD dwMaxComp, dwFileSys, TempLength = 0;
132
133 szDrive[0] = Drive;
134 if (GetVolumeInformationW(szDrive, szText, Length, NULL, &dwMaxComp, &dwFileSys, NULL, 0))
135 {
136 szText[Length-1] = L'\0';
137 TempLength = wcslen(szText);
138 if (!TempLength)
139 {
140 /* load default volume label */
141 TempLength = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, &szText[Length+1], (sizeof(szText)/sizeof(WCHAR))- Length - 2);
142 }
143 }
144 if (TempLength + 4 < Length)
145 {
146 szText[TempLength] = L' ';
147 szText[TempLength+1] = L'(';
148 szText[TempLength+2] = szDrive[0];
149 szText[TempLength+3] = L')';
150 TempLength +=4;
151 }
152
153 if (TempLength < Length)
154 szText[TempLength] = L'\0';
155 else
156 szText[Length-1] = L'\0';
157 }
158
159
160 VOID
161 InitializeChkDskDialog(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
162 {
163 WCHAR szText[100];
164 UINT Length;
165 SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pContext);
166
167 Length = GetWindowTextW(hwndDlg, szText, sizeof(szText)/sizeof(WCHAR));
168
169 GetDriveNameWithLetter(&szText[Length +1], (sizeof(szText)/sizeof(WCHAR))-Length-1, pContext->Drive);
170 szText[Length] = L' ';
171 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
172 SetWindowText(hwndDlg, szText);
173 }
174
175 HWND ChkdskDrvDialog = NULL;
176 BOOLEAN bChkdskSuccess = FALSE;
177
178 BOOLEAN
179 NTAPI
180 ChkdskCallback(
181 IN CALLBACKCOMMAND Command,
182 IN ULONG SubAction,
183 IN PVOID ActionInfo)
184 {
185 PDWORD Progress;
186 PBOOLEAN pSuccess;
187 switch(Command)
188 {
189 case PROGRESS:
190 Progress = (PDWORD)ActionInfo;
191 SendDlgItemMessageW(ChkdskDrvDialog, 14002, PBM_SETPOS, (WPARAM)*Progress, 0);
192 break;
193 case DONE:
194 pSuccess = (PBOOLEAN)ActionInfo;
195 bChkdskSuccess = (*pSuccess);
196 break;
197
198 case VOLUMEINUSE:
199 case INSUFFICIENTRIGHTS:
200 case FSNOTSUPPORTED:
201 case CLUSTERSIZETOOSMALL:
202 bChkdskSuccess = FALSE;
203 FIXME("\n");
204 break;
205
206 default:
207 break;
208 }
209
210 return TRUE;
211 }
212
213 VOID
214 ChkDskNow(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
215 {
216 DWORD ClusterSize = 0, dwMaxComponentLength, FileSystemFlags;
217 WCHAR szFs[30];
218 WCHAR szDrive[] = {'C',':','\\', 0};
219 WCHAR szVolumeLabel[40];
220 ULARGE_INTEGER TotalNumberOfFreeBytes, FreeBytesAvailableUser;
221 BOOLEAN bCorrectErrors = FALSE, bScanDrive = FALSE;
222
223 szDrive[0] = pContext->Drive;
224 if(!GetVolumeInformationW(szDrive, szVolumeLabel, sizeof(szVolumeLabel)/sizeof(WCHAR), NULL, &dwMaxComponentLength, &FileSystemFlags, szFs, sizeof(szFs)/sizeof(WCHAR)))
225 {
226 FIXME("failed to get drive fs type\n");
227 return;
228 }
229
230 if (!GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfFreeBytes, NULL))
231 {
232 FIXME("failed to get drive space type\n");
233 return;
234 }
235
236 if (!GetDefaultClusterSize(szFs, &ClusterSize, &TotalNumberOfFreeBytes))
237 {
238 FIXME("invalid cluster size\n");
239 return;
240 }
241
242 if (SendDlgItemMessageW(hwndDlg, 14000, BM_GETCHECK, 0, 0) == BST_CHECKED)
243 bCorrectErrors = TRUE;
244
245 if (SendDlgItemMessageW(hwndDlg, 14001, BM_GETCHECK, 0, 0) == BST_CHECKED)
246 bScanDrive = TRUE;
247
248 ChkdskDrvDialog = hwndDlg;
249 bChkdskSuccess = FALSE;
250 SendDlgItemMessageW(hwndDlg, 14002, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
251 pContext->Chkdsk(szDrive, szFs, bCorrectErrors, TRUE, FALSE, bScanDrive, NULL, NULL, ChkdskCallback);
252
253 ChkdskDrvDialog = NULL;
254 pContext->Result = bChkdskSuccess;
255 bChkdskSuccess = FALSE;
256
257 }
258
259 INT_PTR
260 CALLBACK
261 ChkDskDlg(
262 HWND hwndDlg,
263 UINT uMsg,
264 WPARAM wParam,
265 LPARAM lParam
266 )
267 {
268 PFORMAT_DRIVE_CONTEXT pContext;
269 switch(uMsg)
270 {
271 case WM_INITDIALOG:
272 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
273 InitializeChkDskDialog(hwndDlg, (PFORMAT_DRIVE_CONTEXT)lParam);
274 return TRUE;
275 case WM_COMMAND:
276 switch(LOWORD(wParam))
277 {
278 case IDCANCEL:
279 EndDialog(hwndDlg, 0);
280 break;
281 case IDOK:
282 pContext = (PFORMAT_DRIVE_CONTEXT) GetWindowLongPtr(hwndDlg, DWLP_USER);
283 ChkDskNow(hwndDlg, pContext);
284 break;
285 }
286 break;
287 }
288
289 return FALSE;
290 }
291
292
293 static
294 LARGE_INTEGER
295 GetFreeBytesShare(LARGE_INTEGER TotalNumberOfFreeBytes, LARGE_INTEGER TotalNumberOfBytes)
296 {
297 LARGE_INTEGER Temp, Result, Remainder;
298
299 Temp = LargeIntegerDivide(TotalNumberOfBytes, ConvertUlongToLargeInteger(100), &Remainder);
300 if (Temp.QuadPart >= TotalNumberOfFreeBytes.QuadPart)
301 {
302 Result = ConvertUlongToLargeInteger(1);
303 }else
304 {
305 Result = LargeIntegerDivide(TotalNumberOfFreeBytes, Temp, &Remainder);
306 }
307
308 return Result;
309 }
310
311 static
312 void
313 PaintStaticControls(HWND hwndDlg, LPDRAWITEMSTRUCT drawItem)
314 {
315 HBRUSH hBrush;
316
317 if (drawItem->CtlID == 14013)
318 {
319 hBrush = CreateSolidBrush(RGB(0, 0, 255));
320 if (hBrush)
321 {
322 FillRect(drawItem->hDC, &drawItem->rcItem, hBrush);
323 DeleteObject((HGDIOBJ)hBrush);
324 }
325 }else if (drawItem->CtlID == 14014)
326 {
327 hBrush = CreateSolidBrush(RGB(255, 0, 255));
328 if (hBrush)
329 {
330 FillRect(drawItem->hDC, &drawItem->rcItem, hBrush);
331 DeleteObject((HGDIOBJ)hBrush);
332 }
333 }
334 else if (drawItem->CtlID == 14015)
335 {
336 HBRUSH hBlueBrush;
337 HBRUSH hMagBrush;
338 RECT rect;
339 LONG horzsize;
340 LARGE_INTEGER Result;
341 WCHAR szBuffer[20];
342
343 hBlueBrush = CreateSolidBrush(RGB(0, 0, 255));
344 hMagBrush = CreateSolidBrush(RGB(255, 0, 255));
345
346 SendDlgItemMessageW(hwndDlg, 14007, WM_GETTEXT, 20, (LPARAM)szBuffer);
347 Result.QuadPart = _wtoi(szBuffer);
348
349 CopyRect(&rect, &drawItem->rcItem);
350 horzsize = rect.right - rect.left;
351 Result.QuadPart = (Result.QuadPart * horzsize) / 100;
352
353 rect.right = drawItem->rcItem.right - Result.QuadPart;
354 FillRect(drawItem->hDC, &rect, hBlueBrush);
355 rect.left = rect.right;
356 rect.right = drawItem->rcItem.right;
357 FillRect(drawItem->hDC, &rect, hMagBrush);
358 DeleteObject(hBlueBrush);
359 DeleteObject(hMagBrush);
360 }
361 }
362
363 static
364 void
365 InitializeGeneralDriveDialog(HWND hwndDlg, WCHAR * szDrive)
366 {
367 WCHAR szVolumeName[MAX_PATH+1] = {0};
368 DWORD MaxComponentLength = 0;
369 DWORD FileSystemFlags = 0;
370 WCHAR FileSystemName[MAX_PATH+1] = {0};
371 WCHAR szFormat[50];
372 WCHAR szBuffer[128];
373 BOOL ret;
374 UINT DriveType;
375 ULARGE_INTEGER FreeBytesAvailable;
376 LARGE_INTEGER TotalNumberOfFreeBytes;
377 LARGE_INTEGER TotalNumberOfBytes;
378
379 ret = GetVolumeInformationW(szDrive, szVolumeName, MAX_PATH+1, NULL, &MaxComponentLength, &FileSystemFlags, FileSystemName, MAX_PATH+1);
380 if (ret)
381 {
382 /* set volume label */
383 SendDlgItemMessageW(hwndDlg, 14001, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szVolumeName);
384
385 /* set filesystem type */
386 SendDlgItemMessageW(hwndDlg, 14003, WM_SETTEXT, (WPARAM)NULL, (LPARAM)FileSystemName);
387
388 }
389
390 DriveType = GetDriveTypeW(szDrive);
391 if (DriveType == DRIVE_FIXED)
392 {
393
394 if(GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailable, (PULARGE_INTEGER)&TotalNumberOfBytes, (PULARGE_INTEGER)&TotalNumberOfFreeBytes))
395 {
396 WCHAR szResult[128];
397 LARGE_INTEGER Result;
398 #ifdef IOCTL_DISK_GET_LENGTH_INFO_IMPLEMENTED
399 HANDLE hVolume;
400 DWORD BytesReturned = 0;
401
402 swprintf(szResult, L"\\\\.\\%c:", towupper(szDrive[0]));
403 hVolume = CreateFileW(szResult, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
404 if (hVolume != INVALID_HANDLE_VALUE)
405 {
406 ret = DeviceIoControl(hVolume, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, (LPVOID)&TotalNumberOfBytes, sizeof(ULARGE_INTEGER), &BytesReturned, NULL);
407 if (ret && StrFormatByteSizeW(LengthInformation.Length.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
408 SendDlgItemMessageW(hwndDlg, 14008, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
409
410 CloseHandle(hVolume);
411 }
412 TRACE("szResult %s hVOlume %p ret %d LengthInformation %ul Bytesreturned %d\n", debugstr_w(szResult), hVolume, ret, LengthInformation.Length.QuadPart, BytesReturned);
413 #else
414 if (ret && StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
415 SendDlgItemMessageW(hwndDlg, 14008, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
416 #endif
417
418 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart - FreeBytesAvailable.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
419 SendDlgItemMessageW(hwndDlg, 14004, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
420
421 if (StrFormatByteSizeW(FreeBytesAvailable.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
422 SendDlgItemMessageW(hwndDlg, 14006, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
423
424 Result = GetFreeBytesShare(TotalNumberOfFreeBytes, TotalNumberOfBytes);
425 /* set free bytes percentage */
426 swprintf(szResult, L"%02d%%", Result.QuadPart);
427 SendDlgItemMessageW(hwndDlg, 14007, WM_SETTEXT, (WPARAM)0, (LPARAM)szResult);
428 /* store used share amount */
429 Result = LargeIntegerSubtract(ConvertUlongToLargeInteger(100), Result);
430 swprintf(szResult, L"%02d%%", Result.QuadPart);
431 SendDlgItemMessageW(hwndDlg, 14005, WM_SETTEXT, (WPARAM)0, (LPARAM)szResult);
432 if (LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
433 SendDlgItemMessageW(hwndDlg, 14002, WM_SETTEXT, (WPARAM)0, (LPARAM)szBuffer);
434
435 }
436 }
437 /* set drive description */
438 SendDlgItemMessageW(hwndDlg, 14010, WM_GETTEXT, (WPARAM)50, (LPARAM)szFormat);
439 swprintf(szBuffer, szFormat, szDrive);
440 SendDlgItemMessageW(hwndDlg, 14010, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szBuffer);
441 }
442
443
444 INT_PTR
445 CALLBACK
446 DriveGeneralDlg(
447 HWND hwndDlg,
448 UINT uMsg,
449 WPARAM wParam,
450 LPARAM lParam
451 )
452 {
453 LPPROPSHEETPAGEW ppsp;
454 LPDRAWITEMSTRUCT drawItem;
455 STARTUPINFOW si;
456 PROCESS_INFORMATION pi;
457 WCHAR * lpstr;
458 WCHAR szPath[MAX_PATH];
459 UINT length;
460 LPPSHNOTIFY lppsn;
461
462 switch(uMsg)
463 {
464 case WM_INITDIALOG:
465 ppsp = (LPPROPSHEETPAGEW)lParam;
466 if (ppsp == NULL)
467 break;
468 lpstr = (WCHAR *)ppsp->lParam;
469 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lpstr);
470 InitializeGeneralDriveDialog(hwndDlg, lpstr);
471 return TRUE;
472 case WM_DRAWITEM:
473 drawItem = (LPDRAWITEMSTRUCT)lParam;
474 if (drawItem->CtlID >= 14013 && drawItem->CtlID <= 14015)
475 {
476 PaintStaticControls(hwndDlg, drawItem);
477 return TRUE;
478 }
479 break;
480 case WM_COMMAND:
481 if (LOWORD(wParam) == 14011)
482 {
483 lpstr = (WCHAR*)GetWindowLongPtr(hwndDlg, DWLP_USER);
484 ZeroMemory( &si, sizeof(si) );
485 si.cb = sizeof(si);
486 ZeroMemory( &pi, sizeof(pi) );
487 if (!GetSystemDirectoryW(szPath, MAX_PATH))
488 break;
489 wcscat(szPath, L"\\cleanmgr.exe /D ");
490 length = wcslen(szPath);
491 szPath[length] = lpstr[0];
492 szPath[length+1] = L'\0';
493 if (CreateProcessW(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
494 {
495 CloseHandle(pi.hProcess);
496 CloseHandle(pi.hThread);
497 }
498 break;
499 }
500 case WM_NOTIFY:
501 lppsn = (LPPSHNOTIFY) lParam;
502 if (LOWORD(wParam) == 14001)
503 {
504 if (HIWORD(wParam) == EN_CHANGE)
505 {
506 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
507 }
508 break;
509 }
510 if (lppsn->hdr.code == PSN_APPLY)
511 {
512 lpstr = (LPWSTR)GetWindowLong(hwndDlg, DWLP_USER);
513 if (lpstr && SendDlgItemMessageW(hwndDlg, 14001, WM_GETTEXT, sizeof(szPath)/sizeof(WCHAR), (LPARAM)szPath))
514 {
515 szPath[(sizeof(szPath)/sizeof(WCHAR))-1] = L'\0';
516 SetVolumeLabelW(lpstr, szPath);
517 }
518 SetWindowLong( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR );
519 return TRUE;
520 }
521 break;
522
523 default:
524 break;
525 }
526
527
528 return FALSE;
529 }
530
531 INT_PTR
532 CALLBACK
533 DriveExtraDlg(
534 HWND hwndDlg,
535 UINT uMsg,
536 WPARAM wParam,
537 LPARAM lParam
538 )
539 {
540 STARTUPINFOW si;
541 PROCESS_INFORMATION pi;
542 WCHAR szPath[MAX_PATH + 10];
543 WCHAR szArg[MAX_PATH];
544 WCHAR * szDrive;
545 LPPROPSHEETPAGEW ppsp;
546 DWORD dwSize;
547 FORMAT_DRIVE_CONTEXT Context;
548
549 switch (uMsg)
550 {
551 case WM_INITDIALOG:
552 ppsp = (LPPROPSHEETPAGEW)lParam;
553 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)ppsp->lParam);
554 return TRUE;
555 case WM_COMMAND:
556 ZeroMemory( &si, sizeof(si) );
557 si.cb = sizeof(si);
558 ZeroMemory( &pi, sizeof(pi) );
559
560 szDrive = (WCHAR*)GetWindowLongPtr(hwndDlg, DWLP_USER);
561 switch(LOWORD(wParam))
562 {
563 case 14000:
564 if (InitializeFmifsLibrary(&Context))
565 {
566 Context.Drive = szDrive[0];
567 DialogBoxParamW(shell32_hInstance, L"CHKDSK_DLG", hwndDlg, ChkDskDlg, (LPARAM)&Context);
568 FreeLibrary(Context.hLibrary);
569 }
570 break;
571 case 14001:
572 dwSize = sizeof(szPath);
573 if (RegGetValueW(HKEY_LOCAL_MACHINE,
574 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\DefragPath",
575 NULL,
576 RRF_RT_REG_EXPAND_SZ,
577 NULL,
578 (PVOID)szPath,
579 &dwSize) == S_OK)
580 {
581 swprintf(szArg, szPath, szDrive[0]);
582 if (!GetSystemDirectoryW(szPath, MAX_PATH))
583 break;
584 szDrive = PathAddBackslashW(szPath);
585 if (!szDrive)
586 break;
587
588 wcscat(szDrive, L"mmc.exe");
589 if (CreateProcessW(szPath, szArg, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
590 {
591 CloseHandle(pi.hProcess);
592 CloseHandle(pi.hThread);
593 }
594 }
595 break;
596 case 14002:
597 dwSize = sizeof(szPath);
598 if (RegGetValueW(HKEY_LOCAL_MACHINE,
599 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\BackupPath",
600 NULL,
601 RRF_RT_REG_EXPAND_SZ,
602 NULL,
603 (PVOID)szPath,
604 &dwSize) == S_OK)
605 {
606 if (CreateProcessW(szPath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
607 {
608 CloseHandle(pi.hProcess);
609 CloseHandle(pi.hThread);
610 }
611 }
612 }
613 break;
614 }
615 return FALSE;
616 }
617
618 INT_PTR
619 CALLBACK
620 DriveHardwareDlg(
621 HWND hwndDlg,
622 UINT uMsg,
623 WPARAM wParam,
624 LPARAM lParam
625 )
626 {
627 GUID Guids[1];
628 Guids[0] = GUID_DEVCLASS_DISKDRIVE;
629
630 UNREFERENCED_PARAMETER(lParam);
631 UNREFERENCED_PARAMETER(wParam);
632
633 switch(uMsg)
634 {
635 case WM_INITDIALOG:
636 /* create the hardware page */
637 DeviceCreateHardwarePageEx(hwndDlg,
638 Guids,
639 sizeof(Guids) / sizeof(Guids[0]),
640 0);
641 break;
642 }
643
644 return FALSE;
645 }
646
647 static
648 const
649 struct
650 {
651 LPSTR resname;
652 DLGPROC dlgproc;
653 } PropPages[] =
654 {
655 { "DRIVE_GENERAL_DLG", DriveGeneralDlg },
656 { "DRIVE_EXTRA_DLG", DriveExtraDlg },
657 { "DRIVE_HARDWARE_DLG", DriveHardwareDlg },
658 };
659
660 HRESULT
661 CALLBACK
662 AddPropSheetPageProc(HPROPSHEETPAGE hpage, LPARAM lParam)
663 {
664 PROPSHEETHEADER *ppsh = (PROPSHEETHEADER *)lParam;
665 if (ppsh != NULL && ppsh->nPages < MAX_PROPERTY_SHEET_PAGE)
666 {
667 ppsh->phpage[ppsh->nPages++] = hpage;
668 return TRUE;
669 }
670 return FALSE;
671 }
672
673 BOOL
674 SH_ShowDriveProperties(WCHAR * drive, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST * apidl)
675 {
676 HPSXA hpsx = NULL;
677 HPROPSHEETPAGE hpsp[MAX_PROPERTY_SHEET_PAGE];
678 PROPSHEETHEADERW psh;
679 BOOL ret;
680 UINT i;
681 WCHAR szName[MAX_PATH];
682 DWORD dwMaxComponent, dwFileSysFlags;
683 IDataObject * pDataObj = NULL;
684
685 ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
686 psh.dwSize = sizeof(PROPSHEETHEADERW);
687 //psh.dwFlags = PSH_USECALLBACK | PSH_PROPTITLE;
688 psh.hwndParent = NULL;
689 psh.nStartPage = 0;
690 psh.phpage = hpsp;
691
692
693 if (GetVolumeInformationW(drive, szName, sizeof(szName)/sizeof(WCHAR), NULL, &dwMaxComponent,
694 &dwFileSysFlags, NULL, 0))
695 {
696 psh.pszCaption = szName;
697 psh.dwFlags |= PSH_PROPTITLE;
698 if (!wcslen(szName))
699 {
700 /* FIXME
701 * check if disk is a really a local hdd
702 */
703 i = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, szName, sizeof(szName)/sizeof(WCHAR));
704 if (i > 0 && i < (sizeof(szName)/sizeof(WCHAR)) + 6)
705 {
706 szName[i] = L' ';
707 szName[i+1] = L'(';
708 wcscpy(&szName[i+2], drive);
709 szName[i+4] = L')';
710 szName[i+5] = L'\0';
711 }
712 }
713 }
714
715 for (i = 0; i < DRIVE_PROPERTY_PAGES; i++)
716 {
717 HPROPSHEETPAGE hprop = SH_CreatePropertySheetPage(PropPages[i].resname, PropPages[i].dlgproc, (LPARAM)drive, NULL);
718 if (hprop)
719 {
720 hpsp[psh.nPages] = hprop;
721 psh.nPages++;
722 }
723 }
724 if (SHCreateDataObject(pidlFolder, 1, apidl, NULL, &IID_IDataObject, (void**)&pDataObj) == S_OK)
725 {
726 hpsx = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, L"Drive", MAX_PROPERTY_SHEET_PAGE-DRIVE_PROPERTY_PAGES, pDataObj);
727 if (hpsx)
728 {
729 SHAddFromPropSheetExtArray(hpsx, (LPFNADDPROPSHEETPAGE)AddPropSheetPageProc, (LPARAM)&psh);
730 }
731 }
732
733 ret = PropertySheetW(&psh);
734 if (pDataObj)
735 IDataObject_Release(pDataObj);
736
737 if (hpsx)
738 SHDestroyPropSheetExtArray(hpsx);
739
740 if (ret < 0)
741 return FALSE;
742 else
743 return TRUE;
744 }
745
746 BOOL
747 GetDefaultClusterSize(LPWSTR szFs, PDWORD pClusterSize, PULARGE_INTEGER TotalNumberOfBytes)
748 {
749 DWORD ClusterSize;
750
751 if (!wcsicmp(szFs, L"FAT16") ||
752 !wcsicmp(szFs, L"FAT")) //REACTOS HACK
753 {
754 if (TotalNumberOfBytes->QuadPart <= (16 * 1024 * 1024))
755 ClusterSize = 2048;
756 else if (TotalNumberOfBytes->QuadPart <= (32 * 1024 * 1024))
757 ClusterSize = 512;
758 else if (TotalNumberOfBytes->QuadPart <= (64 * 1024 * 1024))
759 ClusterSize = 1024;
760 else if (TotalNumberOfBytes->QuadPart <= (128 * 1024 * 1024))
761 ClusterSize = 2048;
762 else if (TotalNumberOfBytes->QuadPart <= (256 * 1024 * 1024))
763 ClusterSize = 4096;
764 else if (TotalNumberOfBytes->QuadPart <= (512 * 1024 * 1024))
765 ClusterSize = 8192;
766 else if (TotalNumberOfBytes->QuadPart <= (1024 * 1024 * 1024))
767 ClusterSize = 16384;
768 else if (TotalNumberOfBytes->QuadPart <= (2048LL * 1024LL * 1024LL))
769 ClusterSize = 32768;
770 else if (TotalNumberOfBytes->QuadPart <= (4096LL * 1024LL * 1024LL))
771 ClusterSize = 8192;
772 else
773 return FALSE;
774 }
775 else if (!wcsicmp(szFs, L"FAT32"))
776 {
777 if (TotalNumberOfBytes->QuadPart <=(64 * 1024 * 1024))
778 ClusterSize = 512;
779 else if (TotalNumberOfBytes->QuadPart <= (128 * 1024 * 1024))
780 ClusterSize = 1024;
781 else if (TotalNumberOfBytes->QuadPart <= (256 * 1024 * 1024))
782 ClusterSize = 2048;
783 else if (TotalNumberOfBytes->QuadPart <= (8192LL * 1024LL * 1024LL))
784 ClusterSize = 2048;
785 else if (TotalNumberOfBytes->QuadPart <= (16384LL * 1024LL * 1024LL))
786 ClusterSize = 8192;
787 else if (TotalNumberOfBytes->QuadPart <= (32768LL * 1024LL * 1024LL))
788 ClusterSize = 16384;
789 else
790 return FALSE;
791 }
792 else if (!wcsicmp(szFs, L"NTFS"))
793 {
794 if (TotalNumberOfBytes->QuadPart <=(512 * 1024 * 1024))
795 ClusterSize = 512;
796 else if (TotalNumberOfBytes->QuadPart <= (1024 * 1024 * 1024))
797 ClusterSize = 1024;
798 else if (TotalNumberOfBytes->QuadPart <= (2048LL * 1024LL * 1024LL))
799 ClusterSize = 2048;
800 else
801 ClusterSize = 2048;
802 }
803 else
804 return FALSE;
805
806 *pClusterSize = ClusterSize;
807 return TRUE;
808 }
809
810
811 VOID
812 InsertDefaultClusterSizeForFs(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
813 {
814 WCHAR szFs[100] = {0};
815 WCHAR szDrive[4] = { L'C', ':', '\\', 0 };
816 INT iSelIndex;
817 ULARGE_INTEGER FreeBytesAvailableUser, TotalNumberOfBytes;
818 DWORD ClusterSize;
819 LRESULT lIndex;
820 HWND hDlgCtrl;
821
822 hDlgCtrl = GetDlgItem(hwndDlg, 28677);
823 iSelIndex = SendMessage(hDlgCtrl, CB_GETCURSEL, 0, 0);
824 if (iSelIndex == CB_ERR)
825 return;
826
827 if (SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)szFs) == CB_ERR)
828 return;
829
830 szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0';
831 szDrive[0] = pContext->Drive + 'A';
832
833 if (!GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfBytes, NULL))
834 return;
835
836 if (!wcsicmp(szFs, L"FAT16") ||
837 !wcsicmp(szFs, L"FAT")) //REACTOS HACK
838 {
839 if (!GetDefaultClusterSize(szFs, &ClusterSize, &TotalNumberOfBytes))
840 {
841 TRACE("FAT16 is not supported on hdd larger than 4G current %lu\n", TotalNumberOfBytes.QuadPart);
842 SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0);
843 return;
844 }
845
846 if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, szFs, sizeof(szFs)/sizeof(WCHAR)))
847 {
848 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
849 szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0';
850 SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0);
851 lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs);
852 if (lIndex != CB_ERR)
853 SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
854 SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0);
855 }
856 }
857 else if (!wcsicmp(szFs, L"FAT32"))
858 {
859 if (!GetDefaultClusterSize(szFs, &ClusterSize, &TotalNumberOfBytes))
860 {
861 TRACE("FAT32 is not supported on hdd larger than 32G current %lu\n", TotalNumberOfBytes.QuadPart);
862 SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0);
863 return;
864 }
865
866 if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, szFs, sizeof(szFs)/sizeof(WCHAR)))
867 {
868 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
869 szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0';
870 SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0);
871 lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs);
872 if (lIndex != CB_ERR)
873 SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
874 SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0);
875 }
876 }
877 else if (!wcsicmp(szFs, L"NTFS"))
878 {
879 if (!GetDefaultClusterSize(szFs, &ClusterSize, &TotalNumberOfBytes))
880 {
881 TRACE("NTFS is not supported on hdd larger than 2TB current %lu\n", TotalNumberOfBytes.QuadPart);
882 SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0);
883 return;
884 }
885
886 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
887 if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, szFs, sizeof(szFs)/sizeof(WCHAR)))
888 {
889 szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0';
890 SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0);
891 lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs);
892 if (lIndex != CB_ERR)
893 SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
894 SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0);
895 }
896 ClusterSize = 512;
897 for (lIndex = 0; lIndex < 4; lIndex++)
898 {
899 TotalNumberOfBytes.QuadPart = ClusterSize;
900 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szFs, sizeof(szFs)/sizeof(WCHAR)))
901 {
902 lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs);
903 if (lIndex != CB_ERR)
904 SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
905 }
906 ClusterSize *= 2;
907 }
908 }
909 else
910 {
911 FIXME("unknown fs\n");
912 SendDlgItemMessageW(hwndDlg, 28680, CB_RESETCONTENT, iSelIndex, 0);
913 return;
914 }
915 }
916
917 VOID
918 InitializeFormatDriveDlg(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
919 {
920 WCHAR szText[120];
921 WCHAR szDrive[4] = { L'C', ':', '\\', 0 };
922 WCHAR szFs[30] = {0};
923 INT Length, TempLength;
924 DWORD dwSerial, dwMaxComp, dwFileSys;
925 ULARGE_INTEGER FreeBytesAvailableUser, TotalNumberOfBytes;
926 DWORD dwIndex, dwDefault;
927 UCHAR uMinor, uMajor;
928 BOOLEAN Latest;
929 HWND hDlgCtrl;
930
931 Length = GetWindowTextW(hwndDlg, szText, sizeof(szText)/sizeof(WCHAR));
932 szDrive[0] = pContext->Drive + L'A';
933 if (GetVolumeInformationW(szDrive, &szText[Length+1], (sizeof(szText)/sizeof(WCHAR))- Length - 2, &dwSerial, &dwMaxComp, &dwFileSys, szFs, sizeof(szFs)/sizeof(WCHAR)))
934 {
935 szText[Length] = L' ';
936 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
937 TempLength = wcslen(&szText[Length+1]);
938 if (!TempLength)
939 {
940 /* load default volume label */
941 TempLength = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, &szText[Length+1], (sizeof(szText)/sizeof(WCHAR))- Length - 2);
942 }
943 else
944 {
945 /* set volume label */
946 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
947 SendDlgItemMessageW(hwndDlg, 28679, WM_SETTEXT, 0, (LPARAM)&szText[Length+1]);
948 }
949 Length += TempLength + 1;
950 }
951
952 if (Length + 4 < (sizeof(szText)/sizeof(WCHAR)))
953 {
954 szText[Length] = L' ';
955 szText[Length+1] = L'(';
956 szText[Length+2] = szDrive[0];
957 szText[Length+3] = L')';
958 Length +=4;
959 }
960
961 if (Length < (sizeof(szText)/sizeof(WCHAR)))
962 szText[Length] = L'\0';
963 else
964 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
965
966 /* set window text */
967 SetWindowTextW(hwndDlg, szText);
968
969 if (GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfBytes, NULL))
970 {
971 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szText, sizeof(szText)/sizeof(WCHAR)))
972 {
973 /* add drive capacity */
974 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
975 SendDlgItemMessageW(hwndDlg, 28673, CB_ADDSTRING, 0, (LPARAM)szText);
976 SendDlgItemMessageW(hwndDlg, 28673, CB_SETCURSEL, 0, (LPARAM)0);
977 }
978 }
979
980 if (pContext->Options & SHFMT_OPT_FULL)
981 {
982 /* check quick format button */
983 SendDlgItemMessageW(hwndDlg, 28674, BM_SETCHECK, BST_CHECKED, 0);
984 }
985
986 /* enumerate all available filesystems */
987 dwIndex = 0;
988 dwDefault = 0;
989 hDlgCtrl = GetDlgItem(hwndDlg, 28677);
990
991 while(pContext->QueryAvailableFileSystemFormat(dwIndex, szText, &uMajor, &uMinor, &Latest))
992 {
993 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
994 if (!wcsicmp(szText, szFs))
995 dwDefault = dwIndex;
996
997 SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szText);
998 dwIndex++;
999 }
1000
1001 if (!dwIndex)
1002 {
1003 ERR("no filesystem providers\n");
1004 return;
1005 }
1006
1007 /* select default filesys */
1008 SendMessageW(hDlgCtrl, CB_SETCURSEL, dwDefault, 0);
1009 /* setup cluster combo */
1010 InsertDefaultClusterSizeForFs(hwndDlg, pContext);
1011 /* hide progress control */
1012 ShowWindow(GetDlgItem(hwndDlg, 28678), SW_HIDE);
1013 }
1014
1015 HWND FormatDrvDialog = NULL;
1016 BOOLEAN bSuccess = FALSE;
1017
1018
1019 BOOLEAN
1020 NTAPI
1021 FormatExCB(
1022 IN CALLBACKCOMMAND Command,
1023 IN ULONG SubAction,
1024 IN PVOID ActionInfo)
1025 {
1026 PDWORD Progress;
1027 PBOOLEAN pSuccess;
1028 switch(Command)
1029 {
1030 case PROGRESS:
1031 Progress = (PDWORD)ActionInfo;
1032 SendDlgItemMessageW(FormatDrvDialog, 28678, PBM_SETPOS, (WPARAM)*Progress, 0);
1033 break;
1034 case DONE:
1035 pSuccess = (PBOOLEAN)ActionInfo;
1036 bSuccess = (*pSuccess);
1037 break;
1038
1039 case VOLUMEINUSE:
1040 case INSUFFICIENTRIGHTS:
1041 case FSNOTSUPPORTED:
1042 case CLUSTERSIZETOOSMALL:
1043 bSuccess = FALSE;
1044 FIXME("\n");
1045 break;
1046
1047 default:
1048 break;
1049 }
1050
1051 return TRUE;
1052 }
1053
1054
1055
1056
1057
1058 VOID
1059 FormatDrive(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
1060 {
1061 WCHAR szDrive[4] = { L'C', ':', '\\', 0 };
1062 WCHAR szFileSys[40] = {0};
1063 WCHAR szLabel[40] = {0};
1064 INT iSelIndex;
1065 UINT Length;
1066 HWND hDlgCtrl;
1067 BOOL QuickFormat;
1068 DWORD ClusterSize;
1069
1070 /* set volume path */
1071 szDrive[0] = pContext->Drive;
1072
1073 /* get filesystem */
1074 hDlgCtrl = GetDlgItem(hwndDlg, 28677);
1075 iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
1076 if (iSelIndex == CB_ERR)
1077 {
1078 FIXME("\n");
1079 return;
1080 }
1081 Length = SendMessageW(hDlgCtrl, CB_GETLBTEXTLEN, iSelIndex, 0);
1082 if (Length == CB_ERR || Length + 1> sizeof(szFileSys)/sizeof(WCHAR))
1083 {
1084 FIXME("\n");
1085 return;
1086 }
1087
1088 /* retrieve the file system */
1089 SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)szFileSys);
1090 szFileSys[(sizeof(szFileSys)/sizeof(WCHAR))-1] = L'\0';
1091
1092 /* retrieve the volume label */
1093 hDlgCtrl = GetWindow(hwndDlg, 28679);
1094 Length = SendMessageW(hDlgCtrl, WM_GETTEXTLENGTH, 0, 0);
1095 if (Length + 1 > sizeof(szLabel)/sizeof(WCHAR))
1096 {
1097 FIXME("\n");
1098 return;
1099 }
1100 SendMessageW(hDlgCtrl, WM_GETTEXT, sizeof(szLabel)/sizeof(WCHAR), (LPARAM)szLabel);
1101 szLabel[(sizeof(szLabel)/sizeof(WCHAR))-1] = L'\0';
1102
1103 /* check for quickformat */
1104 if (SendDlgItemMessageW(hwndDlg, 28674, BM_GETCHECK, 0, 0) == BST_CHECKED)
1105 QuickFormat = TRUE;
1106 else
1107 QuickFormat = FALSE;
1108
1109 /* get the cluster size */
1110 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
1111 iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
1112 if (iSelIndex == CB_ERR)
1113 {
1114 FIXME("\n");
1115 return;
1116 }
1117 ClusterSize = SendMessageW(hDlgCtrl, CB_GETITEMDATA, iSelIndex, 0);
1118 if (ClusterSize == CB_ERR)
1119 {
1120 FIXME("\n");
1121 return;
1122 }
1123
1124 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
1125 ShowWindow(hDlgCtrl, SW_SHOW);
1126 SendMessageW(hDlgCtrl, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
1127 bSuccess = FALSE;
1128
1129 /* FIXME
1130 * will cause display problems
1131 * when performing more than one format
1132 */
1133 FormatDrvDialog = hwndDlg;
1134
1135 pContext->FormatEx(szDrive,
1136 FMIFS_HARDDISK, /* FIXME */
1137 szFileSys,
1138 szLabel,
1139 QuickFormat,
1140 ClusterSize,
1141 FormatExCB);
1142
1143 ShowWindow(hDlgCtrl, SW_HIDE);
1144 FormatDrvDialog = NULL;
1145 if (!bSuccess)
1146 {
1147 pContext->Result = SHFMT_ERROR;
1148 }
1149 else if (QuickFormat)
1150 {
1151 pContext->Result = SHFMT_OPT_FULL;
1152 }
1153 else
1154 {
1155 pContext->Result = FALSE;
1156 }
1157 }
1158
1159
1160 BOOL
1161 CALLBACK
1162 FormatDriveDlg(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
1163 {
1164 PFORMAT_DRIVE_CONTEXT pContext;
1165
1166 switch(uMsg)
1167 {
1168 case WM_INITDIALOG:
1169 InitializeFormatDriveDlg(hwndDlg, (PFORMAT_DRIVE_CONTEXT)lParam);
1170 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
1171 return TRUE;
1172 case WM_COMMAND:
1173 switch(LOWORD(wParam))
1174 {
1175 case IDOK:
1176 pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
1177 FormatDrive(hwndDlg, pContext);
1178 break;
1179 case IDCANCEL:
1180 pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
1181 EndDialog(hwndDlg, pContext->Result);
1182 break;
1183 case 28677: // filesystem combo
1184 if (HIWORD(wParam) == CBN_SELENDOK)
1185 {
1186 pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
1187 InsertDefaultClusterSizeForFs(hwndDlg, pContext);
1188 }
1189 break;
1190 }
1191 }
1192 return FALSE;
1193 }
1194
1195
1196 BOOL
1197 InitializeFmifsLibrary(PFORMAT_DRIVE_CONTEXT pContext)
1198 {
1199 INITIALIZE_FMIFS InitFmifs;
1200 BOOLEAN ret;
1201 HMODULE hLibrary;
1202
1203 hLibrary = pContext->hLibrary = LoadLibraryW(L"fmifs.dll");
1204 if(!hLibrary)
1205 {
1206 ERR("failed to load fmifs.dll\n");
1207 return FALSE;
1208 }
1209
1210 InitFmifs = (INITIALIZE_FMIFS)GetProcAddress(hLibrary, "InitializeFmIfs");
1211 if (!InitFmifs)
1212 {
1213 ERR("InitializeFmIfs export is missing\n");
1214 FreeLibrary(hLibrary);
1215 return FALSE;
1216 }
1217
1218 ret = (*InitFmifs)(NULL, DLL_PROCESS_ATTACH, NULL);
1219 if (!ret)
1220 {
1221 ERR("fmifs failed to initialize\n");
1222 FreeLibrary(hLibrary);
1223 return FALSE;
1224 }
1225
1226 pContext->QueryAvailableFileSystemFormat = (QUERY_AVAILABLEFSFORMAT)GetProcAddress(hLibrary, "QueryAvailableFileSystemFormat");
1227 if (!pContext->QueryAvailableFileSystemFormat)
1228 {
1229 ERR("QueryAvailableFileSystemFormat export is missing\n");
1230 FreeLibrary(hLibrary);
1231 return FALSE;
1232 }
1233
1234 pContext->FormatEx = (FORMAT_EX) GetProcAddress(hLibrary, "FormatEx");
1235 if (!pContext->FormatEx)
1236 {
1237 ERR("FormatEx export is missing\n");
1238 FreeLibrary(hLibrary);
1239 return FALSE;
1240 }
1241
1242 pContext->EnableVolumeCompression = (ENABLEVOLUMECOMPRESSION) GetProcAddress(hLibrary, "EnableVolumeCompression");
1243 if (!pContext->FormatEx)
1244 {
1245 ERR("EnableVolumeCompression export is missing\n");
1246 FreeLibrary(hLibrary);
1247 return FALSE;
1248 }
1249
1250 pContext->Chkdsk = (CHKDSK) GetProcAddress(hLibrary, "Chkdsk");
1251 if (!pContext->Chkdsk)
1252 {
1253 ERR("Chkdsk export is missing\n");
1254 FreeLibrary(hLibrary);
1255 return FALSE;
1256 }
1257
1258 return TRUE;
1259 }
1260
1261 /*************************************************************************
1262 * SHFormatDrive (SHELL32.@)
1263 */
1264
1265 DWORD
1266 WINAPI
1267 SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options)
1268 {
1269 FORMAT_DRIVE_CONTEXT Context;
1270 int result;
1271
1272 TRACE("%p, 0x%08x, 0x%08x, 0x%08x - stub\n", hwnd, drive, fmtID, options);
1273
1274 if (!InitializeFmifsLibrary(&Context))
1275 {
1276 ERR("failed to initialize fmifs\n");
1277 return SHFMT_NOFORMAT;
1278 }
1279
1280 Context.Drive = drive;
1281 Context.Options = options;
1282
1283 result = DialogBoxParamW(shell32_hInstance, L"FORMAT_DLG", hwnd, FormatDriveDlg, (LPARAM)&Context);
1284
1285 FreeLibrary(Context.hLibrary);
1286 return result;
1287 }
1288
1289