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