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