* Fix multiple bugs in SHFormatDrive dialog
[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
96 typedef struct
97 {
98 WCHAR Drive;
99 UINT Options;
100 HMODULE hLibrary;
101 QUERY_AVAILABLEFSFORMAT QueryAvailableFileSystemFormat;
102 FORMAT_EX FormatEx;
103 ENABLEVOLUMECOMPRESSION EnableVolumeCompression;
104 UINT Result;
105 }FORMAT_DRIVE_CONTEXT, *PFORMAT_DRIVE_CONTEXT;
106
107 HWND WINAPI
108 DeviceCreateHardwarePageEx(HWND hWndParent,
109 LPGUID lpGuids,
110 UINT uNumberOfGuids,
111 HWPAGE_DISPLAYMODE DisplayMode);
112
113 HPROPSHEETPAGE SH_CreatePropertySheetPage(LPSTR resname, DLGPROC dlgproc, LPARAM lParam, LPWSTR szTitle);
114
115 #define DRIVE_PROPERTY_PAGES (3)
116
117 extern HINSTANCE shell32_hInstance;
118
119 static
120 LARGE_INTEGER
121 GetFreeBytesShare(LARGE_INTEGER TotalNumberOfFreeBytes, LARGE_INTEGER TotalNumberOfBytes)
122 {
123 LARGE_INTEGER Temp, Result, Remainder;
124
125 Temp = LargeIntegerDivide(TotalNumberOfBytes, ConvertUlongToLargeInteger(100), &Remainder);
126 if (Temp.QuadPart >= TotalNumberOfFreeBytes.QuadPart)
127 {
128 Result = ConvertUlongToLargeInteger(1);
129 }else
130 {
131 Result = LargeIntegerDivide(TotalNumberOfFreeBytes, Temp, &Remainder);
132 }
133
134 return Result;
135 }
136
137 static
138 void
139 PaintStaticControls(HWND hwndDlg, LPDRAWITEMSTRUCT drawItem)
140 {
141 HBRUSH hBrush;
142
143 if (drawItem->CtlID == 14013)
144 {
145 hBrush = CreateSolidBrush(RGB(0, 0, 255));
146 if (hBrush)
147 {
148 FillRect(drawItem->hDC, &drawItem->rcItem, hBrush);
149 DeleteObject((HGDIOBJ)hBrush);
150 }
151 }else if (drawItem->CtlID == 14014)
152 {
153 hBrush = CreateSolidBrush(RGB(255, 0, 255));
154 if (hBrush)
155 {
156 FillRect(drawItem->hDC, &drawItem->rcItem, hBrush);
157 DeleteObject((HGDIOBJ)hBrush);
158 }
159 }
160 else if (drawItem->CtlID == 14015)
161 {
162 HBRUSH hBlueBrush;
163 HBRUSH hMagBrush;
164 RECT rect;
165 LONG horzsize;
166 LARGE_INTEGER Result;
167 WCHAR szBuffer[20];
168
169 hBlueBrush = CreateSolidBrush(RGB(0, 0, 255));
170 hMagBrush = CreateSolidBrush(RGB(255, 0, 255));
171
172 SendDlgItemMessageW(hwndDlg, 14007, WM_GETTEXT, 20, (LPARAM)szBuffer);
173 Result.QuadPart = _wtoi(szBuffer);
174
175 CopyRect(&rect, &drawItem->rcItem);
176 horzsize = rect.right - rect.left;
177 Result.QuadPart = (Result.QuadPart * horzsize) / 100;
178
179 rect.right = rect.left + Result.QuadPart;
180 FillRect(drawItem->hDC, &rect, hMagBrush);
181 rect.left = rect.right;
182 rect.right = drawItem->rcItem.right;
183 FillRect(drawItem->hDC, &rect, hBlueBrush);
184 DeleteObject(hBlueBrush);
185 DeleteObject(hMagBrush);
186 }
187 }
188
189 static
190 void
191 InitializeGeneralDriveDialog(HWND hwndDlg, WCHAR * szDrive)
192 {
193 WCHAR szVolumeName[MAX_PATH+1] = {0};
194 DWORD MaxComponentLength = 0;
195 DWORD FileSystemFlags = 0;
196 WCHAR FileSystemName[MAX_PATH+1] = {0};
197 WCHAR szFormat[50];
198 WCHAR szBuffer[128];
199 BOOL ret;
200 UINT DriveType;
201 ULARGE_INTEGER FreeBytesAvailable;
202 LARGE_INTEGER TotalNumberOfFreeBytes;
203 LARGE_INTEGER TotalNumberOfBytes;
204
205 ret = GetVolumeInformationW(szDrive, szVolumeName, MAX_PATH+1, NULL, &MaxComponentLength, &FileSystemFlags, FileSystemName, MAX_PATH+1);
206 if (ret)
207 {
208 /* set volume label */
209 SendDlgItemMessageW(hwndDlg, 14001, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szVolumeName);
210
211 /* set filesystem type */
212 SendDlgItemMessageW(hwndDlg, 14003, WM_SETTEXT, (WPARAM)NULL, (LPARAM)FileSystemName);
213
214 }
215
216 DriveType = GetDriveTypeW(szDrive);
217 if (DriveType == DRIVE_FIXED)
218 {
219
220 if(GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailable, (PULARGE_INTEGER)&TotalNumberOfBytes, (PULARGE_INTEGER)&TotalNumberOfFreeBytes))
221 {
222 WCHAR szResult[128];
223 LARGE_INTEGER Result;
224 #ifdef IOCTL_DISK_GET_LENGTH_INFO_IMPLEMENTED
225 HANDLE hVolume;
226 DWORD BytesReturned = 0;
227
228 sprintfW(szResult, L"\\\\.\\%c:", towupper(szDrive[0]));
229 hVolume = CreateFileW(szResult, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
230 if (hVolume != INVALID_HANDLE_VALUE)
231 {
232 ret = DeviceIoControl(hVolume, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, (LPVOID)&TotalNumberOfBytes, sizeof(ULARGE_INTEGER), &BytesReturned, NULL);
233 if (ret && StrFormatByteSizeW(LengthInformation.Length.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
234 SendDlgItemMessageW(hwndDlg, 14008, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
235
236 CloseHandle(hVolume);
237 }
238 TRACE("szResult %s hVOlume %p ret %d LengthInformation %ul Bytesreturned %d\n", debugstr_w(szResult), hVolume, ret, LengthInformation.Length.QuadPart, BytesReturned);
239 #else
240 if (ret && StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
241 SendDlgItemMessageW(hwndDlg, 14008, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
242 #endif
243
244 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart - FreeBytesAvailable.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
245 SendDlgItemMessageW(hwndDlg, 14004, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
246
247 if (StrFormatByteSizeW(FreeBytesAvailable.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
248 SendDlgItemMessageW(hwndDlg, 14006, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
249
250 Result = GetFreeBytesShare(TotalNumberOfFreeBytes, TotalNumberOfBytes);
251 /* set free bytes percentage */
252 swprintf(szResult, L"%02d%%", Result.QuadPart);
253 SendDlgItemMessageW(hwndDlg, 14007, WM_SETTEXT, (WPARAM)0, (LPARAM)szResult);
254 /* store used share amount */
255 Result = LargeIntegerSubtract(ConvertUlongToLargeInteger(100), Result);
256 swprintf(szResult, L"%02d%%", Result.QuadPart);
257 SendDlgItemMessageW(hwndDlg, 14005, WM_SETTEXT, (WPARAM)0, (LPARAM)szResult);
258 if (LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
259 SendDlgItemMessageW(hwndDlg, 14002, WM_SETTEXT, (WPARAM)0, (LPARAM)szBuffer);
260
261 }
262 }
263 /* set drive description */
264 SendDlgItemMessageW(hwndDlg, 14010, WM_GETTEXT, (WPARAM)50, (LPARAM)szFormat);
265 swprintf(szBuffer, szFormat, szDrive);
266 SendDlgItemMessageW(hwndDlg, 14010, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szBuffer);
267 }
268
269
270 INT_PTR
271 CALLBACK
272 DriveGeneralDlg(
273 HWND hwndDlg,
274 UINT uMsg,
275 WPARAM wParam,
276 LPARAM lParam
277 )
278 {
279 LPPROPSHEETPAGEW ppsp;
280 LPDRAWITEMSTRUCT drawItem;
281 STARTUPINFOW si;
282 PROCESS_INFORMATION pi;
283 WCHAR * lpstr;
284 WCHAR szPath[MAX_PATH];
285 UINT length;
286 LPPSHNOTIFY lppsn;
287
288 switch(uMsg)
289 {
290 case WM_INITDIALOG:
291 ppsp = (LPPROPSHEETPAGEW)lParam;
292 if (ppsp == NULL)
293 break;
294 lpstr = (WCHAR *)ppsp->lParam;
295 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lpstr);
296 InitializeGeneralDriveDialog(hwndDlg, lpstr);
297 return TRUE;
298 case WM_DRAWITEM:
299 drawItem = (LPDRAWITEMSTRUCT)lParam;
300 if (drawItem->CtlID >= 14013 && drawItem->CtlID <= 14015)
301 {
302 PaintStaticControls(hwndDlg, drawItem);
303 return TRUE;
304 }
305 break;
306 case WM_COMMAND:
307 if (LOWORD(wParam) == 14011)
308 {
309 lpstr = (WCHAR*)GetWindowLongPtr(hwndDlg, DWLP_USER);
310 ZeroMemory( &si, sizeof(si) );
311 si.cb = sizeof(si);
312 ZeroMemory( &pi, sizeof(pi) );
313 if (!GetSystemDirectoryW(szPath, MAX_PATH))
314 break;
315 wcscat(szPath, L"\\cleanmgr.exe /D ");
316 length = wcslen(szPath);
317 szPath[length] = lpstr[0];
318 szPath[length+1] = L'\0';
319 if (CreateProcessW(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
320 {
321 CloseHandle(pi.hProcess);
322 CloseHandle(pi.hThread);
323 }
324 break;
325 }
326 case WM_NOTIFY:
327 lppsn = (LPPSHNOTIFY) lParam;
328 if (LOWORD(wParam) == 14001)
329 {
330 if (HIWORD(wParam) == EN_CHANGE)
331 {
332 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
333 }
334 break;
335 }
336 if (lppsn->hdr.code == PSN_APPLY)
337 {
338 lpstr = (LPWSTR)GetWindowLong(hwndDlg, DWLP_USER);
339 if (lpstr && SendDlgItemMessageW(hwndDlg, 14001, WM_GETTEXT, sizeof(szPath)/sizeof(WCHAR), (LPARAM)szPath))
340 {
341 szPath[(sizeof(szPath)/sizeof(WCHAR))-1] = L'\0';
342 SetVolumeLabelW(lpstr, szPath);
343 }
344 SetWindowLong( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR );
345 return TRUE;
346 }
347 break;
348
349 default:
350 break;
351 }
352
353
354 return FALSE;
355 }
356
357 INT_PTR
358 CALLBACK
359 DriveExtraDlg(
360 HWND hwndDlg,
361 UINT uMsg,
362 WPARAM wParam,
363 LPARAM lParam
364 )
365 {
366 STARTUPINFOW si;
367 PROCESS_INFORMATION pi;
368 WCHAR szPath[MAX_PATH];
369 WCHAR szArg[MAX_PATH];
370 WCHAR * szDrive;
371 UINT length;
372 LPPROPSHEETPAGEW ppsp;
373
374 switch (uMsg)
375 {
376 case WM_INITDIALOG:
377 ppsp = (LPPROPSHEETPAGEW)lParam;
378 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)ppsp->lParam);
379 return TRUE;
380 case WM_COMMAND:
381 ZeroMemory( &si, sizeof(si) );
382 si.cb = sizeof(si);
383 ZeroMemory( &pi, sizeof(pi) );
384 if (!GetSystemDirectoryW(szPath, MAX_PATH))
385 break;
386 szDrive = (WCHAR*)GetWindowLongPtr(hwndDlg, DWLP_USER);
387 switch(LOWORD(wParam))
388 {
389 case 14000:
390 ///
391 /// FIXME
392 /// show checkdsk dialog
393 ///
394 break;
395 case 14001:
396 szArg[0] = L'"';
397 wcscpy(&szArg[1], szPath);
398 wcscat(szPath, L"\\mmc.exe");
399 wcscat(szArg, L"\\dfrg.msc\" ");
400 length = wcslen(szArg);
401 szArg[length] = szDrive[0];
402 szArg[length+1] = L':';
403 szArg[length+2] = L'\0';
404 if (CreateProcessW(szPath, szArg, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
405 {
406 CloseHandle(pi.hProcess);
407 CloseHandle(pi.hThread);
408 }
409 break;
410 case 14002:
411 wcscat(szPath, L"\\ntbackup.exe");
412 if (CreateProcessW(szPath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
413 {
414 CloseHandle(pi.hProcess);
415 CloseHandle(pi.hThread);
416 }
417 }
418 break;
419 }
420 return FALSE;
421 }
422
423 INT_PTR
424 CALLBACK
425 DriveHardwareDlg(
426 HWND hwndDlg,
427 UINT uMsg,
428 WPARAM wParam,
429 LPARAM lParam
430 )
431 {
432 GUID Guids[1];
433 Guids[0] = GUID_DEVCLASS_DISKDRIVE;
434
435 UNREFERENCED_PARAMETER(lParam);
436 UNREFERENCED_PARAMETER(wParam);
437
438 switch(uMsg)
439 {
440 case WM_INITDIALOG:
441 /* create the hardware page */
442 DeviceCreateHardwarePageEx(hwndDlg,
443 Guids,
444 sizeof(Guids) / sizeof(Guids[0]),
445 0);
446 break;
447 }
448
449 return FALSE;
450 }
451
452 static
453 const
454 struct
455 {
456 LPSTR resname;
457 DLGPROC dlgproc;
458 } PropPages[] =
459 {
460 { "DRIVE_GENERAL_DLG", DriveGeneralDlg },
461 { "DRIVE_EXTRA_DLG", DriveExtraDlg },
462 { "DRIVE_HARDWARE_DLG", DriveHardwareDlg },
463 };
464
465 BOOL
466 CALLBACK
467 AddPropSheetPageProc(HPROPSHEETPAGE hpage, LPARAM lParam)
468 {
469 PROPSHEETHEADER *ppsh = (PROPSHEETHEADER *)lParam;
470 if (ppsh != NULL && ppsh->nPages < MAX_PROPERTY_SHEET_PAGE)
471 {
472 ppsh->phpage[ppsh->nPages++] = hpage;
473 return TRUE;
474 }
475 return FALSE;
476 }
477
478 BOOL
479 SH_ShowDriveProperties(WCHAR * drive)
480 {
481 HPSXA hpsx;
482 HPROPSHEETPAGE hpsp[MAX_PROPERTY_SHEET_PAGE];
483 PROPSHEETHEADERW psh;
484 BOOL ret;
485 UINT i;
486 WCHAR szName[MAX_PATH];
487 DWORD dwMaxComponent, dwFileSysFlags;
488
489 ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
490 psh.dwSize = sizeof(PROPSHEETHEADERW);
491 //psh.dwFlags = PSH_USECALLBACK | PSH_PROPTITLE;
492 psh.hwndParent = NULL;
493 psh.nStartPage = 0;
494 psh.phpage = hpsp;
495
496
497 if (GetVolumeInformationW(drive, szName, sizeof(szName)/sizeof(WCHAR), NULL, &dwMaxComponent,
498 &dwFileSysFlags, NULL, 0))
499 {
500 psh.pszCaption = szName;
501 psh.dwFlags |= PSH_PROPTITLE;
502 if (!wcslen(szName))
503 {
504 /* FIXME
505 * check if disk is a really a local hdd
506 */
507 i = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, szName, sizeof(szName)/sizeof(WCHAR));
508 if (i > 0 && i < (sizeof(szName)/sizeof(WCHAR)) + 6)
509 {
510 szName[i] = L' ';
511 szName[i+1] = L'(';
512 wcscpy(&szName[i+2], drive);
513 szName[i+4] = L')';
514 szName[i+5] = L'\0';
515 }
516 }
517 }
518
519
520 for (i = 0; i < DRIVE_PROPERTY_PAGES; i++)
521 {
522 HPROPSHEETPAGE hprop = SH_CreatePropertySheetPage(PropPages[i].resname, PropPages[i].dlgproc, (LPARAM)drive, NULL);
523 if (hprop)
524 {
525 hpsp[psh.nPages] = hprop;
526 psh.nPages++;
527 }
528 }
529
530 hpsx = SHCreatePropSheetExtArray(HKEY_CLASSES_ROOT,
531 L"Drive",
532 MAX_PROPERTY_SHEET_PAGE-DRIVE_PROPERTY_PAGES);
533
534 SHAddFromPropSheetExtArray(hpsx,
535 (LPFNADDPROPSHEETPAGE)AddPropSheetPageProc,
536 (LPARAM)&psh);
537
538 ret = PropertySheetW(&psh);
539 if (ret < 0)
540 return FALSE;
541 else
542 return TRUE;
543 }
544
545
546
547
548
549 VOID
550 InsertDefaultClusterSizeForFs(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
551 {
552 WCHAR szFs[100] = {0};
553 WCHAR szDrive[4] = { L'C', ':', '\\', 0 };
554 INT iSelIndex;
555 ULARGE_INTEGER FreeBytesAvailableUser, TotalNumberOfBytes;
556 DWORD ClusterSize;
557 LRESULT lIndex;
558 HWND hDlgCtrl;
559
560 hDlgCtrl = GetDlgItem(hwndDlg, 28677);
561 iSelIndex = SendMessage(hDlgCtrl, CB_GETCURSEL, 0, 0);
562 if (iSelIndex == CB_ERR)
563 return;
564
565 if (SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)szFs) == CB_ERR)
566 return;
567
568 szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0';
569 szDrive[0] = pContext->Drive + 'A';
570
571 if (!GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfBytes, NULL))
572 return;
573
574 if (!wcsicmp(szFs, L"FAT16") ||
575 !wcsicmp(szFs, L"FAT")) //REACTOS HACK
576 {
577 if (TotalNumberOfBytes.QuadPart <= (16 * 1024 * 1024))
578 ClusterSize = 2048;
579 else if (TotalNumberOfBytes.QuadPart <= (32 * 1024 * 1024))
580 ClusterSize = 512;
581 else if (TotalNumberOfBytes.QuadPart <= (64 * 1024 * 1024))
582 ClusterSize = 1024;
583 else if (TotalNumberOfBytes.QuadPart <= (128 * 1024 * 1024))
584 ClusterSize = 2048;
585 else if (TotalNumberOfBytes.QuadPart <= (256 * 1024 * 1024))
586 ClusterSize = 4096;
587 else if (TotalNumberOfBytes.QuadPart <= (512 * 1024 * 1024))
588 ClusterSize = 8192;
589 else if (TotalNumberOfBytes.QuadPart <= (1024 * 1024 * 1024))
590 ClusterSize = 16384;
591 else if (TotalNumberOfBytes.QuadPart <= (2048LL * 1024LL * 1024LL))
592 ClusterSize = 32768;
593 else if (TotalNumberOfBytes.QuadPart <= (4096LL * 1024LL * 1024LL))
594 ClusterSize = 8192;
595 else
596 {
597 TRACE("FAT16 is not supported on hdd larger than 4G current %lu\n", TotalNumberOfBytes.QuadPart);
598 SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0);
599 return;
600 }
601 if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, szFs, sizeof(szFs)/sizeof(WCHAR)))
602 {
603 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
604 szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0';
605 SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0);
606 lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs);
607 if (lIndex != CB_ERR)
608 SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
609 SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0);
610 }
611 }
612 else if (!wcsicmp(szFs, L"FAT32"))
613 {
614 if (TotalNumberOfBytes.QuadPart <=(64 * 1024 * 1024))
615 ClusterSize = 512;
616 else if (TotalNumberOfBytes.QuadPart <= (128 * 1024 * 1024))
617 ClusterSize = 1024;
618 else if (TotalNumberOfBytes.QuadPart <= (256 * 1024 * 1024))
619 ClusterSize = 2048;
620 else if (TotalNumberOfBytes.QuadPart <= (8192LL * 1024LL * 1024LL))
621 ClusterSize = 2048;
622 else if (TotalNumberOfBytes.QuadPart <= (16384LL * 1024LL * 1024LL))
623 ClusterSize = 8192;
624 else if (TotalNumberOfBytes.QuadPart <= (32768LL * 1024LL * 1024LL))
625 ClusterSize = 16384;
626 else
627 {
628 TRACE("FAT32 is not supported on hdd larger than 32G current %lu\n", TotalNumberOfBytes.QuadPart);
629 SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0);
630 return;
631 }
632
633 if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, szFs, sizeof(szFs)/sizeof(WCHAR)))
634 {
635 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
636 szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0';
637 SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0);
638 lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs);
639 if (lIndex != CB_ERR)
640 SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
641 SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0);
642 }
643 }
644 else if (!wcsicmp(szFs, L"NTFS"))
645 {
646 if (TotalNumberOfBytes.QuadPart <=(512 * 1024 * 1024))
647 ClusterSize = 512;
648 else if (TotalNumberOfBytes.QuadPart <= (1024 * 1024 * 1024))
649 ClusterSize = 1024;
650 else if (TotalNumberOfBytes.QuadPart <= (2048LL * 1024LL * 1024LL))
651 ClusterSize = 2048;
652 else
653 ClusterSize = 2048;
654
655 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
656 if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, szFs, sizeof(szFs)/sizeof(WCHAR)))
657 {
658 szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0';
659 SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0);
660 lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs);
661 if (lIndex != CB_ERR)
662 SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
663 SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0);
664 }
665 ClusterSize = 512;
666 for (lIndex = 0; lIndex < 4; lIndex++)
667 {
668 TotalNumberOfBytes.QuadPart = ClusterSize;
669 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szFs, sizeof(szFs)/sizeof(WCHAR)))
670 {
671 lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs);
672 if (lIndex != CB_ERR)
673 SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
674 }
675 ClusterSize *= 2;
676 }
677 }
678 else
679 {
680 FIXME("unknown fs\n");
681 SendDlgItemMessageW(hwndDlg, 28680, CB_RESETCONTENT, iSelIndex, 0);
682 return;
683 }
684 }
685
686 VOID
687 InitializeFormatDriveDlg(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
688 {
689 WCHAR szText[120];
690 WCHAR szDrive[4] = { L'C', ':', '\\', 0 };
691 WCHAR szFs[30] = {0};
692 INT Length, TempLength;
693 DWORD dwSerial, dwMaxComp, dwFileSys;
694 ULARGE_INTEGER FreeBytesAvailableUser, TotalNumberOfBytes;
695 DWORD dwIndex, dwDefault;
696 UCHAR uMinor, uMajor;
697 BOOLEAN Latest;
698 HWND hDlgCtrl;
699
700 Length = GetWindowTextW(hwndDlg, szText, sizeof(szText)/sizeof(WCHAR));
701 szDrive[0] = pContext->Drive + L'A';
702 if (GetVolumeInformationW(szDrive, &szText[Length+1], (sizeof(szText)/sizeof(WCHAR))- Length - 2, &dwSerial, &dwMaxComp, &dwFileSys, szFs, sizeof(szFs)/sizeof(WCHAR)))
703 {
704 szText[Length] = L' ';
705 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
706 TempLength = wcslen(&szText[Length+1]);
707 if (!TempLength)
708 {
709 /* load default volume label */
710 TempLength = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, &szText[Length+1], (sizeof(szText)/sizeof(WCHAR))- Length - 2);
711 }
712 else
713 {
714 /* set volume label */
715 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
716 SendDlgItemMessageW(hwndDlg, 28679, WM_SETTEXT, 0, (LPARAM)&szText[Length+1]);
717 }
718 Length += TempLength + 1;
719 }
720
721 if (Length + 4 < (sizeof(szText)/sizeof(WCHAR)))
722 {
723 szText[Length] = L' ';
724 szText[Length+1] = L'(';
725 szText[Length+2] = szDrive[0];
726 szText[Length+3] = L')';
727 Length +=4;
728 }
729
730 if (Length < (sizeof(szText)/sizeof(WCHAR)))
731 szText[Length] = L'\0';
732 else
733 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
734
735 /* set window text */
736 SetWindowTextW(hwndDlg, szText);
737
738 if (GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfBytes, NULL))
739 {
740 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szText, sizeof(szText)/sizeof(WCHAR)))
741 {
742 /* add drive capacity */
743 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
744 SendDlgItemMessageW(hwndDlg, 28673, CB_ADDSTRING, 0, (LPARAM)szText);
745 SendDlgItemMessageW(hwndDlg, 28673, CB_SETCURSEL, 0, (LPARAM)0);
746 }
747 }
748
749 if (pContext->Options & SHFMT_OPT_FULL)
750 {
751 /* check quick format button */
752 SendDlgItemMessageW(hwndDlg, 28674, BM_SETCHECK, BST_CHECKED, 0);
753 }
754
755 /* enumerate all available filesystems */
756 dwIndex = 0;
757 dwDefault = 0;
758 hDlgCtrl = GetDlgItem(hwndDlg, 28677);
759
760 while(pContext->QueryAvailableFileSystemFormat(dwIndex, szText, &uMajor, &uMinor, &Latest))
761 {
762 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
763 if (!wcsicmp(szText, szFs))
764 dwDefault = dwIndex;
765
766 SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szText);
767 dwIndex++;
768 }
769
770 if (!dwIndex)
771 {
772 ERR("no filesystem providers\n");
773 return;
774 }
775
776 /* select default filesys */
777 SendMessageW(hDlgCtrl, CB_SETCURSEL, dwDefault, 0);
778 /* setup cluster combo */
779 InsertDefaultClusterSizeForFs(hwndDlg, pContext);
780 /* hide progress control */
781 ShowWindow(GetDlgItem(hwndDlg, 28678), SW_HIDE);
782 }
783
784 HWND FormatDrvDialog = NULL;
785 BOOLEAN bSuccess = FALSE;
786
787
788 BOOLEAN
789 NTAPI
790 FormatExCB(
791 IN CALLBACKCOMMAND Command,
792 IN ULONG SubAction,
793 IN PVOID ActionInfo)
794 {
795 PDWORD Progress;
796 PBOOLEAN pSuccess;
797 switch(Command)
798 {
799 case PROGRESS:
800 Progress = (PDWORD)ActionInfo;
801 SendDlgItemMessageW(FormatDrvDialog, 28678, PBM_SETPOS, (WPARAM)*Progress, 0);
802 break;
803 case DONE:
804 pSuccess = (PBOOLEAN)ActionInfo;
805 bSuccess = (*pSuccess);
806 break;
807
808 case VOLUMEINUSE:
809 case INSUFFICIENTRIGHTS:
810 case FSNOTSUPPORTED:
811 case CLUSTERSIZETOOSMALL:
812 bSuccess = FALSE;
813 FIXME("\n");
814 break;
815
816 default:
817 break;
818 }
819
820 return TRUE;
821 }
822
823
824
825
826
827 VOID
828 FormatDrive(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
829 {
830 WCHAR szDrive[4] = { L'C', ':', '\\', 0 };
831 WCHAR szFileSys[40] = {0};
832 WCHAR szLabel[40] = {0};
833 INT iSelIndex;
834 UINT Length;
835 HWND hDlgCtrl;
836 BOOL QuickFormat;
837 DWORD ClusterSize;
838
839 /* set volume path */
840 szDrive[0] = pContext->Drive;
841
842 /* get filesystem */
843 hDlgCtrl = GetDlgItem(hwndDlg, 28677);
844 iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
845 if (iSelIndex == CB_ERR)
846 {
847 FIXME("\n");
848 return;
849 }
850 Length = SendMessageW(hDlgCtrl, CB_GETLBTEXTLEN, iSelIndex, 0);
851 if (Length == CB_ERR || Length + 1> sizeof(szFileSys)/sizeof(WCHAR))
852 {
853 FIXME("\n");
854 return;
855 }
856
857 /* retrieve the file system */
858 SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)szFileSys);
859 szFileSys[(sizeof(szFileSys)/sizeof(WCHAR))-1] = L'\0';
860
861 /* retrieve the volume label */
862 hDlgCtrl = GetWindow(hwndDlg, 28679);
863 Length = SendMessageW(hDlgCtrl, WM_GETTEXTLENGTH, 0, 0);
864 if (Length + 1 > sizeof(szLabel)/sizeof(WCHAR))
865 {
866 FIXME("\n");
867 return;
868 }
869 SendMessageW(hDlgCtrl, WM_GETTEXT, sizeof(szLabel)/sizeof(WCHAR), (LPARAM)szLabel);
870 szLabel[(sizeof(szLabel)/sizeof(WCHAR))-1] = L'\0';
871
872 /* check for quickformat */
873 if (SendDlgItemMessageW(hwndDlg, 28674, BM_GETCHECK, 0, 0) == BST_CHECKED)
874 QuickFormat = TRUE;
875 else
876 QuickFormat = FALSE;
877
878 /* get the cluster size */
879 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
880 iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
881 if (iSelIndex == CB_ERR)
882 {
883 FIXME("\n");
884 return;
885 }
886 ClusterSize = SendMessageW(hDlgCtrl, CB_GETITEMDATA, iSelIndex, 0);
887 if (ClusterSize == CB_ERR)
888 {
889 FIXME("\n");
890 return;
891 }
892
893 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
894 ShowWindow(hDlgCtrl, SW_SHOW);
895 SendMessageW(hDlgCtrl, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
896 bSuccess = FALSE;
897
898 /* FIXME
899 * will cause display problems
900 * when performing more than one format
901 */
902 FormatDrvDialog = hwndDlg;
903
904 pContext->FormatEx(szDrive,
905 FMIFS_HARDDISK, /* FIXME */
906 szFileSys,
907 szLabel,
908 QuickFormat,
909 ClusterSize,
910 FormatExCB);
911
912 ShowWindow(hDlgCtrl, SW_HIDE);
913 FormatDrvDialog = NULL;
914 if (!bSuccess)
915 {
916 pContext->Result = SHFMT_ERROR;
917 }
918 else if (QuickFormat)
919 {
920 pContext->Result = SHFMT_OPT_FULL;
921 }
922 else
923 {
924 pContext->Result = FALSE;
925 }
926 }
927
928
929 BOOL
930 CALLBACK
931 FormatDriveDlg(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
932 {
933 PFORMAT_DRIVE_CONTEXT pContext;
934
935 switch(uMsg)
936 {
937 case WM_INITDIALOG:
938 InitializeFormatDriveDlg(hwndDlg, (PFORMAT_DRIVE_CONTEXT)lParam);
939 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
940 return TRUE;
941 case WM_COMMAND:
942 switch(LOWORD(wParam))
943 {
944 case IDOK:
945 pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
946 FormatDrive(hwndDlg, pContext);
947 break;
948 case IDCANCEL:
949 pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
950 EndDialog(hwndDlg, pContext->Result);
951 break;
952 case 28677: // filesystem combo
953 if (HIWORD(wParam) == CBN_SELENDOK)
954 {
955 pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
956 InsertDefaultClusterSizeForFs(hwndDlg, pContext);
957 }
958 break;
959 }
960 }
961 return FALSE;
962 }
963
964
965 BOOL
966 InitializeFmifsLibrary(PFORMAT_DRIVE_CONTEXT pContext)
967 {
968 INITIALIZE_FMIFS InitFmifs;
969 BOOLEAN ret;
970 HMODULE hLibrary;
971
972 hLibrary = pContext->hLibrary = LoadLibraryW(L"fmifs.dll");
973 if(!hLibrary)
974 {
975 ERR("failed to load fmifs.dll\n");
976 return FALSE;
977 }
978
979 InitFmifs = (INITIALIZE_FMIFS)GetProcAddress(hLibrary, "InitializeFmIfs");
980 if (!InitFmifs)
981 {
982 ERR("InitializeFmIfs export is missing\n");
983 FreeLibrary(hLibrary);
984 return FALSE;
985 }
986
987 ret = (*InitFmifs)(NULL, DLL_PROCESS_ATTACH, NULL);
988 if (!ret)
989 {
990 ERR("fmifs failed to initialize\n");
991 FreeLibrary(hLibrary);
992 return FALSE;
993 }
994
995 pContext->QueryAvailableFileSystemFormat = (QUERY_AVAILABLEFSFORMAT)GetProcAddress(hLibrary, "QueryAvailableFileSystemFormat");
996 if (!pContext->QueryAvailableFileSystemFormat)
997 {
998 ERR("QueryAvailableFileSystemFormat export is missing\n");
999 FreeLibrary(hLibrary);
1000 return FALSE;
1001 }
1002
1003 pContext->FormatEx = (FORMAT_EX) GetProcAddress(hLibrary, "FormatEx");
1004 if (!pContext->FormatEx)
1005 {
1006 ERR("FormatEx export is missing\n");
1007 FreeLibrary(hLibrary);
1008 return FALSE;
1009 }
1010
1011 pContext->EnableVolumeCompression = (ENABLEVOLUMECOMPRESSION) GetProcAddress(hLibrary, "EnableVolumeCompression");
1012 if (!pContext->FormatEx)
1013 {
1014 ERR("EnableVolumeCompression export is missing\n");
1015 FreeLibrary(hLibrary);
1016 return FALSE;
1017 }
1018
1019 return TRUE;
1020 }
1021
1022 /*************************************************************************
1023 * SHFormatDrive (SHELL32.@)
1024 */
1025
1026 DWORD
1027 WINAPI
1028 SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options)
1029 {
1030 FORMAT_DRIVE_CONTEXT Context;
1031 int result;
1032
1033 TRACE("%p, 0x%08x, 0x%08x, 0x%08x - stub\n", hwnd, drive, fmtID, options);
1034
1035 if (!InitializeFmifsLibrary(&Context))
1036 {
1037 ERR("failed to initialize fmifs\n");
1038 return SHFMT_NOFORMAT;
1039 }
1040
1041 Context.Drive = drive;
1042 Context.Options = options;
1043
1044 result = DialogBoxParamW(shell32_hInstance, L"FORMAT_DLG", hwnd, FormatDriveDlg, (LPARAM)&Context);
1045
1046 FreeLibrary(Context.hLibrary);
1047 return result;
1048 }
1049
1050