xref: /reactos/dll/win32/shell32/dialogs/drive.cpp (revision d2c667c6)
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     return E_FAIL;
232 }
233 
234 static VOID
235 InsertDefaultClusterSizeForFs(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
236 {
237     WCHAR wszBuf[100] = {0};
238     WCHAR wszDefaultSize[100] = {0};
239     PCWSTR pwszFsSizeLimit;
240     WCHAR szDrive[] = L"C:\\";
241     INT iSelIndex;
242     ULARGE_INTEGER FreeBytesAvailableUser, TotalNumberOfBytes;
243     DWORD ClusterSize;
244     LRESULT lIndex;
245     HWND hDlgCtrl;
246 
247     hDlgCtrl = GetDlgItem(hwndDlg, 28677);
248     iSelIndex = SendMessage(hDlgCtrl, CB_GETCURSEL, 0, 0);
249     if (iSelIndex == CB_ERR)
250         return;
251 
252     if (SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)wszBuf) == CB_ERR)
253         return;
254 
255     szDrive[0] = pContext->Drive + L'A';
256 
257     if (!GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfBytes, NULL))
258         return;
259 
260     if (!wcsicmp(wszBuf, L"FAT16") ||
261         !wcsicmp(wszBuf, L"FAT")) // REACTOS HACK
262     {
263         pwszFsSizeLimit = L"4GB";
264     }
265     else if (!wcsicmp(wszBuf, L"FAT32"))
266     {
267         pwszFsSizeLimit = L"32GB";
268     }
269     else if (!wcsicmp(wszBuf, L"FATX"))
270     {
271         pwszFsSizeLimit = L"1GB/32GB";
272     }
273     else if (!wcsicmp(wszBuf, L"NTFS"))
274     {
275         pwszFsSizeLimit = L"256TB";
276     }
277     else if (!wcsicmp(wszBuf, L"EXT2"))
278     {
279         pwszFsSizeLimit = L"32TB";
280     }
281     else
282     {
283         pwszFsSizeLimit = L"16EB";
284     }
285 
286     if (!wcsicmp(wszBuf, L"FAT16") ||
287         !wcsicmp(wszBuf, L"FAT") || // REACTOS HACK
288         !wcsicmp(wszBuf, L"FAT32") ||
289         !wcsicmp(wszBuf, L"FATX") ||
290         !wcsicmp(wszBuf, L"NTFS") ||
291         !wcsicmp(wszBuf, L"EXT2") ||
292         !wcsicmp(wszBuf, L"BtrFS"))
293     {
294         if (!GetDefaultClusterSize(wszBuf, &ClusterSize, &TotalNumberOfBytes))
295         {
296             TRACE("%S is not supported on drive larger than %S, current size: %lu\n", wszBuf, pwszFsSizeLimit, TotalNumberOfBytes.QuadPart);
297             SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0);
298             return;
299         }
300 
301         if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, wszDefaultSize, _countof(wszDefaultSize)))
302         {
303             hDlgCtrl = GetDlgItem(hwndDlg, 28680); // Get the window handle of "allocation unit size" combobox
304             SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0);
305             lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)wszDefaultSize);
306             if (lIndex != CB_ERR)
307                 SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
308             SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0);
309         }
310 
311         if (!wcsicmp(wszBuf, L"NTFS"))
312         {
313             ClusterSize = 512;
314             for (lIndex = 0; lIndex < 4; lIndex++)
315             {
316                 TotalNumberOfBytes.QuadPart = ClusterSize;
317                 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, wszDefaultSize, _countof(wszDefaultSize)))
318                 {
319                     lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)wszDefaultSize);
320                     if (lIndex != CB_ERR)
321                         SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
322                 }
323                 ClusterSize *= 2;
324             }
325         }
326 
327         SendMessageW(GetDlgItem(hwndDlg, 28675), BM_SETCHECK, BST_UNCHECKED, 0);
328         if (!wcsicmp(wszBuf, L"EXT2") ||
329             !wcsicmp(wszBuf, L"BtrFS") ||
330             !wcsicmp(wszBuf, L"NTFS"))
331         {
332             /* Enable the "Enable Compression" button */
333             EnableWindow(GetDlgItem(hwndDlg, 28675), TRUE);
334         }
335         else
336         {
337             /* Disable the "Enable Compression" button */
338             EnableWindow(GetDlgItem(hwndDlg, 28675), FALSE);
339         }
340     }
341     else
342     {
343         FIXME("Unknown filesystem: %ls\n", wszBuf);
344         SendDlgItemMessageW(hwndDlg, 28680, CB_RESETCONTENT, iSelIndex, 0);
345         return;
346     }
347 }
348 
349 static VOID
350 InitializeFormatDriveDlg(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
351 {
352     WCHAR szText[120];
353     WCHAR szDrive[] = L"C:\\";
354     WCHAR szFs[30] = L"";
355     INT cchText;
356     ULARGE_INTEGER FreeBytesAvailableUser, TotalNumberOfBytes;
357     DWORD dwIndex, dwDefault;
358     UCHAR uMinor, uMajor;
359     BOOLEAN Latest;
360     HWND hwndFileSystems;
361 
362     cchText = GetWindowTextW(hwndDlg, szText, _countof(szText) - 1);
363     if (cchText < 0)
364         cchText = 0;
365     szText[cchText++] = L' ';
366     szDrive[0] = pContext->Drive + L'A';
367     if (GetVolumeInformationW(szDrive, &szText[cchText], _countof(szText) - cchText, NULL, NULL, NULL, szFs, _countof(szFs)))
368     {
369         if (szText[cchText] == UNICODE_NULL)
370         {
371             /* load default volume label */
372             cchText += LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, &szText[cchText], _countof(szText) - cchText);
373         }
374         else
375         {
376             /* set volume label */
377             SetDlgItemTextW(hwndDlg, 28679, &szText[cchText]);
378             cchText += wcslen(&szText[cchText]);
379         }
380     }
381 
382     StringCchPrintfW(szText + cchText, _countof(szText) - cchText, L" (%c:)", szDrive[0]);
383 
384     /* set window text */
385     SetWindowTextW(hwndDlg, szText);
386 
387     if (GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfBytes, NULL))
388     {
389         if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szText, _countof(szText)))
390         {
391             /* add drive capacity */
392             SendDlgItemMessageW(hwndDlg, 28673, CB_ADDSTRING, 0, (LPARAM)szText);
393             SendDlgItemMessageW(hwndDlg, 28673, CB_SETCURSEL, 0, (LPARAM)0);
394         }
395     }
396 
397     if (pContext->Options & SHFMT_OPT_FULL)
398     {
399         /* check quick format button */
400         SendDlgItemMessageW(hwndDlg, 28674, BM_SETCHECK, BST_CHECKED, 0);
401     }
402 
403     /* enumerate all available filesystems */
404     dwIndex = 0;
405     dwDefault = 0;
406     hwndFileSystems = GetDlgItem(hwndDlg, 28677);
407 
408     while(QueryAvailableFileSystemFormat(dwIndex, szText, &uMajor, &uMinor, &Latest))
409     {
410         if (!wcsicmp(szText, szFs))
411             dwDefault = dwIndex;
412 
413         SendMessageW(hwndFileSystems, CB_ADDSTRING, 0, (LPARAM)szText);
414         dwIndex++;
415     }
416 
417     if (!dwIndex)
418     {
419         ERR("no filesystem providers\n");
420         return;
421     }
422 
423     /* select default filesys */
424     SendMessageW(hwndFileSystems, CB_SETCURSEL, dwDefault, 0);
425     /* setup cluster combo */
426     InsertDefaultClusterSizeForFs(hwndDlg, pContext);
427 }
428 
429 static HWND FormatDrvDialog = NULL;
430 static BOOLEAN bSuccess = FALSE;
431 
432 static BOOLEAN NTAPI
433 FormatExCB(
434     IN CALLBACKCOMMAND Command,
435     IN ULONG SubAction,
436     IN PVOID ActionInfo)
437 {
438     PDWORD Progress;
439     PBOOLEAN pSuccess;
440     switch(Command)
441     {
442         case PROGRESS:
443             Progress = (PDWORD)ActionInfo;
444             SendDlgItemMessageW(FormatDrvDialog, 28678, PBM_SETPOS, (WPARAM)*Progress, 0);
445             break;
446         case DONE:
447             pSuccess = (PBOOLEAN)ActionInfo;
448             bSuccess = (*pSuccess);
449             ShellMessageBoxW(shell32_hInstance, FormatDrvDialog, MAKEINTRESOURCEW(IDS_FORMAT_COMPLETE), MAKEINTRESOURCEW(IDS_FORMAT_TITLE), MB_OK | MB_ICONINFORMATION);
450             SendDlgItemMessageW(FormatDrvDialog, 28678, PBM_SETPOS, 0, 0);
451             break;
452 
453         case VOLUMEINUSE:
454         case INSUFFICIENTRIGHTS:
455         case FSNOTSUPPORTED:
456         case CLUSTERSIZETOOSMALL:
457             bSuccess = FALSE;
458             FIXME("Unsupported command in FormatExCB\n");
459             break;
460 
461         default:
462             break;
463     }
464 
465     return TRUE;
466 }
467 
468 VOID
469 FormatDrive(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
470 {
471     WCHAR szDrive[4] = { L'C', ':', '\\', 0 };
472     WCHAR szFileSys[40] = {0};
473     WCHAR szLabel[40] = {0};
474     INT iSelIndex;
475     UINT Length;
476     HWND hDlgCtrl;
477     BOOL QuickFormat;
478     DWORD ClusterSize;
479     DWORD DriveType;
480     FMIFS_MEDIA_FLAG MediaFlag = FMIFS_HARDDISK;
481 
482     /* set volume path */
483     szDrive[0] = pContext->Drive + L'A';
484 
485     /* get filesystem */
486     hDlgCtrl = GetDlgItem(hwndDlg, 28677);
487     iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
488     if (iSelIndex == CB_ERR)
489     {
490         ERR("Unable to get file system selection\n");
491         return;
492     }
493     Length = SendMessageW(hDlgCtrl, CB_GETLBTEXTLEN, iSelIndex, 0);
494     if ((int)Length == CB_ERR || Length + 1 > _countof(szFileSys))
495     {
496         ERR("Unable to get file system selection\n");
497         return;
498     }
499 
500     /* retrieve the file system */
501     SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)szFileSys);
502     szFileSys[_countof(szFileSys)-1] = L'\0';
503 
504     /* retrieve the volume label */
505     hDlgCtrl = GetWindow(hwndDlg, 28679);
506     Length = SendMessageW(hDlgCtrl, WM_GETTEXTLENGTH, 0, 0);
507     if (Length + 1 > _countof(szLabel))
508     {
509         ERR("Unable to get volume label\n");
510         return;
511     }
512     SendMessageW(hDlgCtrl, WM_GETTEXT, _countof(szLabel), (LPARAM)szLabel);
513     szLabel[(sizeof(szLabel)/sizeof(WCHAR))-1] = L'\0';
514 
515     /* check for quickformat */
516     if (SendDlgItemMessageW(hwndDlg, 28674, BM_GETCHECK, 0, 0) == BST_CHECKED)
517         QuickFormat = TRUE;
518     else
519         QuickFormat = FALSE;
520 
521     /* get the cluster size */
522     hDlgCtrl = GetDlgItem(hwndDlg, 28680);
523     iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
524     if (iSelIndex == CB_ERR)
525     {
526         FIXME("\n");
527         return;
528     }
529     ClusterSize = SendMessageW(hDlgCtrl, CB_GETITEMDATA, iSelIndex, 0);
530     if ((int)ClusterSize == CB_ERR)
531     {
532         FIXME("\n");
533         return;
534     }
535 
536     hDlgCtrl = GetDlgItem(hwndDlg, 28680);
537     SendMessageW(hDlgCtrl, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
538     bSuccess = FALSE;
539 
540     /* FIXME
541      * will cause display problems
542      * when performing more than one format
543      */
544     FormatDrvDialog = hwndDlg;
545 
546     /* See if the drive is removable or not */
547     DriveType = GetDriveTypeW(szDrive);
548     switch (DriveType)
549     {
550         case DRIVE_UNKNOWN:
551         case DRIVE_REMOTE:
552         case DRIVE_CDROM:
553         case DRIVE_NO_ROOT_DIR:
554         {
555             FIXME("\n");
556             return;
557         }
558 
559         case DRIVE_REMOVABLE:
560             MediaFlag = FMIFS_FLOPPY;
561             break;
562 
563         case DRIVE_FIXED:
564         case DRIVE_RAMDISK:
565             MediaFlag = FMIFS_HARDDISK;
566             break;
567     }
568 
569     /* Format the drive */
570     FormatEx(szDrive,
571              MediaFlag,
572              szFileSys,
573              szLabel,
574              QuickFormat,
575              ClusterSize,
576              FormatExCB);
577 
578     FormatDrvDialog = NULL;
579     if (!bSuccess)
580     {
581         pContext->Result = SHFMT_ERROR;
582     }
583     else if (QuickFormat)
584     {
585         pContext->Result = SHFMT_OPT_FULL;
586     }
587     else
588     {
589         pContext->Result = FALSE;
590     }
591 }
592 
593 struct FORMAT_DRIVE_PARAMS
594 {
595     HWND hwndDlg;
596     PFORMAT_DRIVE_CONTEXT pContext;
597 };
598 
599 static unsigned __stdcall DoFormatDrive(void *args)
600 {
601     FORMAT_DRIVE_PARAMS *pParams = reinterpret_cast<FORMAT_DRIVE_PARAMS *>(args);
602     HWND hwndDlg = pParams->hwndDlg;
603     PFORMAT_DRIVE_CONTEXT pContext = pParams->pContext;
604 
605 	/* Disable controls during format */
606     HMENU hSysMenu = GetSystemMenu(hwndDlg, FALSE);
607     EnableMenuItem(hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
608     EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
609     EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE);
610     EnableWindow(GetDlgItem(hwndDlg, 28673), FALSE);
611     EnableWindow(GetDlgItem(hwndDlg, 28677), FALSE);
612     EnableWindow(GetDlgItem(hwndDlg, 28680), FALSE);
613     EnableWindow(GetDlgItem(hwndDlg, 28679), FALSE);
614     EnableWindow(GetDlgItem(hwndDlg, 28674), FALSE);
615 
616     FormatDrive(hwndDlg, pContext);
617 
618 	/* Re-enable controls after format */
619     EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
620     EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), TRUE);
621     EnableWindow(GetDlgItem(hwndDlg, 28673), TRUE);
622     EnableWindow(GetDlgItem(hwndDlg, 28677), TRUE);
623     EnableWindow(GetDlgItem(hwndDlg, 28680), TRUE);
624     EnableWindow(GetDlgItem(hwndDlg, 28679), TRUE);
625     EnableWindow(GetDlgItem(hwndDlg, 28674), TRUE);
626     EnableMenuItem(hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_ENABLED);
627     pContext->bFormattingNow = FALSE;
628 
629     delete pParams;
630     return 0;
631 }
632 
633 static INT_PTR CALLBACK
634 FormatDriveDlg(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
635 {
636     PFORMAT_DRIVE_CONTEXT pContext;
637 
638     switch(uMsg)
639     {
640         case WM_INITDIALOG:
641             InitializeFormatDriveDlg(hwndDlg, (PFORMAT_DRIVE_CONTEXT)lParam);
642             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
643             return TRUE;
644         case WM_COMMAND:
645             switch(LOWORD(wParam))
646             {
647                 case IDOK:
648                     pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
649                     if (pContext->bFormattingNow)
650                         break;
651 
652                     if (ShellMessageBoxW(shell32_hInstance, hwndDlg,
653                                          MAKEINTRESOURCEW(IDS_FORMAT_WARNING),
654                                          MAKEINTRESOURCEW(IDS_FORMAT_TITLE),
655                                          MB_OKCANCEL | MB_ICONWARNING) == IDOK)
656                     {
657                         pContext->bFormattingNow = TRUE;
658 
659                         FORMAT_DRIVE_PARAMS *pParams = new FORMAT_DRIVE_PARAMS;
660                         pParams->hwndDlg = hwndDlg;
661                         pParams->pContext = pContext;
662 
663                         unsigned tid;
664                         HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, DoFormatDrive, pParams, 0, &tid);
665                         CloseHandle(hThread);
666                     }
667                     break;
668                 case IDCANCEL:
669                     pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
670                     if (pContext->bFormattingNow)
671                         break;
672 
673                     EndDialog(hwndDlg, pContext->Result);
674                     break;
675                 case 28677: // filesystem combo
676                     if (HIWORD(wParam) == CBN_SELENDOK)
677                     {
678                         pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
679                         if (pContext->bFormattingNow)
680                             break;
681 
682                         InsertDefaultClusterSizeForFs(hwndDlg, pContext);
683                     }
684                     break;
685             }
686     }
687     return FALSE;
688 }
689 
690 /*************************************************************************
691  *              SHFormatDrive (SHELL32.@)
692  */
693 
694 DWORD
695 WINAPI
696 SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options)
697 {
698     FORMAT_DRIVE_CONTEXT Context;
699     int result;
700 
701     TRACE("%p, 0x%08x, 0x%08x, 0x%08x - stub\n", hwnd, drive, fmtID, options);
702 
703     Context.Drive = drive;
704     Context.Options = options;
705     Context.Result = FALSE;
706     Context.bFormattingNow = FALSE;
707 
708     if (!IsSystemDrive(&Context))
709     {
710         result = DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_FORMAT_DRIVE), hwnd, FormatDriveDlg, (LPARAM)&Context);
711     }
712     else
713     {
714         result = SHFMT_ERROR;
715         ShellMessageBoxW(shell32_hInstance, hwnd, MAKEINTRESOURCEW(IDS_NO_FORMAT), MAKEINTRESOURCEW(IDS_NO_FORMAT_TITLE), MB_OK | MB_ICONWARNING);
716         TRACE("SHFormatDrive(): The provided drive for format is a system volume! Aborting...\n");
717     }
718 
719     return result;
720 }
721