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