[SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / folders / CRegFolder.cpp
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)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)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)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 }