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