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