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