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