Reactos
at master 786 lines 27 kB view raw
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}