1 /* 2 * Virtual Workplace folder 3 * 4 * Copyright 1997 Marcus Meissner 5 * Copyright 1998, 1999, 2002 Juergen Schmied 6 * Copyright 2009 Andrew Hill 7 * Copyright 2017-2024 Katayama Hirofumi MZ 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 22 */ 23 24 #include <precomp.h> 25 #include <process.h> 26 27 WINE_DEFAULT_DEBUG_CHANNEL(shell); 28 29 /* 30 CDrivesFolder should create a CRegFolder to represent the virtual items that exist only in 31 the registry. The CRegFolder is aggregated by the CDrivesFolder. 32 The CDrivesFolderEnum class should enumerate only drives on the system. Since the CRegFolder 33 implementation of IShellFolder::EnumObjects enumerates the virtual items, the 34 CDrivesFolderEnum is only responsible for returning the physical items. 35 36 2. At least on my XP system, the drive pidls returned are of type PT_DRIVE1, not PT_DRIVE 37 3. The parsing name returned for my computer is incorrect. It should be "My Computer" 38 */ 39 40 static int iDriveIconIds[7] = { IDI_SHELL_DRIVE, /* DRIVE_UNKNOWN */ 41 IDI_SHELL_CDROM, /* DRIVE_NO_ROOT_DIR*/ 42 IDI_SHELL_3_14_FLOPPY, /* DRIVE_REMOVABLE*/ 43 IDI_SHELL_DRIVE, /* DRIVE_FIXED*/ 44 IDI_SHELL_NETDRIVE, /* DRIVE_REMOTE*/ 45 IDI_SHELL_CDROM, /* DRIVE_CDROM*/ 46 IDI_SHELL_RAMDISK /* DRIVE_RAMDISK*/ 47 }; 48 49 static int iDriveTypeIds[7] = { IDS_DRIVE_FIXED, /* DRIVE_UNKNOWN */ 50 IDS_DRIVE_FIXED, /* DRIVE_NO_ROOT_DIR*/ 51 IDS_DRIVE_FLOPPY, /* DRIVE_REMOVABLE*/ 52 IDS_DRIVE_FIXED, /* DRIVE_FIXED*/ 53 IDS_DRIVE_NETWORK, /* DRIVE_REMOTE*/ 54 IDS_DRIVE_CDROM, /* DRIVE_CDROM*/ 55 IDS_DRIVE_FIXED /* DRIVE_RAMDISK*/ 56 }; 57 58 static const REQUIREDREGITEM g_RequiredItems[] = 59 { 60 { CLSID_ControlPanel, 0, 0x50 }, 61 }; 62 static const REGFOLDERINFO g_RegFolderInfo = 63 { 64 PT_COMPUTER_REGITEM, 65 _countof(g_RequiredItems), g_RequiredItems, 66 CLSID_MyComputer, 67 L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 68 L"MyComputer", 69 }; 70 71 static const CLSID* IsRegItem(PCUITEMID_CHILD pidl) 72 { 73 if (pidl && pidl->mkid.cb == 2 + 2 + sizeof(CLSID)) 74 { 75 if (pidl->mkid.abID[0] == PT_SHELLEXT || pidl->mkid.abID[0] == PT_GUID) // FIXME: Remove PT_GUID when CRegFolder is fixed 76 return (const CLSID*)(&pidl->mkid.abID[2]); 77 } 78 return NULL; 79 } 80 81 BOOL _ILGetDriveType(LPCITEMIDLIST pidl) 82 { 83 WCHAR szDrive[8]; 84 if (!_ILGetDrive(pidl, szDrive, _countof(szDrive))) 85 { 86 ERR("pidl %p is not a drive\n", pidl); 87 return DRIVE_UNKNOWN; 88 } 89 return ::GetDriveTypeW(szDrive); 90 } 91 92 BOOL SHELL32_IsShellFolderNamespaceItemHidden(LPCWSTR SubKey, REFCLSID Clsid) 93 { 94 // If this function returns true, the item should be hidden in DefView but not in the Explorer folder tree. 95 WCHAR path[MAX_PATH], name[CHARS_IN_GUID]; 96 wsprintfW(path, L"%s\\%s", REGSTR_PATH_EXPLORER, SubKey); 97 SHELL32_GUIDToStringW(Clsid, name); 98 DWORD data = 0, size = sizeof(data); 99 return !RegGetValueW(HKEY_CURRENT_USER, path, name, RRF_RT_DWORD, NULL, &data, &size) && data; 100 } 101 102 /*********************************************************************** 103 * IShellFolder implementation 104 */ 105 106 #define RETRY_COUNT 3 107 #define RETRY_SLEEP 250 108 static BOOL TryToLockOrUnlockDrive(HANDLE hDrive, BOOL bLock) 109 { 110 DWORD dwError, dwBytesReturned; 111 DWORD dwCode = (bLock ? FSCTL_LOCK_VOLUME : FSCTL_UNLOCK_VOLUME); 112 for (DWORD i = 0; i < RETRY_COUNT; ++i) 113 { 114 if (DeviceIoControl(hDrive, dwCode, NULL, 0, NULL, 0, &dwBytesReturned, NULL)) 115 return TRUE; 116 117 dwError = GetLastError(); 118 if (dwError == ERROR_INVALID_FUNCTION) 119 break; /* don't sleep if function is not implemented */ 120 121 Sleep(RETRY_SLEEP); 122 } 123 SetLastError(dwError); 124 return FALSE; 125 } 126 127 // NOTE: See also https://support.microsoft.com/en-us/help/165721/how-to-ejecting-removable-media-in-windows-nt-windows-2000-windows-xp 128 static BOOL DoEjectDrive(const WCHAR *physical, UINT nDriveType, INT *pnStringID) 129 { 130 /* GENERIC_WRITE isn't needed for umount */ 131 DWORD dwAccessMode = GENERIC_READ; 132 DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; 133 134 HANDLE hDrive = CreateFile(physical, dwAccessMode, dwShareMode, 0, OPEN_EXISTING, 0, NULL); 135 if (hDrive == INVALID_HANDLE_VALUE) 136 return FALSE; 137 138 BOOL bResult, bNeedUnlock = FALSE; 139 DWORD dwBytesReturned, dwError = NO_ERROR; 140 PREVENT_MEDIA_REMOVAL removal; 141 do 142 { 143 bResult = TryToLockOrUnlockDrive(hDrive, TRUE); 144 if (!bResult) 145 { 146 dwError = GetLastError(); 147 *pnStringID = IDS_CANTLOCKVOLUME; /* Unable to lock volume */ 148 break; 149 } 150 bResult = DeviceIoControl(hDrive, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL); 151 if (!bResult) 152 { 153 dwError = GetLastError(); 154 *pnStringID = IDS_CANTDISMOUNTVOLUME; /* Unable to dismount volume */ 155 bNeedUnlock = TRUE; 156 break; 157 } 158 removal.PreventMediaRemoval = FALSE; 159 bResult = DeviceIoControl(hDrive, IOCTL_STORAGE_MEDIA_REMOVAL, &removal, sizeof(removal), NULL, 160 0, &dwBytesReturned, NULL); 161 if (!bResult) 162 { 163 *pnStringID = IDS_CANTEJECTMEDIA; /* Unable to eject media */ 164 dwError = GetLastError(); 165 bNeedUnlock = TRUE; 166 break; 167 } 168 bResult = DeviceIoControl(hDrive, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwBytesReturned, NULL); 169 if (!bResult) 170 { 171 *pnStringID = IDS_CANTEJECTMEDIA; /* Unable to eject media */ 172 dwError = GetLastError(); 173 bNeedUnlock = TRUE; 174 break; 175 } 176 } while (0); 177 178 if (bNeedUnlock) 179 { 180 TryToLockOrUnlockDrive(hDrive, FALSE); 181 } 182 183 CloseHandle(hDrive); 184 185 SetLastError(dwError); 186 return bResult; 187 } 188 189 // A callback function for finding the stub windows. 190 static BOOL CALLBACK 191 EnumStubProc(HWND hwnd, LPARAM lParam) 192 { 193 CSimpleArray<HWND> *pStubs = reinterpret_cast<CSimpleArray<HWND> *>(lParam); 194 195 WCHAR szClass[64]; 196 GetClassNameW(hwnd, szClass, _countof(szClass)); 197 198 if (lstrcmpiW(szClass, L"StubWindow32") == 0) 199 { 200 pStubs->Add(hwnd); 201 } 202 203 return TRUE; 204 } 205 206 // Another callback function to find the owned window of the stub window. 207 static BOOL CALLBACK 208 EnumStubProc2(HWND hwnd, LPARAM lParam) 209 { 210 HWND *phwnd = reinterpret_cast<HWND *>(lParam); 211 212 if (phwnd[0] == GetWindow(hwnd, GW_OWNER)) 213 { 214 phwnd[1] = hwnd; 215 return FALSE; 216 } 217 218 return TRUE; 219 } 220 221 // Parameters for format_drive_thread function below. 222 struct THREAD_PARAMS 223 { 224 UINT nDriveNumber; 225 }; 226 227 static unsigned __stdcall format_drive_thread(void *args) 228 { 229 THREAD_PARAMS *params = (THREAD_PARAMS *)args; 230 UINT nDriveNumber = params->nDriveNumber; 231 LONG_PTR nProp = nDriveNumber | 0x7F00; 232 233 // Search the stub windows that already exist. 234 CSimpleArray<HWND> old_stubs; 235 EnumWindows(EnumStubProc, (LPARAM)&old_stubs); 236 237 for (INT n = 0; n < old_stubs.GetSize(); ++n) 238 { 239 HWND hwndStub = old_stubs[n]; 240 241 // The target stub window has the prop. 242 if (GetPropW(hwndStub, L"DriveNumber") == (HANDLE)nProp) 243 { 244 // Found. 245 HWND ahwnd[2]; 246 ahwnd[0] = hwndStub; 247 ahwnd[1] = NULL; 248 EnumWindows(EnumStubProc2, (LPARAM)ahwnd); 249 250 // Activate. 251 BringWindowToTop(ahwnd[1]); 252 253 delete params; 254 return 0; 255 } 256 } 257 258 // Create a stub window. 259 DWORD style = WS_DISABLED | WS_CLIPSIBLINGS | WS_CAPTION; 260 DWORD exstyle = WS_EX_WINDOWEDGE | WS_EX_APPWINDOW; 261 CStubWindow32 stub; 262 if (!stub.Create(NULL, NULL, NULL, style, exstyle)) 263 { 264 ERR("StubWindow32 creation failed\n"); 265 delete params; 266 return 0; 267 } 268 269 // Add prop to the target stub window. 270 SetPropW(stub, L"DriveNumber", (HANDLE)nProp); 271 272 // Do format. 273 SHFormatDrive(stub, nDriveNumber, SHFMT_ID_DEFAULT, 0); 274 275 // Clean up. 276 RemovePropW(stub, L"DriveNumber"); 277 stub.DestroyWindow(); 278 delete params; 279 280 return 0; 281 } 282 283 static HRESULT DoFormatDrive(HWND hwnd, UINT nDriveNumber) 284 { 285 THREAD_PARAMS *params = new THREAD_PARAMS; 286 params->nDriveNumber = nDriveNumber; 287 288 // Create thread to avoid locked. 289 unsigned tid; 290 HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, format_drive_thread, params, 0, &tid); 291 if (hThread == NULL) 292 { 293 delete params; 294 return E_FAIL; 295 } 296 297 CloseHandle(hThread); 298 299 return S_OK; 300 } 301 302 HRESULT CALLBACK DrivesContextMenuCallback(IShellFolder *psf, 303 HWND hwnd, 304 IDataObject *pdtobj, 305 UINT uMsg, 306 WPARAM wParam, 307 LPARAM lParam) 308 { 309 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND) 310 return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg); 311 312 PIDLIST_ABSOLUTE pidlFolder; 313 PUITEMID_CHILD *apidl; 314 UINT cidl; 315 UINT nDriveType; 316 DWORD dwFlags; 317 HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl); 318 if (FAILED_UNEXPECTEDLY(hr)) 319 return hr; 320 321 WCHAR szDrive[8] = {0}; 322 if (!_ILGetDrive(apidl[0], szDrive, _countof(szDrive))) 323 { 324 ERR("pidl is not a drive\n"); 325 SHFree(pidlFolder); 326 _ILFreeaPidl(apidl, cidl); 327 return E_FAIL; 328 } 329 nDriveType = GetDriveTypeW(szDrive); 330 GetVolumeInformationW(szDrive, NULL, 0, NULL, NULL, &dwFlags, NULL, 0); 331 332 // custom command IDs 333 #if 0 // Disabled until our menu building system is fixed 334 #define CMDID_FORMAT 0 335 #define CMDID_EJECT 1 336 #define CMDID_DISCONNECT 2 337 #else 338 /* FIXME: These IDs should start from 0, however there is difference 339 * between ours and Windows' menu building systems, which should be fixed. */ 340 #define CMDID_FORMAT 1 341 #define CMDID_EJECT 2 342 #define CMDID_DISCONNECT 3 343 #endif 344 345 if (uMsg == DFM_MERGECONTEXTMENU) 346 { 347 QCMINFO *pqcminfo = (QCMINFO *)lParam; 348 349 UINT idCmdFirst = pqcminfo->idCmdFirst; 350 UINT idCmd = 0; 351 if (!(dwFlags & FILE_READ_ONLY_VOLUME) && nDriveType != DRIVE_REMOTE) 352 { 353 /* add separator and Format */ 354 idCmd = idCmdFirst + CMDID_FORMAT; 355 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0); 356 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED); 357 } 358 if (nDriveType == DRIVE_REMOVABLE || nDriveType == DRIVE_CDROM) 359 { 360 /* add separator and Eject */ 361 idCmd = idCmdFirst + CMDID_EJECT; 362 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0); 363 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_EJECT), MFS_ENABLED); 364 } 365 if (nDriveType == DRIVE_REMOTE) 366 { 367 /* add separator and Disconnect */ 368 idCmd = idCmdFirst + CMDID_DISCONNECT; 369 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0); 370 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_DISCONNECT), MFS_ENABLED); 371 } 372 373 if (idCmd) 374 #if 0 // see FIXME above 375 pqcminfo->idCmdFirst = ++idCmd; 376 #else 377 pqcminfo->idCmdFirst = (idCmd + 2); 378 #endif 379 hr = S_OK; 380 } 381 else if (uMsg == DFM_INVOKECOMMAND) 382 { 383 WCHAR wszBuf[4] = L"A:\\"; 384 wszBuf[0] = (WCHAR)szDrive[0]; 385 386 INT nStringID = 0; 387 DWORD dwError = NO_ERROR; 388 389 if (wParam == DFM_CMD_PROPERTIES) 390 { 391 // pdtobj should be valid at this point! 392 ATLASSERT(pdtobj); 393 hr = SH_ShowDriveProperties(wszBuf, pdtobj) ? S_OK : E_UNEXPECTED; 394 if (FAILED(hr)) 395 { 396 dwError = ERROR_CAN_NOT_COMPLETE; 397 nStringID = IDS_CANTSHOWPROPERTIES; 398 } 399 } 400 else 401 { 402 if (wParam == CMDID_FORMAT) 403 { 404 hr = DoFormatDrive(hwnd, szDrive[0] - 'A'); 405 } 406 else if (wParam == CMDID_EJECT) 407 { 408 /* do eject */ 409 WCHAR physical[10]; 410 wsprintfW(physical, _T("\\\\.\\%c:"), szDrive[0]); 411 412 if (DoEjectDrive(physical, nDriveType, &nStringID)) 413 { 414 SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_PATHW | SHCNF_FLUSHNOWAIT, wszBuf, NULL); 415 } 416 else 417 { 418 dwError = GetLastError(); 419 } 420 } 421 else if (wParam == CMDID_DISCONNECT) 422 { 423 /* do disconnect */ 424 wszBuf[2] = UNICODE_NULL; 425 dwError = WNetCancelConnection2W(wszBuf, 0, FALSE); 426 if (dwError == NO_ERROR) 427 { 428 SHChangeNotify(SHCNE_DRIVEREMOVED, SHCNF_PATHW | SHCNF_FLUSHNOWAIT, wszBuf, NULL); 429 } 430 else 431 { 432 nStringID = IDS_CANTDISCONNECT; 433 } 434 } 435 } 436 437 if (nStringID != 0) 438 { 439 /* show error message */ 440 WCHAR szFormat[128], szMessage[128]; 441 LoadStringW(shell32_hInstance, nStringID, szFormat, _countof(szFormat)); 442 wsprintfW(szMessage, szFormat, dwError); 443 MessageBoxW(hwnd, szMessage, NULL, MB_ICONERROR); 444 } 445 } 446 447 SHFree(pidlFolder); 448 _ILFreeaPidl(apidl, cidl); 449 450 return hr; 451 } 452 453 HRESULT CDrivesContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder, 454 HWND hwnd, 455 UINT cidl, 456 PCUITEMID_CHILD_ARRAY apidl, 457 IShellFolder *psf, 458 IContextMenu **ppcm) 459 { 460 HKEY hKeys[2]; 461 UINT cKeys = 0; 462 AddClassKeyToArray(L"Drive", hKeys, &cKeys); 463 AddClassKeyToArray(L"Folder", hKeys, &cKeys); 464 465 return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, DrivesContextMenuCallback, cKeys, hKeys, ppcm); 466 } 467 468 static HRESULT 469 getIconLocationForDrive(IShellFolder *psf, PCITEMID_CHILD pidl, UINT uFlags, 470 LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags) 471 { 472 WCHAR wszPath[MAX_PATH]; 473 WCHAR wszAutoRunInfPath[MAX_PATH]; 474 WCHAR wszValue[MAX_PATH], wszTemp[MAX_PATH]; 475 476 // get path 477 if (!ILGetDisplayNameExW(psf, pidl, wszPath, 0)) 478 return E_FAIL; 479 if (!PathIsDirectoryW(wszPath)) 480 return E_FAIL; 481 482 // build the full path of autorun.inf 483 StringCchCopyW(wszAutoRunInfPath, _countof(wszAutoRunInfPath), wszPath); 484 PathAppendW(wszAutoRunInfPath, L"autorun.inf"); 485 486 // autorun.inf --> wszValue 487 if (GetPrivateProfileStringW(L"autorun", L"icon", NULL, wszValue, _countof(wszValue), 488 wszAutoRunInfPath) && wszValue[0] != 0) 489 { 490 // wszValue --> wszTemp 491 ExpandEnvironmentStringsW(wszValue, wszTemp, _countof(wszTemp)); 492 493 // parse the icon location 494 *piIndex = PathParseIconLocationW(wszTemp); 495 496 // wszPath + wszTemp --> wszPath 497 if (PathIsRelativeW(wszTemp)) 498 PathAppendW(wszPath, wszTemp); 499 else 500 StringCchCopyW(wszPath, _countof(wszPath), wszTemp); 501 502 // wszPath --> szIconFile 503 GetFullPathNameW(wszPath, cchMax, szIconFile, NULL); 504 505 return S_OK; 506 } 507 508 return E_FAIL; 509 } 510 511 static HRESULT 512 getLabelForDrive(LPWSTR wszPath, LPWSTR wszLabel) 513 { 514 WCHAR wszAutoRunInfPath[MAX_PATH]; 515 WCHAR wszTemp[MAX_PATH]; 516 517 if (!PathIsDirectoryW(wszPath)) 518 return E_FAIL; 519 520 StringCchCopyW(wszAutoRunInfPath, _countof(wszAutoRunInfPath), wszPath); 521 PathAppendW(wszAutoRunInfPath, L"autorun.inf"); 522 523 if (GetPrivateProfileStringW(L"autorun", L"label", NULL, wszTemp, _countof(wszTemp), 524 wszAutoRunInfPath) && wszTemp[0] != 0) 525 { 526 StringCchCopyW(wszLabel, _countof(wszTemp), wszTemp); 527 return S_OK; 528 } 529 530 return E_FAIL; 531 } 532 533 BOOL IsDriveFloppyA(LPCSTR pszDriveRoot); 534 535 HRESULT CDrivesExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut) 536 { 537 CComPtr<IDefaultExtractIconInit> initIcon; 538 HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon)); 539 if (FAILED_UNEXPECTEDLY(hr)) 540 return hr; 541 542 CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName; 543 UINT DriveType = GetDriveTypeA(pszDrive); 544 if (DriveType > DRIVE_RAMDISK) 545 DriveType = DRIVE_FIXED; 546 547 WCHAR wTemp[MAX_PATH]; 548 int icon_idx, reg_idx; 549 UINT flags = 0; 550 551 switch (DriveType) 552 { 553 case DRIVE_FIXED: 554 case DRIVE_UNKNOWN: 555 reg_idx = IDI_SHELL_DRIVE; 556 break; 557 case DRIVE_CDROM: 558 reg_idx = IDI_SHELL_CDROM; 559 break; 560 case DRIVE_REMOTE: 561 reg_idx = IDI_SHELL_NETDRIVE; 562 break; 563 case DRIVE_REMOVABLE: 564 if (!IsDriveFloppyA(pszDrive)) 565 reg_idx = IDI_SHELL_REMOVEABLE; 566 else 567 reg_idx = IDI_SHELL_3_14_FLOPPY; 568 break; 569 case DRIVE_RAMDISK: 570 reg_idx = IDI_SHELL_RAMDISK; 571 break; 572 case DRIVE_NO_ROOT_DIR: 573 default: 574 reg_idx = IDI_SHELL_DOCUMENT; 575 break; 576 } 577 578 hr = getIconLocationForDrive(psf, pidl, 0, wTemp, _countof(wTemp), 579 &icon_idx, &flags); 580 if (SUCCEEDED(hr)) 581 { 582 initIcon->SetNormalIcon(wTemp, icon_idx); 583 } 584 else if (HLM_GetIconW(reg_idx - 1, wTemp, _countof(wTemp), &icon_idx)) 585 { 586 initIcon->SetNormalIcon(wTemp, icon_idx); 587 } 588 else if ((DriveType == DRIVE_FIXED || DriveType == DRIVE_UNKNOWN) && 589 (HCR_GetIconW(L"Drive", wTemp, NULL, _countof(wTemp), &icon_idx))) 590 { 591 initIcon->SetNormalIcon(wTemp, icon_idx); 592 } 593 else 594 { 595 if (DriveType == DRIVE_REMOVABLE && !IsDriveFloppyA(pszDrive)) 596 { 597 icon_idx = IDI_SHELL_REMOVEABLE; 598 } 599 else 600 { 601 icon_idx = iDriveIconIds[DriveType]; 602 } 603 initIcon->SetNormalIcon(swShell32Name, -icon_idx); 604 } 605 606 return initIcon->QueryInterface(riid, ppvOut); 607 } 608 609 class CDrivesFolderEnum : 610 public CEnumIDListBase 611 { 612 public: 613 HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags, IEnumIDList* pRegEnumerator) 614 { 615 /* enumerate the folders */ 616 if (dwFlags & SHCONTF_FOLDERS) 617 { 618 WCHAR wszDriveName[] = {'A', ':', '\\', '\0'}; 619 DWORD dwDrivemap = GetLogicalDrives(); 620 621 while (wszDriveName[0] <= 'Z') 622 { 623 if(dwDrivemap & 0x00000001L) 624 AddToEnumList(_ILCreateDrive(wszDriveName)); 625 wszDriveName[0]++; 626 dwDrivemap = dwDrivemap >> 1; 627 } 628 } 629 630 /* Enumerate the items of the reg folder */ 631 AppendItemsFromEnumerator(pRegEnumerator); 632 633 return S_OK; 634 } 635 636 BEGIN_COM_MAP(CDrivesFolderEnum) 637 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) 638 END_COM_MAP() 639 }; 640 641 /*********************************************************************** 642 * IShellFolder [MyComputer] implementation 643 */ 644 645 static const shvheader MyComputerSFHeader[] = { 646 {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15}, 647 {IDS_SHV_COLUMN_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10}, 648 {IDS_SHV_COLUMN_DISK_CAPACITY, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}, 649 {IDS_SHV_COLUMN_DISK_AVAILABLE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}, 650 {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 10}, 651 }; 652 653 static const DWORD dwComputerAttributes = 654 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | 655 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER; 656 static const DWORD dwControlPanelAttributes = 657 SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK; 658 static const DWORD dwDriveAttributes = 659 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | 660 SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK; 661 662 CDrivesFolder::CDrivesFolder() 663 { 664 pidlRoot = NULL; 665 } 666 667 CDrivesFolder::~CDrivesFolder() 668 { 669 TRACE("-- destroying IShellFolder(%p)\n", this); 670 SHFree(pidlRoot); 671 } 672 673 HRESULT WINAPI CDrivesFolder::FinalConstruct() 674 { 675 pidlRoot = _ILCreateMyComputer(); /* my qualified pidl */ 676 if (pidlRoot == NULL) 677 return E_OUTOFMEMORY; 678 679 REGFOLDERINITDATA RegInit = { static_cast<IShellFolder*>(this), &g_RegFolderInfo }; 680 HRESULT hr = CRegFolder_CreateInstance(&RegInit, 681 pidlRoot, 682 IID_PPV_ARG(IShellFolder2, &m_regFolder)); 683 684 return hr; 685 } 686 687 /************************************************************************** 688 * CDrivesFolder::ParseDisplayName 689 */ 690 HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, 691 DWORD * pchEaten, PIDLIST_RELATIVE * ppidl, DWORD * pdwAttributes) 692 { 693 HRESULT hr = E_INVALIDARG; 694 695 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this, 696 hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName), 697 pchEaten, ppidl, pdwAttributes); 698 699 if (!ppidl) 700 return hr; 701 702 *ppidl = NULL; 703 704 if (!lpszDisplayName) 705 return hr; 706 707 /* handle CLSID paths */ 708 if (lpszDisplayName[0] == L':' && lpszDisplayName[1] == L':') 709 { 710 return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, 711 pdwAttributes); 712 } 713 714 if (lpszDisplayName[0] && 715 ((L'A' <= lpszDisplayName[0] && lpszDisplayName[0] <= L'Z') || 716 (L'a' <= lpszDisplayName[0] && lpszDisplayName[0] <= L'z')) && 717 lpszDisplayName[1] == L':' && lpszDisplayName[2] == L'\\') 718 { 719 // "C:\..." 720 WCHAR szRoot[8]; 721 PathBuildRootW(szRoot, ((*lpszDisplayName - 1) & 0x1F)); 722 723 if (SHIsFileSysBindCtx(pbc, NULL) != S_OK && !(BindCtx_GetMode(pbc, 0) & STGM_CREATE)) 724 { 725 if (::GetDriveType(szRoot) == DRIVE_NO_ROOT_DIR) 726 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 727 } 728 729 CComHeapPtr<ITEMIDLIST> pidlTemp(_ILCreateDrive(szRoot)); 730 if (!pidlTemp) 731 return E_OUTOFMEMORY; 732 733 if (lpszDisplayName[3]) 734 { 735 CComPtr<IShellFolder> pChildFolder; 736 hr = BindToObject(pidlTemp, pbc, IID_PPV_ARG(IShellFolder, &pChildFolder)); 737 if (FAILED_UNEXPECTEDLY(hr)) 738 return hr; 739 740 ULONG chEaten; 741 CComHeapPtr<ITEMIDLIST> pidlChild; 742 hr = pChildFolder->ParseDisplayName(hwndOwner, pbc, &lpszDisplayName[3], &chEaten, 743 &pidlChild, pdwAttributes); 744 if (FAILED_UNEXPECTEDLY(hr)) 745 return hr; 746 747 hr = SHILCombine(pidlTemp, pidlChild, ppidl); 748 } 749 else 750 { 751 *ppidl = pidlTemp.Detach(); 752 if (pdwAttributes && *pdwAttributes) 753 GetAttributesOf(1, (PCUITEMID_CHILD_ARRAY)ppidl, pdwAttributes); 754 hr = S_OK; 755 } 756 } 757 758 TRACE("(%p)->(-- ret=0x%08x)\n", this, hr); 759 760 return hr; 761 } 762 763 /************************************************************************** 764 * CDrivesFolder::EnumObjects 765 */ 766 HRESULT WINAPI CDrivesFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) 767 { 768 CComPtr<IEnumIDList> pRegEnumerator; 769 m_regFolder->EnumObjects(hwndOwner, dwFlags, &pRegEnumerator); 770 771 return ShellObjectCreatorInit<CDrivesFolderEnum>(hwndOwner, dwFlags, pRegEnumerator, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); 772 } 773 774 /************************************************************************** 775 * CDrivesFolder::BindToObject 776 */ 777 HRESULT WINAPI CDrivesFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) 778 { 779 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, 780 pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut); 781 782 if (!pidl) 783 return E_INVALIDARG; 784 785 if (_ILIsSpecialFolder(pidl)) 786 return m_regFolder->BindToObject(pidl, pbcReserved, riid, ppvOut); 787 788 CHAR* pchDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName; 789 790 PERSIST_FOLDER_TARGET_INFO pfti = {0}; 791 pfti.dwAttributes = -1; 792 pfti.csidl = -1; 793 pfti.szTargetParsingName[0] = *pchDrive; 794 pfti.szTargetParsingName[1] = L':'; 795 pfti.szTargetParsingName[2] = L'\\'; 796 797 HRESULT hr = SHELL32_BindToSF(pidlRoot, 798 &pfti, 799 pidl, 800 &CLSID_ShellFSFolder, 801 riid, 802 ppvOut); 803 if (FAILED_UNEXPECTEDLY(hr)) 804 return hr; 805 806 return S_OK; 807 } 808 809 /************************************************************************** 810 * CDrivesFolder::BindToStorage 811 */ 812 HRESULT WINAPI CDrivesFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) 813 { 814 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, 815 pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut); 816 817 *ppvOut = NULL; 818 return E_NOTIMPL; 819 } 820 821 /************************************************************************** 822 * CDrivesFolder::CompareIDs 823 */ 824 825 HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) 826 { 827 HRESULT hres; 828 829 if (!pidl1 || !pidl2) 830 { 831 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2); 832 return E_INVALIDARG; 833 } 834 835 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2)) 836 return m_regFolder->CompareIDs(lParam, pidl1, pidl2); 837 838 UINT iColumn = LOWORD(lParam); 839 if (!_ILIsDrive(pidl1) || !_ILIsDrive(pidl2) || iColumn >= _countof(MyComputerSFHeader)) 840 return E_INVALIDARG; 841 842 CHAR* pszDrive1 = _ILGetDataPointer(pidl1)->u.drive.szDriveName; 843 CHAR* pszDrive2 = _ILGetDataPointer(pidl2)->u.drive.szDriveName; 844 845 int result; 846 switch (MyComputerSFHeader[iColumn].colnameid) 847 { 848 case IDS_SHV_COLUMN_NAME: 849 { 850 result = _stricmp(pszDrive1, pszDrive2); 851 hres = MAKE_COMPARE_HRESULT(result); 852 break; 853 } 854 case IDS_SHV_COLUMN_TYPE: 855 { 856 /* We want to return immediately because SHELL32_CompareDetails also compares children. */ 857 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2); 858 } 859 case IDS_SHV_COLUMN_DISK_CAPACITY: 860 case IDS_SHV_COLUMN_DISK_AVAILABLE: 861 { 862 ULARGE_INTEGER Drive1Available, Drive1Total, Drive2Available, Drive2Total; 863 864 if (GetVolumeInformationA(pszDrive1, NULL, 0, NULL, NULL, NULL, NULL, 0)) 865 GetDiskFreeSpaceExA(pszDrive1, &Drive1Available, &Drive1Total, NULL); 866 else 867 Drive1Available.QuadPart = Drive1Total.QuadPart = 0; 868 869 if (GetVolumeInformationA(pszDrive2, NULL, 0, NULL, NULL, NULL, NULL, 0)) 870 GetDiskFreeSpaceExA(pszDrive2, &Drive2Available, &Drive2Total, NULL); 871 else 872 Drive2Available.QuadPart = Drive2Total.QuadPart = 0; 873 874 LARGE_INTEGER Diff; 875 if (lParam == 3) /* Size */ 876 Diff.QuadPart = Drive1Total.QuadPart - Drive2Total.QuadPart; 877 else /* Size available */ 878 Diff.QuadPart = Drive1Available.QuadPart - Drive2Available.QuadPart; 879 880 hres = MAKE_COMPARE_HRESULT(Diff.QuadPart); 881 break; 882 } 883 case IDS_SHV_COLUMN_COMMENTS: 884 hres = MAKE_COMPARE_HRESULT(0); 885 break; 886 DEFAULT_UNREACHABLE; 887 } 888 889 if (HRESULT_CODE(hres) == 0) 890 return SHELL32_CompareChildren(this, lParam, pidl1, pidl2); 891 892 return hres; 893 } 894 895 /************************************************************************** 896 * CDrivesFolder::CreateViewObject 897 */ 898 HRESULT WINAPI CDrivesFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut) 899 { 900 CComPtr<IShellView> pShellView; 901 HRESULT hr = E_INVALIDARG; 902 903 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this, 904 hwndOwner, shdebugstr_guid (&riid), ppvOut); 905 906 if (!ppvOut) 907 return hr; 908 909 *ppvOut = NULL; 910 911 if (IsEqualIID(riid, IID_IDropTarget)) 912 { 913 WARN("IDropTarget not implemented\n"); 914 hr = E_NOTIMPL; 915 } 916 else if (IsEqualIID(riid, IID_IContextMenu)) 917 { 918 HKEY hKeys[16]; 919 UINT cKeys = 0; 920 AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys); 921 922 DEFCONTEXTMENU dcm; 923 dcm.hwnd = hwndOwner; 924 dcm.pcmcb = this; 925 dcm.pidlFolder = pidlRoot; 926 dcm.psf = this; 927 dcm.cidl = 0; 928 dcm.apidl = NULL; 929 dcm.cKeys = cKeys; 930 dcm.aKeys = hKeys; 931 dcm.punkAssociationInfo = NULL; 932 hr = SHCreateDefaultContextMenu(&dcm, riid, ppvOut); 933 } 934 else if (IsEqualIID(riid, IID_IShellView)) 935 { 936 SFV_CREATE sfvparams = { sizeof(SFV_CREATE), this, NULL, static_cast<IShellFolderViewCB*>(this) }; 937 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut); 938 } 939 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut); 940 return hr; 941 } 942 943 /************************************************************************** 944 * CDrivesFolder::GetAttributesOf 945 */ 946 HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut) 947 { 948 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", 949 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0); 950 951 if (cidl && !apidl) 952 return E_INVALIDARG; 953 954 if (*rgfInOut == 0) 955 *rgfInOut = ~0; 956 957 /* FIXME: always add SFGAO_CANLINK */ 958 if(cidl == 0) 959 *rgfInOut &= dwComputerAttributes; 960 else 961 { 962 for (UINT i = 0; i < cidl; ++i) 963 { 964 if (_ILIsDrive(apidl[i])) 965 { 966 *rgfInOut &= dwDriveAttributes; 967 968 if (_ILGetDriveType(apidl[i]) == DRIVE_CDROM) 969 *rgfInOut &= ~SFGAO_CANRENAME; // CD-ROM drive cannot rename 970 } 971 else if (_ILIsControlPanel(apidl[i])) 972 { 973 *rgfInOut &= dwControlPanelAttributes; 974 } 975 else if (_ILIsSpecialFolder(*apidl)) 976 { 977 m_regFolder->GetAttributesOf(1, &apidl[i], rgfInOut); 978 } 979 else 980 { 981 ERR("Got unknown pidl type!\n"); 982 } 983 } 984 } 985 986 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */ 987 *rgfInOut &= ~SFGAO_VALIDATE; 988 989 TRACE("-- result=0x%08x\n", *rgfInOut); 990 return S_OK; 991 } 992 993 /************************************************************************** 994 * CDrivesFolder::GetUIObjectOf 995 * 996 * PARAMETERS 997 * hwndOwner [in] Parent window for any output 998 * cidl [in] array size 999 * apidl [in] simple pidl array 1000 * riid [in] Requested Interface 1001 * prgfInOut [ ] reserved 1002 * ppvObject [out] Resulting Interface 1003 * 1004 */ 1005 HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner, 1006 UINT cidl, PCUITEMID_CHILD_ARRAY apidl, 1007 REFIID riid, UINT *prgfInOut, LPVOID *ppvOut) 1008 { 1009 LPVOID pObj = NULL; 1010 HRESULT hr = E_INVALIDARG; 1011 1012 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this, 1013 hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut); 1014 1015 if (!ppvOut) 1016 return hr; 1017 1018 *ppvOut = NULL; 1019 1020 if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1)) 1021 { 1022 if (_ILIsDrive(apidl[0])) 1023 hr = CDrivesContextMenu_CreateInstance(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj); 1024 else 1025 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); 1026 } 1027 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1)) 1028 { 1029 hr = IDataObject_Constructor(hwndOwner, 1030 pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj); 1031 } 1032 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1)) 1033 { 1034 if (_ILIsDrive(apidl[0])) 1035 hr = CDrivesExtractIcon_CreateInstance(this, apidl[0], riid, &pObj); 1036 else 1037 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); 1038 } 1039 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1)) 1040 { 1041 CComPtr<IShellFolder> psfChild; 1042 hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild)); 1043 if (FAILED_UNEXPECTEDLY(hr)) 1044 return hr; 1045 1046 return psfChild->CreateViewObject(NULL, riid, ppvOut); 1047 } 1048 else 1049 hr = E_NOINTERFACE; 1050 1051 if (SUCCEEDED(hr) && !pObj) 1052 hr = E_OUTOFMEMORY; 1053 1054 *ppvOut = pObj; 1055 TRACE("(%p)->hr=0x%08x\n", this, hr); 1056 return hr; 1057 } 1058 1059 /************************************************************************** 1060 * CDrivesFolder::GetDisplayNameOf 1061 */ 1062 HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) 1063 { 1064 LPWSTR pszPath; 1065 HRESULT hr = S_OK; 1066 1067 TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet); 1068 pdump (pidl); 1069 1070 if (!strRet) 1071 return E_INVALIDARG; 1072 1073 if (!_ILIsPidlSimple (pidl)) 1074 { 1075 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet); 1076 } 1077 else if (_ILIsSpecialFolder(pidl)) 1078 { 1079 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet); 1080 } 1081 else if (!_ILIsDrive(pidl)) 1082 { 1083 ERR("Wrong pidl type\n"); 1084 return E_INVALIDARG; 1085 } 1086 1087 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR)); 1088 if (!pszPath) 1089 return E_OUTOFMEMORY; 1090 1091 pszPath[0] = 0; 1092 1093 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */ 1094 /* long view "lw_name (C:)" */ 1095 if (!(dwFlags & SHGDN_FORPARSING)) 1096 { 1097 WCHAR wszDrive[18] = {0}; 1098 1099 lstrcpynW(wszDrive, pszPath, 4); 1100 pszPath[0] = L'\0'; 1101 1102 if (!SUCCEEDED(getLabelForDrive(wszDrive, pszPath))) 1103 { 1104 DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags; 1105 1106 GetVolumeInformationW(wszDrive, pszPath, 1107 MAX_PATH - 7, 1108 &dwVolumeSerialNumber, 1109 &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0); 1110 pszPath[MAX_PATH-1] = L'\0'; 1111 1112 if (!wcslen(pszPath)) 1113 { 1114 UINT DriveType, ResourceId; 1115 DriveType = GetDriveTypeW(wszDrive); 1116 1117 switch (DriveType) 1118 { 1119 case DRIVE_FIXED: 1120 ResourceId = IDS_DRIVE_FIXED; 1121 break; 1122 case DRIVE_REMOTE: 1123 ResourceId = IDS_DRIVE_NETWORK; 1124 break; 1125 case DRIVE_CDROM: 1126 ResourceId = IDS_DRIVE_CDROM; 1127 break; 1128 default: 1129 ResourceId = 0; 1130 } 1131 1132 if (ResourceId) 1133 { 1134 dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH); 1135 if (dwFileSystemFlags > MAX_PATH - 7) 1136 pszPath[MAX_PATH-7] = L'\0'; 1137 } 1138 } 1139 } 1140 wcscat(pszPath, L" ("); 1141 wszDrive[2] = L'\0'; 1142 wcscat(pszPath, wszDrive); 1143 wcscat(pszPath, L")"); 1144 } 1145 1146 if (SUCCEEDED(hr)) 1147 { 1148 strRet->uType = STRRET_WSTR; 1149 strRet->pOleStr = pszPath; 1150 } 1151 else 1152 CoTaskMemFree(pszPath); 1153 1154 TRACE("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr)); 1155 return hr; 1156 } 1157 1158 /************************************************************************** 1159 * CDrivesFolder::SetNameOf 1160 * Changes the name of a file object or subfolder, possibly changing its item 1161 * identifier in the process. 1162 * 1163 * PARAMETERS 1164 * hwndOwner [in] Owner window for output 1165 * pidl [in] simple pidl of item to change 1166 * lpszName [in] the items new display name 1167 * dwFlags [in] SHGNO formatting flags 1168 * ppidlOut [out] simple pidl returned 1169 */ 1170 HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, 1171 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) 1172 { 1173 WCHAR szName[30]; 1174 1175 if (_ILIsDrive(pidl)) 1176 { 1177 if (_ILSimpleGetTextW(pidl, szName, _countof(szName))) 1178 SetVolumeLabelW(szName, lpName); 1179 if (pPidlOut) 1180 *pPidlOut = _ILCreateDrive(szName); 1181 return S_OK; 1182 } 1183 1184 return m_regFolder->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut); 1185 } 1186 1187 HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid) 1188 { 1189 FIXME("(%p)\n", this); 1190 return E_NOTIMPL; 1191 } 1192 1193 HRESULT WINAPI CDrivesFolder::EnumSearches(IEnumExtraSearch ** ppenum) 1194 { 1195 FIXME("(%p)\n", this); 1196 return E_NOTIMPL; 1197 } 1198 1199 HRESULT WINAPI CDrivesFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay) 1200 { 1201 TRACE("(%p)\n", this); 1202 1203 if (pSort) 1204 *pSort = 0; 1205 if (pDisplay) 1206 *pDisplay = 0; 1207 return S_OK; 1208 } 1209 1210 HRESULT WINAPI CDrivesFolder::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF * pcsFlags) 1211 { 1212 TRACE("(%p)\n", this); 1213 1214 if (!pcsFlags || iColumn >= _countof(MyComputerSFHeader)) 1215 return E_INVALIDARG; 1216 *pcsFlags = MyComputerSFHeader[iColumn].colstate; 1217 return S_OK; 1218 } 1219 1220 HRESULT WINAPI CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID * pscid, VARIANT * pv) 1221 { 1222 FIXME("(%p)\n", this); 1223 return E_NOTIMPL; 1224 } 1225 1226 HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) 1227 { 1228 HRESULT hr; 1229 1230 TRACE("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd); 1231 1232 if (!psd || iColumn >= _countof(MyComputerSFHeader)) 1233 return E_INVALIDARG; 1234 1235 if (!pidl) 1236 { 1237 psd->fmt = MyComputerSFHeader[iColumn].fmt; 1238 psd->cxChar = MyComputerSFHeader[iColumn].cxChar; 1239 return SHSetStrRet(&psd->str, MyComputerSFHeader[iColumn].colnameid); 1240 } 1241 else if (!_ILIsDrive(pidl)) 1242 { 1243 switch (MyComputerSFHeader[iColumn].colnameid) 1244 { 1245 case IDS_SHV_COLUMN_NAME: 1246 case IDS_SHV_COLUMN_TYPE: 1247 return m_regFolder->GetDetailsOf(pidl, iColumn, psd); 1248 case IDS_SHV_COLUMN_DISK_CAPACITY: 1249 case IDS_SHV_COLUMN_DISK_AVAILABLE: 1250 return SHSetStrRet(&psd->str, ""); /* blank col */ 1251 case IDS_SHV_COLUMN_COMMENTS: 1252 return m_regFolder->GetDetailsOf(pidl, 2, psd); /* 2 = comments */ 1253 DEFAULT_UNREACHABLE; 1254 } 1255 } 1256 else 1257 { 1258 ULARGE_INTEGER ulTotalBytes, ulFreeBytes; 1259 CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName; 1260 UINT DriveType = GetDriveTypeA(pszDrive); 1261 if (DriveType > DRIVE_RAMDISK) 1262 DriveType = DRIVE_FIXED; 1263 1264 switch (MyComputerSFHeader[iColumn].colnameid) 1265 { 1266 case IDS_SHV_COLUMN_NAME: 1267 hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str); 1268 break; 1269 case IDS_SHV_COLUMN_TYPE: 1270 if (DriveType == DRIVE_REMOVABLE && !IsDriveFloppyA(pszDrive)) 1271 hr = SHSetStrRet(&psd->str, IDS_DRIVE_REMOVABLE); 1272 else 1273 hr = SHSetStrRet(&psd->str, iDriveTypeIds[DriveType]); 1274 break; 1275 case IDS_SHV_COLUMN_DISK_CAPACITY: 1276 case IDS_SHV_COLUMN_DISK_AVAILABLE: 1277 psd->str.cStr[0] = 0x00; 1278 psd->str.uType = STRRET_CSTR; 1279 if (GetVolumeInformationA(pszDrive, NULL, 0, NULL, NULL, NULL, NULL, 0)) 1280 { 1281 GetDiskFreeSpaceExA(pszDrive, &ulFreeBytes, &ulTotalBytes, NULL); 1282 if (iColumn == 2) 1283 StrFormatByteSize64A(ulTotalBytes.QuadPart, psd->str.cStr, MAX_PATH); 1284 else 1285 StrFormatByteSize64A(ulFreeBytes.QuadPart, psd->str.cStr, MAX_PATH); 1286 } 1287 hr = S_OK; 1288 break; 1289 case IDS_SHV_COLUMN_COMMENTS: 1290 hr = SHSetStrRet(&psd->str, ""); /* FIXME: comments */ 1291 break; 1292 DEFAULT_UNREACHABLE; 1293 } 1294 } 1295 1296 return hr; 1297 } 1298 1299 HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid) 1300 { 1301 FIXME("(%p)\n", this); 1302 return E_NOTIMPL; 1303 } 1304 1305 /************************************************************************ 1306 * CDrivesFolder::GetClassID 1307 */ 1308 HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId) 1309 { 1310 TRACE("(%p)\n", this); 1311 1312 if (!lpClassId) 1313 return E_POINTER; 1314 1315 *lpClassId = CLSID_MyComputer; 1316 return S_OK; 1317 } 1318 1319 /************************************************************************ 1320 * CDrivesFolder::Initialize 1321 * 1322 * NOTES: it makes no sense to change the pidl 1323 */ 1324 HRESULT WINAPI CDrivesFolder::Initialize(PCIDLIST_ABSOLUTE pidl) 1325 { 1326 return S_OK; 1327 } 1328 1329 /************************************************************************** 1330 * CDrivesFolder::GetCurFolder 1331 */ 1332 HRESULT WINAPI CDrivesFolder::GetCurFolder(PIDLIST_ABSOLUTE *pidl) 1333 { 1334 TRACE("(%p)->(%p)\n", this, pidl); 1335 1336 if (!pidl) 1337 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */ 1338 1339 *pidl = ILClone(pidlRoot); 1340 return S_OK; 1341 } 1342 1343 /************************************************************************** 1344 * CDrivesFolder::ShouldShow 1345 */ 1346 HRESULT WINAPI CDrivesFolder::ShouldShow(IShellFolder *psf, PCIDLIST_ABSOLUTE pidlFolder, PCUITEMID_CHILD pidlItem) 1347 { 1348 if (const CLSID* pClsid = IsRegItem(pidlItem)) 1349 return SHELL32_IsShellFolderNamespaceItemHidden(L"HideMyComputerIcons", *pClsid) ? S_FALSE : S_OK; 1350 return S_OK; 1351 } 1352 1353 /************************************************************************/ 1354 /* IContextMenuCB interface */ 1355 1356 HRESULT WINAPI CDrivesFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam) 1357 { 1358 enum { IDC_PROPERTIES }; 1359 /* no data object means no selection */ 1360 if (!pdtobj) 1361 { 1362 if (uMsg == DFM_INVOKECOMMAND && wParam == IDC_PROPERTIES) 1363 { 1364 // "System" properties 1365 return SHELL_ExecuteControlPanelCPL(hwndOwner, L"sysdm.cpl") ? S_OK : E_FAIL; 1366 } 1367 else if (uMsg == DFM_MERGECONTEXTMENU) 1368 { 1369 QCMINFO *pqcminfo = (QCMINFO *)lParam; 1370 HMENU hpopup = CreatePopupMenu(); 1371 _InsertMenuItemW(hpopup, 0, TRUE, IDC_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED); 1372 pqcminfo->idCmdFirst = Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR); 1373 DestroyMenu(hpopup); 1374 return S_OK; 1375 } 1376 } 1377 return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg); 1378 } 1379