[SHELL32] -Remove IShellView_Constructor and CDefView_Constructor. Use SHCreateShellF...
[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 HRESULT hr = E_INVALIDARG;
518
519 TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
520 this, hwndOwner, shdebugstr_guid (&riid), ppvOut);
521
522 if (!ppvOut)
523 return hr;
524
525 *ppvOut = NULL;
526
527 if (IsEqualIID (riid, IID_IDropTarget))
528 {
529 hr = m_DesktopFSFolder->CreateViewObject(hwndOwner, riid, ppvOut);
530 }
531 else if (IsEqualIID (riid, IID_IContextMenu))
532 {
533 HKEY hKeys[16];
534 UINT cKeys = 0;
535 AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys);
536
537 DEFCONTEXTMENU dcm;
538 dcm.hwnd = hwndOwner;
539 dcm.pcmcb = this;
540 dcm.pidlFolder = pidlRoot;
541 dcm.psf = this;
542 dcm.cidl = 0;
543 dcm.apidl = NULL;
544 dcm.cKeys = cKeys;
545 dcm.aKeys = hKeys;
546 dcm.punkAssociationInfo = NULL;
547 hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut);
548 }
549 else if (IsEqualIID (riid, IID_IShellView))
550 {
551 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this};
552 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
553 }
554 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
555 return hr;
556 }
557
558 /**************************************************************************
559 * CDesktopFolder::GetAttributesOf
560 */
561 HRESULT WINAPI CDesktopFolder::GetAttributesOf(
562 UINT cidl,
563 PCUITEMID_CHILD_ARRAY apidl,
564 DWORD *rgfInOut)
565 {
566 HRESULT hr = S_OK;
567
568 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
569 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
570
571 if (cidl && !apidl)
572 return E_INVALIDARG;
573
574 if (*rgfInOut == 0)
575 *rgfInOut = ~0;
576
577 if(cidl == 0)
578 *rgfInOut &= dwDesktopAttributes;
579 else
580 {
581 /* TODO: always add SFGAO_CANLINK */
582 for (UINT i = 0; i < cidl; ++i)
583 {
584 pdump(*apidl);
585 if (_ILIsDesktop(*apidl))
586 *rgfInOut &= dwDesktopAttributes;
587 else if (_ILIsMyComputer(apidl[i]))
588 *rgfInOut &= dwMyComputerAttributes;
589 else if (_ILIsNetHood(apidl[i]))
590 *rgfInOut &= dwMyNetPlacesAttributes;
591 else if (_ILIsFolder(apidl[i]) || _ILIsValue(apidl[i]) || _ILIsSpecialFolder(apidl[i]))
592 {
593 CComPtr<IShellFolder2> psf;
594 HRESULT hr = _GetSFFromPidl(apidl[i], &psf);
595 if (FAILED_UNEXPECTEDLY(hr))
596 continue;
597
598 psf->GetAttributesOf(1, &apidl[i], rgfInOut);
599 }
600 else
601 ERR("Got an unknown pidl type!!!\n");
602 }
603 }
604 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
605 *rgfInOut &= ~SFGAO_VALIDATE;
606
607 TRACE("-- result=0x%08x\n", *rgfInOut);
608
609 return hr;
610 }
611
612 /**************************************************************************
613 * CDesktopFolder::GetUIObjectOf
614 *
615 * PARAMETERS
616 * HWND hwndOwner, //[in ] Parent window for any output
617 * UINT cidl, //[in ] array size
618 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
619 * REFIID riid, //[in ] Requested Interface
620 * UINT* prgfInOut, //[ ] reserved
621 * LPVOID* ppvObject) //[out] Resulting Interface
622 *
623 */
624 HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
625 HWND hwndOwner,
626 UINT cidl,
627 PCUITEMID_CHILD_ARRAY apidl,
628 REFIID riid,
629 UINT *prgfInOut,
630 LPVOID *ppvOut)
631 {
632 LPVOID pObj = NULL;
633 HRESULT hr = E_INVALIDARG;
634
635 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
636 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
637
638 if (!ppvOut)
639 return hr;
640
641 *ppvOut = NULL;
642
643 if (cidl == 1 && !_ILIsSpecialFolder(apidl[0]))
644 {
645 CComPtr<IShellFolder2> psf;
646 HRESULT hr = _GetSFFromPidl(apidl[0], &psf);
647 if (FAILED_UNEXPECTEDLY(hr))
648 return hr;
649
650 return psf->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut);
651 }
652
653 if (IsEqualIID (riid, IID_IContextMenu))
654 {
655 if (_ILIsSpecialFolder(apidl[0]))
656 {
657 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
658 }
659 else
660 {
661 /* Do not use the context menu of the CFSFolder here. */
662 /* We need to pass a pointer of the CDesktopFolder so as the data object that the context menu gets is rooted to the desktop */
663 /* Otherwise operations like that involve items from both user and shared desktop will not work */
664 HKEY hKeys[16];
665 UINT cKeys = 0;
666 AddFSClassKeysToArray(apidl[0], hKeys, &cKeys);
667
668 DEFCONTEXTMENU dcm;
669 dcm.hwnd = hwndOwner;
670 dcm.pcmcb = this;
671 dcm.pidlFolder = pidlRoot;
672 dcm.psf = this;
673 dcm.cidl = cidl;
674 dcm.apidl = apidl;
675 dcm.cKeys = cKeys;
676 dcm.aKeys = hKeys;
677 dcm.punkAssociationInfo = NULL;
678 hr = SHCreateDefaultContextMenu (&dcm, riid, &pObj);
679 }
680 }
681 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
682 {
683 hr = IDataObject_Constructor( hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
684 }
685 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
686 {
687 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
688 }
689 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1))
690 {
691 CComPtr<IShellFolder> psfChild;
692 hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild));
693 if (FAILED_UNEXPECTEDLY(hr))
694 return hr;
695
696 return psfChild->CreateViewObject(NULL, riid, ppvOut);
697 }
698 else
699 hr = E_NOINTERFACE;
700
701 if (SUCCEEDED(hr) && !pObj)
702 hr = E_OUTOFMEMORY;
703
704 *ppvOut = pObj;
705 TRACE ("(%p)->hr=0x%08x\n", this, hr);
706 return hr;
707 }
708
709 /**************************************************************************
710 * CDesktopFolder::GetDisplayNameOf
711 *
712 * NOTES
713 * special case: pidl = null gives desktop-name back
714 */
715 HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
716 {
717 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
718 pdump (pidl);
719
720 if (!strRet)
721 return E_INVALIDARG;
722
723 if (!_ILIsPidlSimple (pidl))
724 {
725 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
726 }
727 else if (_ILIsDesktop(pidl))
728 {
729 if ((GET_SHGDN_RELATION(dwFlags) == SHGDN_NORMAL) && (GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING))
730 return SHSetStrRet(strRet, sPathTarget);
731 else
732 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet);
733 }
734
735 /* file system folder or file rooted at the desktop */
736 CComPtr<IShellFolder2> psf;
737 HRESULT hr = _GetSFFromPidl(pidl, &psf);
738 if (FAILED_UNEXPECTEDLY(hr))
739 return hr;
740
741 return psf->GetDisplayNameOf(pidl, dwFlags, strRet);
742 }
743
744 /**************************************************************************
745 * CDesktopFolder::SetNameOf
746 * Changes the name of a file object or subfolder, possibly changing its item
747 * identifier in the process.
748 *
749 * PARAMETERS
750 * HWND hwndOwner, //[in ] Owner window for output
751 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
752 * LPCOLESTR lpszName, //[in ] the items new display name
753 * DWORD dwFlags, //[in ] SHGNO formatting flags
754 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
755 */
756 HRESULT WINAPI CDesktopFolder::SetNameOf(
757 HWND hwndOwner,
758 PCUITEMID_CHILD pidl, /* simple pidl */
759 LPCOLESTR lpName,
760 DWORD dwFlags,
761 PITEMID_CHILD *pPidlOut)
762 {
763 CComPtr<IShellFolder2> psf;
764 HRESULT hr = _GetSFFromPidl(pidl, &psf);
765 if (FAILED_UNEXPECTEDLY(hr))
766 return hr;
767
768 return psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
769 }
770
771 HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid)
772 {
773 FIXME ("(%p)\n", this);
774 return E_NOTIMPL;
775 }
776
777 HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum)
778 {
779 FIXME ("(%p)\n", this);
780 return E_NOTIMPL;
781 }
782
783 HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
784 {
785 TRACE ("(%p)\n", this);
786
787 if (pSort)
788 *pSort = 0;
789 if (pDisplay)
790 *pDisplay = 0;
791
792 return S_OK;
793 }
794
795 HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
796 {
797 TRACE ("(%p)\n", this);
798
799 if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
800 return E_INVALIDARG;
801
802 *pcsFlags = DesktopSFHeader[iColumn].pcsFlags;
803
804 return S_OK;
805 }
806
807 HRESULT WINAPI CDesktopFolder::GetDetailsEx(
808 PCUITEMID_CHILD pidl,
809 const SHCOLUMNID *pscid,
810 VARIANT *pv)
811 {
812 FIXME ("(%p)\n", this);
813
814 return E_NOTIMPL;
815 }
816
817 HRESULT WINAPI CDesktopFolder::GetDetailsOf(
818 PCUITEMID_CHILD pidl,
819 UINT iColumn,
820 SHELLDETAILS *psd)
821 {
822 if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
823 return E_INVALIDARG;
824
825 if (!pidl)
826 {
827 psd->fmt = DesktopSFHeader[iColumn].fmt;
828 psd->cxChar = DesktopSFHeader[iColumn].cxChar;
829 return SHSetStrRet(&psd->str, DesktopSFHeader[iColumn].colnameid);
830 }
831
832 CComPtr<IShellFolder2> psf;
833 HRESULT hr = _GetSFFromPidl(pidl, &psf);
834 if (FAILED_UNEXPECTEDLY(hr))
835 return hr;
836
837 hr = psf->GetDetailsOf(pidl, iColumn, psd);
838 if (FAILED_UNEXPECTEDLY(hr))
839 return hr;
840
841 return hr;
842 }
843
844 HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
845 {
846 FIXME ("(%p)\n", this);
847 return E_NOTIMPL;
848 }
849
850 HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId)
851 {
852 TRACE ("(%p)\n", this);
853
854 if (!lpClassId)
855 return E_POINTER;
856
857 *lpClassId = CLSID_ShellDesktop;
858
859 return S_OK;
860 }
861
862 HRESULT WINAPI CDesktopFolder::Initialize(LPCITEMIDLIST pidl)
863 {
864 TRACE ("(%p)->(%p)\n", this, pidl);
865
866 return E_INVALIDARG;
867 }
868
869 HRESULT WINAPI CDesktopFolder::GetCurFolder(LPITEMIDLIST * pidl)
870 {
871 TRACE ("(%p)->(%p)\n", this, pidl);
872
873 if (!pidl)
874 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */
875 *pidl = ILClone (pidlRoot);
876 return S_OK;
877 }
878
879 HRESULT WINAPI CDesktopFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
880 {
881 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND)
882 return S_OK;
883
884 /* no data object means no selection */
885 if (!pdtobj)
886 {
887 if (uMsg == DFM_INVOKECOMMAND && wParam == DFM_CMD_PROPERTIES)
888 {
889 if (32 >= (UINT)ShellExecuteW(hwndOwner, L"open", L"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL))
890 return E_FAIL;
891 return S_OK;
892 }
893 else if (uMsg == DFM_MERGECONTEXTMENU)
894 {
895 QCMINFO *pqcminfo = (QCMINFO *)lParam;
896 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
897 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, FCIDM_SHVIEW_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
898 }
899
900 return S_OK;
901 }
902
903 PIDLIST_ABSOLUTE pidlFolder;
904 PUITEMID_CHILD *apidl;
905 UINT cidl;
906 HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
907 if (FAILED_UNEXPECTEDLY(hr))
908 return hr;
909
910 if (cidl > 1)
911 ERR("SHMultiFileProperties is not yet implemented\n");
912
913 STRRET strFile;
914 hr = GetDisplayNameOf(apidl[0], SHGDN_FORPARSING, &strFile);
915 if (SUCCEEDED(hr))
916 {
917 hr = SH_ShowPropertiesDialog(strFile.pOleStr, pidlFolder, apidl);
918 if (FAILED(hr))
919 ERR("SH_ShowPropertiesDialog failed\n");
920 }
921 else
922 {
923 ERR("Failed to get display name\n");
924 }
925
926 SHFree(pidlFolder);
927 _ILFreeaPidl(apidl, cidl);
928
929 return hr;
930 }
931
932 /*************************************************************************
933 * SHGetDesktopFolder [SHELL32.@]
934 */
935 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
936 {
937 HRESULT hres = S_OK;
938 TRACE("\n");
939
940 if(!psf) return E_INVALIDARG;
941 *psf = NULL;
942 hres = CDesktopFolder::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellFolder, psf));
943
944 TRACE("-- %p->(%p)\n",psf, *psf);
945 return hres;
946 }