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