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