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