[SHELL] IPersistFolder2::GetCurFolder takes a PIDLIST_ABSOLUTE*. CORE-16385
[reactos.git] / dll / win32 / shell32 / shellmenu / CMergedFolder.cpp
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(LPCITEMIDLIST 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 }