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