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