xref: /reactos/dll/win32/shell32/dialogs/drive.cpp (revision ea6e7740)
1 /*
2  *                 Shell Library Functions
3  *
4  * Copyright 2005 Johannes Anderwald
5  * Copyright 2017 Katayama Hirofumi MZ
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include "precomp.h"
23 #include <process.h>
24 
25 WINE_DEFAULT_DEBUG_CHANNEL(shell);
26 
27 typedef struct
28 {
29     WCHAR   Drive;
30     UINT    Options;
31     UINT Result;
32     BOOL bFormattingNow;
33 } FORMAT_DRIVE_CONTEXT, *PFORMAT_DRIVE_CONTEXT;
34 
35 EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj);
36 HPROPSHEETPAGE SH_CreatePropertySheetPage(LPCSTR resname, DLGPROC dlgproc, LPARAM lParam, LPWSTR szTitle);
37 
38 /*
39  * TODO: In Windows the Shell doesn't know by itself if a drive is
40  * a system one or not but rather a packet message is being sent by
41  * FMIFS library code and further translated into specific packet
42  * status codes in the Shell, the packet being _FMIFS_PACKET_TYPE.
43  *
44  * With that being said, most of this code as well as FMIFS library code
45  * have to be refactored in order to comply with the way Windows works.
46  *
47  * See the enum definition for more details:
48  * https://github.com/microsoft/winfile/blob/master/src/fmifs.h#L23
49  */
50 static BOOL
51 IsSystemDrive(PFORMAT_DRIVE_CONTEXT pContext)
52 {
53     WCHAR wszDriveLetter[6], wszSystemDrv[6];
54 
55     wszDriveLetter[0] = pContext->Drive + L'A';
56     StringCchCatW(wszDriveLetter, _countof(wszDriveLetter), L":");
57 
58     if (!GetEnvironmentVariableW(L"SystemDrive", wszSystemDrv, _countof(wszSystemDrv)))
59         return FALSE;
60 
61     if (!wcsicmp(wszDriveLetter, wszSystemDrv))
62         return TRUE;
63 
64     return FALSE;
65 }
66 
67 static BOOL
68 GetDefaultClusterSize(LPWSTR szFs, PDWORD pClusterSize, PULARGE_INTEGER TotalNumberOfBytes)
69 {
70     DWORD ClusterSize;
71 
72     if (!wcsicmp(szFs, L"FAT16") ||
73         !wcsicmp(szFs, L"FAT")) // REACTOS HACK
74     {
75         if (TotalNumberOfBytes->QuadPart <= (16 * 1024 * 1024))
76             ClusterSize = 2048;
77         else if (TotalNumberOfBytes->QuadPart <= (32 * 1024 * 1024))
78             ClusterSize = 512;
79         else if (TotalNumberOfBytes->QuadPart <= (64 * 1024 * 1024))
80             ClusterSize = 1024;
81         else if (TotalNumberOfBytes->QuadPart <= (128 * 1024 * 1024))
82             ClusterSize = 2048;
83         else if (TotalNumberOfBytes->QuadPart <= (256 * 1024 * 1024))
84             ClusterSize = 4096;
85         else if (TotalNumberOfBytes->QuadPart <= (512 * 1024 * 1024))
86             ClusterSize = 8192;
87         else if (TotalNumberOfBytes->QuadPart <= (1024 * 1024 * 1024))
88             ClusterSize = 16384;
89         else if (TotalNumberOfBytes->QuadPart <= (2048LL * 1024LL * 1024LL))
90             ClusterSize = 32768;
91         else if (TotalNumberOfBytes->QuadPart <= (4096LL * 1024LL * 1024LL))
92             ClusterSize = 8192;
93         else
94             return FALSE;
95     }
96     else if (!wcsicmp(szFs, L"FAT32"))
97     {
98         if (TotalNumberOfBytes->QuadPart <= (64 * 1024 * 1024))
99             ClusterSize = 512;
100         else if (TotalNumberOfBytes->QuadPart <= (128   * 1024 * 1024))
101             ClusterSize = 1024;
102         else if (TotalNumberOfBytes->QuadPart <= (256   * 1024 * 1024))
103             ClusterSize = 2048;
104         else if (TotalNumberOfBytes->QuadPart <= (8192LL  * 1024LL * 1024LL))
105             ClusterSize = 2048;
106         else if (TotalNumberOfBytes->QuadPart <= (16384LL * 1024LL * 1024LL))
107             ClusterSize = 8192;
108         else if (TotalNumberOfBytes->QuadPart <= (32768LL * 1024LL * 1024LL))
109             ClusterSize = 16384;
110         else
111             return FALSE;
112     }
113     else if (!wcsicmp(szFs, L"FATX"))
114     {
115         if (TotalNumberOfBytes->QuadPart <= (16 * 1024 * 1024))
116             ClusterSize = 2048;
117         else if (TotalNumberOfBytes->QuadPart <= (32 * 1024 * 1024))
118             ClusterSize = 512;
119         else if (TotalNumberOfBytes->QuadPart <= (64 * 1024 * 1024))
120             ClusterSize = 1024;
121         else if (TotalNumberOfBytes->QuadPart <= (128 * 1024 * 1024))
122             ClusterSize = 2048;
123         else if (TotalNumberOfBytes->QuadPart <= (256 * 1024 * 1024))
124             ClusterSize = 4096;
125         else if (TotalNumberOfBytes->QuadPart <= (8192LL * 1024LL * 1024LL))
126             ClusterSize = 2048;
127         else if (TotalNumberOfBytes->QuadPart <= (16384LL * 1024LL * 1024LL))
128             ClusterSize = 8192;
129         else if (TotalNumberOfBytes->QuadPart <= (32768LL * 1024LL * 1024LL))
130             ClusterSize = 16384;
131         else
132             return FALSE;
133     }
134     else if (!wcsicmp(szFs, L"NTFS"))
135     {
136         if (TotalNumberOfBytes->QuadPart <= (512 * 1024 * 1024))
137             ClusterSize = 512;
138         else if (TotalNumberOfBytes->QuadPart <= (1024 * 1024 * 1024))
139             ClusterSize = 1024;
140         else if (TotalNumberOfBytes->QuadPart <= (2048LL * 1024LL * 1024LL))
141             ClusterSize = 2048;
142         else
143             ClusterSize = 2048;
144     }
145     else if (!wcsicmp(szFs, L"EXT2"))
146     {
147         // auto block size calculation
148         ClusterSize = 0;
149     }
150     else if (!wcsicmp(szFs, L"BtrFS"))
151     {
152         // auto block size calculation
153         ClusterSize = 0;
154     }
155     else
156         return FALSE;
157 
158     *pClusterSize = ClusterSize;
159     return TRUE;
160 }
161 
162 typedef struct _DRIVE_PROP_PAGE
163 {
164     LPCSTR resname;
165     DLGPROC dlgproc;
166     UINT DriveType;
167 } DRIVE_PROP_PAGE;
168 
169 HRESULT
170 SH_ShowDriveProperties(WCHAR *pwszDrive, LPCITEMIDLIST pidlFolder, PCUITEMID_CHILD_ARRAY apidl)
171 {
172     HPSXA hpsx = NULL;
173     HPROPSHEETPAGE hpsp[MAX_PROPERTY_SHEET_PAGE];
174     PROPSHEETHEADERW psh;
175     CComObject<CDrvDefExt> *pDrvDefExt = NULL;
176     WCHAR wszName[256];
177 
178     ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
179     psh.dwSize = sizeof(PROPSHEETHEADERW);
180     psh.dwFlags = 0; // FIXME: make it modeless
181     psh.hwndParent = NULL;
182     psh.nStartPage = 0;
183     psh.phpage = hpsp;
184 
185     LPITEMIDLIST completePidl = ILCombine(pidlFolder, apidl[0]);
186     if (!completePidl)
187         return E_OUTOFMEMORY;
188 
189     if (ILGetDisplayNameExW(NULL, completePidl, wszName, ILGDN_NORMAL))
190     {
191         psh.pszCaption = wszName;
192         psh.dwFlags |= PSH_PROPTITLE;
193     }
194 
195     ILFree(completePidl);
196 
197     CComPtr<IDataObject> pDataObj;
198     HRESULT hr = SHCreateDataObject(pidlFolder, 1, apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj));
199 
200     if (SUCCEEDED(hr))
201     {
202         hr = CComObject<CDrvDefExt>::CreateInstance(&pDrvDefExt);
203         if (SUCCEEDED(hr))
204         {
205             pDrvDefExt->AddRef(); // CreateInstance returns object with 0 ref count
206             hr = pDrvDefExt->Initialize(pidlFolder, pDataObj, NULL);
207             if (SUCCEEDED(hr))
208             {
209                 hr = pDrvDefExt->AddPages(AddPropSheetPageCallback, (LPARAM)&psh);
210                 if (FAILED(hr))
211                     ERR("AddPages failed\n");
212             } else
213                 ERR("Initialize failed\n");
214         }
215 
216         hpsx = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, L"Drive", MAX_PROPERTY_SHEET_PAGE, pDataObj);
217         if (hpsx)
218             SHAddFromPropSheetExtArray(hpsx, (LPFNADDPROPSHEETPAGE)AddPropSheetPageCallback, (LPARAM)&psh);
219     }
220 
221     // NOTE: Currently property sheet is modal. If we make it modeless, then it returns HWND.
222     INT_PTR ret = PropertySheetW(&psh);
223 
224     if (hpsx)
225         SHDestroyPropSheetExtArray(hpsx);
226     if (pDrvDefExt)
227         pDrvDefExt->Release();
228 
229     if (ret > 0)
230         return S_OK;
231     if (ret == 0)
232         return S_FALSE;
233     return E_FAIL;
234 }
235 
236 static VOID
237 InsertDefaultClusterSizeForFs(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
238 {
239     WCHAR wszBuf[100] = {0};
240     WCHAR wszDefaultSize[100] = {0};
241     PCWSTR pwszFsSizeLimit;
242     WCHAR szDrive[] = L"C:\\";
243     INT iSelIndex;
244     ULARGE_INTEGER FreeBytesAvailableUser, TotalNumberOfBytes;
245     DWORD ClusterSize;
246     LRESULT lIndex;
247     HWND hDlgCtrl;
248 
249     hDlgCtrl = GetDlgItem(hwndDlg, 28677);
250     iSelIndex = SendMessage(hDlgCtrl, CB_GETCURSEL, 0, 0);
251     if (iSelIndex == CB_ERR)
252         return;
253 
254     if (SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)wszBuf) == CB_ERR)
255         return;
256 
257     szDrive[0] = pContext->Drive + L'A';
258 
259     if (!GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfBytes, NULL))
260         return;
261 
262     if (!wcsicmp(wszBuf, L"FAT16") ||
263         !wcsicmp(wszBuf, L"FAT")) // REACTOS HACK
264     {
265         pwszFsSizeLimit = L"4GB";
266     }
267     else if (!wcsicmp(wszBuf, L"FAT32"))
268     {
269         pwszFsSizeLimit = L"32GB";
270     }
271     else if (!wcsicmp(wszBuf, L"FATX"))
272     {
273         pwszFsSizeLimit = L"1GB/32GB";
274     }
275     else if (!wcsicmp(wszBuf, L"NTFS"))
276     {
277         pwszFsSizeLimit = L"256TB";
278     }
279     else if (!wcsicmp(wszBuf, L"EXT2"))
280     {
281         pwszFsSizeLimit = L"32TB";
282     }
283     else
284     {
285         pwszFsSizeLimit = L"16EB";
286     }
287 
288     if (!wcsicmp(wszBuf, L"FAT16") ||
289         !wcsicmp(wszBuf, L"FAT") || // REACTOS HACK
290         !wcsicmp(wszBuf, L"FAT32") ||
291         !wcsicmp(wszBuf, L"FATX") ||
292         !wcsicmp(wszBuf, L"NTFS") ||
293         !wcsicmp(wszBuf, L"EXT2") ||
294         !wcsicmp(wszBuf, L"BtrFS"))
295     {
296         if (!GetDefaultClusterSize(wszBuf, &ClusterSize, &TotalNumberOfBytes))
297         {
298             TRACE("%S is not supported on drive larger than %S, current size: %lu\n", wszBuf, pwszFsSizeLimit, TotalNumberOfBytes.QuadPart);
299             SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0);
300             return;
301         }
302 
303         if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, wszDefaultSize, _countof(wszDefaultSize)))
304         {
305             hDlgCtrl = GetDlgItem(hwndDlg, 28680); // Get the window handle of "allocation unit size" combobox
306             SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0);
307             lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)wszDefaultSize);
308             if (lIndex != CB_ERR)
309                 SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
310             SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0);
311         }
312 
313         if (!wcsicmp(wszBuf, L"NTFS"))
314         {
315             ClusterSize = 512;
316             for (lIndex = 0; lIndex < 4; lIndex++)
317             {
318                 TotalNumberOfBytes.QuadPart = ClusterSize;
319                 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, wszDefaultSize, _countof(wszDefaultSize)))
320                 {
321                     lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)wszDefaultSize);
322                     if (lIndex != CB_ERR)
323                         SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
324                 }
325                 ClusterSize *= 2;
326             }
327         }
328 
329         SendMessageW(GetDlgItem(hwndDlg, 28675), BM_SETCHECK, BST_UNCHECKED, 0);
330         if (!wcsicmp(wszBuf, L"EXT2") ||
331             !wcsicmp(wszBuf, L"BtrFS") ||
332             !wcsicmp(wszBuf, L"NTFS"))
333         {
334             /* Enable the "Enable Compression" button */
335             EnableWindow(GetDlgItem(hwndDlg, 28675), TRUE);
336         }
337         else
338         {
339             /* Disable the "Enable Compression" button */
340             EnableWindow(GetDlgItem(hwndDlg, 28675), FALSE);
341         }
342     }
343     else
344     {
345         FIXME("Unknown filesystem: %ls\n", wszBuf);
346         SendDlgItemMessageW(hwndDlg, 28680, CB_RESETCONTENT, iSelIndex, 0);
347         return;
348     }
349 }
350 
351 static VOID
352 InitializeFormatDriveDlg(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
353 {
354     WCHAR szText[120];
355     WCHAR szDrive[] = L"C:\\";
356     WCHAR szFs[30] = L"";
357     INT cchText;
358     ULARGE_INTEGER FreeBytesAvailableUser, TotalNumberOfBytes;
359     DWORD dwIndex, dwDefault;
360     UCHAR uMinor, uMajor;
361     BOOLEAN Latest;
362     HWND hwndFileSystems;
363 
364     cchText = GetWindowTextW(hwndDlg, szText, _countof(szText) - 1);
365     if (cchText < 0)
366         cchText = 0;
367     szText[cchText++] = L' ';
368     szDrive[0] = pContext->Drive + L'A';
369     if (GetVolumeInformationW(szDrive, &szText[cchText], _countof(szText) - cchText, NULL, NULL, NULL, szFs, _countof(szFs)))
370     {
371         if (szText[cchText] == UNICODE_NULL)
372         {
373             /* load default volume label */
374             cchText += LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, &szText[cchText], _countof(szText) - cchText);
375         }
376         else
377         {
378             /* set volume label */
379             SetDlgItemTextW(hwndDlg, 28679, &szText[cchText]);
380             cchText += wcslen(&szText[cchText]);
381         }
382     }
383 
384     StringCchPrintfW(szText + cchText, _countof(szText) - cchText, L" (%c:)", szDrive[0]);
385 
386     /* set window text */
387     SetWindowTextW(hwndDlg, szText);
388 
389     if (GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfBytes, NULL))
390     {
391         if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szText, _countof(szText)))
392         {
393             /* add drive capacity */
394             SendDlgItemMessageW(hwndDlg, 28673, CB_ADDSTRING, 0, (LPARAM)szText);
395             SendDlgItemMessageW(hwndDlg, 28673, CB_SETCURSEL, 0, (LPARAM)0);
396         }
397     }
398 
399     if (pContext->Options & SHFMT_OPT_FULL)
400     {
401         /* check quick format button */
402         SendDlgItemMessageW(hwndDlg, 28674, BM_SETCHECK, BST_CHECKED, 0);
403     }
404 
405     /* enumerate all available filesystems */
406     dwIndex = 0;
407     dwDefault = 0;
408     hwndFileSystems = GetDlgItem(hwndDlg, 28677);
409 
410     while(QueryAvailableFileSystemFormat(dwIndex, szText, &uMajor, &uMinor, &Latest))
411     {
412         if (!wcsicmp(szText, szFs))
413             dwDefault = dwIndex;
414 
415         SendMessageW(hwndFileSystems, CB_ADDSTRING, 0, (LPARAM)szText);
416         dwIndex++;
417     }
418 
419     if (!dwIndex)
420     {
421         ERR("no filesystem providers\n");
422         return;
423     }
424 
425     /* select default filesys */
426     SendMessageW(hwndFileSystems, CB_SETCURSEL, dwDefault, 0);
427     /* setup cluster combo */
428     InsertDefaultClusterSizeForFs(hwndDlg, pContext);
429 }
430 
431 static HWND FormatDrvDialog = NULL;
432 static BOOLEAN bSuccess = FALSE;
433 
434 static BOOLEAN NTAPI
435 FormatExCB(
436     IN CALLBACKCOMMAND Command,
437     IN ULONG SubAction,
438     IN PVOID ActionInfo)
439 {
440     PDWORD Progress;
441     PBOOLEAN pSuccess;
442     switch(Command)
443     {
444         case PROGRESS:
445             Progress = (PDWORD)ActionInfo;
446             SendDlgItemMessageW(FormatDrvDialog, 28678, PBM_SETPOS, (WPARAM)*Progress, 0);
447             break;
448         case DONE:
449             pSuccess = (PBOOLEAN)ActionInfo;
450             bSuccess = (*pSuccess);
451             ShellMessageBoxW(shell32_hInstance, FormatDrvDialog, MAKEINTRESOURCEW(IDS_FORMAT_COMPLETE), MAKEINTRESOURCEW(IDS_FORMAT_TITLE), MB_OK | MB_ICONINFORMATION);
452             SendDlgItemMessageW(FormatDrvDialog, 28678, PBM_SETPOS, 0, 0);
453             break;
454 
455         case VOLUMEINUSE:
456         case INSUFFICIENTRIGHTS:
457         case FSNOTSUPPORTED:
458         case CLUSTERSIZETOOSMALL:
459             bSuccess = FALSE;
460             FIXME("Unsupported command in FormatExCB\n");
461             break;
462 
463         default:
464             break;
465     }
466 
467     return TRUE;
468 }
469 
470 VOID
471 FormatDrive(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
472 {
473     WCHAR szDrive[4] = { L'C', ':', '\\', 0 };
474     WCHAR szFileSys[40] = {0};
475     WCHAR szLabel[40] = {0};
476     INT iSelIndex;
477     UINT Length;
478     HWND hDlgCtrl;
479     BOOL QuickFormat;
480     DWORD ClusterSize;
481     DWORD DriveType;
482     FMIFS_MEDIA_FLAG MediaFlag = FMIFS_HARDDISK;
483 
484     /* set volume path */
485     szDrive[0] = pContext->Drive + L'A';
486 
487     /* get filesystem */
488     hDlgCtrl = GetDlgItem(hwndDlg, 28677);
489     iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
490     if (iSelIndex == CB_ERR)
491     {
492         ERR("Unable to get file system selection\n");
493         return;
494     }
495     Length = SendMessageW(hDlgCtrl, CB_GETLBTEXTLEN, iSelIndex, 0);
496     if ((int)Length == CB_ERR || Length + 1 > _countof(szFileSys))
497     {
498         ERR("Unable to get file system selection\n");
499         return;
500     }
501 
502     /* retrieve the file system */
503     SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)szFileSys);
504     szFileSys[_countof(szFileSys)-1] = L'\0';
505 
506     /* retrieve the volume label */
507     hDlgCtrl = GetWindow(hwndDlg, 28679);
508     Length = SendMessageW(hDlgCtrl, WM_GETTEXTLENGTH, 0, 0);
509     if (Length + 1 > _countof(szLabel))
510     {
511         ERR("Unable to get volume label\n");
512         return;
513     }
514     SendMessageW(hDlgCtrl, WM_GETTEXT, _countof(szLabel), (LPARAM)szLabel);
515     szLabel[(sizeof(szLabel)/sizeof(WCHAR))-1] = L'\0';
516 
517     /* check for quickformat */
518     if (SendDlgItemMessageW(hwndDlg, 28674, BM_GETCHECK, 0, 0) == BST_CHECKED)
519         QuickFormat = TRUE;
520     else
521         QuickFormat = FALSE;
522 
523     /* get the cluster size */
524     hDlgCtrl = GetDlgItem(hwndDlg, 28680);
525     iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
526     if (iSelIndex == CB_ERR)
527     {
528         FIXME("\n");
529         return;
530     }
531     ClusterSize = SendMessageW(hDlgCtrl, CB_GETITEMDATA, iSelIndex, 0);
532     if ((int)ClusterSize == CB_ERR)
533     {
534         FIXME("\n");
535         return;
536     }
537 
538     hDlgCtrl = GetDlgItem(hwndDlg, 28680);
539     SendMessageW(hDlgCtrl, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
540     bSuccess = FALSE;
541 
542     /* FIXME
543      * will cause display problems
544      * when performing more than one format
545      */
546     FormatDrvDialog = hwndDlg;
547 
548     /* See if the drive is removable or not */
549     DriveType = GetDriveTypeW(szDrive);
550     switch (DriveType)
551     {
552         case DRIVE_UNKNOWN:
553         case DRIVE_REMOTE:
554         case DRIVE_CDROM:
555         case DRIVE_NO_ROOT_DIR:
556         {
557             FIXME("\n");
558             return;
559         }
560 
561         case DRIVE_REMOVABLE:
562             MediaFlag = FMIFS_FLOPPY;
563             break;
564 
565         case DRIVE_FIXED:
566         case DRIVE_RAMDISK:
567             MediaFlag = FMIFS_HARDDISK;
568             break;
569     }
570 
571     /* Format the drive */
572     FormatEx(szDrive,
573              MediaFlag,
574              szFileSys,
575              szLabel,
576              QuickFormat,
577              ClusterSize,
578              FormatExCB);
579 
580     FormatDrvDialog = NULL;
581     if (!bSuccess)
582     {
583         pContext->Result = SHFMT_ERROR;
584     }
585     else if (QuickFormat)
586     {
587         pContext->Result = SHFMT_OPT_FULL;
588     }
589     else
590     {
591         pContext->Result = FALSE;
592     }
593 }
594 
595 struct FORMAT_DRIVE_PARAMS
596 {
597     HWND hwndDlg;
598     PFORMAT_DRIVE_CONTEXT pContext;
599 };
600 
601 static unsigned __stdcall DoFormatDrive(void *args)
602 {
603     FORMAT_DRIVE_PARAMS *pParams = reinterpret_cast<FORMAT_DRIVE_PARAMS *>(args);
604     HWND hwndDlg = pParams->hwndDlg;
605     PFORMAT_DRIVE_CONTEXT pContext = pParams->pContext;
606 
607 	/* Disable controls during format */
608     HMENU hSysMenu = GetSystemMenu(hwndDlg, FALSE);
609     EnableMenuItem(hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
610     EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
611     EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE);
612     EnableWindow(GetDlgItem(hwndDlg, 28673), FALSE);
613     EnableWindow(GetDlgItem(hwndDlg, 28677), FALSE);
614     EnableWindow(GetDlgItem(hwndDlg, 28680), FALSE);
615     EnableWindow(GetDlgItem(hwndDlg, 28679), FALSE);
616     EnableWindow(GetDlgItem(hwndDlg, 28674), FALSE);
617 
618     FormatDrive(hwndDlg, pContext);
619 
620 	/* Re-enable controls after format */
621     EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
622     EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), TRUE);
623     EnableWindow(GetDlgItem(hwndDlg, 28673), TRUE);
624     EnableWindow(GetDlgItem(hwndDlg, 28677), TRUE);
625     EnableWindow(GetDlgItem(hwndDlg, 28680), TRUE);
626     EnableWindow(GetDlgItem(hwndDlg, 28679), TRUE);
627     EnableWindow(GetDlgItem(hwndDlg, 28674), TRUE);
628     EnableMenuItem(hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_ENABLED);
629     pContext->bFormattingNow = FALSE;
630 
631     delete pParams;
632     return 0;
633 }
634 
635 static INT_PTR CALLBACK
636 FormatDriveDlg(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
637 {
638     PFORMAT_DRIVE_CONTEXT pContext;
639 
640     switch(uMsg)
641     {
642         case WM_INITDIALOG:
643             InitializeFormatDriveDlg(hwndDlg, (PFORMAT_DRIVE_CONTEXT)lParam);
644             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
645             return TRUE;
646         case WM_COMMAND:
647             switch(LOWORD(wParam))
648             {
649                 case IDOK:
650                     pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
651                     if (pContext->bFormattingNow)
652                         break;
653 
654                     if (ShellMessageBoxW(shell32_hInstance, hwndDlg,
655                                          MAKEINTRESOURCEW(IDS_FORMAT_WARNING),
656                                          MAKEINTRESOURCEW(IDS_FORMAT_TITLE),
657                                          MB_OKCANCEL | MB_ICONWARNING) == IDOK)
658                     {
659                         pContext->bFormattingNow = TRUE;
660 
661                         FORMAT_DRIVE_PARAMS *pParams = new FORMAT_DRIVE_PARAMS;
662                         pParams->hwndDlg = hwndDlg;
663                         pParams->pContext = pContext;
664 
665                         unsigned tid;
666                         HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, DoFormatDrive, pParams, 0, &tid);
667                         CloseHandle(hThread);
668                     }
669                     break;
670                 case IDCANCEL:
671                     pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
672                     if (pContext->bFormattingNow)
673                         break;
674 
675                     EndDialog(hwndDlg, pContext->Result);
676                     break;
677                 case 28677: // filesystem combo
678                     if (HIWORD(wParam) == CBN_SELENDOK)
679                     {
680                         pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
681                         if (pContext->bFormattingNow)
682                             break;
683 
684                         InsertDefaultClusterSizeForFs(hwndDlg, pContext);
685                     }
686                     break;
687             }
688     }
689     return FALSE;
690 }
691 
692 /*************************************************************************
693  *              SHFormatDrive (SHELL32.@)
694  */
695 
696 DWORD
697 WINAPI
698 SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options)
699 {
700     FORMAT_DRIVE_CONTEXT Context;
701     int result;
702 
703     TRACE("%p, 0x%08x, 0x%08x, 0x%08x - stub\n", hwnd, drive, fmtID, options);
704 
705     Context.Drive = drive;
706     Context.Options = options;
707     Context.Result = FALSE;
708     Context.bFormattingNow = FALSE;
709 
710     if (!IsSystemDrive(&Context))
711     {
712         result = DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_FORMAT_DRIVE), hwnd, FormatDriveDlg, (LPARAM)&Context);
713     }
714     else
715     {
716         result = SHFMT_ERROR;
717         ShellMessageBoxW(shell32_hInstance, hwnd, MAKEINTRESOURCEW(IDS_NO_FORMAT), MAKEINTRESOURCEW(IDS_NO_FORMAT_TITLE), MB_OK | MB_ICONWARNING);
718         TRACE("SHFormatDrive(): The provided drive for format is a system volume! Aborting...\n");
719     }
720 
721     return result;
722 }
723