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