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 static DWORD CALLBACK DoFormatDriveThread(LPVOID args) 190 { 191 UINT nDrive = PtrToUlong(args); 192 WCHAR szPath[] = { LOWORD(L'A' + nDrive), L'\0' }; // Arbitrary, just needs to include nDrive 193 CStubWindow32 stub; 194 HRESULT hr = stub.CreateStub(CStubWindow32::TYPE_FORMATDRIVE, szPath, NULL); 195 if (FAILED(hr)) 196 return hr; 197 SHFormatDrive(stub, nDrive, SHFMT_ID_DEFAULT, 0); 198 return stub.DestroyWindow(); 199 } 200 201 static HRESULT DoFormatDriveAsync(HWND hwnd, UINT nDrive) 202 { 203 BOOL succ = SHCreateThread(DoFormatDriveThread, UlongToPtr(nDrive), CTF_PROCESS_REF, NULL); 204 return succ ? S_OK : E_FAIL; 205 } 206 207 HRESULT CALLBACK DrivesContextMenuCallback(IShellFolder *psf, 208 HWND hwnd, 209 IDataObject *pdtobj, 210 UINT uMsg, 211 WPARAM wParam, 212 LPARAM lParam) 213 { 214 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND) 215 return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg); 216 217 PIDLIST_ABSOLUTE pidlFolder; 218 PUITEMID_CHILD *apidl; 219 UINT cidl; 220 UINT nDriveType; 221 DWORD dwFlags; 222 HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl); 223 if (FAILED_UNEXPECTEDLY(hr)) 224 return hr; 225 226 WCHAR szDrive[8] = {0}; 227 if (!_ILGetDrive(apidl[0], szDrive, _countof(szDrive))) 228 { 229 ERR("pidl is not a drive\n"); 230 SHFree(pidlFolder); 231 _ILFreeaPidl(apidl, cidl); 232 return E_FAIL; 233 } 234 nDriveType = GetDriveTypeW(szDrive); 235 GetVolumeInformationW(szDrive, NULL, 0, NULL, NULL, &dwFlags, NULL, 0); 236 237 // custom command IDs 238 #if 0 // Disabled until our menu building system is fixed 239 #define CMDID_FORMAT 0 240 #define CMDID_EJECT 1 241 #define CMDID_DISCONNECT 2 242 #else 243 /* FIXME: These IDs should start from 0, however there is difference 244 * between ours and Windows' menu building systems, which should be fixed. */ 245 #define CMDID_FORMAT 1 246 #define CMDID_EJECT 2 247 #define CMDID_DISCONNECT 3 248 #endif 249 250 if (uMsg == DFM_MERGECONTEXTMENU) 251 { 252 QCMINFO *pqcminfo = (QCMINFO *)lParam; 253 254 UINT idCmdFirst = pqcminfo->idCmdFirst; 255 UINT idCmd = 0; 256 if (!(dwFlags & FILE_READ_ONLY_VOLUME) && nDriveType != DRIVE_REMOTE) 257 { 258 /* add separator and Format */ 259 idCmd = idCmdFirst + CMDID_FORMAT; 260 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0); 261 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED); 262 } 263 if (nDriveType == DRIVE_REMOVABLE || nDriveType == DRIVE_CDROM) 264 { 265 /* add separator and Eject */ 266 idCmd = idCmdFirst + CMDID_EJECT; 267 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0); 268 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_EJECT), MFS_ENABLED); 269 } 270 if (nDriveType == DRIVE_REMOTE) 271 { 272 /* add separator and Disconnect */ 273 idCmd = idCmdFirst + CMDID_DISCONNECT; 274 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0); 275 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_DISCONNECT), MFS_ENABLED); 276 } 277 278 if (idCmd) 279 #if 0 // see FIXME above 280 pqcminfo->idCmdFirst = ++idCmd; 281 #else 282 pqcminfo->idCmdFirst = (idCmd + 2); 283 #endif 284 hr = S_OK; 285 } 286 else if (uMsg == DFM_INVOKECOMMAND) 287 { 288 WCHAR wszBuf[4] = L"A:\\"; 289 wszBuf[0] = (WCHAR)szDrive[0]; 290 291 INT nStringID = 0; 292 DWORD dwError = NO_ERROR; 293 294 if (wParam == DFM_CMD_PROPERTIES) 295 { 296 ATLASSERT(pdtobj); 297 hr = SHELL32_ShowFilesystemItemPropertiesDialogAsync(pdtobj); 298 // Not setting nStringID because SHOpenPropSheet already displayed an error box 299 } 300 else 301 { 302 if (wParam == CMDID_FORMAT) 303 { 304 hr = DoFormatDriveAsync(hwnd, szDrive[0] - 'A'); 305 } 306 else if (wParam == CMDID_EJECT) 307 { 308 /* do eject */ 309 WCHAR physical[10]; 310 wsprintfW(physical, _T("\\\\.\\%c:"), szDrive[0]); 311 312 if (DoEjectDrive(physical, nDriveType, &nStringID)) 313 { 314 SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_PATHW | SHCNF_FLUSHNOWAIT, wszBuf, NULL); 315 } 316 else 317 { 318 dwError = GetLastError(); 319 } 320 } 321 else if (wParam == CMDID_DISCONNECT) 322 { 323 /* do disconnect */ 324 wszBuf[2] = UNICODE_NULL; 325 dwError = WNetCancelConnection2W(wszBuf, 0, FALSE); 326 if (dwError == NO_ERROR) 327 { 328 SHChangeNotify(SHCNE_DRIVEREMOVED, SHCNF_PATHW | SHCNF_FLUSHNOWAIT, wszBuf, NULL); 329 } 330 else 331 { 332 nStringID = IDS_CANTDISCONNECT; 333 } 334 } 335 } 336 337 if (nStringID != 0) 338 { 339 /* show error message */ 340 WCHAR szFormat[128], szMessage[128]; 341 LoadStringW(shell32_hInstance, nStringID, szFormat, _countof(szFormat)); 342 wsprintfW(szMessage, szFormat, dwError); 343 MessageBoxW(hwnd, szMessage, NULL, MB_ICONERROR); 344 } 345 } 346 347 SHFree(pidlFolder); 348 _ILFreeaPidl(apidl, cidl); 349 350 return hr; 351 } 352 353 HRESULT CDrivesContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder, 354 HWND hwnd, 355 UINT cidl, 356 PCUITEMID_CHILD_ARRAY apidl, 357 IShellFolder *psf, 358 IContextMenu **ppcm) 359 { 360 HKEY hKeys[2]; 361 UINT cKeys = 0; 362 AddClassKeyToArray(L"Drive", hKeys, &cKeys); 363 AddClassKeyToArray(L"Folder", hKeys, &cKeys); 364 365 return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, DrivesContextMenuCallback, cKeys, hKeys, ppcm); 366 } 367 368 static HRESULT 369 getIconLocationForDrive(IShellFolder *psf, PCITEMID_CHILD pidl, UINT uFlags, 370 LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags) 371 { 372 WCHAR wszPath[MAX_PATH]; 373 WCHAR wszAutoRunInfPath[MAX_PATH]; 374 WCHAR wszValue[MAX_PATH], wszTemp[MAX_PATH]; 375 376 // get path 377 if (!ILGetDisplayNameExW(psf, pidl, wszPath, 0)) 378 return E_FAIL; 379 if (!PathIsDirectoryW(wszPath)) 380 return E_FAIL; 381 382 // build the full path of autorun.inf 383 StringCchCopyW(wszAutoRunInfPath, _countof(wszAutoRunInfPath), wszPath); 384 PathAppendW(wszAutoRunInfPath, L"autorun.inf"); 385 386 // autorun.inf --> wszValue 387 if (GetPrivateProfileStringW(L"autorun", L"icon", NULL, wszValue, _countof(wszValue), 388 wszAutoRunInfPath) && wszValue[0] != 0) 389 { 390 // wszValue --> wszTemp 391 ExpandEnvironmentStringsW(wszValue, wszTemp, _countof(wszTemp)); 392 393 // parse the icon location 394 *piIndex = PathParseIconLocationW(wszTemp); 395 396 // wszPath + wszTemp --> wszPath 397 if (PathIsRelativeW(wszTemp)) 398 PathAppendW(wszPath, wszTemp); 399 else 400 StringCchCopyW(wszPath, _countof(wszPath), wszTemp); 401 402 // wszPath --> szIconFile 403 GetFullPathNameW(wszPath, cchMax, szIconFile, NULL); 404 405 return S_OK; 406 } 407 408 return E_FAIL; 409 } 410 411 static HRESULT 412 getLabelForDrive(LPWSTR wszPath, LPWSTR wszLabel) 413 { 414 WCHAR wszAutoRunInfPath[MAX_PATH]; 415 WCHAR wszTemp[MAX_PATH]; 416 417 if (!PathIsDirectoryW(wszPath)) 418 return E_FAIL; 419 420 StringCchCopyW(wszAutoRunInfPath, _countof(wszAutoRunInfPath), wszPath); 421 PathAppendW(wszAutoRunInfPath, L"autorun.inf"); 422 423 if (GetPrivateProfileStringW(L"autorun", L"label", NULL, wszTemp, _countof(wszTemp), 424 wszAutoRunInfPath) && wszTemp[0] != 0) 425 { 426 StringCchCopyW(wszLabel, _countof(wszTemp), wszTemp); 427 return S_OK; 428 } 429 430 return E_FAIL; 431 } 432 433 BOOL IsDriveFloppyA(LPCSTR pszDriveRoot); 434 435 HRESULT CDrivesExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut) 436 { 437 CComPtr<IDefaultExtractIconInit> initIcon; 438 HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon)); 439 if (FAILED_UNEXPECTEDLY(hr)) 440 return hr; 441 442 CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName; 443 UINT DriveType = GetDriveTypeA(pszDrive); 444 if (DriveType > DRIVE_RAMDISK) 445 DriveType = DRIVE_FIXED; 446 447 WCHAR wTemp[MAX_PATH]; 448 int icon_idx, reg_idx; 449 UINT flags = 0; 450 451 switch (DriveType) 452 { 453 case DRIVE_FIXED: 454 case DRIVE_UNKNOWN: 455 reg_idx = IDI_SHELL_DRIVE; 456 break; 457 case DRIVE_CDROM: 458 reg_idx = IDI_SHELL_CDROM; 459 break; 460 case DRIVE_REMOTE: 461 reg_idx = IDI_SHELL_NETDRIVE; 462 break; 463 case DRIVE_REMOVABLE: 464 if (!IsDriveFloppyA(pszDrive)) 465 reg_idx = IDI_SHELL_REMOVEABLE; 466 else 467 reg_idx = IDI_SHELL_3_14_FLOPPY; 468 break; 469 case DRIVE_RAMDISK: 470 reg_idx = IDI_SHELL_RAMDISK; 471 break; 472 case DRIVE_NO_ROOT_DIR: 473 default: 474 reg_idx = IDI_SHELL_DOCUMENT; 475 break; 476 } 477 478 hr = getIconLocationForDrive(psf, pidl, 0, wTemp, _countof(wTemp), 479 &icon_idx, &flags); 480 if (SUCCEEDED(hr)) 481 { 482 initIcon->SetNormalIcon(wTemp, icon_idx); 483 } 484 else if (HLM_GetIconW(reg_idx - 1, wTemp, _countof(wTemp), &icon_idx)) 485 { 486 initIcon->SetNormalIcon(wTemp, icon_idx); 487 } 488 else if ((DriveType == DRIVE_FIXED || DriveType == DRIVE_UNKNOWN) && 489 (HCR_GetIconW(L"Drive", wTemp, NULL, _countof(wTemp), &icon_idx))) 490 { 491 initIcon->SetNormalIcon(wTemp, icon_idx); 492 } 493 else 494 { 495 if (DriveType == DRIVE_REMOVABLE && !IsDriveFloppyA(pszDrive)) 496 { 497 icon_idx = IDI_SHELL_REMOVEABLE; 498 } 499 else 500 { 501 icon_idx = iDriveIconIds[DriveType]; 502 } 503 initIcon->SetNormalIcon(swShell32Name, -icon_idx); 504 } 505 506 return initIcon->QueryInterface(riid, ppvOut); 507 } 508 509 class CDrivesFolderEnum : 510 public CEnumIDListBase 511 { 512 public: 513 HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags, IEnumIDList* pRegEnumerator) 514 { 515 /* enumerate the folders */ 516 if (dwFlags & SHCONTF_FOLDERS) 517 { 518 WCHAR wszDriveName[] = {'A', ':', '\\', '\0'}; 519 DWORD dwDrivemap = GetLogicalDrives(); 520 521 while (wszDriveName[0] <= 'Z') 522 { 523 if(dwDrivemap & 0x00000001L) 524 AddToEnumList(_ILCreateDrive(wszDriveName)); 525 wszDriveName[0]++; 526 dwDrivemap = dwDrivemap >> 1; 527 } 528 } 529 530 /* Enumerate the items of the reg folder */ 531 AppendItemsFromEnumerator(pRegEnumerator); 532 533 return S_OK; 534 } 535 536 BEGIN_COM_MAP(CDrivesFolderEnum) 537 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) 538 END_COM_MAP() 539 }; 540 541 /*********************************************************************** 542 * IShellFolder [MyComputer] implementation 543 */ 544 545 static const shvheader MyComputerSFHeader[] = { 546 {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15}, 547 {IDS_SHV_COLUMN_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10}, 548 {IDS_SHV_COLUMN_DISK_CAPACITY, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}, 549 {IDS_SHV_COLUMN_DISK_AVAILABLE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}, 550 {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 10}, 551 }; 552 553 static const DWORD dwComputerAttributes = 554 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | 555 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER; 556 static const DWORD dwControlPanelAttributes = 557 SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK; 558 static const DWORD dwDriveAttributes = 559 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | 560 SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK | SFGAO_CANCOPY; 561 562 CDrivesFolder::CDrivesFolder() 563 { 564 pidlRoot = NULL; 565 } 566 567 CDrivesFolder::~CDrivesFolder() 568 { 569 TRACE("-- destroying IShellFolder(%p)\n", this); 570 SHFree(pidlRoot); 571 } 572 573 HRESULT WINAPI CDrivesFolder::FinalConstruct() 574 { 575 pidlRoot = _ILCreateMyComputer(); /* my qualified pidl */ 576 if (pidlRoot == NULL) 577 return E_OUTOFMEMORY; 578 579 REGFOLDERINITDATA RegInit = { static_cast<IShellFolder*>(this), &g_RegFolderInfo }; 580 HRESULT hr = CRegFolder_CreateInstance(&RegInit, 581 pidlRoot, 582 IID_PPV_ARG(IShellFolder2, &m_regFolder)); 583 584 return hr; 585 } 586 587 /************************************************************************** 588 * CDrivesFolder::ParseDisplayName 589 */ 590 HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, 591 DWORD * pchEaten, PIDLIST_RELATIVE * ppidl, DWORD * pdwAttributes) 592 { 593 HRESULT hr = E_INVALIDARG; 594 595 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this, 596 hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName), 597 pchEaten, ppidl, pdwAttributes); 598 599 if (!ppidl) 600 return hr; 601 602 *ppidl = NULL; 603 604 if (!lpszDisplayName) 605 return hr; 606 607 /* handle CLSID paths */ 608 if (lpszDisplayName[0] == L':' && lpszDisplayName[1] == L':') 609 { 610 return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, 611 pdwAttributes); 612 } 613 614 if (((L'A' <= lpszDisplayName[0] && lpszDisplayName[0] <= L'Z') || 615 (L'a' <= lpszDisplayName[0] && lpszDisplayName[0] <= L'z')) && 616 lpszDisplayName[1] == L':' && (lpszDisplayName[2] == L'\\' || !lpszDisplayName[2])) 617 { 618 // "C:\..." 619 WCHAR szRoot[8]; 620 PathBuildRootW(szRoot, ((*lpszDisplayName - 1) & 0x1F)); 621 622 if (SHIsFileSysBindCtx(pbc, NULL) != S_OK && !(BindCtx_GetMode(pbc, 0) & STGM_CREATE)) 623 { 624 if (::GetDriveType(szRoot) == DRIVE_NO_ROOT_DIR) 625 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 626 } 627 628 CComHeapPtr<ITEMIDLIST> pidlTemp(_ILCreateDrive(szRoot)); 629 if (!pidlTemp) 630 return E_OUTOFMEMORY; 631 632 if (lpszDisplayName[2] && lpszDisplayName[3]) 633 { 634 CComPtr<IShellFolder> pChildFolder; 635 hr = BindToObject(pidlTemp, pbc, IID_PPV_ARG(IShellFolder, &pChildFolder)); 636 if (FAILED_UNEXPECTEDLY(hr)) 637 return hr; 638 639 ULONG chEaten; 640 CComHeapPtr<ITEMIDLIST> pidlChild; 641 hr = pChildFolder->ParseDisplayName(hwndOwner, pbc, &lpszDisplayName[3], &chEaten, 642 &pidlChild, pdwAttributes); 643 if (FAILED_UNEXPECTEDLY(hr)) 644 return hr; 645 646 hr = SHILCombine(pidlTemp, pidlChild, ppidl); 647 } 648 else 649 { 650 *ppidl = pidlTemp.Detach(); 651 if (pdwAttributes && *pdwAttributes) 652 GetAttributesOf(1, (PCUITEMID_CHILD_ARRAY)ppidl, pdwAttributes); 653 hr = S_OK; 654 } 655 } 656 657 TRACE("(%p)->(-- ret=0x%08x)\n", this, hr); 658 659 return hr; 660 } 661 662 /************************************************************************** 663 * CDrivesFolder::EnumObjects 664 */ 665 HRESULT WINAPI CDrivesFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) 666 { 667 CComPtr<IEnumIDList> pRegEnumerator; 668 m_regFolder->EnumObjects(hwndOwner, dwFlags, &pRegEnumerator); 669 670 return ShellObjectCreatorInit<CDrivesFolderEnum>(hwndOwner, dwFlags, pRegEnumerator, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); 671 } 672 673 /************************************************************************** 674 * CDrivesFolder::BindToObject 675 */ 676 HRESULT WINAPI CDrivesFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) 677 { 678 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, 679 pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut); 680 681 if (!pidl) 682 return E_INVALIDARG; 683 684 if (_ILIsSpecialFolder(pidl)) 685 return m_regFolder->BindToObject(pidl, pbcReserved, riid, ppvOut); 686 687 CHAR* pchDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName; 688 689 PERSIST_FOLDER_TARGET_INFO pfti = {0}; 690 pfti.dwAttributes = -1; 691 pfti.csidl = -1; 692 pfti.szTargetParsingName[0] = *pchDrive; 693 pfti.szTargetParsingName[1] = L':'; 694 pfti.szTargetParsingName[2] = L'\\'; 695 696 HRESULT hr = SHELL32_BindToSF(pidlRoot, 697 &pfti, 698 pidl, 699 &CLSID_ShellFSFolder, 700 riid, 701 ppvOut); 702 if (FAILED_UNEXPECTEDLY(hr)) 703 return hr; 704 705 return S_OK; 706 } 707 708 /************************************************************************** 709 * CDrivesFolder::BindToStorage 710 */ 711 HRESULT WINAPI CDrivesFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) 712 { 713 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, 714 pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut); 715 716 *ppvOut = NULL; 717 return E_NOTIMPL; 718 } 719 720 /************************************************************************** 721 * CDrivesFolder::CompareIDs 722 */ 723 724 HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) 725 { 726 HRESULT hres; 727 728 if (!pidl1 || !pidl2) 729 { 730 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2); 731 return E_INVALIDARG; 732 } 733 734 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2)) 735 return m_regFolder->CompareIDs(lParam, pidl1, pidl2); 736 737 UINT iColumn = LOWORD(lParam); 738 if (!_ILIsDrive(pidl1) || !_ILIsDrive(pidl2) || iColumn >= _countof(MyComputerSFHeader)) 739 return E_INVALIDARG; 740 741 CHAR* pszDrive1 = _ILGetDataPointer(pidl1)->u.drive.szDriveName; 742 CHAR* pszDrive2 = _ILGetDataPointer(pidl2)->u.drive.szDriveName; 743 744 int result; 745 switch (MyComputerSFHeader[iColumn].colnameid) 746 { 747 case IDS_SHV_COLUMN_NAME: 748 { 749 result = _stricmp(pszDrive1, pszDrive2); 750 hres = MAKE_COMPARE_HRESULT(result); 751 break; 752 } 753 case IDS_SHV_COLUMN_TYPE: 754 { 755 /* We want to return immediately because SHELL32_CompareDetails also compares children. */ 756 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2); 757 } 758 case IDS_SHV_COLUMN_DISK_CAPACITY: 759 case IDS_SHV_COLUMN_DISK_AVAILABLE: 760 { 761 ULARGE_INTEGER Drive1Available, Drive1Total, Drive2Available, Drive2Total; 762 763 if (GetVolumeInformationA(pszDrive1, NULL, 0, NULL, NULL, NULL, NULL, 0)) 764 GetDiskFreeSpaceExA(pszDrive1, &Drive1Available, &Drive1Total, NULL); 765 else 766 Drive1Available.QuadPart = Drive1Total.QuadPart = 0; 767 768 if (GetVolumeInformationA(pszDrive2, NULL, 0, NULL, NULL, NULL, NULL, 0)) 769 GetDiskFreeSpaceExA(pszDrive2, &Drive2Available, &Drive2Total, NULL); 770 else 771 Drive2Available.QuadPart = Drive2Total.QuadPart = 0; 772 773 LARGE_INTEGER Diff; 774 if (lParam == 3) /* Size */ 775 Diff.QuadPart = Drive1Total.QuadPart - Drive2Total.QuadPart; 776 else /* Size available */ 777 Diff.QuadPart = Drive1Available.QuadPart - Drive2Available.QuadPart; 778 779 hres = MAKE_COMPARE_HRESULT(Diff.QuadPart); 780 break; 781 } 782 case IDS_SHV_COLUMN_COMMENTS: 783 hres = MAKE_COMPARE_HRESULT(0); 784 break; 785 DEFAULT_UNREACHABLE; 786 } 787 788 if (HRESULT_CODE(hres) == 0) 789 return SHELL32_CompareChildren(this, lParam, pidl1, pidl2); 790 791 return hres; 792 } 793 794 /************************************************************************** 795 * CDrivesFolder::CreateViewObject 796 */ 797 HRESULT WINAPI CDrivesFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut) 798 { 799 CComPtr<IShellView> pShellView; 800 HRESULT hr = E_INVALIDARG; 801 802 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this, 803 hwndOwner, shdebugstr_guid (&riid), ppvOut); 804 805 if (!ppvOut) 806 return hr; 807 808 *ppvOut = NULL; 809 810 if (IsEqualIID(riid, IID_IDropTarget)) 811 { 812 WARN("IDropTarget not implemented\n"); 813 hr = E_NOTIMPL; 814 } 815 else if (IsEqualIID(riid, IID_IContextMenu)) 816 { 817 DEFCONTEXTMENU dcm = { hwndOwner, this, pidlRoot, this }; 818 hr = SHCreateDefaultContextMenu(&dcm, riid, ppvOut); 819 } 820 else if (IsEqualIID(riid, IID_IShellView)) 821 { 822 SFV_CREATE sfvparams = { sizeof(SFV_CREATE), this, NULL, static_cast<IShellFolderViewCB*>(this) }; 823 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut); 824 } 825 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut); 826 return hr; 827 } 828 829 /************************************************************************** 830 * CDrivesFolder::GetAttributesOf 831 */ 832 HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut) 833 { 834 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", 835 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0); 836 837 if (cidl && !apidl) 838 return E_INVALIDARG; 839 840 if (*rgfInOut == 0) 841 *rgfInOut = ~0; 842 843 /* FIXME: always add SFGAO_CANLINK */ 844 if(cidl == 0) 845 *rgfInOut &= dwComputerAttributes; 846 else 847 { 848 for (UINT i = 0; i < cidl; ++i) 849 { 850 if (_ILIsDrive(apidl[i])) 851 { 852 *rgfInOut &= dwDriveAttributes; 853 854 if (_ILGetDriveType(apidl[i]) == DRIVE_CDROM) 855 *rgfInOut &= ~SFGAO_CANRENAME; // CD-ROM drive cannot rename 856 } 857 else if (_ILIsControlPanel(apidl[i])) 858 { 859 *rgfInOut &= dwControlPanelAttributes; 860 } 861 else if (_ILIsSpecialFolder(*apidl)) 862 { 863 m_regFolder->GetAttributesOf(1, &apidl[i], rgfInOut); 864 } 865 else 866 { 867 ERR("Got unknown pidl type!\n"); 868 } 869 } 870 } 871 872 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */ 873 *rgfInOut &= ~SFGAO_VALIDATE; 874 875 TRACE("-- result=0x%08x\n", *rgfInOut); 876 return S_OK; 877 } 878 879 /************************************************************************** 880 * CDrivesFolder::GetUIObjectOf 881 * 882 * PARAMETERS 883 * hwndOwner [in] Parent window for any output 884 * cidl [in] array size 885 * apidl [in] simple pidl array 886 * riid [in] Requested Interface 887 * prgfInOut [ ] reserved 888 * ppvObject [out] Resulting Interface 889 * 890 */ 891 HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner, 892 UINT cidl, PCUITEMID_CHILD_ARRAY apidl, 893 REFIID riid, UINT *prgfInOut, LPVOID *ppvOut) 894 { 895 LPVOID pObj = NULL; 896 HRESULT hr = E_INVALIDARG; 897 898 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this, 899 hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut); 900 901 if (!ppvOut) 902 return hr; 903 904 *ppvOut = NULL; 905 906 if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1)) 907 { 908 if (_ILIsDrive(apidl[0])) 909 hr = CDrivesContextMenu_CreateInstance(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj); 910 else 911 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); 912 } 913 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1)) 914 { 915 hr = IDataObject_Constructor(hwndOwner, 916 pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj); 917 } 918 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1)) 919 { 920 if (_ILIsDrive(apidl[0])) 921 hr = CDrivesExtractIcon_CreateInstance(this, apidl[0], riid, &pObj); 922 else 923 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); 924 } 925 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1)) 926 { 927 CComPtr<IShellFolder> psfChild; 928 hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild)); 929 if (FAILED_UNEXPECTEDLY(hr)) 930 return hr; 931 932 return psfChild->CreateViewObject(NULL, riid, ppvOut); 933 } 934 else 935 hr = E_NOINTERFACE; 936 937 if (SUCCEEDED(hr) && !pObj) 938 hr = E_OUTOFMEMORY; 939 940 *ppvOut = pObj; 941 TRACE("(%p)->hr=0x%08x\n", this, hr); 942 return hr; 943 } 944 945 /************************************************************************** 946 * CDrivesFolder::GetDisplayNameOf 947 */ 948 HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) 949 { 950 LPWSTR pszPath; 951 HRESULT hr = S_OK; 952 953 TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet); 954 pdump (pidl); 955 956 if (!strRet) 957 return E_INVALIDARG; 958 959 if (!_ILIsPidlSimple (pidl)) 960 { 961 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet); 962 } 963 else if (_ILIsSpecialFolder(pidl)) 964 { 965 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet); 966 } 967 else if (!_ILIsDrive(pidl)) 968 { 969 ERR("Wrong pidl type\n"); 970 return E_INVALIDARG; 971 } 972 973 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR)); 974 if (!pszPath) 975 return E_OUTOFMEMORY; 976 977 pszPath[0] = 0; 978 979 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */ 980 /* long view "lw_name (C:)" */ 981 if (!(dwFlags & SHGDN_FORPARSING)) 982 { 983 WCHAR wszDrive[18] = {0}; 984 985 lstrcpynW(wszDrive, pszPath, 4); 986 pszPath[0] = L'\0'; 987 988 if (!SUCCEEDED(getLabelForDrive(wszDrive, pszPath))) 989 { 990 DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags; 991 992 GetVolumeInformationW(wszDrive, pszPath, 993 MAX_PATH - 7, 994 &dwVolumeSerialNumber, 995 &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0); 996 pszPath[MAX_PATH-1] = L'\0'; 997 998 if (!wcslen(pszPath)) 999 { 1000 UINT DriveType, ResourceId; 1001 DriveType = GetDriveTypeW(wszDrive); 1002 1003 switch (DriveType) 1004 { 1005 case DRIVE_FIXED: 1006 ResourceId = IDS_DRIVE_FIXED; 1007 break; 1008 case DRIVE_REMOTE: 1009 ResourceId = IDS_DRIVE_NETWORK; 1010 break; 1011 case DRIVE_CDROM: 1012 ResourceId = IDS_DRIVE_CDROM; 1013 break; 1014 default: 1015 ResourceId = 0; 1016 } 1017 1018 if (ResourceId) 1019 { 1020 dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH); 1021 if (dwFileSystemFlags > MAX_PATH - 7) 1022 pszPath[MAX_PATH-7] = L'\0'; 1023 } 1024 } 1025 } 1026 wcscat(pszPath, L" ("); 1027 wszDrive[2] = L'\0'; 1028 wcscat(pszPath, wszDrive); 1029 wcscat(pszPath, L")"); 1030 } 1031 1032 if (SUCCEEDED(hr)) 1033 { 1034 strRet->uType = STRRET_WSTR; 1035 strRet->pOleStr = pszPath; 1036 } 1037 else 1038 CoTaskMemFree(pszPath); 1039 1040 TRACE("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr)); 1041 return hr; 1042 } 1043 1044 /************************************************************************** 1045 * CDrivesFolder::SetNameOf 1046 * Changes the name of a file object or subfolder, possibly changing its item 1047 * identifier in the process. 1048 * 1049 * PARAMETERS 1050 * hwndOwner [in] Owner window for output 1051 * pidl [in] simple pidl of item to change 1052 * lpszName [in] the items new display name 1053 * dwFlags [in] SHGNO formatting flags 1054 * ppidlOut [out] simple pidl returned 1055 */ 1056 HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, 1057 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) 1058 { 1059 WCHAR szName[30]; 1060 1061 if (_ILIsDrive(pidl)) 1062 { 1063 if (_ILSimpleGetTextW(pidl, szName, _countof(szName))) 1064 SetVolumeLabelW(szName, lpName); 1065 if (pPidlOut) 1066 *pPidlOut = _ILCreateDrive(szName); 1067 return S_OK; 1068 } 1069 1070 return m_regFolder->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut); 1071 } 1072 1073 HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid) 1074 { 1075 FIXME("(%p)\n", this); 1076 return E_NOTIMPL; 1077 } 1078 1079 HRESULT WINAPI CDrivesFolder::EnumSearches(IEnumExtraSearch ** ppenum) 1080 { 1081 FIXME("(%p)\n", this); 1082 return E_NOTIMPL; 1083 } 1084 1085 HRESULT WINAPI CDrivesFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay) 1086 { 1087 TRACE("(%p)\n", this); 1088 1089 if (pSort) 1090 *pSort = 0; 1091 if (pDisplay) 1092 *pDisplay = 0; 1093 return S_OK; 1094 } 1095 1096 HRESULT WINAPI CDrivesFolder::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF * pcsFlags) 1097 { 1098 TRACE("(%p)\n", this); 1099 1100 if (!pcsFlags || iColumn >= _countof(MyComputerSFHeader)) 1101 return E_INVALIDARG; 1102 *pcsFlags = MyComputerSFHeader[iColumn].colstate; 1103 return S_OK; 1104 } 1105 1106 HRESULT WINAPI CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID * pscid, VARIANT * pv) 1107 { 1108 FIXME("(%p)\n", this); 1109 return E_NOTIMPL; 1110 } 1111 1112 HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) 1113 { 1114 HRESULT hr; 1115 1116 TRACE("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd); 1117 1118 if (!psd || iColumn >= _countof(MyComputerSFHeader)) 1119 return E_INVALIDARG; 1120 1121 if (!pidl) 1122 { 1123 psd->fmt = MyComputerSFHeader[iColumn].fmt; 1124 psd->cxChar = MyComputerSFHeader[iColumn].cxChar; 1125 return SHSetStrRet(&psd->str, MyComputerSFHeader[iColumn].colnameid); 1126 } 1127 else if (!_ILIsDrive(pidl)) 1128 { 1129 switch (MyComputerSFHeader[iColumn].colnameid) 1130 { 1131 case IDS_SHV_COLUMN_NAME: 1132 case IDS_SHV_COLUMN_TYPE: 1133 return m_regFolder->GetDetailsOf(pidl, iColumn, psd); 1134 case IDS_SHV_COLUMN_DISK_CAPACITY: 1135 case IDS_SHV_COLUMN_DISK_AVAILABLE: 1136 return SHSetStrRet(&psd->str, ""); /* blank col */ 1137 case IDS_SHV_COLUMN_COMMENTS: 1138 return m_regFolder->GetDetailsOf(pidl, 2, psd); /* 2 = comments */ 1139 DEFAULT_UNREACHABLE; 1140 } 1141 } 1142 else 1143 { 1144 ULARGE_INTEGER ulTotalBytes, ulFreeBytes; 1145 CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName; 1146 UINT DriveType = GetDriveTypeA(pszDrive); 1147 if (DriveType > DRIVE_RAMDISK) 1148 DriveType = DRIVE_FIXED; 1149 1150 switch (MyComputerSFHeader[iColumn].colnameid) 1151 { 1152 case IDS_SHV_COLUMN_NAME: 1153 hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str); 1154 break; 1155 case IDS_SHV_COLUMN_TYPE: 1156 if (DriveType == DRIVE_REMOVABLE && !IsDriveFloppyA(pszDrive)) 1157 hr = SHSetStrRet(&psd->str, IDS_DRIVE_REMOVABLE); 1158 else 1159 hr = SHSetStrRet(&psd->str, iDriveTypeIds[DriveType]); 1160 break; 1161 case IDS_SHV_COLUMN_DISK_CAPACITY: 1162 case IDS_SHV_COLUMN_DISK_AVAILABLE: 1163 psd->str.cStr[0] = 0x00; 1164 psd->str.uType = STRRET_CSTR; 1165 if (GetVolumeInformationA(pszDrive, NULL, 0, NULL, NULL, NULL, NULL, 0)) 1166 { 1167 GetDiskFreeSpaceExA(pszDrive, &ulFreeBytes, &ulTotalBytes, NULL); 1168 if (iColumn == 2) 1169 StrFormatByteSize64A(ulTotalBytes.QuadPart, psd->str.cStr, MAX_PATH); 1170 else 1171 StrFormatByteSize64A(ulFreeBytes.QuadPart, psd->str.cStr, MAX_PATH); 1172 } 1173 hr = S_OK; 1174 break; 1175 case IDS_SHV_COLUMN_COMMENTS: 1176 hr = SHSetStrRet(&psd->str, ""); /* FIXME: comments */ 1177 break; 1178 DEFAULT_UNREACHABLE; 1179 } 1180 } 1181 1182 return hr; 1183 } 1184 1185 HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid) 1186 { 1187 FIXME("(%p)\n", this); 1188 return E_NOTIMPL; 1189 } 1190 1191 /************************************************************************ 1192 * CDrivesFolder::GetClassID 1193 */ 1194 HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId) 1195 { 1196 TRACE("(%p)\n", this); 1197 1198 if (!lpClassId) 1199 return E_POINTER; 1200 1201 *lpClassId = CLSID_MyComputer; 1202 return S_OK; 1203 } 1204 1205 /************************************************************************ 1206 * CDrivesFolder::Initialize 1207 * 1208 * NOTES: it makes no sense to change the pidl 1209 */ 1210 HRESULT WINAPI CDrivesFolder::Initialize(PCIDLIST_ABSOLUTE pidl) 1211 { 1212 return S_OK; 1213 } 1214 1215 /************************************************************************** 1216 * CDrivesFolder::GetCurFolder 1217 */ 1218 HRESULT WINAPI CDrivesFolder::GetCurFolder(PIDLIST_ABSOLUTE *pidl) 1219 { 1220 TRACE("(%p)->(%p)\n", this, pidl); 1221 1222 if (!pidl) 1223 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */ 1224 1225 *pidl = ILClone(pidlRoot); 1226 return S_OK; 1227 } 1228 1229 /************************************************************************** 1230 * CDrivesFolder::ShouldShow 1231 */ 1232 HRESULT WINAPI CDrivesFolder::ShouldShow(IShellFolder *psf, PCIDLIST_ABSOLUTE pidlFolder, PCUITEMID_CHILD pidlItem) 1233 { 1234 if (const CLSID* pClsid = IsRegItem(pidlItem)) 1235 return SHELL32_IsShellFolderNamespaceItemHidden(L"HideMyComputerIcons", *pClsid) ? S_FALSE : S_OK; 1236 return S_OK; 1237 } 1238 1239 /************************************************************************/ 1240 /* IContextMenuCB interface */ 1241 1242 HRESULT WINAPI CDrivesFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam) 1243 { 1244 enum { IDC_PROPERTIES }; 1245 /* no data object means no selection */ 1246 if (!pdtobj) 1247 { 1248 if (uMsg == DFM_INVOKECOMMAND && wParam == IDC_PROPERTIES) 1249 { 1250 // "System" properties 1251 return SHELL_ExecuteControlPanelCPL(hwndOwner, L"sysdm.cpl") ? S_OK : E_FAIL; 1252 } 1253 else if (uMsg == DFM_MERGECONTEXTMENU) // TODO: DFM_MERGECONTEXTMENU_BOTTOM 1254 { 1255 QCMINFO *pqcminfo = (QCMINFO *)lParam; 1256 HMENU hpopup = CreatePopupMenu(); 1257 _InsertMenuItemW(hpopup, 0, TRUE, IDC_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED); 1258 pqcminfo->idCmdFirst = Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR); 1259 DestroyMenu(hpopup); 1260 return S_OK; 1261 } 1262 } 1263 return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg); 1264 } 1265