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