sync to trunk head (37079)
[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+6];
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)-6);
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 if (Length < 0)
933 Length = 0;
934 szDrive[0] = pContext->Drive + L'A';
935 if (GetVolumeInformationW(szDrive, &szText[Length+1], (sizeof(szText)/sizeof(WCHAR))- Length - 2, &dwSerial, &dwMaxComp, &dwFileSys, szFs, sizeof(szFs)/sizeof(WCHAR)))
936 {
937 szText[Length] = L' ';
938 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
939 TempLength = wcslen(&szText[Length+1]);
940 if (!TempLength)
941 {
942 /* load default volume label */
943 TempLength = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, &szText[Length+1], (sizeof(szText)/sizeof(WCHAR))- Length - 2);
944 }
945 else
946 {
947 /* set volume label */
948 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
949 SendDlgItemMessageW(hwndDlg, 28679, WM_SETTEXT, 0, (LPARAM)&szText[Length+1]);
950 }
951 Length += TempLength + 1;
952 }
953
954 if (Length + 4 < (sizeof(szText)/sizeof(WCHAR)))
955 {
956 szText[Length] = L' ';
957 szText[Length+1] = L'(';
958 szText[Length+2] = szDrive[0];
959 szText[Length+3] = L')';
960 Length +=4;
961 }
962
963 if (Length < (sizeof(szText)/sizeof(WCHAR)))
964 szText[Length] = L'\0';
965 else
966 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
967
968 /* set window text */
969 SetWindowTextW(hwndDlg, szText);
970
971 if (GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfBytes, NULL))
972 {
973 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szText, sizeof(szText)/sizeof(WCHAR)))
974 {
975 /* add drive capacity */
976 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
977 SendDlgItemMessageW(hwndDlg, 28673, CB_ADDSTRING, 0, (LPARAM)szText);
978 SendDlgItemMessageW(hwndDlg, 28673, CB_SETCURSEL, 0, (LPARAM)0);
979 }
980 }
981
982 if (pContext->Options & SHFMT_OPT_FULL)
983 {
984 /* check quick format button */
985 SendDlgItemMessageW(hwndDlg, 28674, BM_SETCHECK, BST_CHECKED, 0);
986 }
987
988 /* enumerate all available filesystems */
989 dwIndex = 0;
990 dwDefault = 0;
991 hDlgCtrl = GetDlgItem(hwndDlg, 28677);
992
993 while(pContext->QueryAvailableFileSystemFormat(dwIndex, szText, &uMajor, &uMinor, &Latest))
994 {
995 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
996 if (!wcsicmp(szText, szFs))
997 dwDefault = dwIndex;
998
999 SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szText);
1000 dwIndex++;
1001 }
1002
1003 if (!dwIndex)
1004 {
1005 ERR("no filesystem providers\n");
1006 return;
1007 }
1008
1009 /* select default filesys */
1010 SendMessageW(hDlgCtrl, CB_SETCURSEL, dwDefault, 0);
1011 /* setup cluster combo */
1012 InsertDefaultClusterSizeForFs(hwndDlg, pContext);
1013 /* hide progress control */
1014 ShowWindow(GetDlgItem(hwndDlg, 28678), SW_HIDE);
1015 }
1016
1017 HWND FormatDrvDialog = NULL;
1018 BOOLEAN bSuccess = FALSE;
1019
1020
1021 BOOLEAN
1022 NTAPI
1023 FormatExCB(
1024 IN CALLBACKCOMMAND Command,
1025 IN ULONG SubAction,
1026 IN PVOID ActionInfo)
1027 {
1028 PDWORD Progress;
1029 PBOOLEAN pSuccess;
1030 switch(Command)
1031 {
1032 case PROGRESS:
1033 Progress = (PDWORD)ActionInfo;
1034 SendDlgItemMessageW(FormatDrvDialog, 28678, PBM_SETPOS, (WPARAM)*Progress, 0);
1035 break;
1036 case DONE:
1037 pSuccess = (PBOOLEAN)ActionInfo;
1038 bSuccess = (*pSuccess);
1039 break;
1040
1041 case VOLUMEINUSE:
1042 case INSUFFICIENTRIGHTS:
1043 case FSNOTSUPPORTED:
1044 case CLUSTERSIZETOOSMALL:
1045 bSuccess = FALSE;
1046 FIXME("\n");
1047 break;
1048
1049 default:
1050 break;
1051 }
1052
1053 return TRUE;
1054 }
1055
1056
1057
1058
1059
1060 VOID
1061 FormatDrive(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
1062 {
1063 WCHAR szDrive[4] = { L'C', ':', '\\', 0 };
1064 WCHAR szFileSys[40] = {0};
1065 WCHAR szLabel[40] = {0};
1066 INT iSelIndex;
1067 UINT Length;
1068 HWND hDlgCtrl;
1069 BOOL QuickFormat;
1070 DWORD ClusterSize;
1071
1072 /* set volume path */
1073 szDrive[0] = pContext->Drive;
1074
1075 /* get filesystem */
1076 hDlgCtrl = GetDlgItem(hwndDlg, 28677);
1077 iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
1078 if (iSelIndex == CB_ERR)
1079 {
1080 FIXME("\n");
1081 return;
1082 }
1083 Length = SendMessageW(hDlgCtrl, CB_GETLBTEXTLEN, iSelIndex, 0);
1084 if (Length == CB_ERR || Length + 1> sizeof(szFileSys)/sizeof(WCHAR))
1085 {
1086 FIXME("\n");
1087 return;
1088 }
1089
1090 /* retrieve the file system */
1091 SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)szFileSys);
1092 szFileSys[(sizeof(szFileSys)/sizeof(WCHAR))-1] = L'\0';
1093
1094 /* retrieve the volume label */
1095 hDlgCtrl = GetWindow(hwndDlg, 28679);
1096 Length = SendMessageW(hDlgCtrl, WM_GETTEXTLENGTH, 0, 0);
1097 if (Length + 1 > sizeof(szLabel)/sizeof(WCHAR))
1098 {
1099 FIXME("\n");
1100 return;
1101 }
1102 SendMessageW(hDlgCtrl, WM_GETTEXT, sizeof(szLabel)/sizeof(WCHAR), (LPARAM)szLabel);
1103 szLabel[(sizeof(szLabel)/sizeof(WCHAR))-1] = L'\0';
1104
1105 /* check for quickformat */
1106 if (SendDlgItemMessageW(hwndDlg, 28674, BM_GETCHECK, 0, 0) == BST_CHECKED)
1107 QuickFormat = TRUE;
1108 else
1109 QuickFormat = FALSE;
1110
1111 /* get the cluster size */
1112 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
1113 iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
1114 if (iSelIndex == CB_ERR)
1115 {
1116 FIXME("\n");
1117 return;
1118 }
1119 ClusterSize = SendMessageW(hDlgCtrl, CB_GETITEMDATA, iSelIndex, 0);
1120 if (ClusterSize == CB_ERR)
1121 {
1122 FIXME("\n");
1123 return;
1124 }
1125
1126 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
1127 ShowWindow(hDlgCtrl, SW_SHOW);
1128 SendMessageW(hDlgCtrl, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
1129 bSuccess = FALSE;
1130
1131 /* FIXME
1132 * will cause display problems
1133 * when performing more than one format
1134 */
1135 FormatDrvDialog = hwndDlg;
1136
1137 pContext->FormatEx(szDrive,
1138 FMIFS_HARDDISK, /* FIXME */
1139 szFileSys,
1140 szLabel,
1141 QuickFormat,
1142 ClusterSize,
1143 FormatExCB);
1144
1145 ShowWindow(hDlgCtrl, SW_HIDE);
1146 FormatDrvDialog = NULL;
1147 if (!bSuccess)
1148 {
1149 pContext->Result = SHFMT_ERROR;
1150 }
1151 else if (QuickFormat)
1152 {
1153 pContext->Result = SHFMT_OPT_FULL;
1154 }
1155 else
1156 {
1157 pContext->Result = FALSE;
1158 }
1159 }
1160
1161
1162 BOOL
1163 CALLBACK
1164 FormatDriveDlg(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
1165 {
1166 PFORMAT_DRIVE_CONTEXT pContext;
1167
1168 switch(uMsg)
1169 {
1170 case WM_INITDIALOG:
1171 InitializeFormatDriveDlg(hwndDlg, (PFORMAT_DRIVE_CONTEXT)lParam);
1172 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
1173 return TRUE;
1174 case WM_COMMAND:
1175 switch(LOWORD(wParam))
1176 {
1177 case IDOK:
1178 pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
1179 FormatDrive(hwndDlg, pContext);
1180 break;
1181 case IDCANCEL:
1182 pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
1183 EndDialog(hwndDlg, pContext->Result);
1184 break;
1185 case 28677: // filesystem combo
1186 if (HIWORD(wParam) == CBN_SELENDOK)
1187 {
1188 pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
1189 InsertDefaultClusterSizeForFs(hwndDlg, pContext);
1190 }
1191 break;
1192 }
1193 }
1194 return FALSE;
1195 }
1196
1197
1198 BOOL
1199 InitializeFmifsLibrary(PFORMAT_DRIVE_CONTEXT pContext)
1200 {
1201 INITIALIZE_FMIFS InitFmifs;
1202 BOOLEAN ret;
1203 HMODULE hLibrary;
1204
1205 hLibrary = pContext->hLibrary = LoadLibraryW(L"fmifs.dll");
1206 if(!hLibrary)
1207 {
1208 ERR("failed to load fmifs.dll\n");
1209 return FALSE;
1210 }
1211
1212 InitFmifs = (INITIALIZE_FMIFS)GetProcAddress(hLibrary, "InitializeFmIfs");
1213 if (!InitFmifs)
1214 {
1215 ERR("InitializeFmIfs export is missing\n");
1216 FreeLibrary(hLibrary);
1217 return FALSE;
1218 }
1219
1220 ret = (*InitFmifs)(NULL, DLL_PROCESS_ATTACH, NULL);
1221 if (!ret)
1222 {
1223 ERR("fmifs failed to initialize\n");
1224 FreeLibrary(hLibrary);
1225 return FALSE;
1226 }
1227
1228 pContext->QueryAvailableFileSystemFormat = (QUERY_AVAILABLEFSFORMAT)GetProcAddress(hLibrary, "QueryAvailableFileSystemFormat");
1229 if (!pContext->QueryAvailableFileSystemFormat)
1230 {
1231 ERR("QueryAvailableFileSystemFormat export is missing\n");
1232 FreeLibrary(hLibrary);
1233 return FALSE;
1234 }
1235
1236 pContext->FormatEx = (FORMAT_EX) GetProcAddress(hLibrary, "FormatEx");
1237 if (!pContext->FormatEx)
1238 {
1239 ERR("FormatEx export is missing\n");
1240 FreeLibrary(hLibrary);
1241 return FALSE;
1242 }
1243
1244 pContext->EnableVolumeCompression = (ENABLEVOLUMECOMPRESSION) GetProcAddress(hLibrary, "EnableVolumeCompression");
1245 if (!pContext->FormatEx)
1246 {
1247 ERR("EnableVolumeCompression export is missing\n");
1248 FreeLibrary(hLibrary);
1249 return FALSE;
1250 }
1251
1252 pContext->Chkdsk = (CHKDSK) GetProcAddress(hLibrary, "Chkdsk");
1253 if (!pContext->Chkdsk)
1254 {
1255 ERR("Chkdsk export is missing\n");
1256 FreeLibrary(hLibrary);
1257 return FALSE;
1258 }
1259
1260 return TRUE;
1261 }
1262
1263 /*************************************************************************
1264 * SHFormatDrive (SHELL32.@)
1265 */
1266
1267 DWORD
1268 WINAPI
1269 SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options)
1270 {
1271 FORMAT_DRIVE_CONTEXT Context;
1272 int result;
1273
1274 TRACE("%p, 0x%08x, 0x%08x, 0x%08x - stub\n", hwnd, drive, fmtID, options);
1275
1276 if (!InitializeFmifsLibrary(&Context))
1277 {
1278 ERR("failed to initialize fmifs\n");
1279 return SHFMT_NOFORMAT;
1280 }
1281
1282 Context.Drive = drive;
1283 Context.Options = options;
1284
1285 result = DialogBoxParamW(shell32_hInstance, L"FORMAT_DLG", hwnd, FormatDriveDlg, (LPARAM)&Context);
1286
1287 FreeLibrary(Context.hLibrary);
1288 return result;
1289 }
1290
1291