Reactos
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#include <ndk/obfuncs.h> // For NtQueryObject
25
26WINE_DEFAULT_DEBUG_CHANNEL(shell);
27
28extern BOOL IsDriveFloppyW(LPCWSTR pszDriveRoot);
29
30typedef struct
31{
32 WCHAR Drive; // Note: This is the drive number, not a drive letter
33 UINT Options;
34 UINT Result;
35 BOOL bFormattingNow;
36 HWND hWndMain;
37 HWND hWndTip, hWndTipTrigger;
38 struct tagTip { UNICODE_STRING Name; WCHAR Buffer[400]; } Tip;
39} FORMAT_DRIVE_CONTEXT, *PFORMAT_DRIVE_CONTEXT;
40
41static inline BOOL
42DevIoCtl(HANDLE hDevice, UINT Code, LPVOID pIn, UINT cbIn, LPVOID pOut, UINT cbOut)
43{
44 DWORD cb = 0;
45 return DeviceIoControl(hDevice, Code, pIn, cbIn, pOut, cbOut, &cb, NULL);
46}
47
48static BOOL IsFloppy(PCWSTR pszDrive)
49{
50 return GetDriveTypeW(pszDrive) == DRIVE_REMOVABLE && IsDriveFloppyW(pszDrive);
51}
52
53/*
54 * TODO: In Windows the Shell doesn't know by itself if a drive is
55 * a system one or not but rather a packet message is being sent by
56 * FMIFS library code and further translated into specific packet
57 * status codes in the Shell, the packet being _FMIFS_PACKET_TYPE.
58 *
59 * With that being said, most of this code as well as FMIFS library code
60 * have to be refactored in order to comply with the way Windows works.
61 *
62 * See the enum definition for more details:
63 * https://github.com/microsoft/winfile/blob/master/src/fmifs.h#L23
64 */
65static BOOL
66IsSystemDrive(PFORMAT_DRIVE_CONTEXT pContext)
67{
68 WCHAR wszSystemDrv[MAX_PATH];
69 wszSystemDrv[0] = UNICODE_NULL;
70 GetSystemDirectory(wszSystemDrv, _countof(wszSystemDrv));
71 return (wszSystemDrv[0] | 32) == pContext->Drive + L'a';
72}
73
74static HANDLE
75OpenLogicalDriveHandle(WORD DriveNumber)
76{
77 const WCHAR szPath[] = { '\\', '\\', '?', '\\', WCHAR(DriveNumber + 'A'), ':', '\0' };
78 return CreateFileW(szPath, FILE_READ_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
79 NULL, OPEN_EXISTING, 0, NULL);
80}
81
82static BOOL
83GetLogicalDriveSize(WORD DriveNumber, ULARGE_INTEGER &Result)
84{
85 BOOL bSuccess = FALSE;
86 const WCHAR szDrivePath[] = { WCHAR(DriveNumber + 'A'), ':', '\\', '\0' };
87
88 HANDLE hDevice = OpenLogicalDriveHandle(DriveNumber);
89 if (hDevice != INVALID_HANDLE_VALUE)
90 {
91 GET_LENGTH_INFORMATION LengthInfo;
92 bSuccess = DevIoCtl(hDevice, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &LengthInfo, sizeof(LengthInfo));
93 Result.QuadPart = LengthInfo.Length.QuadPart;
94 if (!bSuccess && GetDriveTypeW(szDrivePath) == DRIVE_REMOVABLE) // Blank floppy
95 {
96 DISK_GEOMETRY dg;
97 bSuccess = DevIoCtl(hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg));
98 if (bSuccess)
99 Result.QuadPart = dg.Cylinders.QuadPart * dg.TracksPerCylinder * dg.SectorsPerTrack * dg.BytesPerSector;
100 }
101 CloseHandle(hDevice);
102 }
103 if (!bSuccess || !Result.QuadPart)
104 bSuccess = GetDiskFreeSpaceExW(szDrivePath, NULL, &Result, NULL); // Note: Not exact if NTFS quotas are in effect
105 return bSuccess;
106}
107
108static PWSTR
109CreateTipText(FORMAT_DRIVE_CONTEXT &Ctx)
110{
111 HANDLE hDevice = OpenLogicalDriveHandle(Ctx.Drive);
112 if (hDevice == INVALID_HANDLE_VALUE)
113 return NULL;
114
115 ULONG cb;
116 ZeroMemory(&Ctx.Tip, sizeof(Ctx.Tip));
117 NtQueryObject(hDevice, ObjectNameInformation, &Ctx.Tip, sizeof(Ctx.Tip), &cb);
118 if (Ctx.Tip.Name.Buffer && Ctx.Tip.Name.Buffer[0] == '\\')
119 StringCbCatW(Ctx.Tip.Name.Buffer, sizeof(Ctx.Tip) - sizeof(UNICODE_STRING), L"\n");
120 else
121 (Ctx.Tip.Name.Buffer = Ctx.Tip.Buffer)[0] = UNICODE_NULL;
122
123 PARTITION_INFORMATION_EX pie;
124 if (!DevIoCtl(hDevice, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &pie, sizeof(pie)))
125 {
126 pie.PartitionStyle = PARTITION_STYLE_RAW;
127 PARTITION_INFORMATION pi;
128 if (DevIoCtl(hDevice, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &pi, sizeof(pi)))
129 {
130 pie.PartitionStyle = PARTITION_STYLE_MBR;
131 pie.PartitionNumber = pi.PartitionNumber;
132 }
133 }
134 CloseHandle(hDevice);
135
136 WCHAR szBuf[150], szGuid[39], *pszTip = Ctx.Tip.Name.Buffer;
137 szBuf[0] = UNICODE_NULL;
138 if (pie.PartitionStyle == PARTITION_STYLE_GPT)
139 {
140 StringFromGUID2(pie.Gpt.PartitionId, szGuid, _countof(szGuid));
141 StringCchPrintfW(szBuf, _countof(szBuf), L"GPT %s %s", szGuid, pie.Gpt.Name);
142 }
143 if (pie.PartitionStyle == PARTITION_STYLE_MBR)
144 {
145 StringCchPrintfW(szBuf, _countof(szBuf), L"MBR (%d)", pie.PartitionNumber);
146 }
147 StringCbCatW(pszTip, sizeof(Ctx.Tip) - sizeof(Ctx.Tip.Name), szBuf);
148 return pszTip;
149}
150
151static BOOL
152GetDefaultClusterSize(LPWSTR szFs, PDWORD pClusterSize, PULARGE_INTEGER TotalNumberOfBytes)
153{
154 DWORD ClusterSize;
155
156 if (!_wcsicmp(szFs, L"FAT16") ||
157 !_wcsicmp(szFs, L"FAT")) // REACTOS HACK
158 {
159 if (TotalNumberOfBytes->QuadPart <= (16 * 1024 * 1024))
160 ClusterSize = 2048;
161 else if (TotalNumberOfBytes->QuadPart <= (32 * 1024 * 1024))
162 ClusterSize = 512;
163 else if (TotalNumberOfBytes->QuadPart <= (64 * 1024 * 1024))
164 ClusterSize = 1024;
165 else if (TotalNumberOfBytes->QuadPart <= (128 * 1024 * 1024))
166 ClusterSize = 2048;
167 else if (TotalNumberOfBytes->QuadPart <= (256 * 1024 * 1024))
168 ClusterSize = 4096;
169 else if (TotalNumberOfBytes->QuadPart <= (512 * 1024 * 1024))
170 ClusterSize = 8192;
171 else if (TotalNumberOfBytes->QuadPart <= (1024 * 1024 * 1024))
172 ClusterSize = 16384;
173 else if (TotalNumberOfBytes->QuadPart <= (2048LL * 1024LL * 1024LL))
174 ClusterSize = 32768;
175 else if (TotalNumberOfBytes->QuadPart <= (4096LL * 1024LL * 1024LL))
176 ClusterSize = 8192;
177 else
178 return FALSE;
179 }
180 else if (!_wcsicmp(szFs, L"FAT32"))
181 {
182 if (TotalNumberOfBytes->QuadPart <= (64 * 1024 * 1024))
183 ClusterSize = 512;
184 else if (TotalNumberOfBytes->QuadPart <= (128 * 1024 * 1024))
185 ClusterSize = 1024;
186 else if (TotalNumberOfBytes->QuadPart <= (256 * 1024 * 1024))
187 ClusterSize = 2048;
188 else if (TotalNumberOfBytes->QuadPart <= (8192LL * 1024LL * 1024LL))
189 ClusterSize = 2048;
190 else if (TotalNumberOfBytes->QuadPart <= (16384LL * 1024LL * 1024LL))
191 ClusterSize = 8192;
192 else if (TotalNumberOfBytes->QuadPart <= (32768LL * 1024LL * 1024LL))
193 ClusterSize = 16384;
194 else
195 return FALSE;
196 }
197 else if (!_wcsicmp(szFs, L"FATX"))
198 {
199 if (TotalNumberOfBytes->QuadPart <= (16 * 1024 * 1024))
200 ClusterSize = 2048;
201 else if (TotalNumberOfBytes->QuadPart <= (32 * 1024 * 1024))
202 ClusterSize = 512;
203 else if (TotalNumberOfBytes->QuadPart <= (64 * 1024 * 1024))
204 ClusterSize = 1024;
205 else if (TotalNumberOfBytes->QuadPart <= (128 * 1024 * 1024))
206 ClusterSize = 2048;
207 else if (TotalNumberOfBytes->QuadPart <= (256 * 1024 * 1024))
208 ClusterSize = 4096;
209 else if (TotalNumberOfBytes->QuadPart <= (8192LL * 1024LL * 1024LL))
210 ClusterSize = 2048;
211 else if (TotalNumberOfBytes->QuadPart <= (16384LL * 1024LL * 1024LL))
212 ClusterSize = 8192;
213 else if (TotalNumberOfBytes->QuadPart <= (32768LL * 1024LL * 1024LL))
214 ClusterSize = 16384;
215 else
216 return FALSE;
217 }
218 else if (!_wcsicmp(szFs, L"NTFS"))
219 {
220 if (TotalNumberOfBytes->QuadPart <= (512 * 1024 * 1024))
221 ClusterSize = 512;
222 else if (TotalNumberOfBytes->QuadPart <= (1024 * 1024 * 1024))
223 ClusterSize = 1024;
224 else if (TotalNumberOfBytes->QuadPart <= (2048LL * 1024LL * 1024LL))
225 ClusterSize = 2048;
226 else
227 ClusterSize = 2048;
228 }
229 else if (!_wcsicmp(szFs, L"EXT2"))
230 {
231 // auto block size calculation
232 ClusterSize = 0;
233 }
234 else if (!_wcsicmp(szFs, L"BtrFS"))
235 {
236 // auto block size calculation
237 ClusterSize = 0;
238 }
239 else
240 return FALSE;
241
242 *pClusterSize = ClusterSize;
243 return TRUE;
244}
245
246static VOID
247InsertDefaultClusterSizeForFs(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
248{
249 WCHAR wszBuf[100] = {0};
250 WCHAR wszDefaultSize[100] = {0};
251 PCWSTR pwszFsSizeLimit;
252 INT iSelIndex;
253 ULARGE_INTEGER TotalNumberOfBytes;
254 DWORD ClusterSize;
255 LRESULT lIndex;
256 HWND hDlgCtrl;
257
258 hDlgCtrl = GetDlgItem(hwndDlg, 28677);
259 iSelIndex = SendMessage(hDlgCtrl, CB_GETCURSEL, 0, 0);
260 if (iSelIndex == CB_ERR)
261 return;
262
263 if (SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)wszBuf) == CB_ERR)
264 return;
265
266 if (!GetLogicalDriveSize(pContext->Drive, TotalNumberOfBytes))
267 return;
268
269 if (!_wcsicmp(wszBuf, L"FAT16") ||
270 !_wcsicmp(wszBuf, L"FAT")) // REACTOS HACK
271 {
272 pwszFsSizeLimit = L"4GB";
273 }
274 else if (!_wcsicmp(wszBuf, L"FAT32"))
275 {
276 pwszFsSizeLimit = L"32GB";
277 }
278 else if (!_wcsicmp(wszBuf, L"FATX"))
279 {
280 pwszFsSizeLimit = L"1GB/32GB";
281 }
282 else if (!_wcsicmp(wszBuf, L"NTFS"))
283 {
284 pwszFsSizeLimit = L"256TB";
285 }
286 else if (!_wcsicmp(wszBuf, L"EXT2"))
287 {
288 pwszFsSizeLimit = L"32TB";
289 }
290 else
291 {
292 pwszFsSizeLimit = L"16EB";
293 }
294
295 if (!_wcsicmp(wszBuf, L"FAT16") ||
296 !_wcsicmp(wszBuf, L"FAT") || // REACTOS HACK
297 !_wcsicmp(wszBuf, L"FAT32") ||
298 !_wcsicmp(wszBuf, L"FATX") ||
299 !_wcsicmp(wszBuf, L"NTFS") ||
300 !_wcsicmp(wszBuf, L"EXT2") ||
301 !_wcsicmp(wszBuf, L"BtrFS"))
302 {
303 if (!GetDefaultClusterSize(wszBuf, &ClusterSize, &TotalNumberOfBytes))
304 {
305 TRACE("%S is not supported on drive larger than %S, current size: %lu\n", wszBuf, pwszFsSizeLimit, TotalNumberOfBytes.QuadPart);
306 SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0);
307 return;
308 }
309
310 if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, wszDefaultSize, _countof(wszDefaultSize)))
311 {
312 hDlgCtrl = GetDlgItem(hwndDlg, 28680); // Get the window handle of "allocation unit size" combobox
313 SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0);
314 lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)wszDefaultSize);
315 if (lIndex != CB_ERR)
316 SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
317 SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0);
318 }
319
320 if (!_wcsicmp(wszBuf, L"NTFS"))
321 {
322 ClusterSize = 512;
323 for (lIndex = 0; lIndex < 4; lIndex++)
324 {
325 TotalNumberOfBytes.QuadPart = ClusterSize;
326 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, wszDefaultSize, _countof(wszDefaultSize)))
327 {
328 lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)wszDefaultSize);
329 if (lIndex != CB_ERR)
330 SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
331 }
332 ClusterSize *= 2;
333 }
334 }
335
336 SendMessageW(GetDlgItem(hwndDlg, 28675), BM_SETCHECK, BST_UNCHECKED, 0);
337#if 0 // TODO: Call EnableVolumeCompression if checked
338 if (!_wcsicmp(wszBuf, L"EXT2") ||
339 !_wcsicmp(wszBuf, L"BtrFS") ||
340 !_wcsicmp(wszBuf, L"NTFS"))
341 {
342 /* Enable the "Enable Compression" button */
343 EnableWindow(GetDlgItem(hwndDlg, 28675), TRUE);
344 }
345 else
346#endif
347 {
348 /* Disable the "Enable Compression" button */
349 EnableWindow(GetDlgItem(hwndDlg, 28675), FALSE);
350 }
351 }
352 else
353 {
354 FIXME("Unknown filesystem: %ls\n", wszBuf);
355 SendDlgItemMessageW(hwndDlg, 28680, CB_RESETCONTENT, iSelIndex, 0);
356 return;
357 }
358}
359
360static VOID
361EnableFormatDriveDlgControls(HWND hwndDlg, int EnableState)
362{
363 BOOL CanClose = EnableState != 0, Enable = EnableState > 0;
364 HMENU hSysMenu = GetSystemMenu(hwndDlg, FALSE);
365 EnableMenuItem(hSysMenu, SC_CLOSE, MF_BYCOMMAND | (CanClose ? MF_ENABLED : MF_GRAYED));
366 EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), CanClose);
367 static const WORD id[] = { IDOK, 28673, 28677, 28680, 28679, 28674 };
368 for (UINT i = 0; i < _countof(id); ++i)
369 EnableWindow(GetDlgItem(hwndDlg, id[i]), Enable);
370}
371
372static VOID
373InitializeFormatDriveDlg(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
374{
375 WCHAR szDrive[] = { WCHAR(pContext->Drive + 'A'), ':', '\\', '\0' };
376 WCHAR szText[120], szFs[30];
377 SIZE_T cchText;
378 ULARGE_INTEGER TotalNumberOfBytes;
379 DWORD dwIndex, dwDefault;
380 UCHAR uMinor, uMajor;
381 BOOLEAN Latest;
382 HWND hwndFileSystems;
383
384 pContext->hWndMain = hwndDlg;
385 pContext->hWndTipTrigger = GetDlgItem(hwndDlg, 30000);
386 TTTOOLINFOW tool;
387 tool.cbSize = sizeof(tool);
388 tool.hwnd = hwndDlg;
389 tool.uFlags = TTF_SUBCLASS | TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
390 tool.uId = (UINT_PTR)pContext->hWndTipTrigger;
391 tool.lpszText = LPSTR_TEXTCALLBACKW;
392 pContext->hWndTip = CreateWindowExW(WS_EX_TOPMOST, TOOLTIPS_CLASSW, NULL, WS_POPUP |
393 TTS_BALLOON | TTS_NOPREFIX | TTS_ALWAYSTIP,
394 0, 0, 0, 0, hwndDlg, NULL, NULL, NULL);
395 SendMessageW(pContext->hWndTip, TTM_ADDTOOLW, 0, (LPARAM)&tool);
396 UINT nIcoSize = GetSystemMetrics(SM_CXSMICON);
397 HICON hIco = (HICON)LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_IDEA), IMAGE_ICON, nIcoSize, nIcoSize, LR_SHARED);
398 SendMessageW(pContext->hWndTipTrigger, STM_SETICON, (WPARAM)hIco, 0);
399
400 cchText = GetWindowTextW(hwndDlg, szText, _countof(szText) - 1);
401 szText[cchText++] = L' ';
402 szFs[0] = UNICODE_NULL;
403 if (GetVolumeInformationW(szDrive, &szText[cchText], _countof(szText) - cchText, NULL, NULL, NULL, szFs, _countof(szFs)))
404 {
405 if (szText[cchText] == UNICODE_NULL)
406 {
407 /* load default volume label */
408 cchText += LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, &szText[cchText], _countof(szText) - cchText);
409 }
410 else
411 {
412 /* set volume label */
413 SetDlgItemTextW(hwndDlg, 28679, &szText[cchText]);
414 cchText += wcslen(&szText[cchText]);
415 }
416 }
417
418 StringCchPrintfW(szText + cchText, _countof(szText) - cchText, L" (%c:)", szDrive[0]);
419
420 /* set window text */
421 SetWindowTextW(hwndDlg, szText);
422
423 if (GetLogicalDriveSize(pContext->Drive, TotalNumberOfBytes))
424 {
425 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szText, _countof(szText)))
426 {
427 /* add drive capacity */
428 SendDlgItemMessageW(hwndDlg, 28673, CB_ADDSTRING, 0, (LPARAM)szText);
429 SendDlgItemMessageW(hwndDlg, 28673, CB_SETCURSEL, 0, (LPARAM)0);
430 }
431 }
432 else
433 {
434 /* No known size, don't allow format (no partition or no floppy) */
435 EnableFormatDriveDlgControls(hwndDlg, -1);
436 }
437
438 if (pContext->Options & SHFMT_OPT_FULL)
439 {
440 /* check quick format button */
441 SendDlgItemMessageW(hwndDlg, 28674, BM_SETCHECK, BST_CHECKED, 0);
442 }
443
444 /* enumerate all available filesystems */
445 dwIndex = 0;
446 dwDefault = 0;
447 hwndFileSystems = GetDlgItem(hwndDlg, 28677);
448
449 int iForceDefault = -1;
450 while (QueryAvailableFileSystemFormat(dwIndex, szText, &uMajor, &uMinor, &Latest))
451 {
452 if (!_wcsicmp(szText, szFs))
453 iForceDefault = dwDefault = dwIndex; /* default to the same filesystem */
454
455 if (iForceDefault < 0 && !_wcsicmp(szText, L"NTFS") && !IsFloppy(szDrive))
456 dwDefault = dwIndex;
457
458 SendMessageW(hwndFileSystems, CB_ADDSTRING, 0, (LPARAM)szText);
459 dwIndex++;
460 }
461
462 if (!dwIndex)
463 {
464 ERR("no filesystem providers\n");
465 return;
466 }
467
468 /* select default filesys */
469 SendMessageW(hwndFileSystems, CB_SETCURSEL, dwDefault, 0);
470 /* setup cluster combo */
471 InsertDefaultClusterSizeForFs(hwndDlg, pContext);
472}
473
474static inline PFORMAT_DRIVE_CONTEXT
475GetFormatContext()
476{
477 // FormatEx does not allow us to specify a context parameter so we have to store it in the thread
478 return (PFORMAT_DRIVE_CONTEXT)NtCurrentTeb()->NtTib.ArbitraryUserPointer;
479}
480
481static BOOLEAN NTAPI
482FormatExCB(
483 IN CALLBACKCOMMAND Command,
484 IN ULONG SubAction,
485 IN PVOID ActionInfo)
486{
487 PFORMAT_DRIVE_CONTEXT pCtx = GetFormatContext();
488 const WCHAR szDrive[] = { WCHAR(pCtx->Drive + 'A'), ':', '\\', '\0' };
489 WCHAR szLabel[40];
490 PDWORD Progress;
491 PBOOLEAN pSuccess;
492 switch(Command)
493 {
494 case PROGRESS:
495 Progress = (PDWORD)ActionInfo;
496 SendDlgItemMessageW(pCtx->hWndMain, 28678, PBM_SETPOS, (WPARAM)*Progress, 0);
497 break;
498 case DONE:
499 pSuccess = (PBOOLEAN)ActionInfo;
500 pCtx->Result = (*pSuccess);
501 SendDlgItemMessageW(pCtx->hWndMain, 28679, WM_GETTEXT, _countof(szLabel), (LPARAM)szLabel);
502 SetVolumeLabelW(szDrive, *szLabel ? szLabel : NULL);
503 ShellMessageBoxW(shell32_hInstance, pCtx->hWndMain, MAKEINTRESOURCEW(IDS_FORMAT_COMPLETE),
504 MAKEINTRESOURCEW(IDS_FORMAT_TITLE), MB_OK | MB_ICONINFORMATION);
505 SendDlgItemMessageW(pCtx->hWndMain, 28678, PBM_SETPOS, 0, 0);
506 break;
507
508 case VOLUMEINUSE:
509 case INSUFFICIENTRIGHTS:
510 case FSNOTSUPPORTED:
511 case CLUSTERSIZETOOSMALL:
512 pCtx->Result = FALSE;
513 FIXME("Unsupported command in FormatExCB\n");
514 break;
515
516 default:
517 break;
518 }
519
520 return TRUE;
521}
522
523static VOID
524FormatDrive(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
525{
526 WCHAR szDrive[] = { WCHAR(pContext->Drive + 'A'), ':', '\\', '\0' };
527 WCHAR szFileSys[40];
528 WCHAR szLabel[40];
529 INT iSelIndex;
530 UINT Length;
531 HWND hDlgCtrl;
532 BOOL QuickFormat;
533 DWORD ClusterSize;
534 DWORD DriveType;
535 FMIFS_MEDIA_FLAG MediaFlag = FMIFS_HARDDISK;
536
537 /* get filesystem */
538 hDlgCtrl = GetDlgItem(hwndDlg, 28677);
539 iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
540 if (iSelIndex == CB_ERR)
541 {
542 ERR("Unable to get file system selection\n");
543 return;
544 }
545 Length = SendMessageW(hDlgCtrl, CB_GETLBTEXTLEN, iSelIndex, 0);
546 if ((int)Length == CB_ERR || Length + 1 > _countof(szFileSys))
547 {
548 ERR("Unable to get file system selection\n");
549 return;
550 }
551
552 /* retrieve the file system */
553 SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)szFileSys);
554 szFileSys[_countof(szFileSys)-1] = L'\0';
555
556 /* retrieve the volume label */
557 hDlgCtrl = GetWindow(hwndDlg, 28679);
558 Length = SendMessageW(hDlgCtrl, WM_GETTEXTLENGTH, 0, 0);
559 if (Length + 1 > _countof(szLabel))
560 {
561 ERR("Unable to get volume label\n");
562 return;
563 }
564 SendMessageW(hDlgCtrl, WM_GETTEXT, _countof(szLabel), (LPARAM)szLabel);
565 szLabel[(sizeof(szLabel)/sizeof(WCHAR))-1] = L'\0';
566
567 /* check for quickformat */
568 if (SendDlgItemMessageW(hwndDlg, 28674, BM_GETCHECK, 0, 0) == BST_CHECKED)
569 QuickFormat = TRUE;
570 else
571 QuickFormat = FALSE;
572
573 /* get the cluster size */
574 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
575 iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
576 if (iSelIndex == CB_ERR)
577 {
578 FIXME("\n");
579 return;
580 }
581 ClusterSize = SendMessageW(hDlgCtrl, CB_GETITEMDATA, iSelIndex, 0);
582 if ((int)ClusterSize == CB_ERR)
583 {
584 FIXME("\n");
585 return;
586 }
587
588 hDlgCtrl = GetDlgItem(hwndDlg, 28680);
589 SendMessageW(hDlgCtrl, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
590
591 /* See if the drive is removable or not */
592 DriveType = GetDriveTypeW(szDrive);
593 switch (DriveType)
594 {
595 case DRIVE_UNKNOWN:
596 case DRIVE_REMOTE:
597 case DRIVE_CDROM:
598 case DRIVE_NO_ROOT_DIR:
599 {
600 FIXME("\n");
601 return;
602 }
603
604 case DRIVE_REMOVABLE:
605 MediaFlag = FMIFS_FLOPPY;
606 break;
607
608 case DRIVE_FIXED:
609 case DRIVE_RAMDISK:
610 MediaFlag = FMIFS_HARDDISK;
611 break;
612 }
613
614 /* Format the drive */
615 pContext->Result = FALSE;
616 NT_TIB &tib = NtCurrentTeb()->NtTib;
617 PVOID BakArbitraryUserPointer = tib.ArbitraryUserPointer;
618 tib.ArbitraryUserPointer = pContext;
619
620 FormatEx(szDrive,
621 MediaFlag,
622 szFileSys,
623 szLabel,
624 QuickFormat,
625 ClusterSize,
626 FormatExCB);
627
628 tib.ArbitraryUserPointer = BakArbitraryUserPointer;
629 if (!pContext->Result)
630 {
631 pContext->Result = SHFMT_ERROR;
632 }
633 else if (QuickFormat)
634 {
635 pContext->Result = SHFMT_OPT_FULL;
636 }
637 else
638 {
639 pContext->Result = FALSE;
640 }
641}
642
643
644
645static DWORD CALLBACK
646FormatDriveThread(PVOID pThreadParameter)
647{
648 PFORMAT_DRIVE_CONTEXT pContext = (PFORMAT_DRIVE_CONTEXT)pThreadParameter;
649 HWND hwndDlg = pContext->hWndMain;
650 WCHAR szDrive[] = { WCHAR(pContext->Drive + 'A'), ':', '\\', '\0' };
651
652 /* Disable controls during format */
653 EnableFormatDriveDlgControls(hwndDlg, FALSE);
654
655 SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_PATHW | SHCNF_FLUSH, szDrive, NULL);
656
657 FormatDrive(hwndDlg, pContext);
658
659 if (pContext->Result != SHFMT_ERROR)
660 SHChangeNotify(SHCNE_MEDIAINSERTED, SHCNF_PATHW, szDrive, NULL);
661 SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATHW, szDrive, NULL);
662
663 /* Re-enable controls after format */
664 EnableFormatDriveDlgControls(hwndDlg, TRUE);
665 pContext->bFormattingNow = FALSE;
666
667 return 0;
668}
669
670static INT_PTR CALLBACK
671FormatDriveDlg(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
672{
673 PFORMAT_DRIVE_CONTEXT pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
674
675 switch(uMsg)
676 {
677 case WM_INITDIALOG:
678 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
679 InitializeFormatDriveDlg(hwndDlg, (PFORMAT_DRIVE_CONTEXT)lParam);
680 return TRUE;
681 case WM_COMMAND:
682 switch(LOWORD(wParam))
683 {
684 case IDOK:
685 if (pContext->bFormattingNow)
686 break;
687
688 if (ShellMessageBoxW(shell32_hInstance, hwndDlg,
689 MAKEINTRESOURCEW(IDS_FORMAT_WARNING),
690 MAKEINTRESOURCEW(IDS_FORMAT_TITLE),
691 MB_OKCANCEL | MB_ICONWARNING) == IDOK)
692 {
693 pContext->bFormattingNow = TRUE;
694 SHCreateThread(FormatDriveThread, pContext, CTF_COINIT | CTF_PROCESS_REF | CTF_FREELIBANDEXIT, NULL);
695 }
696 break;
697 case IDCANCEL:
698 if (pContext->bFormattingNow)
699 break;
700
701 EndDialog(hwndDlg, pContext->Result);
702 break;
703 case 28677: // filesystem combo
704 if (HIWORD(wParam) == CBN_SELENDOK)
705 {
706 if (pContext->bFormattingNow)
707 break;
708
709 InsertDefaultClusterSizeForFs(hwndDlg, pContext);
710 }
711 break;
712 }
713 break;
714 case WM_NOTIFY:
715 {
716 NMTTDISPINFO &ttdi = *(NMTTDISPINFO*)lParam;
717 if (ttdi.hdr.code == TTN_NEEDTEXTW)
718 {
719 ttdi.uFlags |= TTF_DI_SETITEM;
720 if (PWSTR pszTip = CreateTipText(*pContext))
721 ttdi.lpszText = pszTip;
722 }
723 break;
724 }
725 case WM_NEXTDLGCTL:
726 PostMessage(hwndDlg, WM_APP, TRUE, 0); // Delay our action until after focus has changed
727 break;
728 case WM_APP: // Show/Hide tip if tabbed to the info icon
729 {
730 TTTOOLINFOW tool;
731 tool.cbSize = sizeof(tool);
732 tool.hwnd = hwndDlg;
733 tool.uId = (UINT_PTR)pContext->hWndTipTrigger;
734 if (wParam && GetFocus() == pContext->hWndTipTrigger)
735 {
736 RECT r;
737 GetWindowRect(pContext->hWndTipTrigger, &r);
738 r.left += (r.right - r.left) / 2;
739 r.top += (r.bottom - r.top) / 2;
740 SendMessageW(pContext->hWndTip, TTM_TRACKPOSITION, 0, MAKELONG(r.left, r.top));
741 SendMessageW(pContext->hWndTip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&tool);
742 }
743 else
744 {
745 SendMessageW(pContext->hWndTip, TTM_TRACKACTIVATE, FALSE, (LPARAM)&tool);
746 }
747 break;
748 }
749 case WM_MOVING:
750 SendMessage(hwndDlg, WM_APP, FALSE, 0);
751 break;
752 }
753 return FALSE;
754}
755
756/*************************************************************************
757 * SHFormatDrive (SHELL32.@)
758 */
759
760DWORD
761WINAPI
762SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options)
763{
764 FORMAT_DRIVE_CONTEXT Context;
765 int result;
766
767 TRACE("%p, 0x%08x, 0x%08x, 0x%08x - stub\n", hwnd, drive, fmtID, options);
768
769 Context.Drive = drive;
770 Context.Options = options;
771 Context.Result = FALSE;
772 Context.bFormattingNow = FALSE;
773
774 if (!IsSystemDrive(&Context))
775 {
776 result = DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_FORMAT_DRIVE), hwnd, FormatDriveDlg, (LPARAM)&Context);
777 }
778 else
779 {
780 result = SHFMT_ERROR;
781 ShellMessageBoxW(shell32_hInstance, hwnd, MAKEINTRESOURCEW(IDS_NO_FORMAT), MAKEINTRESOURCEW(IDS_NO_FORMAT_TITLE), MB_OK | MB_ICONWARNING);
782 TRACE("SHFormatDrive(): The provided drive for format is a system volume! Aborting...\n");
783 }
784
785 return result;
786}