[SHELL32] -Add Comments as the 2nd column in CDesktopFolder, CDrivesFolder and CRegFo...
[reactos.git] / reactos / dll / win32 / shell32 / folders / CDesktopFolder.cpp
1 /*
2 * Virtual Desktop Folder
3 *
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 * Copyright 2009 Andrew Hill
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include <precomp.h>
24
25 WINE_DEFAULT_DEBUG_CHANNEL(shell);
26
27 /*
28 CDesktopFolder should create two file system folders internally, one representing the
29 user's desktop folder, and the other representing the common desktop folder. It should
30 also create a CRegFolder to represent the virtual items that exist only in the registry.
31 The CRegFolder is aggregated by the CDesktopFolder, and queries for the CLSID_IShellFolder,
32 CLSID_IShellFolder2, or CLSID_IShellIconOverlay interfaces prefer the CRegFolder
33 implementation.
34 The CDesktopFolderEnum class should create two enumerators, one for each of the file
35 system folders, and enumerate the contents of each folder. Since the CRegFolder
36 implementation of IShellFolder::EnumObjects enumerates the virtual items, the
37 CDesktopFolderEnum is only responsible for returning the physical items.
38 CDesktopFolderEnum is incorrect where it filters My Computer from the enumeration
39 if the new start menu is used. The CDesktopViewCallback is responsible for filtering
40 it from the view by handling the IncludeObject query to return S_FALSE. The enumerator
41 always shows My Computer.
42 */
43
44 /* Undocumented functions from shdocvw */
45 extern "C" HRESULT WINAPI IEParseDisplayNameWithBCW(DWORD codepage, LPCWSTR lpszDisplayName, LPBC pbc, LPITEMIDLIST *ppidl);
46
47 class CDesktopFolderEnum :
48 public CEnumIDListBase
49 {
50 private:
51 // CComPtr fDesktopEnumerator;
52 // CComPtr fCommonDesktopEnumerator;
53 public:
54 CDesktopFolderEnum();
55 ~CDesktopFolderEnum();
56 HRESULT WINAPI Initialize(CDesktopFolder *desktopFolder, HWND hwndOwner, DWORD dwFlags);
57
58 BEGIN_COM_MAP(CDesktopFolderEnum)
59 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
60 END_COM_MAP()
61 };
62
63 int SHELL_ConfirmMsgBox(HWND hWnd, LPWSTR lpszText, LPWSTR lpszCaption, HICON hIcon, BOOL bYesToAll);
64
65 static const shvheader DesktopSFHeader[] = {
66 {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
67 {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 10},
68 {IDS_SHV_COLUMN_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10},
69 {IDS_SHV_COLUMN_SIZE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
70 {IDS_SHV_COLUMN_MODIFIED, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 12},
71 {IDS_SHV_COLUMN_ATTRIBUTES, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10}
72 };
73
74 #define DESKTOPSHELLVIEWCOLUMNS 6
75
76 static const DWORD dwDesktopAttributes =
77 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
78 SFGAO_STORAGEANCESTOR | SFGAO_HASPROPSHEET | SFGAO_STORAGE | SFGAO_CANLINK;
79 static const DWORD dwMyComputerAttributes =
80 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
81 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
82 static DWORD dwMyNetPlacesAttributes =
83 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
84 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
85
86
87 CDesktopFolderEnum::CDesktopFolderEnum()
88 {
89 }
90
91 CDesktopFolderEnum::~CDesktopFolderEnum()
92 {
93 }
94
95 static const WCHAR ClassicStartMenuW[] = L"SOFTWARE\\Microsoft\\Windows\\"
96 L"CurrentVersion\\Explorer\\HideDesktopIcons\\ClassicStartMenu";
97
98 static INT
99 IsNamespaceExtensionHidden(const WCHAR *iid)
100 {
101 DWORD Result, dwResult;
102 dwResult = sizeof(DWORD);
103
104 if (RegGetValueW(HKEY_CURRENT_USER, /* FIXME use NewStartPanel when activated */
105 ClassicStartMenuW,
106 iid,
107 RRF_RT_DWORD,
108 NULL,
109 &Result,
110 &dwResult) != ERROR_SUCCESS)
111 {
112 return -1;
113 }
114
115 return Result;
116 }
117
118 /**************************************************************************
119 * CreateDesktopEnumList()
120 */
121
122 HRESULT WINAPI CDesktopFolderEnum::Initialize(CDesktopFolder *desktopFolder, HWND hwndOwner, DWORD dwFlags)
123 {
124 BOOL ret = TRUE;
125 WCHAR szPath[MAX_PATH];
126
127 static const WCHAR MyDocumentsClassString[] = L"{450D8FBA-AD25-11D0-98A8-0800361B1103}";
128 static const WCHAR Desktop_NameSpaceW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\Namespace";
129
130 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
131
132 /* enumerate the root folders */
133 if (dwFlags & SHCONTF_FOLDERS)
134 {
135 HKEY hkey;
136 UINT i;
137 DWORD dwResult;
138
139 /* create the pidl for This item */
140 if (IsNamespaceExtensionHidden(MyDocumentsClassString) < 1)
141 {
142 ret = AddToEnumList(_ILCreateMyDocuments());
143 }
144 ret = AddToEnumList(_ILCreateMyComputer());
145
146 for (i = 0; i < 2; i++)
147 {
148 if (i == 0)
149 dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
150 else
151 dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
152
153 if (dwResult == ERROR_SUCCESS)
154 {
155 WCHAR iid[50];
156 LPITEMIDLIST pidl;
157 int i = 0;
158
159 while (ret)
160 {
161 DWORD size;
162 LONG r;
163
164 size = sizeof (iid) / sizeof (iid[0]);
165 r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
166 if (ERROR_SUCCESS == r)
167 {
168 if (IsNamespaceExtensionHidden(iid) < 1)
169 {
170 pidl = _ILCreateGuidFromStrW(iid);
171 if (pidl != NULL)
172 {
173 if (!HasItemWithCLSID(pidl))
174 {
175 ret = AddToEnumList(pidl);
176 }
177 else
178 {
179 SHFree(pidl);
180 }
181 }
182 }
183 }
184 else if (ERROR_NO_MORE_ITEMS == r)
185 break;
186 else
187 ret = FALSE;
188 i++;
189 }
190 RegCloseKey(hkey);
191 }
192 }
193 for (i = 0; i < 2; i++)
194 {
195 if (i == 0)
196 dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, ClassicStartMenuW, 0, KEY_READ, &hkey);
197 else
198 dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, ClassicStartMenuW, 0, KEY_READ, &hkey);
199
200 if (dwResult == ERROR_SUCCESS)
201 {
202 DWORD j = 0, dwVal, Val, dwType, dwIID;
203 LONG r;
204 WCHAR iid[50];
205
206 while(ret)
207 {
208 dwVal = sizeof(Val);
209 dwIID = sizeof(iid) / sizeof(WCHAR);
210
211 r = RegEnumValueW(hkey, j++, iid, &dwIID, NULL, &dwType, (LPBYTE)&Val, &dwVal);
212 if (r == ERROR_SUCCESS)
213 {
214 if (Val == 0 && dwType == REG_DWORD)
215 {
216 LPITEMIDLIST pidl = _ILCreateGuidFromStrW(iid);
217 if (pidl != NULL)
218 {
219 if (!HasItemWithCLSID(pidl))
220 {
221 AddToEnumList(pidl);
222 }
223 else
224 {
225 SHFree(pidl);
226 }
227 }
228 }
229 }
230 else if (ERROR_NO_MORE_ITEMS == r)
231 break;
232 else
233 ret = FALSE;
234 }
235 RegCloseKey(hkey);
236 }
237
238 }
239 }
240
241 /* enumerate the elements in %windir%\desktop */
242 ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
243 ret = ret && CreateFolderEnumList(szPath, dwFlags);
244
245 ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
246 ret = ret && CreateFolderEnumList(szPath, dwFlags);
247
248 return ret ? S_OK : E_FAIL;
249 }
250
251 CDesktopFolder::CDesktopFolder() :
252 sPathTarget(NULL),
253 pidlRoot(NULL)
254 {
255 }
256
257 CDesktopFolder::~CDesktopFolder()
258 {
259 }
260
261 HRESULT WINAPI CDesktopFolder::FinalConstruct()
262 {
263 WCHAR szMyPath[MAX_PATH];
264 HRESULT hr;
265
266 /* Create the root pidl */
267 pidlRoot = _ILCreateDesktop();
268 if (!pidlRoot)
269 return E_OUTOFMEMORY;
270
271 /* Create the inner fs folder */
272 hr = SHELL32_CoCreateInitSF(pidlRoot,
273 NULL,
274 NULL,
275 &CLSID_ShellFSFolder,
276 CSIDL_DESKTOPDIRECTORY,
277 IID_PPV_ARG(IShellFolder2, &m_DesktopFSFolder));
278 if (FAILED_UNEXPECTEDLY(hr))
279 return hr;
280
281 /* Create the inner shared fs folder. Dont fail on failure. */
282 hr = SHELL32_CoCreateInitSF(pidlRoot,
283 NULL,
284 NULL,
285 &CLSID_ShellFSFolder,
286 CSIDL_COMMON_DESKTOPDIRECTORY,
287 IID_PPV_ARG(IShellFolder2, &m_SharedDesktopFSFolder));
288 if (FAILED_UNEXPECTEDLY(hr))
289 return hr;
290
291 /* Create the inner reg folder */
292 hr = CRegFolder_CreateInstance(&CLSID_ShellDesktop,
293 pidlRoot,
294 L"",
295 IID_PPV_ARG(IShellFolder2, &m_regFolder));
296 if (FAILED_UNEXPECTEDLY(hr))
297 return hr;
298
299 /* Cache the path to the user desktop directory */
300 if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
301 return E_UNEXPECTED;
302
303 sPathTarget = (LPWSTR)SHAlloc((wcslen(szMyPath) + 1) * sizeof(WCHAR));
304 if (!sPathTarget)
305 return E_OUTOFMEMORY;
306
307 wcscpy(sPathTarget, szMyPath);
308 return S_OK;
309 }
310
311 HRESULT CDesktopFolder::_GetSFFromPidl(LPCITEMIDLIST pidl, IShellFolder2** psf)
312 {
313 WCHAR szFileName[MAX_PATH];
314
315 if (_ILIsSpecialFolder(pidl))
316 return m_regFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf));
317
318 lstrcpynW(szFileName, sPathTarget, MAX_PATH - 1);
319 PathAddBackslashW(szFileName);
320 int cLen = wcslen(szFileName);
321
322 if (!_ILSimpleGetTextW(pidl, szFileName + cLen, MAX_PATH - cLen))
323 return E_FAIL;
324
325 if (GetFileAttributes(szFileName) == INVALID_FILE_ATTRIBUTES)
326 return m_SharedDesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf));
327 else
328 return m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf));
329 }
330
331 /**************************************************************************
332 * CDesktopFolder::ParseDisplayName
333 *
334 * NOTES
335 * "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
336 * to MyComputer
337 */
338 HRESULT WINAPI CDesktopFolder::ParseDisplayName(
339 HWND hwndOwner,
340 LPBC pbc,
341 LPOLESTR lpszDisplayName,
342 DWORD *pchEaten,
343 PIDLIST_RELATIVE *ppidl,
344 DWORD *pdwAttributes)
345 {
346 LPCWSTR szNext = NULL;
347 LPITEMIDLIST pidlTemp = NULL;
348 PARSEDURLW urldata;
349 HRESULT hr = S_OK;
350
351 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
352 this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
353 pchEaten, ppidl, pdwAttributes);
354
355 if (!ppidl)
356 return E_INVALIDARG;
357
358 *ppidl = NULL;
359
360 if (!lpszDisplayName)
361 return E_INVALIDARG;
362
363 if (pchEaten)
364 *pchEaten = 0; /* strange but like the original */
365
366 urldata.cbSize = sizeof(urldata);
367
368 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
369 {
370 return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
371 }
372 else if (PathGetDriveNumberW (lpszDisplayName) >= 0)
373 {
374 /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
375 pidlTemp = _ILCreateMyComputer ();
376 szNext = lpszDisplayName;
377 }
378 else if (PathIsUNCW(lpszDisplayName))
379 {
380 pidlTemp = _ILCreateNetwork();
381 szNext = lpszDisplayName;
382 }
383 else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
384 {
385 *ppidl = pidlTemp;
386 return S_OK;
387 }
388 else if (SUCCEEDED(ParseURLW(lpszDisplayName, &urldata)))
389 {
390 if (urldata.nScheme == URL_SCHEME_SHELL) /* handle shell: urls */
391 {
392 TRACE ("-- shell url: %s\n", debugstr_w(urldata.pszSuffix));
393 pidlTemp = _ILCreateGuidFromStrW(urldata.pszSuffix + 2);
394 }
395 else
396 return IEParseDisplayNameWithBCW(CP_ACP, lpszDisplayName, pbc, ppidl);
397 }
398 else
399 {
400 if (*lpszDisplayName)
401 {
402 /* it's a filesystem path on the desktop. Let a FSFolder parse it */
403 hr = m_DesktopFSFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
404 if (SUCCEEDED(hr))
405 return hr;
406
407 return m_SharedDesktopFSFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
408 }
409 else
410 pidlTemp = _ILCreateMyComputer();
411
412 szNext = NULL;
413 }
414
415 if (SUCCEEDED(hr) && pidlTemp)
416 {
417 if (szNext && *szNext)
418 {
419 hr = SHELL32_ParseNextElement(this, hwndOwner, pbc,
420 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
421 }
422 else
423 {
424 if (pdwAttributes && *pdwAttributes)
425 {
426 GetAttributesOf(1, &pidlTemp, pdwAttributes);
427 }
428 }
429 }
430
431 if (SUCCEEDED(hr))
432 *ppidl = pidlTemp;
433 else
434 *ppidl = NULL;
435
436 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
437
438 return hr;
439 }
440
441 /**************************************************************************
442 * CDesktopFolder::EnumObjects
443 */
444 HRESULT WINAPI CDesktopFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
445 {
446 return ShellObjectCreatorInit<CDesktopFolderEnum>(this, hwndOwner, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
447 }
448
449 /**************************************************************************
450 * CDesktopFolder::BindToObject
451 */
452 HRESULT WINAPI CDesktopFolder::BindToObject(
453 PCUIDLIST_RELATIVE pidl,
454 LPBC pbcReserved,
455 REFIID riid,
456 LPVOID *ppvOut)
457 {
458 if (!pidl)
459 return E_INVALIDARG;
460
461 CComPtr<IShellFolder2> psf;
462 HRESULT hr = _GetSFFromPidl(pidl, &psf);
463 if (FAILED_UNEXPECTEDLY(hr))
464 return hr;
465
466 return psf->BindToObject(pidl, pbcReserved, riid, ppvOut);
467 }
468
469 /**************************************************************************
470 * CDesktopFolder::BindToStorage
471 */
472 HRESULT WINAPI CDesktopFolder::BindToStorage(
473 PCUIDLIST_RELATIVE pidl,
474 LPBC pbcReserved,
475 REFIID riid,
476 LPVOID *ppvOut)
477 {
478 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
479 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
480
481 *ppvOut = NULL;
482 return E_NOTIMPL;
483 }
484
485 /**************************************************************************
486 * CDesktopFolder::CompareIDs
487 */
488 HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
489 {
490 bool bIsDesktopFolder1, bIsDesktopFolder2;
491
492 if (!pidl1 || !pidl2)
493 {
494 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2);
495 return E_INVALIDARG;
496 }
497
498 bIsDesktopFolder1 = _ILIsDesktop(pidl1);
499 bIsDesktopFolder2 = _ILIsDesktop(pidl2);
500 if (bIsDesktopFolder1 || bIsDesktopFolder2)
501 return MAKE_COMPARE_HRESULT(bIsDesktopFolder1 - bIsDesktopFolder2);
502
503 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
504 return m_regFolder->CompareIDs(lParam, pidl1, pidl2);
505
506 return m_DesktopFSFolder->CompareIDs(lParam, pidl1, pidl2);
507 }
508
509 /**************************************************************************
510 * CDesktopFolder::CreateViewObject
511 */
512 HRESULT WINAPI CDesktopFolder::CreateViewObject(
513 HWND hwndOwner,
514 REFIID riid,
515 LPVOID *ppvOut)
516 {
517 CComPtr<IShellView> pShellView;
518 HRESULT hr = E_INVALIDARG;
519
520 TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
521 this, hwndOwner, shdebugstr_guid (&riid), ppvOut);
522
523 if (!ppvOut)
524 return hr;
525
526 *ppvOut = NULL;
527
528 if (IsEqualIID (riid, IID_IDropTarget))
529 {
530 hr = m_DesktopFSFolder->CreateViewObject(hwndOwner, riid, ppvOut);
531 }
532 else if (IsEqualIID (riid, IID_IContextMenu))
533 {
534 HKEY hKeys[16];
535 UINT cKeys = 0;
536 AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys);
537
538 DEFCONTEXTMENU dcm;
539 dcm.hwnd = hwndOwner;
540 dcm.pcmcb = this;
541 dcm.pidlFolder = pidlRoot;
542 dcm.psf = this;
543 dcm.cidl = 0;
544 dcm.apidl = NULL;
545 dcm.cKeys = cKeys;
546 dcm.aKeys = hKeys;
547 dcm.punkAssociationInfo = NULL;
548 hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut);
549 }
550 else if (IsEqualIID (riid, IID_IShellView))
551 {
552 hr = IShellView_Constructor((IShellFolder *)this, &pShellView);
553 if (pShellView)
554 hr = pShellView->QueryInterface(riid, ppvOut);
555 }
556 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
557 return hr;
558 }
559
560 /**************************************************************************
561 * CDesktopFolder::GetAttributesOf
562 */
563 HRESULT WINAPI CDesktopFolder::GetAttributesOf(
564 UINT cidl,
565 PCUITEMID_CHILD_ARRAY apidl,
566 DWORD *rgfInOut)
567 {
568 HRESULT hr = S_OK;
569
570 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
571 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
572
573 if (cidl && !apidl)
574 return E_INVALIDARG;
575
576 if (*rgfInOut == 0)
577 *rgfInOut = ~0;
578
579 if(cidl == 0)
580 *rgfInOut &= dwDesktopAttributes;
581 else
582 {
583 /* TODO: always add SFGAO_CANLINK */
584 for (UINT i = 0; i < cidl; ++i)
585 {
586 pdump(*apidl);
587 if (_ILIsDesktop(*apidl))
588 *rgfInOut &= dwDesktopAttributes;
589 else if (_ILIsMyComputer(apidl[i]))
590 *rgfInOut &= dwMyComputerAttributes;
591 else if (_ILIsNetHood(apidl[i]))
592 *rgfInOut &= dwMyNetPlacesAttributes;
593 else if (_ILIsFolder(apidl[i]) || _ILIsValue(apidl[i]) || _ILIsSpecialFolder(apidl[i]))
594 {
595 CComPtr<IShellFolder2> psf;
596 HRESULT hr = _GetSFFromPidl(apidl[i], &psf);
597 if (FAILED_UNEXPECTEDLY(hr))
598 continue;
599
600 psf->GetAttributesOf(1, &apidl[i], rgfInOut);
601 }
602 else
603 ERR("Got an unknown pidl type!!!\n");
604 }
605 }
606 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
607 *rgfInOut &= ~SFGAO_VALIDATE;
608
609 TRACE("-- result=0x%08x\n", *rgfInOut);
610
611 return hr;
612 }
613
614 /**************************************************************************
615 * CDesktopFolder::GetUIObjectOf
616 *
617 * PARAMETERS
618 * HWND hwndOwner, //[in ] Parent window for any output
619 * UINT cidl, //[in ] array size
620 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
621 * REFIID riid, //[in ] Requested Interface
622 * UINT* prgfInOut, //[ ] reserved
623 * LPVOID* ppvObject) //[out] Resulting Interface
624 *
625 */
626 HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
627 HWND hwndOwner,
628 UINT cidl,
629 PCUITEMID_CHILD_ARRAY apidl,
630 REFIID riid,
631 UINT *prgfInOut,
632 LPVOID *ppvOut)
633 {
634 LPVOID pObj = NULL;
635 HRESULT hr = E_INVALIDARG;
636
637 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
638 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
639
640 if (!ppvOut)
641 return hr;
642
643 *ppvOut = NULL;
644
645 if (cidl == 1 && !_ILIsSpecialFolder(apidl[0]))
646 {
647 CComPtr<IShellFolder2> psf;
648 HRESULT hr = _GetSFFromPidl(apidl[0], &psf);
649 if (FAILED_UNEXPECTEDLY(hr))
650 return hr;
651
652 return psf->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut);
653 }
654
655 if (IsEqualIID (riid, IID_IContextMenu))
656 {
657 if (_ILIsSpecialFolder(apidl[0]))
658 {
659 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
660 }
661 else
662 {
663 /* Do not use the context menu of the CFSFolder here. */
664 /* We need to pass a pointer of the CDesktopFolder so as the data object that the context menu gets is rooted to the desktop */
665 /* Otherwise operations like that involve items from both user and shared desktop will not work */
666 HKEY hKeys[16];
667 UINT cKeys = 0;
668 AddFSClassKeysToArray(apidl[0], hKeys, &cKeys);
669
670 DEFCONTEXTMENU dcm;
671 dcm.hwnd = hwndOwner;
672 dcm.pcmcb = this;
673 dcm.pidlFolder = pidlRoot;
674 dcm.psf = this;
675 dcm.cidl = cidl;
676 dcm.apidl = apidl;
677 dcm.cKeys = cKeys;
678 dcm.aKeys = hKeys;
679 dcm.punkAssociationInfo = NULL;
680 hr = SHCreateDefaultContextMenu (&dcm, riid, &pObj);
681 }
682 }
683 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
684 {
685 hr = IDataObject_Constructor( hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
686 }
687 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
688 {
689 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
690 }
691 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1))
692 {
693 CComPtr<IShellFolder> psfChild;
694 hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild));
695 if (FAILED_UNEXPECTEDLY(hr))
696 return hr;
697
698 return psfChild->CreateViewObject(NULL, riid, ppvOut);
699 }
700 else
701 hr = E_NOINTERFACE;
702
703 if (SUCCEEDED(hr) && !pObj)
704 hr = E_OUTOFMEMORY;
705
706 *ppvOut = pObj;
707 TRACE ("(%p)->hr=0x%08x\n", this, hr);
708 return hr;
709 }
710
711 /**************************************************************************
712 * CDesktopFolder::GetDisplayNameOf
713 *
714 * NOTES
715 * special case: pidl = null gives desktop-name back
716 */
717 HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
718 {
719 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
720 pdump (pidl);
721
722 if (!strRet)
723 return E_INVALIDARG;
724
725 if (!_ILIsPidlSimple (pidl))
726 {
727 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
728 }
729 else if (_ILIsDesktop(pidl))
730 {
731 if ((GET_SHGDN_RELATION(dwFlags) == SHGDN_NORMAL) && (GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING))
732 return SHSetStrRet(strRet, sPathTarget);
733 else
734 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet);
735 }
736
737 /* file system folder or file rooted at the desktop */
738 CComPtr<IShellFolder2> psf;
739 HRESULT hr = _GetSFFromPidl(pidl, &psf);
740 if (FAILED_UNEXPECTEDLY(hr))
741 return hr;
742
743 return psf->GetDisplayNameOf(pidl, dwFlags, strRet);
744 }
745
746 /**************************************************************************
747 * CDesktopFolder::SetNameOf
748 * Changes the name of a file object or subfolder, possibly changing its item
749 * identifier in the process.
750 *
751 * PARAMETERS
752 * HWND hwndOwner, //[in ] Owner window for output
753 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
754 * LPCOLESTR lpszName, //[in ] the items new display name
755 * DWORD dwFlags, //[in ] SHGNO formatting flags
756 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
757 */
758 HRESULT WINAPI CDesktopFolder::SetNameOf(
759 HWND hwndOwner,
760 PCUITEMID_CHILD pidl, /* simple pidl */
761 LPCOLESTR lpName,
762 DWORD dwFlags,
763 PITEMID_CHILD *pPidlOut)
764 {
765 CComPtr<IShellFolder2> psf;
766 HRESULT hr = _GetSFFromPidl(pidl, &psf);
767 if (FAILED_UNEXPECTEDLY(hr))
768 return hr;
769
770 return psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
771 }
772
773 HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid)
774 {
775 FIXME ("(%p)\n", this);
776 return E_NOTIMPL;
777 }
778
779 HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum)
780 {
781 FIXME ("(%p)\n", this);
782 return E_NOTIMPL;
783 }
784
785 HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
786 {
787 TRACE ("(%p)\n", this);
788
789 if (pSort)
790 *pSort = 0;
791 if (pDisplay)
792 *pDisplay = 0;
793
794 return S_OK;
795 }
796
797 HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
798 {
799 TRACE ("(%p)\n", this);
800
801 if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
802 return E_INVALIDARG;
803
804 *pcsFlags = DesktopSFHeader[iColumn].pcsFlags;
805
806 return S_OK;
807 }
808
809 HRESULT WINAPI CDesktopFolder::GetDetailsEx(
810 PCUITEMID_CHILD pidl,
811 const SHCOLUMNID *pscid,
812 VARIANT *pv)
813 {
814 FIXME ("(%p)\n", this);
815
816 return E_NOTIMPL;
817 }
818
819 HRESULT WINAPI CDesktopFolder::GetDetailsOf(
820 PCUITEMID_CHILD pidl,
821 UINT iColumn,
822 SHELLDETAILS *psd)
823 {
824 if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
825 return E_INVALIDARG;
826
827 if (!pidl)
828 {
829 psd->fmt = DesktopSFHeader[iColumn].fmt;
830 psd->cxChar = DesktopSFHeader[iColumn].cxChar;
831 return SHSetStrRet(&psd->str, DesktopSFHeader[iColumn].colnameid);
832 }
833
834 CComPtr<IShellFolder2> psf;
835 HRESULT hr = _GetSFFromPidl(pidl, &psf);
836 if (FAILED_UNEXPECTEDLY(hr))
837 return hr;
838
839 hr = psf->GetDetailsOf(pidl, iColumn, psd);
840 if (FAILED_UNEXPECTEDLY(hr))
841 return hr;
842
843 return hr;
844 }
845
846 HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
847 {
848 FIXME ("(%p)\n", this);
849 return E_NOTIMPL;
850 }
851
852 HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId)
853 {
854 TRACE ("(%p)\n", this);
855
856 if (!lpClassId)
857 return E_POINTER;
858
859 *lpClassId = CLSID_ShellDesktop;
860
861 return S_OK;
862 }
863
864 HRESULT WINAPI CDesktopFolder::Initialize(LPCITEMIDLIST pidl)
865 {
866 TRACE ("(%p)->(%p)\n", this, pidl);
867
868 return E_INVALIDARG;
869 }
870
871 HRESULT WINAPI CDesktopFolder::GetCurFolder(LPITEMIDLIST * pidl)
872 {
873 TRACE ("(%p)->(%p)\n", this, pidl);
874
875 if (!pidl)
876 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */
877 *pidl = ILClone (pidlRoot);
878 return S_OK;
879 }
880
881 HRESULT WINAPI CDesktopFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
882 {
883 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND)
884 return S_OK;
885
886 /* no data object means no selection */
887 if (!pdtobj)
888 {
889 if (uMsg == DFM_INVOKECOMMAND && wParam == DFM_CMD_PROPERTIES)
890 {
891 if (32 >= (UINT)ShellExecuteW(hwndOwner, L"open", L"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL))
892 return E_FAIL;
893 return S_OK;
894 }
895 else if (uMsg == DFM_MERGECONTEXTMENU)
896 {
897 QCMINFO *pqcminfo = (QCMINFO *)lParam;
898 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
899 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, FCIDM_SHVIEW_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
900 }
901
902 return S_OK;
903 }
904
905 PIDLIST_ABSOLUTE pidlFolder;
906 PUITEMID_CHILD *apidl;
907 UINT cidl;
908 HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
909 if (FAILED_UNEXPECTEDLY(hr))
910 return hr;
911
912 if (cidl > 1)
913 ERR("SHMultiFileProperties is not yet implemented\n");
914
915 STRRET strFile;
916 hr = GetDisplayNameOf(apidl[0], SHGDN_FORPARSING, &strFile);
917 if (SUCCEEDED(hr))
918 {
919 hr = SH_ShowPropertiesDialog(strFile.pOleStr, pidlFolder, apidl);
920 if (FAILED(hr))
921 ERR("SH_ShowPropertiesDialog failed\n");
922 }
923 else
924 {
925 ERR("Failed to get display name\n");
926 }
927
928 SHFree(pidlFolder);
929 _ILFreeaPidl(apidl, cidl);
930
931 return hr;
932 }
933
934 /*************************************************************************
935 * SHGetDesktopFolder [SHELL32.@]
936 */
937 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
938 {
939 HRESULT hres = S_OK;
940 TRACE("\n");
941
942 if(!psf) return E_INVALIDARG;
943 *psf = NULL;
944 hres = CDesktopFolder::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellFolder, psf));
945
946 TRACE("-- %p->(%p)\n",psf, *psf);
947 return hres;
948 }