Reactos
at listview 816 lines 20 kB view raw
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 26WINE_DEFAULT_DEBUG_CHANNEL(CMergedFolder); 27 28struct LocalPidlInfo 29{ 30 BOOL shared; 31 IShellFolder * parent; 32 LPITEMIDLIST pidl; 33 LPITEMIDLIST pidl2; 34 LPCWSTR parseName; 35}; 36 37class CEnumMergedFolder : 38 public CComObjectRootEx<CComMultiThreadModelNoCS>, 39 public IEnumIDList 40{ 41 42private: 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 53public: 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 STDMETHOD(Next)( 74 ULONG celt, 75 LPITEMIDLIST *rgelt, 76 ULONG *pceltFetched) override; 77 78 STDMETHOD(Skip)(ULONG celt) override; 79 STDMETHOD(Reset)() override; 80 STDMETHOD(Clone)(IEnumIDList **ppenum) override; 81}; 82 83CEnumMergedFolder::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 94CEnumMergedFolder::~CEnumMergedFolder() 95{ 96 DSA_DestroyCallback(m_hDsa, s_DsaDeleteCallback, this); 97} 98 99int 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 108int 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 115HRESULT 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 124HRESULT 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 257HRESULT 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 295HRESULT 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 327HRESULT 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 365HRESULT STDMETHODCALLTYPE CEnumMergedFolder::Skip(ULONG celt) 366{ 367 return Next(celt, NULL, NULL); 368} 369 370HRESULT STDMETHODCALLTYPE CEnumMergedFolder::Reset() 371{ 372 m_hDsaIndex = 0; 373 return S_OK; 374} 375 376HRESULT STDMETHODCALLTYPE CEnumMergedFolder::Clone( 377 IEnumIDList **ppenum) 378{ 379 UNIMPLEMENTED; 380 return E_NOTIMPL; 381} 382 383//----------------------------------------------------------------------------- 384// CMergedFolder 385 386CMergedFolder::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 396CMergedFolder::~CMergedFolder() 397{ 398 if (m_UserLocalPidl) ILFree(m_UserLocalPidl); 399 if (m_AllUsersPidl) ILFree(m_AllUsersPidl); 400} 401 402// IAugmentedShellFolder2 403HRESULT 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 432HRESULT STDMETHODCALLTYPE CMergedFolder::GetNameSpaceID(LPCITEMIDLIST pcidl, LPGUID lpGuid) 433{ 434 UNIMPLEMENTED; 435 return E_NOTIMPL; 436} 437 438HRESULT STDMETHODCALLTYPE CMergedFolder::QueryNameSpace(ULONG dwUnknown, LPGUID lpGuid, IShellFolder ** ppsf) 439{ 440 UNIMPLEMENTED; 441 return E_NOTIMPL; 442} 443 444HRESULT STDMETHODCALLTYPE CMergedFolder::EnumNameSpace(ULONG dwUnknown, PULONG lpUnknown) 445{ 446 UNIMPLEMENTED; 447 return E_NOTIMPL; 448} 449 450HRESULT 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 457HRESULT 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 496HRESULT 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 508HRESULT 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 562HRESULT STDMETHODCALLTYPE CMergedFolder::BindToStorage( 563 LPCITEMIDLIST pidl, 564 LPBC pbcReserved, 565 REFIID riid, 566 void **ppvObj) 567{ 568 UNIMPLEMENTED; 569 return E_NOTIMPL; 570} 571 572HRESULT 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 581HRESULT STDMETHODCALLTYPE CMergedFolder::CreateViewObject( 582 HWND hwndOwner, 583 REFIID riid, 584 void **ppvOut) 585{ 586 UNIMPLEMENTED; 587 return E_NOTIMPL; 588} 589 590HRESULT 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 621HRESULT 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 660HRESULT 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 681HRESULT 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 693HRESULT STDMETHODCALLTYPE CMergedFolder::GetClassID(CLSID *lpClassId) 694{ 695 UNIMPLEMENTED; 696 return E_NOTIMPL; 697} 698 699// IPersistFolder 700HRESULT STDMETHODCALLTYPE CMergedFolder::Initialize(PCIDLIST_ABSOLUTE pidl) 701{ 702 m_shellPidl = ILClone(pidl); 703 return S_OK; 704} 705 706// IPersistFolder2 707HRESULT STDMETHODCALLTYPE CMergedFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl) 708{ 709 if (pidl) 710 *pidl = m_shellPidl; 711 return S_OK; 712} 713 714// IShellFolder2 715HRESULT STDMETHODCALLTYPE CMergedFolder::GetDefaultSearchGUID( 716 GUID *lpguid) 717{ 718 UNIMPLEMENTED; 719 return E_NOTIMPL; 720} 721 722HRESULT STDMETHODCALLTYPE CMergedFolder::EnumSearches( 723 IEnumExtraSearch **ppenum) 724{ 725 UNIMPLEMENTED; 726 return E_NOTIMPL; 727} 728 729HRESULT STDMETHODCALLTYPE CMergedFolder::GetDefaultColumn( 730 DWORD dwReserved, 731 ULONG *pSort, 732 ULONG *pDisplay) 733{ 734 UNIMPLEMENTED; 735 return E_NOTIMPL; 736} 737 738HRESULT STDMETHODCALLTYPE CMergedFolder::GetDefaultColumnState( 739 UINT iColumn, 740 SHCOLSTATEF *pcsFlags) 741{ 742 UNIMPLEMENTED; 743 return E_NOTIMPL; 744} 745 746HRESULT 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 771HRESULT 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 797HRESULT STDMETHODCALLTYPE CMergedFolder::MapColumnToSCID( 798 UINT iColumn, 799 SHCOLUMNID *pscid) 800{ 801 UNIMPLEMENTED; 802 return E_NOTIMPL; 803} 804 805// IAugmentedShellFolder3 806HRESULT STDMETHODCALLTYPE CMergedFolder::QueryNameSpace2(ULONG, QUERYNAMESPACEINFO *) 807{ 808 UNIMPLEMENTED; 809 return E_NOTIMPL; 810} 811 812extern "C" 813HRESULT WINAPI RSHELL_CMergedFolder_CreateInstance(REFIID riid, LPVOID *ppv) 814{ 815 return ShellObjectCreator<CMergedFolder>(riid, ppv); 816}