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