1 /* 2 * Shell Menu Site 3 * 4 * Copyright 2014 David Quintana 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 #include "shellmenu.h" 21 #include <atlwin.h> 22 #include <shlwapi_undoc.h> 23 24 #include "CMergedFolder.h" 25 26 WINE_DEFAULT_DEBUG_CHANNEL(CMergedFolder); 27 28 struct LocalPidlInfo 29 { 30 BOOL shared; 31 IShellFolder * parent; 32 LPITEMIDLIST pidl; 33 LPITEMIDLIST pidl2; 34 LPCWSTR parseName; 35 }; 36 37 class CEnumMergedFolder : 38 public CComObjectRootEx<CComMultiThreadModelNoCS>, 39 public IEnumIDList 40 { 41 42 private: 43 CComPtr<IShellFolder> m_UserLocalFolder; 44 CComPtr<IShellFolder> m_AllUSersFolder; 45 46 HWND m_HwndOwner; 47 SHCONTF m_Flags; 48 49 HDSA m_hDsa; 50 UINT m_hDsaIndex; 51 UINT m_hDsaCount; 52 53 public: 54 CEnumMergedFolder(); 55 virtual ~CEnumMergedFolder(); 56 57 DECLARE_NOT_AGGREGATABLE(CEnumMergedFolder) 58 DECLARE_PROTECT_FINAL_CONSTRUCT() 59 60 BEGIN_COM_MAP(CEnumMergedFolder) 61 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) 62 END_COM_MAP() 63 64 int DsaDeleteCallback(LocalPidlInfo * info); 65 66 static int CALLBACK s_DsaDeleteCallback(void *pItem, void *pData); 67 68 HRESULT SetSources(IShellFolder * userLocal, IShellFolder * allUSers); 69 HRESULT Begin(HWND hwndOwner, SHCONTF flags); 70 HRESULT FindPidlInList(HWND hwndOwner, LPCITEMIDLIST pcidl, LocalPidlInfo * pinfo); 71 HRESULT FindByName(HWND hwndOwner, LPCWSTR strParsingName, LocalPidlInfo * pinfo); 72 73 virtual HRESULT STDMETHODCALLTYPE Next( 74 ULONG celt, 75 LPITEMIDLIST *rgelt, 76 ULONG *pceltFetched); 77 78 virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt); 79 virtual HRESULT STDMETHODCALLTYPE Reset(); 80 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumIDList **ppenum); 81 }; 82 83 CEnumMergedFolder::CEnumMergedFolder() : 84 m_UserLocalFolder(NULL), 85 m_AllUSersFolder(NULL), 86 m_HwndOwner(NULL), 87 m_Flags(0), 88 m_hDsa(NULL), 89 m_hDsaIndex(0), 90 m_hDsaCount(0) 91 { 92 } 93 94 CEnumMergedFolder::~CEnumMergedFolder() 95 { 96 DSA_DestroyCallback(m_hDsa, s_DsaDeleteCallback, this); 97 } 98 99 int CEnumMergedFolder::DsaDeleteCallback(LocalPidlInfo * info) 100 { 101 ILFree(info->pidl); 102 if (info->pidl2) 103 ILFree(info->pidl2); 104 CoTaskMemFree((LPVOID)info->parseName); 105 return 0; 106 } 107 108 int CALLBACK CEnumMergedFolder::s_DsaDeleteCallback(void *pItem, void *pData) 109 { 110 CEnumMergedFolder * mf = (CEnumMergedFolder*) pData; 111 LocalPidlInfo * item = (LocalPidlInfo*) pItem; 112 return mf->DsaDeleteCallback(item); 113 } 114 115 HRESULT CEnumMergedFolder::SetSources(IShellFolder * userLocal, IShellFolder * allUSers) 116 { 117 m_UserLocalFolder = userLocal; 118 m_AllUSersFolder = allUSers; 119 120 TRACE("SetSources %p %p\n", userLocal, allUSers); 121 return S_OK; 122 } 123 124 HRESULT CEnumMergedFolder::Begin(HWND hwndOwner, SHCONTF flags) 125 { 126 HRESULT hr; 127 LPITEMIDLIST pidl = NULL; 128 129 if (m_hDsa && m_HwndOwner == hwndOwner && m_Flags == flags) 130 { 131 return Reset(); 132 } 133 134 TRACE("Search conditions changed, recreating list...\n"); 135 136 CComPtr<IEnumIDList> userLocal; 137 CComPtr<IEnumIDList> allUsers; 138 139 hr = m_UserLocalFolder->EnumObjects(hwndOwner, flags, &userLocal); 140 if (FAILED_UNEXPECTEDLY(hr)) 141 return hr; 142 hr = m_AllUSersFolder->EnumObjects(hwndOwner, flags, &allUsers); 143 if (FAILED_UNEXPECTEDLY(hr)) 144 return hr; 145 146 if (!m_hDsa) 147 { 148 m_hDsa = DSA_Create(sizeof(LocalPidlInfo), 10); 149 } 150 151 DSA_EnumCallback(m_hDsa, s_DsaDeleteCallback, this); 152 DSA_DeleteAllItems(m_hDsa); 153 m_hDsaCount = 0; 154 155 // The sources are not ordered so load all of the items for the user folder first 156 TRACE("Loading Local entries...\n"); 157 for (;;) 158 { 159 hr = userLocal->Next(1, &pidl, NULL); 160 if (FAILED_UNEXPECTEDLY(hr)) 161 return hr; 162 163 if (hr == S_FALSE) 164 break; 165 166 LPWSTR name; 167 STRRET str = { STRRET_WSTR }; 168 hr = m_UserLocalFolder->GetDisplayNameOf(pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, &str); 169 if (FAILED(hr)) 170 return hr; 171 StrRetToStrW(&str, pidl, &name); 172 173 LocalPidlInfo info = { 174 FALSE, 175 m_UserLocalFolder, 176 ILClone(pidl), 177 NULL, 178 name 179 }; 180 181 ILFree(pidl); 182 183 TRACE("Inserting item %d with name %S\n", m_hDsaCount, name); 184 int idx = DSA_InsertItem(m_hDsa, DSA_APPEND, &info); 185 TRACE("New index: %d\n", idx); 186 187 m_hDsaCount++; 188 } 189 190 // Then load the items for the common folder 191 TRACE("Loading Common entries...\n"); 192 for (;;) 193 { 194 hr = allUsers->Next(1, &pidl, NULL); 195 if (FAILED_UNEXPECTEDLY(hr)) 196 return hr; 197 198 if (hr == S_FALSE) 199 break; 200 201 LPWSTR name; 202 STRRET str = { STRRET_WSTR }; 203 hr = m_AllUSersFolder->GetDisplayNameOf(pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, &str); 204 if (FAILED(hr)) 205 return hr; 206 StrRetToStrW(&str, pidl, &name); 207 208 LocalPidlInfo info = { 209 FALSE, 210 m_AllUSersFolder, 211 ILClone(pidl), 212 NULL, 213 name 214 }; 215 216 ILFree(pidl); 217 218 // Try to find an existing entry with the same name, and makr it as shared. 219 // FIXME: This is sub-optimal, a hash table would be a lot more efficient. 220 BOOL bShared = FALSE; 221 for (int i = 0; i < (int)m_hDsaCount; i++) 222 { 223 LocalPidlInfo *pInfo = (LocalPidlInfo *) DSA_GetItemPtr(m_hDsa, i); 224 225 int order = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, 226 pInfo->parseName, lstrlenW(pInfo->parseName), 227 info.parseName, lstrlenW(info.parseName)); 228 229 if (order == CSTR_EQUAL) 230 { 231 TRACE("Item name already exists! Marking '%S' as shared ...\n", name); 232 bShared = TRUE; 233 pInfo->shared = TRUE; 234 pInfo->pidl2 = info.pidl; 235 CoTaskMemFree(name); 236 break; 237 } 238 } 239 240 // If an entry was not found, add a new one for this item 241 if (!bShared) 242 { 243 TRACE("Inserting item %d with name %S\n", m_hDsaCount, name); 244 int idx = DSA_InsertItem(m_hDsa, DSA_APPEND, &info); 245 TRACE("New index: %d\n", idx); 246 247 m_hDsaCount++; 248 } 249 } 250 251 m_HwndOwner = hwndOwner; 252 m_Flags = flags; 253 254 return Reset(); 255 } 256 257 HRESULT CEnumMergedFolder::FindPidlInList(HWND hwndOwner, LPCITEMIDLIST pcidl, LocalPidlInfo * pinfo) 258 { 259 HRESULT hr; 260 261 if (!m_hDsa) 262 { 263 Begin(hwndOwner, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS); 264 } 265 266 TRACE("Searching for pidl { cb=%d } in a list of %d items\n", pcidl->mkid.cb, m_hDsaCount); 267 268 for (int i = 0; i < (int)m_hDsaCount; i++) 269 { 270 LocalPidlInfo * pInfo = (LocalPidlInfo *) DSA_GetItemPtr(m_hDsa, i); 271 if (!pInfo) 272 return E_FAIL; 273 274 TRACE("Comparing with item at %d with parent %p and pidl { cb=%d }\n", i, pInfo->parent, pInfo->pidl->mkid.cb); 275 276 hr = pInfo->parent->CompareIDs(0, pInfo->pidl, pcidl); 277 if (FAILED_UNEXPECTEDLY(hr)) 278 return hr; 279 280 if (hr == S_OK) 281 { 282 *pinfo = *pInfo; 283 return S_OK; 284 } 285 else 286 { 287 TRACE("Comparison returned %d\n", (int) (short) (hr & 0xFFFF)); 288 } 289 } 290 291 TRACE("Pidl not found\n"); 292 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 293 } 294 295 HRESULT CEnumMergedFolder::FindByName(HWND hwndOwner, LPCWSTR strParsingName, LocalPidlInfo * pinfo) 296 { 297 if (!m_hDsa) 298 { 299 Begin(hwndOwner, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS); 300 } 301 302 TRACE("Searching for '%S' in a list of %d items\n", strParsingName, m_hDsaCount); 303 304 for (int i = 0; i < (int) m_hDsaCount; i++) 305 { 306 LocalPidlInfo * pInfo = (LocalPidlInfo *) DSA_GetItemPtr(m_hDsa, i); 307 if (!pInfo) 308 return E_FAIL; 309 310 int order = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, 311 pInfo->parseName, lstrlenW(pInfo->parseName), 312 strParsingName, lstrlenW(strParsingName)); 313 switch (order) 314 { 315 case CSTR_EQUAL: 316 *pinfo = *pInfo; 317 return S_OK; 318 default: 319 continue; 320 } 321 } 322 323 TRACE("Pidl not found\n"); 324 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 325 } 326 327 HRESULT STDMETHODCALLTYPE CEnumMergedFolder::Next( 328 ULONG celt, 329 LPITEMIDLIST *rgelt, 330 ULONG *pceltFetched) 331 { 332 if (pceltFetched) 333 *pceltFetched = 0; 334 335 if (m_hDsaIndex == m_hDsaCount) 336 return S_FALSE; 337 338 for (int i = 0; i < (int)celt;) 339 { 340 LocalPidlInfo * tinfo = (LocalPidlInfo *) DSA_GetItemPtr(m_hDsa, m_hDsaIndex); 341 if (!tinfo) 342 return E_FAIL; 343 344 LocalPidlInfo info = *tinfo; 345 346 TRACE("Returning next item at %d with parent %p and pidl { cb=%d }\n", m_hDsaIndex, info.parent, info.pidl->mkid.cb); 347 348 // FIXME: ILClone shouldn't be needed here! This should be causing leaks 349 if (rgelt) rgelt[i] = ILClone(info.pidl); 350 i++; 351 352 m_hDsaIndex++; 353 if (m_hDsaIndex == m_hDsaCount) 354 { 355 if (pceltFetched) 356 *pceltFetched = i; 357 return (i == (int)celt) ? S_OK : S_FALSE; 358 } 359 } 360 361 if (pceltFetched) *pceltFetched = celt; 362 return S_OK; 363 } 364 365 HRESULT STDMETHODCALLTYPE CEnumMergedFolder::Skip(ULONG celt) 366 { 367 return Next(celt, NULL, NULL); 368 } 369 370 HRESULT STDMETHODCALLTYPE CEnumMergedFolder::Reset() 371 { 372 m_hDsaIndex = 0; 373 return S_OK; 374 } 375 376 HRESULT STDMETHODCALLTYPE CEnumMergedFolder::Clone( 377 IEnumIDList **ppenum) 378 { 379 UNIMPLEMENTED; 380 return E_NOTIMPL; 381 } 382 383 //----------------------------------------------------------------------------- 384 // CMergedFolder 385 386 CMergedFolder::CMergedFolder() : 387 m_UserLocal(NULL), 388 m_AllUsers(NULL), 389 m_EnumSource(NULL), 390 m_UserLocalPidl(NULL), 391 m_AllUsersPidl(NULL), 392 m_shellPidl(NULL) 393 { 394 } 395 396 CMergedFolder::~CMergedFolder() 397 { 398 if (m_UserLocalPidl) ILFree(m_UserLocalPidl); 399 if (m_AllUsersPidl) ILFree(m_AllUsersPidl); 400 } 401 402 // IAugmentedShellFolder2 403 HRESULT STDMETHODCALLTYPE CMergedFolder::AddNameSpace(LPGUID lpGuid, IShellFolder * psf, LPCITEMIDLIST pcidl, ULONG dwUnknown) 404 { 405 if (lpGuid) 406 { 407 TRACE("FIXME: No idea how to handle the GUID\n"); 408 return E_NOTIMPL; 409 } 410 411 TRACE("AddNameSpace %p %p\n", m_UserLocal.p, m_AllUsers.p); 412 413 // FIXME: Use a DSA to store the list of merged namespaces, together with their related info (psf, pidl, ...) 414 // For now, assume only 2 will ever be used, and ignore all the other data. 415 if (!m_UserLocal) 416 { 417 m_UserLocal = psf; 418 m_UserLocalPidl = ILClone(pcidl); 419 return S_OK; 420 } 421 422 if (m_AllUsers) 423 return E_FAIL; 424 425 m_AllUsers = psf; 426 m_AllUsersPidl = ILClone(pcidl); 427 428 m_EnumSource = new CComObject<CEnumMergedFolder>(); 429 return m_EnumSource->SetSources(m_UserLocal, m_AllUsers); 430 } 431 432 HRESULT STDMETHODCALLTYPE CMergedFolder::GetNameSpaceID(LPCITEMIDLIST pcidl, LPGUID lpGuid) 433 { 434 UNIMPLEMENTED; 435 return E_NOTIMPL; 436 } 437 438 HRESULT STDMETHODCALLTYPE CMergedFolder::QueryNameSpace(ULONG dwUnknown, LPGUID lpGuid, IShellFolder ** ppsf) 439 { 440 UNIMPLEMENTED; 441 return E_NOTIMPL; 442 } 443 444 HRESULT STDMETHODCALLTYPE CMergedFolder::EnumNameSpace(ULONG dwUnknown, PULONG lpUnknown) 445 { 446 UNIMPLEMENTED; 447 return E_NOTIMPL; 448 } 449 450 HRESULT STDMETHODCALLTYPE CMergedFolder::UnWrapIDList(LPCITEMIDLIST pcidl, LONG lUnknown, IShellFolder ** ppsf, LPITEMIDLIST * ppidl1, LPITEMIDLIST *ppidl2, LONG * lpUnknown) 451 { 452 UNIMPLEMENTED; 453 return E_NOTIMPL; 454 } 455 456 // IShellFolder 457 HRESULT STDMETHODCALLTYPE CMergedFolder::ParseDisplayName( 458 HWND hwndOwner, 459 LPBC pbcReserved, 460 LPOLESTR lpszDisplayName, 461 ULONG *pchEaten, 462 LPITEMIDLIST *ppidl, 463 ULONG *pdwAttributes) 464 { 465 HRESULT hr; 466 LocalPidlInfo info; 467 468 if (!ppidl) 469 return E_FAIL; 470 471 if (pchEaten) 472 *pchEaten = 0; 473 474 if (pdwAttributes) 475 *pdwAttributes = 0; 476 477 TRACE("ParseDisplayName name=%S\n", lpszDisplayName); 478 479 hr = m_EnumSource->FindByName(hwndOwner, lpszDisplayName, &info); 480 if (FAILED(hr)) 481 { 482 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 483 } 484 485 *ppidl = ILClone(info.pidl); 486 487 if (pchEaten) 488 *pchEaten = lstrlenW(info.parseName); 489 490 if (pdwAttributes) 491 *pdwAttributes = info.parent->GetAttributesOf(1, (LPCITEMIDLIST*)ppidl, pdwAttributes); 492 493 return S_OK; 494 } 495 496 HRESULT STDMETHODCALLTYPE CMergedFolder::EnumObjects( 497 HWND hwndOwner, 498 SHCONTF grfFlags, 499 IEnumIDList **ppenumIDList) 500 { 501 TRACE("EnumObjects\n"); 502 HRESULT hr = m_EnumSource->QueryInterface(IID_PPV_ARG(IEnumIDList, ppenumIDList)); 503 if (FAILED_UNEXPECTEDLY(hr)) 504 return hr; 505 return m_EnumSource->Begin(hwndOwner, grfFlags); 506 } 507 508 HRESULT STDMETHODCALLTYPE CMergedFolder::BindToObject( 509 LPCITEMIDLIST pidl, 510 LPBC pbcReserved, 511 REFIID riid, 512 void **ppvOut) 513 { 514 LocalPidlInfo info; 515 HRESULT hr; 516 517 hr = m_EnumSource->FindPidlInList(NULL, pidl, &info); 518 if (FAILED_UNEXPECTEDLY(hr)) 519 return hr; 520 521 TRACE("BindToObject shared = %d\n", info.shared); 522 523 if (!info.shared) 524 return info.parent->BindToObject(info.pidl, pbcReserved, riid, ppvOut); 525 526 if (riid != IID_IShellFolder) 527 return E_FAIL; 528 529 // Construct a child MergedFolder and return it 530 CComPtr<IShellFolder> fld1; 531 CComPtr<IShellFolder> fld2; 532 533 // In shared folders, the user one takes precedence over the common one, so it will always be on pidl1 534 hr = m_UserLocal->BindToObject(info.pidl, pbcReserved, IID_PPV_ARG(IShellFolder, &fld1)); 535 if (FAILED_UNEXPECTEDLY(hr)) 536 return hr; 537 538 hr = m_AllUsers->BindToObject(info.pidl2, pbcReserved, IID_PPV_ARG(IShellFolder, &fld2)); 539 if (FAILED_UNEXPECTEDLY(hr)) 540 return hr; 541 542 CComPtr<IAugmentedShellFolder> pasf; 543 hr = CMergedFolder_CreateInstance(IID_PPV_ARG(IAugmentedShellFolder, &pasf)); 544 if (FAILED_UNEXPECTEDLY(hr)) 545 return hr; 546 547 hr = pasf->QueryInterface(riid, ppvOut); 548 if (FAILED_UNEXPECTEDLY(hr)) 549 return hr; 550 551 hr = pasf->AddNameSpace(NULL, fld1, info.pidl, 0xFF00); 552 if (FAILED_UNEXPECTEDLY(hr)) 553 return hr; 554 555 hr = pasf->AddNameSpace(NULL, fld2, info.pidl2, 0x0000); 556 if (FAILED_UNEXPECTEDLY(hr)) 557 return hr; 558 559 return hr; 560 } 561 562 HRESULT STDMETHODCALLTYPE CMergedFolder::BindToStorage( 563 LPCITEMIDLIST pidl, 564 LPBC pbcReserved, 565 REFIID riid, 566 void **ppvObj) 567 { 568 UNIMPLEMENTED; 569 return E_NOTIMPL; 570 } 571 572 HRESULT STDMETHODCALLTYPE CMergedFolder::CompareIDs( 573 LPARAM lParam, 574 LPCITEMIDLIST pidl1, 575 LPCITEMIDLIST pidl2) 576 { 577 TRACE("CompareIDs\n"); 578 return m_UserLocal->CompareIDs(lParam, pidl1, pidl2); 579 } 580 581 HRESULT STDMETHODCALLTYPE CMergedFolder::CreateViewObject( 582 HWND hwndOwner, 583 REFIID riid, 584 void **ppvOut) 585 { 586 UNIMPLEMENTED; 587 return E_NOTIMPL; 588 } 589 590 HRESULT STDMETHODCALLTYPE CMergedFolder::GetAttributesOf( 591 UINT cidl, 592 PCUITEMID_CHILD_ARRAY apidl, 593 SFGAOF *rgfInOut) 594 { 595 LocalPidlInfo info; 596 HRESULT hr; 597 598 TRACE("GetAttributesOf\n"); 599 600 for (int i = 0; i < (int)cidl; i++) 601 { 602 LPCITEMIDLIST pidl = apidl[i]; 603 604 hr = m_EnumSource->FindPidlInList(NULL, pidl, &info); 605 if (FAILED_UNEXPECTEDLY(hr)) 606 return hr; 607 608 pidl = info.pidl; 609 610 SFGAOF * pinOut1 = rgfInOut ? rgfInOut + i : NULL; 611 612 hr = info.parent->GetAttributesOf(1, &pidl, pinOut1); 613 614 if (FAILED_UNEXPECTEDLY(hr)) 615 return hr; 616 } 617 618 return S_OK; 619 } 620 621 HRESULT STDMETHODCALLTYPE CMergedFolder::GetUIObjectOf( 622 HWND hwndOwner, 623 UINT cidl, 624 PCUITEMID_CHILD_ARRAY apidl, 625 REFIID riid, 626 UINT *prgfInOut, 627 void **ppvOut) 628 { 629 LocalPidlInfo info; 630 HRESULT hr; 631 632 TRACE("GetUIObjectOf\n"); 633 634 for (int i = 0; i < (int)cidl; i++) 635 { 636 LPCITEMIDLIST pidl = apidl[i]; 637 638 TRACE("Processing GetUIObjectOf item %d of %u...\n", i, cidl); 639 640 hr = m_EnumSource->FindPidlInList(hwndOwner, pidl, &info); 641 if (FAILED_UNEXPECTEDLY(hr)) 642 return hr; 643 644 pidl = info.pidl; 645 646 TRACE("FindPidlInList succeeded with parent %p and pidl { db=%d }\n", info.parent, info.pidl->mkid.cb); 647 648 UINT * pinOut1 = prgfInOut ? prgfInOut+i : NULL; 649 void** ppvOut1 = ppvOut ? ppvOut + i : NULL; 650 651 hr = info.parent->GetUIObjectOf(hwndOwner, 1, &pidl, riid, pinOut1, ppvOut1); 652 653 if (FAILED_UNEXPECTEDLY(hr)) 654 return hr; 655 } 656 657 return S_OK; 658 } 659 660 HRESULT STDMETHODCALLTYPE CMergedFolder::GetDisplayNameOf( 661 LPCITEMIDLIST pidl, 662 SHGDNF uFlags, 663 STRRET *lpName) 664 { 665 LocalPidlInfo info; 666 HRESULT hr; 667 668 TRACE("GetDisplayNameOf\n"); 669 670 hr = m_EnumSource->FindPidlInList(NULL, pidl, &info); 671 if (FAILED_UNEXPECTEDLY(hr)) 672 return hr; 673 674 hr = info.parent->GetDisplayNameOf(info.pidl, uFlags, lpName); 675 676 if (FAILED_UNEXPECTEDLY(hr)) 677 return hr; 678 return S_OK; 679 } 680 681 HRESULT STDMETHODCALLTYPE CMergedFolder::SetNameOf( 682 HWND hwnd, 683 LPCITEMIDLIST pidl, 684 LPCOLESTR lpszName, 685 SHGDNF uFlags, 686 LPITEMIDLIST *ppidlOut) 687 { 688 UNIMPLEMENTED; 689 return E_NOTIMPL; 690 } 691 692 // IPersist 693 HRESULT STDMETHODCALLTYPE CMergedFolder::GetClassID(CLSID *lpClassId) 694 { 695 UNIMPLEMENTED; 696 return E_NOTIMPL; 697 } 698 699 // IPersistFolder 700 HRESULT STDMETHODCALLTYPE CMergedFolder::Initialize(PCIDLIST_ABSOLUTE pidl) 701 { 702 m_shellPidl = ILClone(pidl); 703 return S_OK; 704 } 705 706 // IPersistFolder2 707 HRESULT STDMETHODCALLTYPE CMergedFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl) 708 { 709 if (pidl) 710 *pidl = m_shellPidl; 711 return S_OK; 712 } 713 714 // IShellFolder2 715 HRESULT STDMETHODCALLTYPE CMergedFolder::GetDefaultSearchGUID( 716 GUID *lpguid) 717 { 718 UNIMPLEMENTED; 719 return E_NOTIMPL; 720 } 721 722 HRESULT STDMETHODCALLTYPE CMergedFolder::EnumSearches( 723 IEnumExtraSearch **ppenum) 724 { 725 UNIMPLEMENTED; 726 return E_NOTIMPL; 727 } 728 729 HRESULT STDMETHODCALLTYPE CMergedFolder::GetDefaultColumn( 730 DWORD dwReserved, 731 ULONG *pSort, 732 ULONG *pDisplay) 733 { 734 UNIMPLEMENTED; 735 return E_NOTIMPL; 736 } 737 738 HRESULT STDMETHODCALLTYPE CMergedFolder::GetDefaultColumnState( 739 UINT iColumn, 740 SHCOLSTATEF *pcsFlags) 741 { 742 UNIMPLEMENTED; 743 return E_NOTIMPL; 744 } 745 746 HRESULT STDMETHODCALLTYPE CMergedFolder::GetDetailsEx( 747 LPCITEMIDLIST pidl, 748 const SHCOLUMNID *pscid, 749 VARIANT *pv) 750 { 751 LocalPidlInfo info; 752 HRESULT hr; 753 754 TRACE("GetDetailsEx\n"); 755 756 hr = m_EnumSource->FindPidlInList(NULL, pidl, &info); 757 if (FAILED_UNEXPECTEDLY(hr)) 758 return hr; 759 760 CComPtr<IShellFolder2> parent2; 761 hr = info.parent->QueryInterface(IID_PPV_ARG(IShellFolder2, &parent2)); 762 if (FAILED_UNEXPECTEDLY(hr)) 763 return hr; 764 765 hr = parent2->GetDetailsEx(info.pidl, pscid, pv); 766 if (FAILED_UNEXPECTEDLY(hr)) 767 return hr; 768 return S_OK; 769 } 770 771 HRESULT STDMETHODCALLTYPE CMergedFolder::GetDetailsOf( 772 LPCITEMIDLIST pidl, 773 UINT iColumn, 774 SHELLDETAILS *psd) 775 { 776 LocalPidlInfo info; 777 HRESULT hr; 778 779 TRACE("GetDetailsOf\n"); 780 781 hr = m_EnumSource->FindPidlInList(NULL, pidl, &info); 782 if (FAILED_UNEXPECTEDLY(hr)) 783 return hr; 784 785 CComPtr<IShellFolder2> parent2; 786 hr = info.parent->QueryInterface(IID_PPV_ARG(IShellFolder2, &parent2)); 787 if (FAILED_UNEXPECTEDLY(hr)) 788 return hr; 789 790 hr = parent2->GetDetailsOf(info.pidl, iColumn, psd); 791 792 if (FAILED_UNEXPECTEDLY(hr)) 793 return hr; 794 return S_OK; 795 } 796 797 HRESULT STDMETHODCALLTYPE CMergedFolder::MapColumnToSCID( 798 UINT iColumn, 799 SHCOLUMNID *pscid) 800 { 801 UNIMPLEMENTED; 802 return E_NOTIMPL; 803 } 804 805 // IAugmentedShellFolder3 806 HRESULT STDMETHODCALLTYPE CMergedFolder::QueryNameSpace2(ULONG, QUERYNAMESPACEINFO *) 807 { 808 UNIMPLEMENTED; 809 return E_NOTIMPL; 810 } 811 812 extern "C" 813 HRESULT WINAPI RSHELL_CMergedFolder_CreateInstance(REFIID riid, LPVOID *ppv) 814 { 815 return ShellObjectCreator<CMergedFolder>(riid, ppv); 816 } 817