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