1 /* 2 * Virtual Desktop Folder 3 * 4 * Copyright 1997 Marcus Meissner 5 * Copyright 1998, 1999, 2002 Juergen Schmied 6 * Copyright 2009 Andrew Hill 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 23 #include <precomp.h> 24 #include "CFSFolder.h" // Only for CFSFolder::*FSColumn* helpers! 25 26 WINE_DEFAULT_DEBUG_CHANNEL(shell); 27 28 static BOOL IsSelf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl) 29 { 30 return cidl == 0 || (cidl == 1 && apidl && _ILIsEmpty(apidl[0])); 31 } 32 33 STDMETHODIMP 34 CDesktopFolder::ShellUrlParseDisplayName( 35 HWND hwndOwner, 36 LPBC pbc, 37 LPOLESTR lpszDisplayName, 38 DWORD *pchEaten, 39 PIDLIST_RELATIVE *ppidl, 40 DWORD *pdwAttributes) 41 { 42 LPWSTR pch; 43 INT cch, csidl; 44 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 45 PARSEDURLW ParsedURL = { sizeof(ParsedURL) }; 46 47 ::ParseURLW(lpszDisplayName, &ParsedURL); 48 49 DWORD attrs = (pdwAttributes ? *pdwAttributes : 0) | SFGAO_STREAM; 50 if (ParsedURL.pszSuffix[0] == L':' && ParsedURL.pszSuffix[1] == L':') // It begins from "::" 51 { 52 CComPtr<IShellFolder> psfDesktop; 53 hr = SHGetDesktopFolder(&psfDesktop); 54 if (SUCCEEDED(hr)) 55 { 56 CComPtr<IBindCtx> pBindCtx; 57 hr = ::CreateBindCtx(0, &pBindCtx); 58 if (SUCCEEDED(hr)) 59 { 60 BIND_OPTS BindOps = { sizeof(BindOps) }; 61 BindOps.grfMode = STGM_CREATE; 62 pBindCtx->SetBindOptions(&BindOps); 63 hr = psfDesktop->ParseDisplayName(hwndOwner, pBindCtx, 64 (LPWSTR)ParsedURL.pszSuffix, 65 pchEaten, ppidl, &attrs); 66 } 67 } 68 } 69 else 70 { 71 csidl = Shell_ParseSpecialFolder(ParsedURL.pszSuffix, &pch, &cch); 72 if (csidl == -1) 73 { 74 ERR("\n"); 75 return hr; 76 } 77 78 CComHeapPtr<ITEMIDLIST> pidlLocation; 79 hr = SHGetFolderLocation(hwndOwner, (csidl | CSIDL_FLAG_CREATE), NULL, 0, &pidlLocation); 80 if (FAILED_UNEXPECTEDLY(hr)) 81 return hr; 82 83 if (pch && *pch) 84 { 85 CComPtr<IShellFolder> psfFolder; 86 hr = SHBindToObject(NULL, pidlLocation, IID_PPV_ARG(IShellFolder, &psfFolder)); 87 if (SUCCEEDED(hr)) 88 { 89 CComHeapPtr<ITEMIDLIST> pidlNew; 90 hr = psfFolder->ParseDisplayName(hwndOwner, pbc, pch, pchEaten, &pidlNew, &attrs); 91 if (SUCCEEDED(hr)) 92 { 93 hr = SHILCombine(pidlLocation, pidlNew, ppidl); 94 if (pchEaten) 95 *pchEaten += cch; 96 } 97 } 98 } 99 else 100 { 101 if (attrs) 102 hr = SHGetNameAndFlagsW(pidlLocation, 0, NULL, 0, &attrs); 103 104 if (SUCCEEDED(hr)) 105 { 106 if (pchEaten) 107 *pchEaten = cch; 108 *ppidl = pidlLocation.Detach(); 109 } 110 } 111 } 112 113 // FIXME: SHWindowsPolicy 114 if (SUCCEEDED(hr) && (attrs & SFGAO_STREAM) && 115 !BindCtx_ContainsObject(pbc, STR_PARSE_SHELL_PROTOCOL_TO_FILE_OBJECTS)) 116 { 117 ILFree(*ppidl); 118 *ppidl = NULL; 119 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 120 } 121 122 if (pdwAttributes) 123 *pdwAttributes = attrs; 124 125 // FIXME: SHWindowsPolicy 126 if (FAILED(hr) && !Shell_FailForceReturn(hr)) 127 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 128 129 return hr; 130 } 131 132 STDMETHODIMP 133 CDesktopFolder::HttpUrlParseDisplayName( 134 HWND hwndOwner, 135 LPBC pbc, 136 LPOLESTR lpszDisplayName, 137 DWORD *pchEaten, 138 PIDLIST_RELATIVE *ppidl, 139 DWORD *pdwAttributes) 140 { 141 FIXME("\n"); 142 return E_NOTIMPL; // FIXME 143 } 144 145 /* 146 CDesktopFolder should create two file system folders internally, one representing the 147 user's desktop folder, and the other representing the common desktop folder. It should 148 also create a CRegFolder to represent the virtual items that exist only in the registry. 149 The CRegFolder is aggregated by the CDesktopFolder, and queries for the CLSID_IShellFolder, 150 CLSID_IShellFolder2, or CLSID_IShellIconOverlay interfaces prefer the CRegFolder 151 implementation. 152 The CDesktopFolderEnum class should create two enumerators, one for each of the file 153 system folders, and enumerate the contents of each folder. Since the CRegFolder 154 implementation of IShellFolder::EnumObjects enumerates the virtual items, the 155 CDesktopFolderEnum is only responsible for returning the physical items. 156 CDesktopFolderEnum is incorrect where it filters My Computer from the enumeration 157 if the new start menu is used. The CDesktopViewCallback is responsible for filtering 158 it from the view by handling the IncludeObject query to return S_FALSE. The enumerator 159 always shows My Computer. 160 */ 161 162 /* Undocumented functions from shdocvw */ 163 extern "C" HRESULT WINAPI IEParseDisplayNameWithBCW(DWORD codepage, LPCWSTR lpszDisplayName, LPBC pbc, LPITEMIDLIST *ppidl); 164 165 static const WCHAR ClassicStartMenuW[] = L"SOFTWARE\\Microsoft\\Windows\\" 166 L"CurrentVersion\\Explorer\\HideDesktopIcons\\ClassicStartMenu"; 167 168 static INT 169 IsNamespaceExtensionHidden(const WCHAR *iid) 170 { 171 DWORD Result, dwResult; 172 dwResult = sizeof(DWORD); 173 174 if (RegGetValueW(HKEY_CURRENT_USER, /* FIXME use NewStartPanel when activated */ 175 ClassicStartMenuW, 176 iid, 177 RRF_RT_DWORD, 178 NULL, 179 &Result, 180 &dwResult) != ERROR_SUCCESS) 181 { 182 return -1; 183 } 184 185 return Result; 186 } 187 188 static INT IsNamespaceExtensionHidden(LPCITEMIDLIST pidl) 189 { 190 GUID const *clsid = _ILGetGUIDPointer (pidl); 191 if (!clsid) 192 return -1; 193 194 WCHAR pwszGuid[CHARS_IN_GUID]; 195 SHELL32_GUIDToStringW(*clsid, pwszGuid); 196 return IsNamespaceExtensionHidden(pwszGuid); 197 } 198 199 class CDesktopFolderEnum : 200 public CEnumIDListBase 201 { 202 private: 203 // CComPtr fDesktopEnumerator; 204 // CComPtr fCommonDesktopEnumerator; 205 public: 206 207 void AddItemsFromClassicStartMenuKey(HKEY hKeyRoot) 208 { 209 DWORD dwResult; 210 HKEY hkey; 211 DWORD j = 0, dwVal, Val, dwType, dwIID; 212 LONG r; 213 WCHAR iid[50]; 214 LPITEMIDLIST pidl; 215 216 dwResult = RegOpenKeyExW(hKeyRoot, ClassicStartMenuW, 0, KEY_READ, &hkey); 217 if (dwResult != ERROR_SUCCESS) 218 return; 219 220 while(1) 221 { 222 dwVal = sizeof(Val); 223 dwIID = sizeof(iid) / sizeof(WCHAR); 224 225 r = RegEnumValueW(hkey, j++, iid, &dwIID, NULL, &dwType, (LPBYTE)&Val, &dwVal); 226 if (r != ERROR_SUCCESS) 227 break; 228 229 if (Val == 0 && dwType == REG_DWORD) 230 { 231 pidl = _ILCreateGuidFromStrW(iid); 232 if (pidl != NULL) 233 { 234 if (!HasItemWithCLSID(pidl)) 235 AddToEnumList(pidl); 236 else 237 SHFree(pidl); 238 } 239 } 240 } 241 RegCloseKey(hkey); 242 } 243 244 HRESULT WINAPI Initialize(DWORD dwFlags,IEnumIDList * pRegEnumerator, IEnumIDList *pDesktopEnumerator, IEnumIDList *pCommonDesktopEnumerator) 245 { 246 BOOL ret = TRUE; 247 LPITEMIDLIST pidl; 248 249 static const WCHAR MyDocumentsClassString[] = L"{450D8FBA-AD25-11D0-98A8-0800361B1103}"; 250 static const WCHAR InternetClassString[] = L"{871C5380-42A0-1069-A2EA-08002B30309D}"; 251 252 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags); 253 254 /* enumerate the root folders */ 255 if (dwFlags & SHCONTF_FOLDERS) 256 { 257 AddToEnumList(_ILCreateMyComputer()); 258 if (IsNamespaceExtensionHidden(MyDocumentsClassString) < 1) 259 AddToEnumList(_ILCreateMyDocuments()); 260 if (IsNamespaceExtensionHidden(InternetClassString) < 1) 261 AddToEnumList(_ILCreateIExplore()); 262 263 DWORD dwFetched; 264 while((S_OK == pRegEnumerator->Next(1, &pidl, &dwFetched)) && dwFetched) 265 { 266 if (IsNamespaceExtensionHidden(pidl) < 1) 267 { 268 if (!HasItemWithCLSID(pidl)) 269 AddToEnumList(pidl); 270 else 271 SHFree(pidl); 272 } 273 } 274 AddItemsFromClassicStartMenuKey(HKEY_LOCAL_MACHINE); 275 AddItemsFromClassicStartMenuKey(HKEY_CURRENT_USER); 276 } 277 278 /* Enumerate the items in the two fs folders */ 279 AppendItemsFromEnumerator(pDesktopEnumerator); 280 AppendItemsFromEnumerator(pCommonDesktopEnumerator); 281 282 return ret ? S_OK : E_FAIL; 283 } 284 285 286 BEGIN_COM_MAP(CDesktopFolderEnum) 287 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) 288 END_COM_MAP() 289 }; 290 291 int SHELL_ConfirmMsgBox(HWND hWnd, LPWSTR lpszText, LPWSTR lpszCaption, HICON hIcon, BOOL bYesToAll); 292 293 static const DWORD dwDesktopAttributes = 294 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | 295 SFGAO_STORAGEANCESTOR | SFGAO_HASPROPSHEET | SFGAO_STORAGE; 296 static const DWORD dwMyComputerAttributes = 297 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | 298 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK; 299 static DWORD dwMyNetPlacesAttributes = 300 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | 301 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK; 302 303 CDesktopFolder::CDesktopFolder() : 304 sPathTarget(NULL), 305 pidlRoot(NULL) 306 { 307 } 308 309 CDesktopFolder::~CDesktopFolder() 310 { 311 } 312 313 HRESULT WINAPI CDesktopFolder::FinalConstruct() 314 { 315 WCHAR szMyPath[MAX_PATH]; 316 HRESULT hr; 317 318 /* Create the root pidl */ 319 pidlRoot = _ILCreateDesktop(); 320 if (!pidlRoot) 321 return E_OUTOFMEMORY; 322 323 /* Create the inner fs folder */ 324 hr = SHELL32_CoCreateInitSF(pidlRoot, 325 &CLSID_ShellFSFolder, 326 CSIDL_DESKTOPDIRECTORY, 327 IID_PPV_ARG(IShellFolder2, &m_DesktopFSFolder)); 328 if (FAILED_UNEXPECTEDLY(hr)) 329 return hr; 330 331 /* Create the inner shared fs folder. Dont fail on failure. */ 332 hr = SHELL32_CoCreateInitSF(pidlRoot, 333 &CLSID_ShellFSFolder, 334 CSIDL_COMMON_DESKTOPDIRECTORY, 335 IID_PPV_ARG(IShellFolder2, &m_SharedDesktopFSFolder)); 336 if (FAILED_UNEXPECTEDLY(hr)) 337 return hr; 338 339 /* Create the inner reg folder */ 340 hr = CRegFolder_CreateInstance(&CLSID_ShellDesktop, 341 pidlRoot, 342 L"", 343 L"Desktop", 344 IID_PPV_ARG(IShellFolder2, &m_regFolder)); 345 if (FAILED_UNEXPECTEDLY(hr)) 346 return hr; 347 348 /* Cache the path to the user desktop directory */ 349 if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE )) 350 return E_UNEXPECTED; 351 352 sPathTarget = (LPWSTR)SHAlloc((wcslen(szMyPath) + 1) * sizeof(WCHAR)); 353 if (!sPathTarget) 354 return E_OUTOFMEMORY; 355 356 wcscpy(sPathTarget, szMyPath); 357 return S_OK; 358 } 359 360 HRESULT CDesktopFolder::_GetSFFromPidl(LPCITEMIDLIST pidl, IShellFolder2** psf) 361 { 362 WCHAR szFileName[MAX_PATH]; 363 364 if (_ILIsSpecialFolder(pidl)) 365 return m_regFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf)); 366 367 lstrcpynW(szFileName, sPathTarget, MAX_PATH - 1); 368 PathAddBackslashW(szFileName); 369 int cLen = wcslen(szFileName); 370 371 if (!_ILSimpleGetTextW(pidl, szFileName + cLen, MAX_PATH - cLen)) 372 return E_FAIL; 373 374 if (GetFileAttributes(szFileName) == INVALID_FILE_ATTRIBUTES) 375 return m_SharedDesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf)); 376 else 377 return m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf)); 378 } 379 380 HRESULT CDesktopFolder::_ParseDisplayNameByParent( 381 HWND hwndOwner, 382 LPBC pbc, 383 LPOLESTR lpszDisplayName, 384 DWORD *pchEaten, 385 PIDLIST_RELATIVE *ppidl, 386 DWORD *pdwAttributes) 387 { 388 if (pchEaten) 389 *pchEaten = 0; 390 391 CComHeapPtr<ITEMIDLIST> pidlParent; 392 BOOL bPath = FALSE; 393 WCHAR wch = *lpszDisplayName; 394 if (((L'A' <= wch && wch <= L'Z') || (L'a' <= wch && wch <= L'z')) && 395 (lpszDisplayName[1] == L':')) 396 { 397 // "C:..." 398 bPath = TRUE; 399 pidlParent.Attach(_ILCreateMyComputer()); 400 } 401 else if (PathIsUNCW(lpszDisplayName)) // "\\\\..." 402 { 403 bPath = TRUE; 404 pidlParent.Attach(_ILCreateNetwork()); 405 } 406 407 if (bPath) 408 { 409 if (!pidlParent) 410 return E_OUTOFMEMORY; 411 412 CComPtr<IShellFolder> pParentFolder; 413 SHBindToObject(NULL, pidlParent, IID_PPV_ARG(IShellFolder, &pParentFolder)); 414 415 CComHeapPtr<ITEMIDLIST> pidlChild; 416 HRESULT hr = pParentFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, 417 pchEaten, &pidlChild, pdwAttributes); 418 if (FAILED(hr)) 419 return hr; 420 421 *ppidl = ILCombine(pidlParent, pidlChild); 422 return (*ppidl ? S_OK : E_OUTOFMEMORY); 423 } 424 425 if (!UrlIsW(lpszDisplayName, URLIS_URL) || SHSkipJunctionBinding(pbc, NULL)) 426 return E_INVALIDARG; 427 428 // Now lpszDisplayName is a URL 429 PARSEDURLW ParsedURL = { sizeof(ParsedURL) }; 430 ::ParseURLW(lpszDisplayName, &ParsedURL); 431 432 switch (ParsedURL.nScheme) 433 { 434 case URL_SCHEME_FILE: // "file:..." 435 { 436 // Convert "file://..." to a normal path 437 WCHAR szPath[MAX_PATH]; 438 DWORD cchPath = _countof(szPath); 439 HRESULT hr = PathCreateFromUrlW(lpszDisplayName, szPath, &cchPath, 0); 440 if (FAILED_UNEXPECTEDLY(hr)) 441 return hr; 442 443 CComPtr<IShellFolder> psfDesktop; 444 hr = SHGetDesktopFolder(&psfDesktop); 445 if (FAILED_UNEXPECTEDLY(hr)) 446 return hr; 447 448 // Parse by desktop folder 449 return psfDesktop->ParseDisplayName(hwndOwner, pbc, szPath, pchEaten, ppidl, 450 pdwAttributes); 451 } 452 case URL_SCHEME_HTTP: // "http:..." 453 case URL_SCHEME_HTTPS: // "https:..." 454 { 455 if (!BindCtx_ContainsObject(pbc, STR_PARSE_PREFER_FOLDER_BROWSING)) 456 return E_INVALIDARG; 457 458 return HttpUrlParseDisplayName(hwndOwner, 459 pbc, 460 lpszDisplayName, 461 pchEaten, 462 ppidl, 463 pdwAttributes); 464 } 465 case URL_SCHEME_SHELL: // "shell:..." 466 { 467 return ShellUrlParseDisplayName(hwndOwner, 468 pbc, 469 lpszDisplayName, 470 pchEaten, 471 ppidl, 472 pdwAttributes); 473 } 474 case URL_SCHEME_MSSHELLROOTED: 475 case URL_SCHEME_MSSHELLIDLIST: 476 { 477 WARN("We don't support 'ms-shell-rooted:' and 'ms-shell-idlist:' schemes\n"); 478 break; 479 } 480 default: 481 { 482 TRACE("Scheme: %u\n", ParsedURL.nScheme); 483 break; 484 } 485 } 486 487 return E_INVALIDARG; 488 } 489 490 /************************************************************************** 491 * CDesktopFolder::ParseDisplayName 492 * 493 * NOTES 494 * "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds 495 * to MyComputer 496 */ 497 HRESULT WINAPI CDesktopFolder::ParseDisplayName( 498 HWND hwndOwner, 499 LPBC pbc, 500 LPOLESTR lpszDisplayName, 501 DWORD *pchEaten, 502 PIDLIST_RELATIVE *ppidl, 503 DWORD *pdwAttributes) 504 { 505 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", 506 this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName), 507 pchEaten, ppidl, pdwAttributes); 508 509 if (!ppidl) 510 return E_INVALIDARG; 511 512 *ppidl = NULL; 513 514 if (!lpszDisplayName) 515 return E_INVALIDARG; 516 517 if (!*lpszDisplayName) 518 { 519 *ppidl = _ILCreateMyComputer(); 520 return (*ppidl ? S_OK : E_OUTOFMEMORY); 521 } 522 523 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':') 524 { 525 return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, 526 pdwAttributes); 527 } 528 529 HRESULT hr = _ParseDisplayNameByParent(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, 530 pdwAttributes); 531 if (SUCCEEDED(hr)) 532 { 533 if (BindCtx_ContainsObject(pbc, STR_PARSE_TRANSLATE_ALIASES)) 534 { 535 CComHeapPtr<ITEMIDLIST> pidlAlias; 536 if (SUCCEEDED(Shell_TranslateIDListAlias(*ppidl, NULL, &pidlAlias, 0xFFFF))) 537 { 538 ILFree(*ppidl); 539 *ppidl = pidlAlias.Detach(); 540 } 541 } 542 543 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr); 544 return hr; 545 } 546 547 if (Shell_FailForceReturn(hr)) 548 return hr; 549 550 if (BindCtx_ContainsObject(pbc, STR_DONT_PARSE_RELATIVE)) 551 return E_INVALIDARG; 552 553 if (SHIsFileSysBindCtx(pbc, NULL) == S_OK) 554 return hr; 555 556 BIND_OPTS BindOps = { sizeof(BindOps) }; 557 BOOL bCreate = FALSE; 558 if (pbc && SUCCEEDED(pbc->GetBindOptions(&BindOps)) && (BindOps.grfMode & STGM_CREATE)) 559 { 560 BindOps.grfMode &= ~STGM_CREATE; 561 bCreate = TRUE; 562 pbc->SetBindOptions(&BindOps); 563 } 564 565 if (m_DesktopFSFolder) 566 { 567 hr = m_DesktopFSFolder->ParseDisplayName(hwndOwner, 568 pbc, 569 lpszDisplayName, 570 pchEaten, 571 ppidl, 572 pdwAttributes); 573 } 574 575 if (FAILED(hr) && m_SharedDesktopFSFolder) 576 { 577 hr = m_SharedDesktopFSFolder->ParseDisplayName(hwndOwner, 578 pbc, 579 lpszDisplayName, 580 pchEaten, 581 ppidl, 582 pdwAttributes); 583 } 584 585 if (FAILED(hr) && bCreate && m_DesktopFSFolder) 586 { 587 BindOps.grfMode |= STGM_CREATE; 588 pbc->SetBindOptions(&BindOps); 589 hr = m_DesktopFSFolder->ParseDisplayName(hwndOwner, 590 pbc, 591 lpszDisplayName, 592 pchEaten, 593 ppidl, 594 pdwAttributes); 595 } 596 597 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr); 598 599 return hr; 600 } 601 602 /************************************************************************** 603 * CDesktopFolder::EnumObjects 604 */ 605 HRESULT WINAPI CDesktopFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) 606 { 607 CComPtr<IEnumIDList> pRegEnumerator; 608 CComPtr<IEnumIDList> pDesktopEnumerator; 609 CComPtr<IEnumIDList> pCommonDesktopEnumerator; 610 HRESULT hr; 611 612 hr = m_regFolder->EnumObjects(hwndOwner, dwFlags, &pRegEnumerator); 613 if (FAILED(hr)) 614 ERR("EnumObjects for reg folder failed\n"); 615 616 hr = m_DesktopFSFolder->EnumObjects(hwndOwner, dwFlags, &pDesktopEnumerator); 617 if (FAILED(hr)) 618 ERR("EnumObjects for desktop fs folder failed\n"); 619 620 hr = m_SharedDesktopFSFolder->EnumObjects(hwndOwner, dwFlags, &pCommonDesktopEnumerator); 621 if (FAILED(hr)) 622 ERR("EnumObjects for shared desktop fs folder failed\n"); 623 624 return ShellObjectCreatorInit<CDesktopFolderEnum>(dwFlags,pRegEnumerator, pDesktopEnumerator, pCommonDesktopEnumerator, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); 625 } 626 627 /************************************************************************** 628 * CDesktopFolder::BindToObject 629 */ 630 HRESULT WINAPI CDesktopFolder::BindToObject( 631 PCUIDLIST_RELATIVE pidl, 632 LPBC pbcReserved, 633 REFIID riid, 634 LPVOID *ppvOut) 635 { 636 if (!pidl) 637 return E_INVALIDARG; 638 639 CComPtr<IShellFolder2> psf; 640 HRESULT hr = _GetSFFromPidl(pidl, &psf); 641 if (FAILED_UNEXPECTEDLY(hr)) 642 return hr; 643 644 return psf->BindToObject(pidl, pbcReserved, riid, ppvOut); 645 } 646 647 /************************************************************************** 648 * CDesktopFolder::BindToStorage 649 */ 650 HRESULT WINAPI CDesktopFolder::BindToStorage( 651 PCUIDLIST_RELATIVE pidl, 652 LPBC pbcReserved, 653 REFIID riid, 654 LPVOID *ppvOut) 655 { 656 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", 657 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut); 658 659 *ppvOut = NULL; 660 return E_NOTIMPL; 661 } 662 663 /************************************************************************** 664 * CDesktopFolder::CompareIDs 665 */ 666 HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) 667 { 668 bool bIsDesktopFolder1, bIsDesktopFolder2; 669 670 if (!pidl1 || !pidl2) 671 { 672 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2); 673 return E_INVALIDARG; 674 } 675 676 bIsDesktopFolder1 = _ILIsDesktop(pidl1); 677 bIsDesktopFolder2 = _ILIsDesktop(pidl2); 678 if (bIsDesktopFolder1 || bIsDesktopFolder2) 679 return MAKE_COMPARE_HRESULT(bIsDesktopFolder1 - bIsDesktopFolder2); 680 681 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2)) 682 return m_regFolder->CompareIDs(lParam, pidl1, pidl2); 683 684 return m_DesktopFSFolder->CompareIDs(lParam, pidl1, pidl2); 685 } 686 687 /************************************************************************** 688 * CDesktopFolder::CreateViewObject 689 */ 690 HRESULT WINAPI CDesktopFolder::CreateViewObject( 691 HWND hwndOwner, 692 REFIID riid, 693 LPVOID *ppvOut) 694 { 695 HRESULT hr = E_INVALIDARG; 696 697 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", 698 this, hwndOwner, shdebugstr_guid (&riid), ppvOut); 699 700 if (!ppvOut) 701 return hr; 702 703 *ppvOut = NULL; 704 705 if (IsEqualIID (riid, IID_IDropTarget)) 706 { 707 hr = m_DesktopFSFolder->CreateViewObject(hwndOwner, riid, ppvOut); 708 } 709 else if (IsEqualIID (riid, IID_IContextMenu)) 710 { 711 HKEY hKeys[16]; 712 UINT cKeys = 0; 713 AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys); 714 715 DEFCONTEXTMENU dcm; 716 dcm.hwnd = hwndOwner; 717 dcm.pcmcb = this; 718 dcm.pidlFolder = pidlRoot; 719 dcm.psf = this; 720 dcm.cidl = 0; 721 dcm.apidl = NULL; 722 dcm.cKeys = cKeys; 723 dcm.aKeys = hKeys; 724 dcm.punkAssociationInfo = NULL; 725 hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut); 726 } 727 else if (IsEqualIID (riid, IID_IShellView)) 728 { 729 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this}; 730 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut); 731 } 732 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut); 733 return hr; 734 } 735 736 /************************************************************************** 737 * CDesktopFolder::GetAttributesOf 738 */ 739 HRESULT WINAPI CDesktopFolder::GetAttributesOf( 740 UINT cidl, 741 PCUITEMID_CHILD_ARRAY apidl, 742 DWORD *rgfInOut) 743 { 744 HRESULT hr = S_OK; 745 746 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", 747 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0); 748 749 if (cidl && !apidl) 750 return E_INVALIDARG; 751 752 if (*rgfInOut == 0) 753 *rgfInOut = ~0; 754 755 if(cidl == 0) 756 *rgfInOut &= dwDesktopAttributes; 757 else 758 { 759 /* TODO: always add SFGAO_CANLINK */ 760 for (UINT i = 0; i < cidl; ++i) 761 { 762 pdump(*apidl); 763 if (_ILIsDesktop(*apidl)) 764 *rgfInOut &= dwDesktopAttributes; 765 else if (_ILIsMyComputer(apidl[i])) 766 *rgfInOut &= dwMyComputerAttributes; 767 else if (_ILIsNetHood(apidl[i])) 768 *rgfInOut &= dwMyNetPlacesAttributes; 769 else if (_ILIsFolder(apidl[i]) || _ILIsValue(apidl[i]) || _ILIsSpecialFolder(apidl[i])) 770 { 771 CComPtr<IShellFolder2> psf; 772 HRESULT hr = _GetSFFromPidl(apidl[i], &psf); 773 if (FAILED_UNEXPECTEDLY(hr)) 774 continue; 775 776 psf->GetAttributesOf(1, &apidl[i], rgfInOut); 777 } 778 else 779 ERR("Got an unknown pidl type!!!\n"); 780 } 781 } 782 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */ 783 *rgfInOut &= ~SFGAO_VALIDATE; 784 785 TRACE("-- result=0x%08x\n", *rgfInOut); 786 787 return hr; 788 } 789 790 /************************************************************************** 791 * CDesktopFolder::GetUIObjectOf 792 * 793 * PARAMETERS 794 * HWND hwndOwner, //[in ] Parent window for any output 795 * UINT cidl, //[in ] array size 796 * LPCITEMIDLIST* apidl, //[in ] simple pidl array 797 * REFIID riid, //[in ] Requested Interface 798 * UINT* prgfInOut, //[ ] reserved 799 * LPVOID* ppvObject) //[out] Resulting Interface 800 * 801 */ 802 HRESULT WINAPI CDesktopFolder::GetUIObjectOf( 803 HWND hwndOwner, 804 UINT cidl, 805 PCUITEMID_CHILD_ARRAY apidl, 806 REFIID riid, 807 UINT *prgfInOut, 808 LPVOID *ppvOut) 809 { 810 LPVOID pObj = NULL; 811 HRESULT hr = E_INVALIDARG; 812 813 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", 814 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut); 815 816 if (!ppvOut) 817 return hr; 818 *ppvOut = NULL; 819 820 BOOL self = IsSelf(cidl, apidl); 821 if (cidl == 1 && !_ILIsSpecialFolder(apidl[0]) && !self) 822 { 823 CComPtr<IShellFolder2> psf; 824 HRESULT hr = _GetSFFromPidl(apidl[0], &psf); 825 if (FAILED_UNEXPECTEDLY(hr)) 826 return hr; 827 828 return psf->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut); 829 } 830 831 if (IsEqualIID (riid, IID_IContextMenu)) 832 { 833 // FIXME: m_regFolder vs AddFSClassKeysToArray is incorrect when the selection includes both regitems and FS items 834 if (!self && cidl > 0 && _ILIsSpecialFolder(apidl[0])) 835 { 836 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); 837 } 838 else 839 { 840 /* Do not use the context menu of the CFSFolder here. */ 841 /* We need to pass a pointer of the CDesktopFolder so as the data object that the context menu gets is rooted to the desktop */ 842 /* Otherwise operations like that involve items from both user and shared desktop will not work */ 843 HKEY hKeys[16]; 844 UINT cKeys = 0; 845 if (self) 846 { 847 AddClsidKeyToArray(CLSID_ShellDesktop, hKeys, &cKeys); 848 AddClassKeyToArray(L"Folder", hKeys, &cKeys); 849 } 850 else if (cidl > 0) 851 { 852 AddFSClassKeysToArray(cidl, apidl, hKeys, &cKeys); 853 } 854 855 DEFCONTEXTMENU dcm; 856 dcm.hwnd = hwndOwner; 857 dcm.pcmcb = this; 858 dcm.pidlFolder = pidlRoot; 859 dcm.psf = this; 860 dcm.cidl = cidl; 861 dcm.apidl = apidl; 862 dcm.cKeys = cKeys; 863 dcm.aKeys = hKeys; 864 dcm.punkAssociationInfo = NULL; 865 hr = SHCreateDefaultContextMenu (&dcm, riid, &pObj); 866 } 867 } 868 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1)) 869 { 870 hr = IDataObject_Constructor( hwndOwner, pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj); 871 } 872 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1)) 873 { 874 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); 875 } 876 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1)) 877 { 878 CComPtr<IShellFolder> psfChild; 879 hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild)); 880 if (FAILED_UNEXPECTEDLY(hr)) 881 return hr; 882 883 return psfChild->CreateViewObject(NULL, riid, ppvOut); 884 } 885 else 886 hr = E_NOINTERFACE; 887 888 if (SUCCEEDED(hr) && !pObj) 889 hr = E_OUTOFMEMORY; 890 891 *ppvOut = pObj; 892 TRACE ("(%p)->hr=0x%08x\n", this, hr); 893 return hr; 894 } 895 896 /************************************************************************** 897 * CDesktopFolder::GetDisplayNameOf 898 * 899 * NOTES 900 * special case: pidl = null gives desktop-name back 901 */ 902 HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) 903 { 904 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet); 905 pdump (pidl); 906 907 if (!strRet) 908 return E_INVALIDARG; 909 910 if (!_ILIsPidlSimple (pidl)) 911 { 912 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet); 913 } 914 else if (_ILIsDesktop(pidl)) 915 { 916 if ((GET_SHGDN_RELATION(dwFlags) == SHGDN_NORMAL) && (GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING)) 917 return SHSetStrRet(strRet, sPathTarget); 918 else 919 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet); 920 } 921 922 /* file system folder or file rooted at the desktop */ 923 CComPtr<IShellFolder2> psf; 924 HRESULT hr = _GetSFFromPidl(pidl, &psf); 925 if (FAILED_UNEXPECTEDLY(hr)) 926 return hr; 927 928 return psf->GetDisplayNameOf(pidl, dwFlags, strRet); 929 } 930 931 /************************************************************************** 932 * CDesktopFolder::SetNameOf 933 * Changes the name of a file object or subfolder, possibly changing its item 934 * identifier in the process. 935 * 936 * PARAMETERS 937 * HWND hwndOwner, //[in ] Owner window for output 938 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change 939 * LPCOLESTR lpszName, //[in ] the items new display name 940 * DWORD dwFlags, //[in ] SHGNO formatting flags 941 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned 942 */ 943 HRESULT WINAPI CDesktopFolder::SetNameOf( 944 HWND hwndOwner, 945 PCUITEMID_CHILD pidl, /* simple pidl */ 946 LPCOLESTR lpName, 947 DWORD dwFlags, 948 PITEMID_CHILD *pPidlOut) 949 { 950 CComPtr<IShellFolder2> psf; 951 HRESULT hr = _GetSFFromPidl(pidl, &psf); 952 if (FAILED_UNEXPECTEDLY(hr)) 953 return hr; 954 955 return psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut); 956 } 957 958 HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid) 959 { 960 FIXME ("(%p)\n", this); 961 return E_NOTIMPL; 962 } 963 964 HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum) 965 { 966 FIXME ("(%p)\n", this); 967 return E_NOTIMPL; 968 } 969 970 HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) 971 { 972 TRACE ("(%p)\n", this); 973 974 if (pSort) 975 *pSort = 0; 976 if (pDisplay) 977 *pDisplay = 0; 978 979 return S_OK; 980 } 981 982 HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags) 983 { 984 HRESULT hr; 985 TRACE ("(%p)\n", this); 986 987 if (!pcsFlags) 988 return E_INVALIDARG; 989 990 hr = CFSFolder::GetDefaultFSColumnState(iColumn, *pcsFlags); 991 /* 992 // CDesktopFolder may override the flags if desired (future) 993 switch(iColumn) 994 { 995 case SHFSF_COL_FATTS: 996 *pcsFlags &= ~SHCOLSTATE_ONBYDEFAULT; 997 break; 998 } 999 */ 1000 return hr; 1001 } 1002 1003 HRESULT WINAPI CDesktopFolder::GetDetailsEx( 1004 PCUITEMID_CHILD pidl, 1005 const SHCOLUMNID *pscid, 1006 VARIANT *pv) 1007 { 1008 FIXME ("(%p)\n", this); 1009 1010 return E_NOTIMPL; 1011 } 1012 1013 /************************************************************************* 1014 * Column info functions. 1015 * CFSFolder.h provides defaults for us. 1016 */ 1017 HRESULT CDesktopFolder::GetColumnDetails(UINT iColumn, SHELLDETAILS &sd) 1018 { 1019 /* CDesktopFolder may override the flags and/or name if desired */ 1020 return CFSFolder::GetFSColumnDetails(iColumn, sd); 1021 } 1022 1023 HRESULT WINAPI CDesktopFolder::GetDetailsOf( 1024 PCUITEMID_CHILD pidl, 1025 UINT iColumn, 1026 SHELLDETAILS *psd) 1027 { 1028 if (!psd) 1029 return E_INVALIDARG; 1030 1031 if (!pidl) 1032 { 1033 return GetColumnDetails(iColumn, *psd); 1034 } 1035 1036 CComPtr<IShellFolder2> psf; 1037 HRESULT hr = _GetSFFromPidl(pidl, &psf); 1038 if (FAILED_UNEXPECTEDLY(hr)) 1039 return hr; 1040 1041 hr = psf->GetDetailsOf(pidl, iColumn, psd); 1042 if (FAILED_UNEXPECTEDLY(hr)) 1043 return hr; 1044 1045 return hr; 1046 } 1047 1048 HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) 1049 { 1050 FIXME ("(%p)\n", this); 1051 return E_NOTIMPL; 1052 } 1053 1054 HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId) 1055 { 1056 TRACE ("(%p)\n", this); 1057 1058 if (!lpClassId) 1059 return E_POINTER; 1060 1061 *lpClassId = CLSID_ShellDesktop; 1062 1063 return S_OK; 1064 } 1065 1066 HRESULT WINAPI CDesktopFolder::Initialize(PCIDLIST_ABSOLUTE pidl) 1067 { 1068 TRACE ("(%p)->(%p)\n", this, pidl); 1069 1070 if (!pidl) 1071 return S_OK; 1072 1073 return E_INVALIDARG; 1074 } 1075 1076 HRESULT WINAPI CDesktopFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl) 1077 { 1078 TRACE ("(%p)->(%p)\n", this, pidl); 1079 1080 if (!pidl) 1081 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */ 1082 *pidl = ILClone (pidlRoot); 1083 return S_OK; 1084 } 1085 1086 HRESULT WINAPI CDesktopFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam) 1087 { 1088 enum { IDC_PROPERTIES }; 1089 if (uMsg == DFM_INVOKECOMMAND && wParam == (pdtobj ? DFM_CMD_PROPERTIES : IDC_PROPERTIES)) 1090 { 1091 return SHELL_ExecuteControlPanelCPL(hwndOwner, L"desk.cpl") ? S_OK : E_FAIL; 1092 } 1093 else if (uMsg == DFM_MERGECONTEXTMENU && !pdtobj) // Add Properties item when called for directory background 1094 { 1095 QCMINFO *pqcminfo = (QCMINFO *)lParam; 1096 HMENU hpopup = CreatePopupMenu(); 1097 _InsertMenuItemW(hpopup, 0, TRUE, IDC_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED); 1098 pqcminfo->idCmdFirst = Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR); 1099 DestroyMenu(hpopup); 1100 return S_OK; 1101 } 1102 return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg); 1103 } 1104 1105 /************************************************************************* 1106 * SHGetDesktopFolder [SHELL32.@] 1107 */ 1108 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf) 1109 { 1110 HRESULT hres = S_OK; 1111 TRACE("\n"); 1112 1113 if(!psf) return E_INVALIDARG; 1114 *psf = NULL; 1115 hres = CDesktopFolder::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellFolder, psf)); 1116 1117 TRACE("-- %p->(%p)\n",psf, *psf); 1118 return hres; 1119 } 1120