Reactos
at master 877 lines 28 kB view raw
1/* 2 * Provides default drive shell extension 3 * 4 * Copyright 2005 Johannes Anderwald 5 * Copyright 2012 Rafal Harabien 6 * Copyright 2020 Katayama Hirofumi MZ 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 23#include "precomp.h" 24 25#define _USE_MATH_DEFINES 26#include <math.h> 27#include <devguid.h> 28 29#define NTOS_MODE_USER 30#include <ndk/iofuncs.h> 31#include <ndk/obfuncs.h> 32 33WINE_DEFAULT_DEBUG_CHANNEL(shell); 34 35typedef enum 36{ 37 HWPD_STANDARDLIST = 0, 38 HWPD_LARGELIST, 39 HWPD_MAX = HWPD_LARGELIST 40} HWPAGE_DISPLAYMODE, *PHWPAGE_DISPLAYMODE; 41 42EXTERN_C HWND WINAPI 43DeviceCreateHardwarePageEx(HWND hWndParent, 44 LPGUID lpGuids, 45 UINT uNumberOfGuids, 46 HWPAGE_DISPLAYMODE DisplayMode); 47UINT SH_FormatByteSize(LONGLONG cbSize, LPWSTR pwszResult, UINT cchResultMax); 48 49static VOID 50GetDriveNameWithLetter(LPWSTR pwszText, UINT cchTextMax, LPCWSTR pwszDrive) 51{ 52 DWORD dwMaxComp, dwFileSys; 53 SIZE_T cchText = 0; 54 55 if (GetVolumeInformationW(pwszDrive, pwszText, cchTextMax, NULL, &dwMaxComp, &dwFileSys, NULL, 0)) 56 { 57 cchText = wcslen(pwszText); 58 if (cchText == 0) 59 { 60 /* load default volume label */ 61 cchText = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, pwszText, cchTextMax); 62 } 63 } 64 65 StringCchPrintfW(pwszText + cchText, cchTextMax - cchText, L" (%c:)", pwszDrive[0]); 66} 67 68static VOID 69InitializeChkDskDialog(HWND hwndDlg, LPCWSTR pwszDrive) 70{ 71 WCHAR wszText[100]; 72 UINT Length; 73 SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pwszDrive); 74 75 Length = GetWindowTextW(hwndDlg, wszText, sizeof(wszText) / sizeof(WCHAR)); 76 wszText[Length] = L' '; 77 GetDriveNameWithLetter(&wszText[Length + 1], (sizeof(wszText) / sizeof(WCHAR)) - Length - 1, pwszDrive); 78 SetWindowText(hwndDlg, wszText); 79} 80 81static HWND hChkdskDrvDialog = NULL; 82static BOOLEAN bChkdskSuccess = FALSE; 83 84static BOOLEAN NTAPI 85ChkdskCallback( 86 IN CALLBACKCOMMAND Command, 87 IN ULONG SubAction, 88 IN PVOID ActionInfo) 89{ 90 PDWORD Progress; 91 PBOOLEAN pSuccess; 92 switch(Command) 93 { 94 case PROGRESS: 95 Progress = (PDWORD)ActionInfo; 96 SendDlgItemMessageW(hChkdskDrvDialog, 14002, PBM_SETPOS, (WPARAM)*Progress, 0); 97 break; 98 case DONE: 99 pSuccess = (PBOOLEAN)ActionInfo; 100 bChkdskSuccess = (*pSuccess); 101 break; 102 103 case VOLUMEINUSE: 104 case INSUFFICIENTRIGHTS: 105 case FSNOTSUPPORTED: 106 case CLUSTERSIZETOOSMALL: 107 bChkdskSuccess = FALSE; 108 FIXME("\n"); 109 break; 110 111 default: 112 break; 113 } 114 115 return TRUE; 116} 117 118static VOID 119ChkDskNow(HWND hwndDlg, LPCWSTR pwszDrive) 120{ 121 //DWORD ClusterSize = 0; 122 WCHAR wszFs[30]; 123 ULARGE_INTEGER TotalNumberOfFreeBytes, FreeBytesAvailableUser; 124 BOOLEAN bCorrectErrors = FALSE, bScanDrive = FALSE; 125 126 if(!GetVolumeInformationW(pwszDrive, NULL, 0, NULL, NULL, NULL, wszFs, _countof(wszFs))) 127 { 128 FIXME("failed to get drive fs type\n"); 129 return; 130 } 131 132 if (!GetDiskFreeSpaceExW(pwszDrive, &FreeBytesAvailableUser, &TotalNumberOfFreeBytes, NULL)) 133 { 134 FIXME("failed to get drive space type\n"); 135 return; 136 } 137 138 /*if (!GetDefaultClusterSize(wszFs, &ClusterSize, &TotalNumberOfFreeBytes)) 139 { 140 FIXME("invalid cluster size\n"); 141 return; 142 }*/ 143 144 if (SendDlgItemMessageW(hwndDlg, 14000, BM_GETCHECK, 0, 0) == BST_CHECKED) 145 bCorrectErrors = TRUE; 146 147 if (SendDlgItemMessageW(hwndDlg, 14001, BM_GETCHECK, 0, 0) == BST_CHECKED) 148 bScanDrive = TRUE; 149 150 hChkdskDrvDialog = hwndDlg; 151 bChkdskSuccess = FALSE; 152 SendDlgItemMessageW(hwndDlg, 14002, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); 153 Chkdsk((LPWSTR)pwszDrive, (LPWSTR)wszFs, bCorrectErrors, TRUE, FALSE, bScanDrive, NULL, NULL, ChkdskCallback); // FIXME: casts 154 155 hChkdskDrvDialog = NULL; 156 bChkdskSuccess = FALSE; 157} 158 159static INT_PTR CALLBACK 160ChkDskDlg( 161 HWND hwndDlg, 162 UINT uMsg, 163 WPARAM wParam, 164 LPARAM lParam) 165{ 166 switch(uMsg) 167 { 168 case WM_INITDIALOG: 169 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam); 170 InitializeChkDskDialog(hwndDlg, (LPCWSTR)lParam); 171 return TRUE; 172 case WM_COMMAND: 173 switch(LOWORD(wParam)) 174 { 175 case IDCANCEL: 176 EndDialog(hwndDlg, 0); 177 break; 178 case IDOK: 179 { 180 LPCWSTR pwszDrive = (LPCWSTR)GetWindowLongPtr(hwndDlg, DWLP_USER); 181 ChkDskNow(hwndDlg, pwszDrive); 182 break; 183 } 184 } 185 break; 186 } 187 188 return FALSE; 189} 190 191VOID 192CDrvDefExt::PaintStaticControls(HWND hwndDlg, LPDRAWITEMSTRUCT pDrawItem) 193{ 194 HBRUSH hBrush; 195 196 if (pDrawItem->CtlID == 14013) 197 { 198 hBrush = CreateSolidBrush(RGB(0, 0, 255)); 199 if (hBrush) 200 { 201 FillRect(pDrawItem->hDC, &pDrawItem->rcItem, hBrush); 202 DeleteObject((HGDIOBJ)hBrush); 203 } 204 } 205 else if (pDrawItem->CtlID == 14014) 206 { 207 hBrush = CreateSolidBrush(RGB(255, 0, 255)); 208 if (hBrush) 209 { 210 FillRect(pDrawItem->hDC, &pDrawItem->rcItem, hBrush); 211 DeleteObject((HGDIOBJ)hBrush); 212 } 213 } 214 else if (pDrawItem->CtlID == 14015) 215 { 216 HBRUSH hBlueBrush = CreateSolidBrush(RGB(0, 0, 255)); 217 HBRUSH hMagBrush = CreateSolidBrush(RGB(255, 0, 255)); 218 HBRUSH hbrOld; 219 HPEN hBlackPen = (HPEN)GetStockObject(BLACK_PEN); 220 HPEN hDarkBluePen = CreatePen(PS_SOLID, 1, RGB(0, 0, 128)); 221 HPEN hDarkMagPen = CreatePen(PS_SOLID, 1, RGB(128, 0, 128)); 222 HPEN hOldPen = (HPEN)SelectObject(pDrawItem->hDC, hDarkMagPen); 223 INT xCenter = (pDrawItem->rcItem.left + pDrawItem->rcItem.right) / 2; 224 INT yCenter = (pDrawItem->rcItem.top + pDrawItem->rcItem.bottom - 10) / 2; 225 INT cx = pDrawItem->rcItem.right - pDrawItem->rcItem.left; 226 INT cy = pDrawItem->rcItem.bottom - pDrawItem->rcItem.top - 10; 227 INT xRadial = xCenter + (INT)(cos(M_PI + m_FreeSpacePerc / 100.0f * M_PI * 2.0f) * cx / 2); 228 INT yRadial = yCenter - (INT)(sin(M_PI + m_FreeSpacePerc / 100.0f * M_PI * 2.0f) * cy / 2); 229 230 TRACE("FreeSpace %u a %f cx %d\n", m_FreeSpacePerc, M_PI+m_FreeSpacePerc / 100.0f * M_PI * 2.0f, cx); 231 232 for (INT x = pDrawItem->rcItem.left; x < pDrawItem->rcItem.right; ++x) 233 { 234 double cos_val = (x - xCenter) * 2.0f / cx; 235 INT y = yCenter + (INT)(sin(acos(cos_val)) * cy / 2) - 1; 236 HPEN hCenterPen; 237 238 if (m_FreeSpacePerc < 50 && x == xRadial) 239 SelectObject(pDrawItem->hDC, hDarkBluePen); 240 241 /* Temporarily change pens to draw edges */ 242 if (x == pDrawItem->rcItem.left) 243 hCenterPen = (HPEN)SelectObject(pDrawItem->hDC, hBlackPen); 244 else if (x == pDrawItem->rcItem.right - 1) 245 SelectObject(pDrawItem->hDC, hBlackPen); 246 247 MoveToEx(pDrawItem->hDC, x, y, NULL); 248 LineTo(pDrawItem->hDC, x, y + 10); 249 SetPixel(pDrawItem->hDC, x, y + 10, RGB(0, 0, 0)); 250 251 /* Restore fill section pens */ 252 if (x == pDrawItem->rcItem.left) 253 SelectObject(pDrawItem->hDC, hCenterPen); 254 } 255 256 SelectObject(pDrawItem->hDC, hBlackPen); 257 258 if (m_FreeSpacePerc > 50) 259 { 260 hbrOld = (HBRUSH)SelectObject(pDrawItem->hDC, hMagBrush); 261 262 Ellipse(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top, 263 pDrawItem->rcItem.right, pDrawItem->rcItem.bottom - 10); 264 265 SelectObject(pDrawItem->hDC, hBlueBrush); 266 267 if (m_FreeSpacePerc < 100) 268 { 269 Pie(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top, pDrawItem->rcItem.right, 270 pDrawItem->rcItem.bottom - 10, xRadial, yRadial, pDrawItem->rcItem.left, yCenter); 271 } 272 } 273 else 274 { 275 hbrOld = (HBRUSH)SelectObject(pDrawItem->hDC, hBlueBrush); 276 277 Ellipse(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top, 278 pDrawItem->rcItem.right, pDrawItem->rcItem.bottom - 10); 279 280 SelectObject(pDrawItem->hDC, hMagBrush); 281 282 if (m_FreeSpacePerc > 0) 283 { 284 Pie(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top, pDrawItem->rcItem.right, 285 pDrawItem->rcItem.bottom - 10, pDrawItem->rcItem.left, yCenter, xRadial, yRadial); 286 } 287 } 288 289 SelectObject(pDrawItem->hDC, hbrOld); 290 SelectObject(pDrawItem->hDC, hOldPen); 291 292 DeleteObject(hBlueBrush); 293 DeleteObject(hMagBrush); 294 DeleteObject(hDarkBluePen); 295 DeleteObject(hDarkMagPen); 296 } 297} 298 299// https://stackoverflow.com/questions/3098696/get-information-about-disk-drives-result-on-windows7-32-bit-system/3100268#3100268 300static BOOL 301GetDriveTypeAndCharacteristics(HANDLE hDevice, DEVICE_TYPE *pDeviceType, ULONG *pCharacteristics) 302{ 303 NTSTATUS Status; 304 IO_STATUS_BLOCK IoStatusBlock; 305 FILE_FS_DEVICE_INFORMATION DeviceInfo; 306 307 Status = NtQueryVolumeInformationFile(hDevice, &IoStatusBlock, 308 &DeviceInfo, sizeof(DeviceInfo), 309 FileFsDeviceInformation); 310 if (Status == NO_ERROR) 311 { 312 *pDeviceType = DeviceInfo.DeviceType; 313 *pCharacteristics = DeviceInfo.Characteristics; 314 return TRUE; 315 } 316 317 return FALSE; 318} 319 320BOOL IsDriveFloppyW(LPCWSTR pszDriveRoot) 321{ 322 LPCWSTR RootPath = pszDriveRoot; 323 WCHAR szRoot[16], szDeviceName[16]; 324 UINT uType; 325 HANDLE hDevice; 326 DEVICE_TYPE DeviceType; 327 ULONG ulCharacteristics; 328 BOOL ret; 329 330 lstrcpynW(szRoot, RootPath, _countof(szRoot)); 331 332 if (L'a' <= szRoot[0] && szRoot[0] <= 'z') 333 { 334 szRoot[0] += ('A' - 'a'); 335 } 336 337 if ('A' <= szRoot[0] && szRoot[0] <= L'Z' && 338 szRoot[1] == L':' && szRoot[2] == 0) 339 { 340 // 'C:' --> 'C:\' 341 szRoot[2] = L'\\'; 342 szRoot[3] = 0; 343 } 344 345 if (!PathIsRootW(szRoot)) 346 { 347 return FALSE; 348 } 349 350 uType = GetDriveTypeW(szRoot); 351 if (uType == DRIVE_REMOVABLE) 352 { 353 if (szRoot[0] == L'A' || szRoot[0] == L'B') 354 return TRUE; 355 } 356 else 357 { 358 return FALSE; 359 } 360 361 lstrcpynW(szDeviceName, L"\\\\.\\", _countof(szDeviceName)); 362 szDeviceName[4] = szRoot[0]; 363 szDeviceName[5] = L':'; 364 szDeviceName[6] = UNICODE_NULL; 365 366 hDevice = CreateFileW(szDeviceName, FILE_READ_ATTRIBUTES, 367 FILE_SHARE_READ | FILE_SHARE_WRITE, 368 NULL, OPEN_EXISTING, 0, NULL); 369 if (hDevice == INVALID_HANDLE_VALUE) 370 { 371 return FALSE; 372 } 373 374 ret = FALSE; 375 if (GetDriveTypeAndCharacteristics(hDevice, &DeviceType, &ulCharacteristics)) 376 { 377 if ((ulCharacteristics & FILE_FLOPPY_DISKETTE) == FILE_FLOPPY_DISKETTE) 378 ret = TRUE; 379 } 380 381 CloseHandle(hDevice); 382 383 return ret; 384} 385 386BOOL IsDriveFloppyA(LPCSTR pszDriveRoot) 387{ 388 WCHAR szRoot[8]; 389 MultiByteToWideChar(CP_ACP, 0, pszDriveRoot, -1, szRoot, _countof(szRoot)); 390 return IsDriveFloppyW(szRoot); 391} 392 393VOID 394CDrvDefExt::InitGeneralPage(HWND hwndDlg) 395{ 396 WCHAR wszVolumeName[MAX_PATH+1] = {0}; 397 WCHAR wszFileSystem[MAX_PATH+1] = {0}; 398 WCHAR wszBuf[128]; 399 BOOL bRet, bFloppy = FALSE, bHasFS = FALSE; 400 401 bRet = GetVolumeInformationW(m_wszDrive, wszVolumeName, _countof(wszVolumeName), NULL, NULL, NULL, wszFileSystem, _countof(wszFileSystem)); 402 if (bRet) 403 { 404 /* Set volume label and filesystem */ 405 SetDlgItemTextW(hwndDlg, 14000, wszVolumeName); 406 SetDlgItemTextW(hwndDlg, 14002, wszFileSystem); 407 bHasFS = *wszFileSystem != UNICODE_NULL; 408 } 409 else 410 { 411 LoadStringW(shell32_hInstance, IDS_FS_UNKNOWN, wszFileSystem, _countof(wszFileSystem)); 412 SetDlgItemTextW(hwndDlg, 14002, wszFileSystem); 413 } 414 415 /* Set drive type and icon */ 416 // TODO: Call SHGetFileInfo to get this info 417 UINT DriveType = GetDriveTypeW(m_wszDrive); 418 UINT IconId, TypeStrId; 419 switch (DriveType) 420 { 421 case DRIVE_REMOVABLE: 422 bFloppy = IsDriveFloppyW(m_wszDrive); 423 IconId = bFloppy ? IDI_SHELL_3_14_FLOPPY : IDI_SHELL_REMOVEABLE; 424 TypeStrId = bFloppy ? IDS_DRIVE_FLOPPY : IDS_DRIVE_REMOVABLE; 425 break; 426 case DRIVE_CDROM: IconId = IDI_SHELL_CDROM; TypeStrId = IDS_DRIVE_CDROM; break; 427 case DRIVE_REMOTE: IconId = IDI_SHELL_NETDRIVE; TypeStrId = IDS_DRIVE_NETWORK; break; 428 case DRIVE_RAMDISK: IconId = IDI_SHELL_RAMDISK; break; 429 default: IconId = IDI_SHELL_DRIVE; TypeStrId = IDS_DRIVE_FIXED; 430 } 431 432 BOOL bCanSetLabel = bHasFS; 433 if (DriveType == DRIVE_CDROM || DriveType == DRIVE_REMOTE || bFloppy) 434 { 435 bCanSetLabel = bFloppy && bHasFS; 436 437 /* disk compression */ 438 ShowWindow(GetDlgItem(hwndDlg, 14011), FALSE); 439 440 /* index */ 441 ShowWindow(GetDlgItem(hwndDlg, 14012), FALSE); 442 } 443 /* volume label textbox */ 444 SendMessage(GetDlgItem(hwndDlg, 14000), EM_SETREADONLY, !bCanSetLabel, 0); 445 446 HICON hIcon = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IconId), IMAGE_ICON, 32, 32, LR_SHARED); 447 if (hIcon) 448 SendDlgItemMessageW(hwndDlg, 14016, STM_SETICON, (WPARAM)hIcon, 0); 449 if (TypeStrId && LoadStringW(shell32_hInstance, TypeStrId, wszBuf, _countof(wszBuf))) 450 SetDlgItemTextW(hwndDlg, 14001, wszBuf); 451 452 ULARGE_INTEGER FreeBytesAvailable, TotalNumberOfBytes; 453 if(GetDiskFreeSpaceExW(m_wszDrive, &FreeBytesAvailable, &TotalNumberOfBytes, NULL)) 454 { 455 /* Init free space percentage used for drawing piechart */ 456 m_FreeSpacePerc = (UINT)(FreeBytesAvailable.QuadPart * 100ull / TotalNumberOfBytes.QuadPart); 457 458 /* Used space */ 459 if (SH_FormatByteSize(TotalNumberOfBytes.QuadPart - FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf))) 460 SetDlgItemTextW(hwndDlg, 14003, wszBuf); 461 462 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart - FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf))) 463 SetDlgItemTextW(hwndDlg, 14004, wszBuf); 464 465 /* Free space */ 466 if (SH_FormatByteSize(FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf))) 467 SetDlgItemTextW(hwndDlg, 14005, wszBuf); 468 469 if (StrFormatByteSizeW(FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf))) 470 SetDlgItemTextW(hwndDlg, 14006, wszBuf); 471 472 /* Total space */ 473 if (SH_FormatByteSize(TotalNumberOfBytes.QuadPart, wszBuf, _countof(wszBuf))) 474 SetDlgItemTextW(hwndDlg, 14007, wszBuf); 475 476 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, wszBuf, _countof(wszBuf))) 477 SetDlgItemTextW(hwndDlg, 14008, wszBuf); 478 } 479 else 480 { 481 m_FreeSpacePerc = 0; 482 483 if (SH_FormatByteSize(0, wszBuf, _countof(wszBuf))) 484 { 485 SetDlgItemTextW(hwndDlg, 14003, wszBuf); 486 SetDlgItemTextW(hwndDlg, 14005, wszBuf); 487 SetDlgItemTextW(hwndDlg, 14007, wszBuf); 488 } 489 if (StrFormatByteSizeW(0, wszBuf, _countof(wszBuf))) 490 { 491 SetDlgItemTextW(hwndDlg, 14004, wszBuf); 492 SetDlgItemTextW(hwndDlg, 14006, wszBuf); 493 SetDlgItemTextW(hwndDlg, 14008, wszBuf); 494 } 495 } 496 497 /* Set drive description */ 498 WCHAR wszFormat[50]; 499 GetDlgItemTextW(hwndDlg, 14009, wszFormat, _countof(wszFormat)); 500 swprintf(wszBuf, wszFormat, m_wszDrive[0]); 501 SetDlgItemTextW(hwndDlg, 14009, wszBuf); 502 503 /* show disk cleanup button only for fixed drives */ 504 ShowWindow(GetDlgItem(hwndDlg, 14010), DriveType == DRIVE_FIXED); 505} 506 507INT_PTR CALLBACK 508CDrvDefExt::GeneralPageProc( 509 HWND hwndDlg, 510 UINT uMsg, 511 WPARAM wParam, 512 LPARAM lParam) 513{ 514 switch(uMsg) 515 { 516 case WM_INITDIALOG: 517 { 518 LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam; 519 if (ppsp == NULL) 520 break; 521 522 CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(ppsp->lParam); 523 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pDrvDefExt); 524 pDrvDefExt->InitGeneralPage(hwndDlg); 525 return TRUE; 526 } 527 case WM_DRAWITEM: 528 { 529 LPDRAWITEMSTRUCT pDrawItem = (LPDRAWITEMSTRUCT)lParam; 530 531 if (pDrawItem->CtlID >= 14013 && pDrawItem->CtlID <= 14015) 532 { 533 CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER)); 534 pDrvDefExt->PaintStaticControls(hwndDlg, pDrawItem); 535 return TRUE; 536 } 537 break; 538 } 539 case WM_PAINT: 540 break; 541 case WM_COMMAND: 542 if (LOWORD(wParam) == 14010) /* Disk Cleanup */ 543 { 544 CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER)); 545 WCHAR wszBuf[256]; 546 DWORD cbBuf = sizeof(wszBuf); 547 548 if (RegGetValueW(HKEY_LOCAL_MACHINE, 549 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\CleanupPath", 550 NULL, 551 RRF_RT_REG_SZ, 552 NULL, 553 (PVOID)wszBuf, 554 &cbBuf) == ERROR_SUCCESS) 555 { 556 WCHAR wszCmd[MAX_PATH]; 557 558 StringCbPrintfW(wszCmd, sizeof(wszCmd), wszBuf, pDrvDefExt->m_wszDrive[0]); 559 WCHAR* wszArgs = PathGetArgsW(wszCmd); 560 if (wszArgs && *wszArgs && wszArgs != wszCmd) 561 wszArgs[-1] = UNICODE_NULL; 562 else 563 wszArgs = NULL; 564 565 if (ShellExecuteW(hwndDlg, NULL, wszCmd, wszArgs, NULL, SW_SHOW) <= (HINSTANCE)32) 566 ERR("Failed to create cleanup process %ls\n", wszCmd); 567 } 568 } 569 else if (LOWORD(wParam) == 14000) /* Label */ 570 { 571 if (HIWORD(wParam) == EN_CHANGE) 572 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 573 } 574 break; 575 case WM_NOTIFY: 576 if (((LPNMHDR)lParam)->hwndFrom == GetParent(hwndDlg)) 577 { 578 /* Property Sheet */ 579 LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam; 580 581 if (lppsn->hdr.code == PSN_APPLY) 582 { 583 CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER)); 584 585 HRESULT hr = E_FAIL; 586 HWND hLabel = GetDlgItem(hwndDlg, 14000); 587 WCHAR wszBuf[256]; 588 *wszBuf = UNICODE_NULL; 589 if (GetWindowTextW(hLabel, wszBuf, _countof(wszBuf)) || GetWindowTextLengthW(hLabel) == 0) 590 hr = CDrivesFolder::SetDriveLabel(hwndDlg, pDrvDefExt->m_wszDrive, wszBuf); 591 592 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FAILED(hr) ? PSNRET_INVALID : PSNRET_NOERROR); 593 return TRUE; 594 } 595 } 596 break; 597 598 default: 599 break; 600 } 601 602 return FALSE; 603} 604 605INT_PTR CALLBACK 606CDrvDefExt::ExtraPageProc( 607 HWND hwndDlg, 608 UINT uMsg, 609 WPARAM wParam, 610 LPARAM lParam) 611{ 612 switch (uMsg) 613 { 614 case WM_INITDIALOG: 615 { 616 LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam; 617 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)ppsp->lParam); 618 return TRUE; 619 } 620 case WM_COMMAND: 621 { 622 WCHAR wszBuf[MAX_PATH]; 623 DWORD cbBuf = sizeof(wszBuf); 624 CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER)); 625 626 switch(LOWORD(wParam)) 627 { 628 case 14000: 629 DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_CHECK_DISK), hwndDlg, ChkDskDlg, (LPARAM)pDrvDefExt->m_wszDrive); 630 break; 631 case 14001: 632 if (RegGetValueW(HKEY_LOCAL_MACHINE, 633 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\DefragPath", 634 NULL, 635 RRF_RT_REG_SZ, 636 NULL, 637 (PVOID)wszBuf, 638 &cbBuf) == ERROR_SUCCESS) 639 { 640 WCHAR wszCmd[MAX_PATH]; 641 642 StringCbPrintfW(wszCmd, sizeof(wszCmd), wszBuf, pDrvDefExt->m_wszDrive[0]); 643 644 if (ShellExecuteW(hwndDlg, NULL, wszCmd, NULL, NULL, SW_SHOW) <= (HINSTANCE)32) 645 ERR("Failed to create defrag process %ls\n", wszCmd); 646 } 647 break; 648 case 14002: 649 if (RegGetValueW(HKEY_LOCAL_MACHINE, 650 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\BackupPath", 651 NULL, 652 RRF_RT_REG_SZ, 653 NULL, 654 (PVOID)wszBuf, 655 &cbBuf) == ERROR_SUCCESS) 656 { 657 if (ShellExecuteW(hwndDlg, NULL, wszBuf, NULL, NULL, SW_SHOW) <= (HINSTANCE)32) 658 ERR("Failed to create backup process %ls\n", wszBuf); 659 } 660 } 661 break; 662 } 663 } 664 return FALSE; 665} 666 667INT_PTR CALLBACK 668CDrvDefExt::HardwarePageProc( 669 HWND hwndDlg, 670 UINT uMsg, 671 WPARAM wParam, 672 LPARAM lParam) 673{ 674 UNREFERENCED_PARAMETER(lParam); 675 UNREFERENCED_PARAMETER(wParam); 676 677 switch(uMsg) 678 { 679 case WM_INITDIALOG: 680 { 681 GUID Guids[2]; 682 Guids[0] = GUID_DEVCLASS_DISKDRIVE; 683 Guids[1] = GUID_DEVCLASS_CDROM; 684 685 /* create the hardware page */ 686 DeviceCreateHardwarePageEx(hwndDlg, Guids, _countof(Guids), HWPD_STANDARDLIST); 687 break; 688 } 689 } 690 691 return FALSE; 692} 693 694CDrvDefExt::CDrvDefExt() 695{ 696 m_wszDrive[0] = L'\0'; 697} 698 699CDrvDefExt::~CDrvDefExt() 700{ 701 702} 703 704struct CDrop 705{ 706 HRESULT hr; 707 STGMEDIUM stgm; 708 HDROP hDrop; 709 710 explicit CDrop(IDataObject *pDO) 711 { 712 FORMATETC format = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; 713 hDrop = SUCCEEDED(hr = pDO->GetData(&format, &stgm)) ? (HDROP)stgm.hGlobal : NULL; 714 } 715 716 ~CDrop() 717 { 718 if (hDrop) 719 ReleaseStgMedium(&stgm); 720 } 721 722 UINT GetCount() 723 { 724 return DragQueryFileW(hDrop, -1, NULL, 0); 725 } 726}; 727 728static inline bool 729IsValidDrivePath(PCWSTR Path) 730{ 731 return GetDriveTypeW(Path) > DRIVE_NO_ROOT_DIR; 732} 733 734HRESULT WINAPI 735CDrvDefExt::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pDataObj, HKEY hkeyProgID) 736{ 737 HRESULT hr; 738 739 TRACE("%p %p %p %p\n", this, pidlFolder, pDataObj, hkeyProgID); 740 741 if (!pDataObj) 742 return E_FAIL; 743 744 745 CDrop drop(pDataObj); 746 if (FAILED_UNEXPECTEDLY(hr = drop.hr)) 747 return hr; 748 749 if (!DragQueryFileW(drop.hDrop, 0, m_wszDrive, _countof(m_wszDrive))) 750 { 751 ERR("DragQueryFileW failed\n"); 752 return E_FAIL; 753 } 754 755 if (drop.GetCount() > 1) 756 m_Multiple = pDataObj; 757 758 TRACE("Drive properties %ls\n", m_wszDrive); 759 760 return S_OK; 761} 762 763HRESULT WINAPI 764CDrvDefExt::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) 765{ 766 UNIMPLEMENTED; 767 return E_NOTIMPL; 768} 769 770HRESULT WINAPI 771CDrvDefExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) 772{ 773 UNIMPLEMENTED; 774 return E_NOTIMPL; 775} 776 777HRESULT WINAPI 778CDrvDefExt::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax) 779{ 780 UNIMPLEMENTED; 781 return E_NOTIMPL; 782} 783 784HRESULT 785CDrvDefExt::AddMainPage(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) 786{ 787 WCHAR szTitle[MAX_PATH], *pszTitle = NULL; 788 if (m_Multiple) 789 { 790 CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidl(SHSimpleIDListFromPathW(m_wszDrive)); 791 if (SUCCEEDED(SHGetNameAndFlagsW(pidl, SHGDN_INFOLDER, szTitle, _countof(szTitle), NULL))) 792 pszTitle = szTitle; 793 } 794 795 HPROPSHEETPAGE hPage; 796 hPage = SH_CreatePropertySheetPageEx(IDD_DRIVE_PROPERTIES, GeneralPageProc, (LPARAM)this, 797 pszTitle, &PropSheetPageLifetimeCallback<CDrvDefExt>); 798 HRESULT hr = AddPropSheetPage(hPage, pfnAddPage, lParam); 799 if (FAILED_UNEXPECTEDLY(hr)) 800 return hr; 801 else 802 AddRef(); // For PropSheetPageLifetimeCallback 803 return hr; 804} 805 806HRESULT WINAPI 807CDrvDefExt::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) 808{ 809 HRESULT hr = AddMainPage(pfnAddPage, lParam); 810 if (FAILED_UNEXPECTEDLY(hr)) 811 return hr; 812 813 if (m_Multiple) 814 { 815 CDrop drop(m_Multiple); 816 UINT count = SUCCEEDED(drop.hr) ? drop.GetCount() : 0; 817 for (UINT i = 0; ++i < count;) // Skipping the first drive since it already has a page 818 { 819 CComPtr<CDrvDefExt> SheetExt; 820 if (FAILED_UNEXPECTEDLY(hr = ShellObjectCreator(SheetExt))) 821 continue; 822 if (!DragQueryFileW(drop.hDrop, i, SheetExt->m_wszDrive, _countof(SheetExt->m_wszDrive))) 823 continue; 824 if (!IsValidDrivePath(SheetExt->m_wszDrive)) 825 continue; 826 827 SheetExt->m_Multiple = m_Multiple; 828 SheetExt->AddMainPage(pfnAddPage, lParam); 829 } 830 } 831 else 832 { 833 HPROPSHEETPAGE hPage; 834 if (GetDriveTypeW(m_wszDrive) == DRIVE_FIXED) 835 { 836 hPage = SH_CreatePropertySheetPage(IDD_DRIVE_TOOLS, 837 ExtraPageProc, 838 (LPARAM)this, 839 NULL); 840 if (hPage) 841 pfnAddPage(hPage, lParam); 842 } 843 844 if (GetDriveTypeW(m_wszDrive) != DRIVE_REMOTE) 845 { 846 hPage = SH_CreatePropertySheetPage(IDD_DRIVE_HARDWARE, 847 HardwarePageProc, 848 (LPARAM)this, 849 NULL); 850 if (hPage) 851 pfnAddPage(hPage, lParam); 852 } 853 } 854 855 return S_OK; 856} 857 858HRESULT WINAPI 859CDrvDefExt::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam) 860{ 861 UNIMPLEMENTED; 862 return E_NOTIMPL; 863} 864 865HRESULT WINAPI 866CDrvDefExt::SetSite(IUnknown *punk) 867{ 868 UNIMPLEMENTED; 869 return E_NOTIMPL; 870} 871 872HRESULT WINAPI 873CDrvDefExt::GetSite(REFIID iid, void **ppvSite) 874{ 875 UNIMPLEMENTED; 876 return E_NOTIMPL; 877}