[RSHELL][SHELL32]
[reactos.git] / reactos / 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 extern "C"
387 HRESULT WINAPI CMergedFolder_Constructor(REFIID riid, LPVOID *ppv)
388 {
389 return ShellObjectCreator<CMergedFolder>(riid, ppv);
390 }
391
392 CMergedFolder::CMergedFolder() :
393 m_UserLocal(NULL),
394 m_AllUsers(NULL),
395 m_EnumSource(NULL),
396 m_UserLocalPidl(NULL),
397 m_AllUsersPidl(NULL),
398 m_shellPidl(NULL)
399 {
400 }
401
402 CMergedFolder::~CMergedFolder()
403 {
404 if (m_UserLocalPidl) ILFree(m_UserLocalPidl);
405 if (m_AllUsersPidl) ILFree(m_AllUsersPidl);
406 }
407
408 // IAugmentedShellFolder2
409 HRESULT STDMETHODCALLTYPE CMergedFolder::AddNameSpace(LPGUID lpGuid, IShellFolder * psf, LPCITEMIDLIST pcidl, ULONG dwUnknown)
410 {
411 if (lpGuid)
412 {
413 TRACE("FIXME: No idea how to handle the GUID\n");
414 return E_NOTIMPL;
415 }
416
417 TRACE("AddNameSpace %p %p\n", m_UserLocal.p, m_AllUsers.p);
418
419 // FIXME: Use a DSA to store the list of merged namespaces, together with their related info (psf, pidl, ...)
420 // For now, assume only 2 will ever be used, and ignore all the other data.
421 if (!m_UserLocal)
422 {
423 m_UserLocal = psf;
424 m_UserLocalPidl = ILClone(pcidl);
425 return S_OK;
426 }
427
428 if (m_AllUsers)
429 return E_FAIL;
430
431 m_AllUsers = psf;
432 m_AllUsersPidl = ILClone(pcidl);
433
434 m_EnumSource = new CComObject<CEnumMergedFolder>();
435 return m_EnumSource->SetSources(m_UserLocal, m_AllUsers);
436 }
437
438 HRESULT STDMETHODCALLTYPE CMergedFolder::GetNameSpaceID(LPCITEMIDLIST pcidl, LPGUID lpGuid)
439 {
440 UNIMPLEMENTED;
441 return E_NOTIMPL;
442 }
443
444 HRESULT STDMETHODCALLTYPE CMergedFolder::QueryNameSpace(ULONG dwUnknown, LPGUID lpGuid, IShellFolder ** ppsf)
445 {
446 UNIMPLEMENTED;
447 return E_NOTIMPL;
448 }
449
450 HRESULT STDMETHODCALLTYPE CMergedFolder::EnumNameSpace(ULONG dwUnknown, PULONG lpUnknown)
451 {
452 UNIMPLEMENTED;
453 return E_NOTIMPL;
454 }
455
456 HRESULT STDMETHODCALLTYPE CMergedFolder::UnWrapIDList(LPCITEMIDLIST pcidl, LONG lUnknown, IShellFolder ** ppsf, LPITEMIDLIST * ppidl1, LPITEMIDLIST *ppidl2, LONG * lpUnknown)
457 {
458 UNIMPLEMENTED;
459 return E_NOTIMPL;
460 }
461
462 // IShellFolder
463 HRESULT STDMETHODCALLTYPE CMergedFolder::ParseDisplayName(
464 HWND hwndOwner,
465 LPBC pbcReserved,
466 LPOLESTR lpszDisplayName,
467 ULONG *pchEaten,
468 LPITEMIDLIST *ppidl,
469 ULONG *pdwAttributes)
470 {
471 HRESULT hr;
472 LocalPidlInfo info;
473
474 if (!ppidl)
475 return E_FAIL;
476
477 if (pchEaten)
478 *pchEaten = 0;
479
480 if (pdwAttributes)
481 *pdwAttributes = 0;
482
483 TRACE("ParseDisplayName name=%S\n", lpszDisplayName);
484
485 hr = m_EnumSource->FindByName(hwndOwner, lpszDisplayName, &info);
486 if (FAILED(hr))
487 {
488 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
489 }
490
491 *ppidl = ILClone(info.pidl);
492
493 if (pchEaten)
494 *pchEaten = lstrlenW(info.parseName);
495
496 if (pdwAttributes)
497 *pdwAttributes = info.parent->GetAttributesOf(1, (LPCITEMIDLIST*)ppidl, pdwAttributes);
498
499 return S_OK;
500 }
501
502 HRESULT STDMETHODCALLTYPE CMergedFolder::EnumObjects(
503 HWND hwndOwner,
504 SHCONTF grfFlags,
505 IEnumIDList **ppenumIDList)
506 {
507 TRACE("EnumObjects\n");
508 HRESULT hr = m_EnumSource->QueryInterface(IID_PPV_ARG(IEnumIDList, ppenumIDList));
509 if (FAILED_UNEXPECTEDLY(hr))
510 return hr;
511 return m_EnumSource->Begin(hwndOwner, grfFlags);
512 }
513
514 HRESULT STDMETHODCALLTYPE CMergedFolder::BindToObject(
515 LPCITEMIDLIST pidl,
516 LPBC pbcReserved,
517 REFIID riid,
518 void **ppvOut)
519 {
520 LocalPidlInfo info;
521 HRESULT hr;
522
523 hr = m_EnumSource->FindPidlInList(NULL, pidl, &info);
524 if (FAILED_UNEXPECTEDLY(hr))
525 return hr;
526
527 TRACE("BindToObject shared = %d\n", info.shared);
528
529 if (!info.shared)
530 return info.parent->BindToObject(info.pidl, pbcReserved, riid, ppvOut);
531
532 if (riid != IID_IShellFolder)
533 return E_FAIL;
534
535 // Construct a child MergedFolder and return it
536 CComPtr<IShellFolder> fld1;
537 CComPtr<IShellFolder> fld2;
538
539 // In shared folders, the user one takes precedence over the common one, so it will always be on pidl1
540 hr = m_UserLocal->BindToObject(info.pidl, pbcReserved, IID_PPV_ARG(IShellFolder, &fld1));
541 if (FAILED_UNEXPECTEDLY(hr))
542 return hr;
543
544 hr = m_AllUsers->BindToObject(info.pidl2, pbcReserved, IID_PPV_ARG(IShellFolder, &fld2));
545 if (FAILED_UNEXPECTEDLY(hr))
546 return hr;
547
548 CComPtr<IAugmentedShellFolder> pasf;
549 hr = CMergedFolder_Constructor(IID_PPV_ARG(IAugmentedShellFolder, &pasf));
550 if (FAILED_UNEXPECTEDLY(hr))
551 return hr;
552
553 hr = pasf->QueryInterface(riid, ppvOut);
554 if (FAILED_UNEXPECTEDLY(hr))
555 return hr;
556
557 hr = pasf->AddNameSpace(NULL, fld1, info.pidl, 0xFF00);
558 if (FAILED_UNEXPECTEDLY(hr))
559 return hr;
560
561 hr = pasf->AddNameSpace(NULL, fld2, info.pidl2, 0x0000);
562 if (FAILED_UNEXPECTEDLY(hr))
563 return hr;
564
565 return hr;
566 }
567
568 HRESULT STDMETHODCALLTYPE CMergedFolder::BindToStorage(
569 LPCITEMIDLIST pidl,
570 LPBC pbcReserved,
571 REFIID riid,
572 void **ppvObj)
573 {
574 UNIMPLEMENTED;
575 return E_NOTIMPL;
576 }
577
578 HRESULT STDMETHODCALLTYPE CMergedFolder::CompareIDs(
579 LPARAM lParam,
580 LPCITEMIDLIST pidl1,
581 LPCITEMIDLIST pidl2)
582 {
583 TRACE("CompareIDs\n");
584 return m_UserLocal->CompareIDs(lParam, pidl1, pidl2);
585 }
586
587 HRESULT STDMETHODCALLTYPE CMergedFolder::CreateViewObject(
588 HWND hwndOwner,
589 REFIID riid,
590 void **ppvOut)
591 {
592 UNIMPLEMENTED;
593 return E_NOTIMPL;
594 }
595
596 HRESULT STDMETHODCALLTYPE CMergedFolder::GetAttributesOf(
597 UINT cidl,
598 PCUITEMID_CHILD_ARRAY apidl,
599 SFGAOF *rgfInOut)
600 {
601 LocalPidlInfo info;
602 HRESULT hr;
603
604 TRACE("GetAttributesOf\n");
605
606 for (int i = 0; i < (int)cidl; i++)
607 {
608 LPCITEMIDLIST pidl = apidl[i];
609
610 hr = m_EnumSource->FindPidlInList(NULL, pidl, &info);
611 if (FAILED_UNEXPECTEDLY(hr))
612 return hr;
613
614 pidl = info.pidl;
615
616 SFGAOF * pinOut1 = rgfInOut ? rgfInOut + i : NULL;
617
618 hr = info.parent->GetAttributesOf(1, &pidl, pinOut1);
619
620 if (FAILED_UNEXPECTEDLY(hr))
621 return hr;
622 }
623
624 return S_OK;
625 }
626
627 HRESULT STDMETHODCALLTYPE CMergedFolder::GetUIObjectOf(
628 HWND hwndOwner,
629 UINT cidl,
630 PCUITEMID_CHILD_ARRAY apidl,
631 REFIID riid,
632 UINT *prgfInOut,
633 void **ppvOut)
634 {
635 LocalPidlInfo info;
636 HRESULT hr;
637
638 TRACE("GetUIObjectOf\n");
639
640 for (int i = 0; i < (int)cidl; i++)
641 {
642 LPCITEMIDLIST pidl = apidl[i];
643
644 TRACE("Processing GetUIObjectOf item %d of %u...\n", i, cidl);
645
646 hr = m_EnumSource->FindPidlInList(hwndOwner, pidl, &info);
647 if (FAILED_UNEXPECTEDLY(hr))
648 return hr;
649
650 pidl = info.pidl;
651
652 TRACE("FindPidlInList succeeded with parent %p and pidl { db=%d }\n", info.parent, info.pidl->mkid.cb);
653
654 UINT * pinOut1 = prgfInOut ? prgfInOut+i : NULL;
655 void** ppvOut1 = ppvOut ? ppvOut + i : NULL;
656
657 hr = info.parent->GetUIObjectOf(hwndOwner, 1, &pidl, riid, pinOut1, ppvOut1);
658
659 if (FAILED_UNEXPECTEDLY(hr))
660 return hr;
661 }
662
663 return S_OK;
664 }
665
666 HRESULT STDMETHODCALLTYPE CMergedFolder::GetDisplayNameOf(
667 LPCITEMIDLIST pidl,
668 SHGDNF uFlags,
669 STRRET *lpName)
670 {
671 LocalPidlInfo info;
672 HRESULT hr;
673
674 TRACE("GetDisplayNameOf\n");
675
676 hr = m_EnumSource->FindPidlInList(NULL, pidl, &info);
677 if (FAILED_UNEXPECTEDLY(hr))
678 return hr;
679
680 hr = info.parent->GetDisplayNameOf(info.pidl, uFlags, lpName);
681
682 if (FAILED_UNEXPECTEDLY(hr))
683 return hr;
684 return S_OK;
685 }
686
687 HRESULT STDMETHODCALLTYPE CMergedFolder::SetNameOf(
688 HWND hwnd,
689 LPCITEMIDLIST pidl,
690 LPCOLESTR lpszName,
691 SHGDNF uFlags,
692 LPITEMIDLIST *ppidlOut)
693 {
694 UNIMPLEMENTED;
695 return E_NOTIMPL;
696 }
697
698 // IPersist
699 HRESULT STDMETHODCALLTYPE CMergedFolder::GetClassID(CLSID *lpClassId)
700 {
701 UNIMPLEMENTED;
702 return E_NOTIMPL;
703 }
704
705 // IPersistFolder
706 HRESULT STDMETHODCALLTYPE CMergedFolder::Initialize(LPCITEMIDLIST pidl)
707 {
708 m_shellPidl = ILClone(pidl);
709 return S_OK;
710 }
711
712 // IPersistFolder2
713 HRESULT STDMETHODCALLTYPE CMergedFolder::GetCurFolder(LPITEMIDLIST * pidl)
714 {
715 if (pidl)
716 *pidl = m_shellPidl;
717 return S_OK;
718 }
719
720 // IShellFolder2
721 HRESULT STDMETHODCALLTYPE CMergedFolder::GetDefaultSearchGUID(
722 GUID *lpguid)
723 {
724 UNIMPLEMENTED;
725 return E_NOTIMPL;
726 }
727
728 HRESULT STDMETHODCALLTYPE CMergedFolder::EnumSearches(
729 IEnumExtraSearch **ppenum)
730 {
731 UNIMPLEMENTED;
732 return E_NOTIMPL;
733 }
734
735 HRESULT STDMETHODCALLTYPE CMergedFolder::GetDefaultColumn(
736 DWORD dwReserved,
737 ULONG *pSort,
738 ULONG *pDisplay)
739 {
740 UNIMPLEMENTED;
741 return E_NOTIMPL;
742 }
743
744 HRESULT STDMETHODCALLTYPE CMergedFolder::GetDefaultColumnState(
745 UINT iColumn,
746 SHCOLSTATEF *pcsFlags)
747 {
748 UNIMPLEMENTED;
749 return E_NOTIMPL;
750 }
751
752 HRESULT STDMETHODCALLTYPE CMergedFolder::GetDetailsEx(
753 LPCITEMIDLIST pidl,
754 const SHCOLUMNID *pscid,
755 VARIANT *pv)
756 {
757 LocalPidlInfo info;
758 HRESULT hr;
759
760 TRACE("GetDetailsEx\n");
761
762 hr = m_EnumSource->FindPidlInList(NULL, pidl, &info);
763 if (FAILED_UNEXPECTEDLY(hr))
764 return hr;
765
766 CComPtr<IShellFolder2> parent2;
767 hr = info.parent->QueryInterface(IID_PPV_ARG(IShellFolder2, &parent2));
768 if (FAILED_UNEXPECTEDLY(hr))
769 return hr;
770
771 hr = parent2->GetDetailsEx(info.pidl, pscid, pv);
772 if (FAILED_UNEXPECTEDLY(hr))
773 return hr;
774 return S_OK;
775 }
776
777 HRESULT STDMETHODCALLTYPE CMergedFolder::GetDetailsOf(
778 LPCITEMIDLIST pidl,
779 UINT iColumn,
780 SHELLDETAILS *psd)
781 {
782 LocalPidlInfo info;
783 HRESULT hr;
784
785 TRACE("GetDetailsOf\n");
786
787 hr = m_EnumSource->FindPidlInList(NULL, pidl, &info);
788 if (FAILED_UNEXPECTEDLY(hr))
789 return hr;
790
791 CComPtr<IShellFolder2> parent2;
792 hr = info.parent->QueryInterface(IID_PPV_ARG(IShellFolder2, &parent2));
793 if (FAILED_UNEXPECTEDLY(hr))
794 return hr;
795
796 hr = parent2->GetDetailsOf(info.pidl, iColumn, psd);
797
798 if (FAILED_UNEXPECTEDLY(hr))
799 return hr;
800 return S_OK;
801 }
802
803 HRESULT STDMETHODCALLTYPE CMergedFolder::MapColumnToSCID(
804 UINT iColumn,
805 SHCOLUMNID *pscid)
806 {
807 UNIMPLEMENTED;
808 return E_NOTIMPL;
809 }
810
811 // IAugmentedShellFolder3
812 HRESULT STDMETHODCALLTYPE CMergedFolder::QueryNameSpace2(ULONG, QUERYNAMESPACEINFO *)
813 {
814 UNIMPLEMENTED;
815 return E_NOTIMPL;
816 }