1 /*
2  * ReactOS Shell
3  *
4  * Copyright 2016 Giannis Adamopoulos
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 Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #include <precomp.h>
22 
23 WINE_DEFAULT_DEBUG_CHANNEL (shell);
24 
25 HRESULT CALLBACK RegFolderContextMenuCallback(IShellFolder *psf,
26                                               HWND         hwnd,
27                                               IDataObject  *pdtobj,
28                                               UINT         uMsg,
29                                               WPARAM       wParam,
30                                               LPARAM       lParam)
31 {
32     if (uMsg != DFM_INVOKECOMMAND || wParam != DFM_CMD_PROPERTIES)
33         return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg);
34 
35     PIDLIST_ABSOLUTE pidlFolder;
36     PUITEMID_CHILD *apidl;
37     UINT cidl;
38     HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
39     if (FAILED_UNEXPECTEDLY(hr))
40         return hr;
41 
42     if (_ILIsMyComputer(apidl[0]))
43     {
44         if (!SHELL_ExecuteControlPanelCPL(hwnd, L"sysdm.cpl"))
45         {
46             hr = E_FAIL;
47         }
48     }
49     else if (_ILIsDesktop(apidl[0]))
50     {
51         if (!SHELL_ExecuteControlPanelCPL(hwnd, L"desk.cpl"))
52         {
53             hr = E_FAIL;
54         }
55     }
56     else if (_ILIsNetHood(apidl[0]))
57     {
58         // FIXME path!
59         if (32 >= (UINT_PTR)ShellExecuteW(NULL,
60                                           L"open",
61                                           L"explorer.exe",
62                                           L"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
63                                           NULL,
64                                           SW_SHOWDEFAULT))
65         {
66             hr = E_FAIL;
67         }
68     }
69     else if (_ILIsBitBucket(apidl[0]))
70     {
71         /* FIXME: detect the drive path of bitbucket if appropiate */
72         if (!SH_ShowRecycleBinProperties(L'C'))
73             hr = E_FAIL;
74     }
75     else
76     {
77         /* Tell the caller to run the default action */
78         hr = S_FALSE;
79     }
80 
81     SHFree(pidlFolder);
82     _ILFreeaPidl(apidl, cidl);
83 
84     return hr;
85 }
86 
87 HRESULT CGuidItemContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder,
88                                             HWND hwnd,
89                                             UINT cidl,
90                                             PCUITEMID_CHILD_ARRAY apidl,
91                                             IShellFolder *psf,
92                                             IContextMenu **ppcm)
93 {
94     HKEY hKeys[10];
95     UINT cKeys = 0;
96 
97     GUID *pGuid = _ILGetGUIDPointer(apidl[0]);
98     if (pGuid)
99     {
100         WCHAR key[60];
101         wcscpy(key, L"CLSID\\");
102         StringFromGUID2(*pGuid, &key[6], 39);
103         AddClassKeyToArray(key, hKeys, &cKeys);
104     }
105 
106     // FIXME: CRegFolder should be aggregated by its outer folder and should
107     // provide the attributes for all required non-registry folders.
108     // It currently does not so we have to ask the outer folder ourself so
109     // that we get the correct attributes for My Computer etc.
110     CComPtr<IShellFolder> pOuterSF;
111     SHBindToObject(NULL, pidlFolder, IID_PPV_ARG(IShellFolder, &pOuterSF));
112 
113     SFGAOF att = (psf && cidl) ? SHGetAttributes(pOuterSF ? pOuterSF.p : psf, apidl[0], SFGAO_FOLDER) : 0;
114     if (att & SFGAO_FOLDER)
115         AddClassKeyToArray(L"Folder", hKeys, &cKeys);
116 
117     return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, RegFolderContextMenuCallback, cKeys, hKeys, ppcm);
118 }
119 
120 HRESULT FormatGUIDKey(LPWSTR KeyName, SIZE_T KeySize, LPCWSTR RegPath, const GUID* riid)
121 {
122     WCHAR xriid[40];
123 
124     if (!StringFromGUID2(*riid, xriid, _countof(xriid) - 1))
125         return E_FAIL;
126 
127     return StringCchPrintfW(KeyName, KeySize, RegPath, xriid);
128 }
129 
130 HRESULT CGuidItemExtractIcon_CreateInstance(LPCITEMIDLIST pidl, REFIID iid, LPVOID * ppvOut)
131 {
132     CComPtr<IDefaultExtractIconInit>    initIcon;
133     HRESULT hr;
134     GUID const * riid;
135     int icon_idx;
136     WCHAR wTemp[MAX_PATH];
137 
138     hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit,&initIcon));
139     if (FAILED(hr))
140         return hr;
141 
142     if (_ILIsDesktop(pidl))
143     {
144         initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_DESKTOP);
145         return initIcon->QueryInterface(iid, ppvOut);
146     }
147 
148     riid = _ILGetGUIDPointer(pidl);
149     if (!riid)
150         return E_FAIL;
151 
152     /* Choose a correct icon for Recycle Bin (full or empty) */
153     const WCHAR* iconname = NULL;
154     if (_ILIsBitBucket(pidl))
155     {
156         CComPtr<IEnumIDList> EnumIDList;
157         CoInitialize(NULL);
158 
159         CComPtr<IShellFolder2> psfRecycleBin;
160         CComPtr<IShellFolder> psfDesktop;
161         hr = SHGetDesktopFolder(&psfDesktop);
162 
163         if (SUCCEEDED(hr))
164             hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder2, &psfRecycleBin));
165         if (SUCCEEDED(hr))
166             hr = psfRecycleBin->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &EnumIDList);
167 
168         ULONG itemcount;
169         LPITEMIDLIST pidl = NULL;
170         if (SUCCEEDED(hr) && (hr = EnumIDList->Next(1, &pidl, &itemcount)) == S_OK)
171         {
172             CoTaskMemFree(pidl);
173             iconname = L"Full";
174         } else {
175             iconname = L"Empty";
176         }
177     }
178 
179     /* Prepare registry path for loading icons of My Computer and other shell extensions */
180     WCHAR KeyName[MAX_PATH];
181 
182     hr = FormatGUIDKey(KeyName, _countof(KeyName),
183                        L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\%s",
184                        riid);
185     if (FAILED_UNEXPECTEDLY(hr))
186         return hr;
187 
188     /* Load icon for the current user */
189     BOOL ret = HCU_GetIconW(KeyName, wTemp, iconname, _countof(wTemp), &icon_idx);
190     if (!ret)
191     {
192         /* Failed, load default system-wide icon */
193         hr = FormatGUIDKey(KeyName, _countof(KeyName), L"CLSID\\%s", riid);
194         if (FAILED_UNEXPECTEDLY(hr))
195             return hr;
196 
197         ret = HCR_GetIconW(KeyName, wTemp, iconname, _countof(wTemp), &icon_idx);
198     }
199 
200     if (ret)
201     {
202         /* Success, set loaded icon */
203         initIcon->SetNormalIcon(wTemp, icon_idx);
204     }
205     else
206     {
207         /* Everything has failed, set blank paper icon */
208         WARN("Failed to load an icon for the item, setting blank icon\n");
209         initIcon->SetNormalIcon(swShell32Name, IDI_SHELL_DOCUMENT - 1);
210     }
211 
212     return initIcon->QueryInterface(iid, ppvOut);
213 }
214 
215 class CRegFolderEnum :
216     public CEnumIDListBase
217 {
218     public:
219         CRegFolderEnum();
220         ~CRegFolderEnum();
221         HRESULT Initialize(LPCWSTR lpszEnumKeyName, DWORD dwFlags);
222         HRESULT AddItemsFromKey(HKEY hkey_root, LPCWSTR szRepPath);
223 
224         BEGIN_COM_MAP(CRegFolderEnum)
225         COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
226         END_COM_MAP()
227 };
228 
229 CRegFolderEnum::CRegFolderEnum()
230 {
231 }
232 
233 CRegFolderEnum::~CRegFolderEnum()
234 {
235 }
236 
237 HRESULT CRegFolderEnum::Initialize(LPCWSTR lpszEnumKeyName, DWORD dwFlags)
238 {
239     WCHAR KeyName[MAX_PATH];
240 
241     if (!(dwFlags & SHCONTF_FOLDERS))
242         return S_OK;
243 
244     HRESULT hr = StringCchPrintfW(KeyName, MAX_PATH,
245                                   L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\%s\\Namespace",
246                                   lpszEnumKeyName);
247     if (FAILED_UNEXPECTEDLY(hr))
248         return hr;
249 
250     AddItemsFromKey(HKEY_LOCAL_MACHINE, KeyName);
251     AddItemsFromKey(HKEY_CURRENT_USER, KeyName);
252 
253     return S_OK;
254 }
255 
256 HRESULT CRegFolderEnum::AddItemsFromKey(HKEY hkey_root, LPCWSTR szRepPath)
257 {
258     WCHAR name[MAX_PATH];
259     HKEY hkey;
260 
261     if (RegOpenKeyW(hkey_root, szRepPath, &hkey) != ERROR_SUCCESS)
262         return S_FALSE;
263 
264     for (int idx = 0; ; idx++)
265     {
266         if (RegEnumKeyW(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS)
267             break;
268 
269         /* If the name of the key is not a guid try to get the default value of the key */
270         if (name[0] != L'{')
271         {
272             DWORD dwSize = sizeof(name);
273             RegGetValueW(hkey, name, NULL, RRF_RT_REG_SZ, NULL, name, &dwSize);
274         }
275 
276         if (*name == '{')
277         {
278             LPITEMIDLIST pidl = _ILCreateGuidFromStrW(name);
279 
280             if (pidl)
281                 AddToEnumList(pidl);
282         }
283     }
284 
285     RegCloseKey(hkey);
286 
287     return S_OK;
288 }
289 
290 /*
291  * These columns try to map to CFSFolder's columns because the CDesktopFolder
292  * displays CFSFolder and CRegFolder items in the same view.
293  */
294 enum REGFOLDERCOLUMNINDEX
295 {
296     COL_NAME = SHFSF_COL_NAME,
297     COL_TYPE = SHFSF_COL_TYPE,
298     COL_INFOTIP = SHFSF_COL_COMMENT,
299     REGFOLDERCOLUMNCOUNT = max(COL_INFOTIP, COL_TYPE) + 1
300 };
301 
302 class CRegFolder :
303     public CComObjectRootEx<CComMultiThreadModelNoCS>,
304     public IShellFolder2
305 {
306     private:
307         GUID m_guid;
308         CAtlStringW m_rootPath;
309         CAtlStringW m_enumKeyName;
310         CComHeapPtr<ITEMIDLIST> m_pidlRoot;
311 
312         HRESULT GetGuidItemAttributes (LPCITEMIDLIST pidl, LPDWORD pdwAttributes);
313         BOOL _IsInNameSpace(_In_ LPCITEMIDLIST pidl);
314 
315     public:
316         CRegFolder();
317         ~CRegFolder();
318         HRESULT WINAPI Initialize(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName);
319 
320         // IShellFolder
321         STDMETHOD(ParseDisplayName)(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) override;
322         STDMETHOD(EnumObjects)(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) override;
323         STDMETHOD(BindToObject)(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) override;
324         STDMETHOD(BindToStorage)(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) override;
325         STDMETHOD(CompareIDs)(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) override;
326         STDMETHOD(CreateViewObject)(HWND hwndOwner, REFIID riid, LPVOID *ppvOut) override;
327         STDMETHOD(GetAttributesOf)(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut) override;
328         STDMETHOD(GetUIObjectOf)(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut) override;
329         STDMETHOD(GetDisplayNameOf)(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) override;
330         STDMETHOD(SetNameOf)(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) override;
331 
332         /* ShellFolder2 */
333         STDMETHOD(GetDefaultSearchGUID)(GUID *pguid) override;
334         STDMETHOD(EnumSearches)(IEnumExtraSearch **ppenum) override;
335         STDMETHOD(GetDefaultColumn)(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) override;
336         STDMETHOD(GetDefaultColumnState)(UINT iColumn, DWORD *pcsFlags) override;
337         STDMETHOD(GetDetailsEx)(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) override;
338         STDMETHOD(GetDetailsOf)(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) override;
339         STDMETHOD(MapColumnToSCID)(UINT column, SHCOLUMNID *pscid) override;
340 
341         DECLARE_NOT_AGGREGATABLE(CRegFolder)
342 
343         DECLARE_PROTECT_FINAL_CONSTRUCT()
344 
345         BEGIN_COM_MAP(CRegFolder)
346         COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2)
347         COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder)
348         END_COM_MAP()
349 };
350 
351 CRegFolder::CRegFolder()
352 {
353 }
354 
355 CRegFolder::~CRegFolder()
356 {
357 }
358 
359 HRESULT WINAPI CRegFolder::Initialize(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName)
360 {
361     memcpy(&m_guid, pGuid, sizeof(m_guid));
362 
363     m_rootPath = lpszPath;
364     if (!m_rootPath)
365         return E_OUTOFMEMORY;
366 
367     m_enumKeyName = lpszEnumKeyName;
368     if (!m_enumKeyName)
369         return E_OUTOFMEMORY;
370 
371     m_pidlRoot.Attach(ILClone(pidlRoot));
372     if (!m_pidlRoot)
373         return E_OUTOFMEMORY;
374 
375     return S_OK;
376 }
377 
378 HRESULT CRegFolder::GetGuidItemAttributes (LPCITEMIDLIST pidl, LPDWORD pdwAttributes)
379 {
380     DWORD dwAttributes = *pdwAttributes;
381 
382     /* First try to get them from the registry */
383     if (!HCR_GetFolderAttributes(pidl, pdwAttributes))
384     {
385         /* We couldn't get anything */
386         *pdwAttributes = 0;
387     }
388 
389     /* Items have more attributes when on desktop */
390     if (_ILIsDesktop(m_pidlRoot))
391     {
392         *pdwAttributes |= (dwAttributes & (SFGAO_CANLINK|SFGAO_CANDELETE|SFGAO_CANRENAME|SFGAO_HASPROPSHEET));
393     }
394 
395     /* In any case, links can be created */
396     *pdwAttributes |= (dwAttributes & SFGAO_CANLINK);
397     return S_OK;
398 }
399 
400 BOOL CRegFolder::_IsInNameSpace(_In_ LPCITEMIDLIST pidl)
401 {
402     CLSID clsid = *_ILGetGUIDPointer(pidl);
403     if (IsEqualGUID(clsid, CLSID_Printers))
404         return TRUE;
405     if (IsEqualGUID(clsid, CLSID_ConnectionFolder))
406         return TRUE;
407     FIXME("Check registry\n");
408     return TRUE;
409 }
410 
411 HRESULT WINAPI CRegFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
412         ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes)
413 {
414     if (!ppidl)
415         return E_INVALIDARG;
416 
417     *ppidl = NULL;
418 
419     if (!lpszDisplayName)
420         return E_INVALIDARG;
421 
422     if (lpszDisplayName[0] != L':' || lpszDisplayName[1] != L':')
423     {
424         FIXME("What should we do here?\n");
425         return E_FAIL;
426     }
427 
428     LPWSTR pch, pchNextOfComma = NULL;
429     for (pch = &lpszDisplayName[2]; *pch && *pch != L'\\'; ++pch)
430     {
431         if (*pch == L',' && !pchNextOfComma)
432             pchNextOfComma = pch + 1;
433     }
434 
435     CLSID clsid;
436     if (!GUIDFromStringW(&lpszDisplayName[2], &clsid))
437         return CO_E_CLASSSTRING;
438 
439     if (pchNextOfComma)
440     {
441         FIXME("Delegate folder\n");
442         return E_FAIL;
443     }
444 
445     CComHeapPtr<ITEMIDLIST> pidlTemp(_ILCreateGuid(PT_GUID, clsid));
446     if (!pidlTemp)
447         return E_OUTOFMEMORY;
448 
449     if (!_IsInNameSpace(pidlTemp) && !(BindCtx_GetMode(pbc, 0) & STGM_CREATE))
450         return E_INVALIDARG;
451 
452     *ppidl = pidlTemp.Detach();
453 
454     if (!*pch)
455     {
456         if (pdwAttributes && *pdwAttributes)
457             GetGuidItemAttributes(*ppidl, pdwAttributes);
458 
459         return S_OK;
460     }
461 
462     HRESULT hr = SHELL32_ParseNextElement(this, hwndOwner, pbc, ppidl, pch + 1, pchEaten,
463                                           pdwAttributes);
464     if (FAILED(hr))
465     {
466         ILFree(*ppidl);
467         *ppidl = NULL;
468     }
469     return hr;
470 }
471 
472 HRESULT WINAPI CRegFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
473 {
474     return ShellObjectCreatorInit<CRegFolderEnum>(m_enumKeyName, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
475 }
476 
477 HRESULT WINAPI CRegFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
478 {
479     CComPtr<IPersistFolder> pFolder;
480     HRESULT hr;
481 
482     if (!ppvOut || !pidl || !pidl->mkid.cb)
483         return E_INVALIDARG;
484 
485     *ppvOut = NULL;
486 
487     GUID *pGUID = _ILGetGUIDPointer(pidl);
488     if (!pGUID)
489     {
490         ERR("CRegFolder::BindToObject called for non guid item!\n");
491         return E_INVALIDARG;
492     }
493 
494     hr = SHELL32_BindToSF(m_pidlRoot, NULL, pidl, pGUID, riid, ppvOut);
495     if (FAILED_UNEXPECTEDLY(hr))
496         return hr;
497 
498     return S_OK;
499 }
500 
501 HRESULT WINAPI CRegFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
502 {
503     return E_NOTIMPL;
504 }
505 
506 HRESULT WINAPI CRegFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
507 {
508     if (!pidl1 || !pidl2 || pidl1->mkid.cb == 0 || pidl2->mkid.cb == 0)
509     {
510         ERR("Got an empty pidl!\n");
511         return E_INVALIDARG;
512     }
513 
514     GUID const *clsid1 = _ILGetGUIDPointer (pidl1);
515     GUID const *clsid2 = _ILGetGUIDPointer (pidl2);
516 
517     if (!clsid1 && !clsid2)
518     {
519         ERR("Got no guid pidl!\n");
520         return E_INVALIDARG;
521     }
522     else if (clsid1 && clsid2)
523     {
524         if (memcmp(clsid1, clsid2, sizeof(GUID)) == 0)
525             return SHELL32_CompareChildren(this, lParam, pidl1, pidl2);
526 
527         return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
528     }
529 
530     /* Guid folders come first compared to everything else */
531     /* And Drives come before folders in My Computer */
532     if (_ILIsMyComputer(m_pidlRoot))
533     {
534         return MAKE_COMPARE_HRESULT(clsid1 ? 1 : -1);
535     }
536     else
537     {
538         return MAKE_COMPARE_HRESULT(clsid1 ? -1 : 1);
539     }
540 }
541 
542 HRESULT WINAPI CRegFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
543 {
544     return E_NOTIMPL;
545 }
546 
547 HRESULT WINAPI CRegFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
548 {
549     if (!rgfInOut || !cidl || !apidl)
550         return E_INVALIDARG;
551 
552     if (*rgfInOut == 0)
553         *rgfInOut = ~0;
554 
555     while(cidl > 0 && *apidl)
556     {
557         if (_ILIsSpecialFolder(*apidl))
558             GetGuidItemAttributes(*apidl, rgfInOut);
559         else
560             ERR("Got unknown pidl\n");
561         apidl++;
562         cidl--;
563     }
564 
565     /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
566     *rgfInOut &= ~SFGAO_VALIDATE;
567 
568     return S_OK;
569 }
570 
571 HRESULT WINAPI CRegFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
572         REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
573 {
574     LPVOID pObj = NULL;
575     HRESULT hr = E_INVALIDARG;
576 
577     if (!ppvOut)
578         return hr;
579 
580     *ppvOut = NULL;
581 
582     if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
583     {
584         hr = CGuidItemExtractIcon_CreateInstance(apidl[0], riid, &pObj);
585     }
586     else if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
587     {
588         if (!_ILGetGUIDPointer (apidl[0]))
589         {
590             ERR("Got non guid item!\n");
591             return E_FAIL;
592         }
593 
594         hr = CGuidItemContextMenu_CreateInstance(m_pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj);
595     }
596     else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
597     {
598         hr = IDataObject_Constructor (hwndOwner, m_pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj);
599     }
600     else
601     {
602         hr = E_NOINTERFACE;
603     }
604 
605     *ppvOut = pObj;
606     return hr;
607 
608 }
609 
610 HRESULT WINAPI CRegFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
611 {
612     if (!strRet || (!_ILIsSpecialFolder(pidl) && pidl != NULL))
613         return E_INVALIDARG;
614 
615     if (!pidl || !pidl->mkid.cb)
616     {
617         if ((GET_SHGDN_RELATION(dwFlags) == SHGDN_NORMAL) && (GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING))
618         {
619             LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
620             if (!pszPath)
621                 return E_OUTOFMEMORY;
622 
623             /* parsing name like ::{...} */
624             pszPath[0] = ':';
625             pszPath[1] = ':';
626             SHELL32_GUIDToStringW(m_guid, &pszPath[2]);
627 
628             strRet->uType = STRRET_WSTR;
629             strRet->pOleStr = pszPath;
630 
631             return S_OK;
632         }
633         else
634         {
635             BOOL bRet;
636             WCHAR wstrName[MAX_PATH+1];
637             bRet = HCR_GetClassNameW(m_guid, wstrName, MAX_PATH);
638             if (!bRet)
639                 return E_FAIL;
640 
641             return SHSetStrRet(strRet, wstrName);
642 
643         }
644     }
645 
646     HRESULT hr;
647     GUID const *clsid = _ILGetGUIDPointer (pidl);
648 
649     /* First of all check if we need to query the name from the child item */
650     if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING &&
651         GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL)
652     {
653         int bWantsForParsing = FALSE;
654 
655         /*
656             * We can only get a filesystem path from a shellfolder if the
657             *  value WantsFORPARSING in CLSID\\{...}\\shellfolder exists.
658             *
659             * Exception: The MyComputer folder doesn't have this key,
660             *   but any other filesystem backed folder it needs it.
661             */
662         if (IsEqualIID (*clsid, CLSID_MyComputer))
663         {
664             bWantsForParsing = TRUE;
665         }
666         else
667         {
668             HKEY hkeyClass;
669             if (HCR_RegOpenClassIDKey(*clsid, &hkeyClass))
670             {
671                 LONG res = SHGetValueW(hkeyClass, L"Shellfolder", L"WantsForParsing", NULL, NULL, NULL);
672                 bWantsForParsing = (res == ERROR_SUCCESS);
673                 RegCloseKey(hkeyClass);
674             }
675         }
676 
677         if (bWantsForParsing)
678         {
679             /*
680              * we need the filesystem path to the destination folder.
681              * Only the folder itself can know it
682              */
683             return SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags, strRet);
684         }
685     }
686 
687     /* Allocate the buffer for the result */
688     SIZE_T cchPath = MAX_PATH + 1;
689     LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc(cchPath * sizeof(WCHAR));
690     if (!pszPath)
691         return E_OUTOFMEMORY;
692 
693     hr = S_OK;
694 
695     if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING)
696     {
697         SIZE_T pathlen = 0;
698         PWCHAR pItemName = pszPath; // GET_SHGDN_RELATION(dwFlags) == SHGDN_INFOLDER
699         if (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER)
700         {
701             hr = StringCchCopyW(pszPath, cchPath, m_rootPath);
702             if (SUCCEEDED(hr))
703             {
704                 pathlen = wcslen(pszPath);
705                 pItemName = &pszPath[pathlen];
706                 if (pathlen)
707                 {
708                     if (++pathlen < cchPath)
709                         *pItemName++ = L'\\';
710                     else
711                         hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
712                 }
713             }
714         }
715 
716         if (SUCCEEDED(hr) && pathlen + 2 + 38 + 1 < cchPath)
717         {
718             /* parsing name like ::{...} */
719             pItemName[0] = L':';
720             pItemName[1] = L':';
721             SHELL32_GUIDToStringW(*clsid, &pItemName[2]);
722         }
723         else
724         {
725             hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
726         }
727     }
728     else
729     {
730         /* user friendly name */
731         if (!HCR_GetClassNameW(*clsid, pszPath, cchPath))
732             hr = E_FAIL;
733     }
734 
735     if (SUCCEEDED(hr))
736     {
737         strRet->uType = STRRET_WSTR;
738         strRet->pOleStr = pszPath;
739     }
740     else
741     {
742         CoTaskMemFree(pszPath);
743     }
744 
745     return hr;
746 }
747 
748 HRESULT WINAPI CRegFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl,    /* simple pidl */
749         LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
750 {
751     GUID const *clsid = _ILGetGUIDPointer (pidl);
752     LPOLESTR pStr;
753     HRESULT hr;
754     WCHAR szName[100];
755 
756     if (!clsid)
757     {
758         ERR("Pidl is not reg item!\n");
759         return E_FAIL;
760     }
761 
762     hr = StringFromCLSID(*clsid, &pStr);
763     if (FAILED_UNEXPECTEDLY(hr))
764         return hr;
765 
766     swprintf(szName, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\%s", pStr);
767 
768     DWORD cbData = (wcslen(lpName) + 1) * sizeof(WCHAR);
769     LONG res = SHSetValueW(HKEY_CURRENT_USER, szName, NULL, RRF_RT_REG_SZ, lpName, cbData);
770 
771     CoTaskMemFree(pStr);
772 
773     if (res == ERROR_SUCCESS)
774     {
775         return pPidlOut ? SHILClone(pidl, pPidlOut) : S_OK;
776     }
777 
778     return E_FAIL;
779 }
780 
781 
782 HRESULT WINAPI CRegFolder::GetDefaultSearchGUID(GUID *pguid)
783 {
784     return E_NOTIMPL;
785 }
786 
787 HRESULT WINAPI CRegFolder::EnumSearches(IEnumExtraSearch ** ppenum)
788 {
789     return E_NOTIMPL;
790 }
791 
792 HRESULT WINAPI CRegFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
793 {
794     if (pSort)
795         *pSort = 0;
796     if (pDisplay)
797         *pDisplay = 0;
798 
799     return S_OK;
800 }
801 
802 HRESULT WINAPI CRegFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
803 {
804     if (iColumn >= REGFOLDERCOLUMNCOUNT)
805         return E_INVALIDARG;
806     *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT;
807     return S_OK;
808 }
809 
810 HRESULT WINAPI CRegFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
811 {
812     return E_NOTIMPL;
813 }
814 
815 HRESULT WINAPI CRegFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
816 {
817     if (!psd)
818         return E_INVALIDARG;
819 
820     if (!pidl)
821     {
822         TRACE("CRegFolder has no column info\n");
823         return E_INVALIDARG;
824     }
825 
826     GUID const *clsid = _ILGetGUIDPointer (pidl);
827 
828     if (!clsid)
829     {
830         ERR("Pidl is not reg item!\n");
831         return E_INVALIDARG;
832     }
833 
834     switch(iColumn)
835     {
836         case COL_NAME:
837             return GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
838         case COL_TYPE:
839             return SHSetStrRet(&psd->str, IDS_SYSTEMFOLDER);
840         case COL_INFOTIP:
841             HKEY hKey;
842             if (!HCR_RegOpenClassIDKey(*clsid, &hKey))
843                 return SHSetStrRet(&psd->str, "");
844 
845             psd->str.cStr[0] = 0x00;
846             psd->str.uType = STRRET_CSTR;
847             RegLoadMUIStringA(hKey, "InfoTip", psd->str.cStr, MAX_PATH, NULL, 0, NULL);
848             RegCloseKey(hKey);
849             return S_OK;
850         default:
851             /* Return an empty string when we area asked for a column we don't support.
852                Only  the regfolder is supposed to do this as it supports less columns compared to other folder
853                and its contents are supposed to be presented alongside items that support more columns. */
854             return SHSetStrRet(&psd->str, "");
855     }
856     return E_FAIL;
857 }
858 
859 HRESULT WINAPI CRegFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
860 {
861     return E_NOTIMPL;
862 }
863 
864 /* In latest windows version this is exported but it takes different arguments! */
865 HRESULT CRegFolder_CreateInstance(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName, REFIID riid, void **ppv)
866 {
867     return ShellObjectCreatorInit<CRegFolder>(pGuid, pidlRoot, lpszPath, lpszEnumKeyName, riid, ppv);
868 }
869