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