[SDK][SHELL32] Augment the internally used IDataObject with some extra formats
[reactos.git] / 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_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 }