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