b104e13e3f06b831eed2b837e3d40fe5fb5bb410
[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(HWND hwndOwner, DWORD dwFlags, IEnumIDList *pDesktopEnumerator, IEnumIDList *pCommonDesktopEnumerator);
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(HWND hwndOwner, DWORD dwFlags, IEnumIDList *pDesktopEnumerator, IEnumIDList *pCommonDesktopEnumerator)
123 {
124 BOOL ret = TRUE;
125 LPITEMIDLIST pidl;
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 int i = 0;
157
158 while (ret)
159 {
160 DWORD size;
161 LONG r;
162
163 size = sizeof (iid) / sizeof (iid[0]);
164 r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
165 if (ERROR_SUCCESS == r)
166 {
167 if (IsNamespaceExtensionHidden(iid) < 1)
168 {
169 pidl = _ILCreateGuidFromStrW(iid);
170 if (pidl != NULL)
171 {
172 if (!HasItemWithCLSID(pidl))
173 {
174 ret = AddToEnumList(pidl);
175 }
176 else
177 {
178 SHFree(pidl);
179 }
180 }
181 }
182 }
183 else if (ERROR_NO_MORE_ITEMS == r)
184 break;
185 else
186 ret = FALSE;
187 i++;
188 }
189 RegCloseKey(hkey);
190 }
191 }
192 for (i = 0; i < 2; i++)
193 {
194 if (i == 0)
195 dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, ClassicStartMenuW, 0, KEY_READ, &hkey);
196 else
197 dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, ClassicStartMenuW, 0, KEY_READ, &hkey);
198
199 if (dwResult == ERROR_SUCCESS)
200 {
201 DWORD j = 0, dwVal, Val, dwType, dwIID;
202 LONG r;
203 WCHAR iid[50];
204
205 while(ret)
206 {
207 dwVal = sizeof(Val);
208 dwIID = sizeof(iid) / sizeof(WCHAR);
209
210 r = RegEnumValueW(hkey, j++, iid, &dwIID, NULL, &dwType, (LPBYTE)&Val, &dwVal);
211 if (r == ERROR_SUCCESS)
212 {
213 if (Val == 0 && dwType == REG_DWORD)
214 {
215 pidl = _ILCreateGuidFromStrW(iid);
216 if (pidl != NULL)
217 {
218 if (!HasItemWithCLSID(pidl))
219 {
220 AddToEnumList(pidl);
221 }
222 else
223 {
224 SHFree(pidl);
225 }
226 }
227 }
228 }
229 else if (ERROR_NO_MORE_ITEMS == r)
230 break;
231 else
232 ret = FALSE;
233 }
234 RegCloseKey(hkey);
235 }
236
237 }
238 }
239
240 DWORD dwFetched;
241
242 /* Enumerate the items in the two fs folders */
243 if (pDesktopEnumerator)
244 {
245 while((S_OK == pDesktopEnumerator->Next(1, &pidl, &dwFetched)) && dwFetched)
246 AddToEnumList(pidl);
247 }
248
249 if (pCommonDesktopEnumerator)
250 {
251 while((S_OK == pCommonDesktopEnumerator->Next(1, &pidl, &dwFetched)) && dwFetched)
252 AddToEnumList(pidl);
253 }
254
255 return ret ? S_OK : E_FAIL;
256 }
257
258 CDesktopFolder::CDesktopFolder() :
259 sPathTarget(NULL),
260 pidlRoot(NULL)
261 {
262 }
263
264 CDesktopFolder::~CDesktopFolder()
265 {
266 }
267
268 HRESULT WINAPI CDesktopFolder::FinalConstruct()
269 {
270 WCHAR szMyPath[MAX_PATH];
271 HRESULT hr;
272
273 /* Create the root pidl */
274 pidlRoot = _ILCreateDesktop();
275 if (!pidlRoot)
276 return E_OUTOFMEMORY;
277
278 /* Create the inner fs folder */
279 hr = SHELL32_CoCreateInitSF(pidlRoot,
280 &CLSID_ShellFSFolder,
281 CSIDL_DESKTOPDIRECTORY,
282 IID_PPV_ARG(IShellFolder2, &m_DesktopFSFolder));
283 if (FAILED_UNEXPECTEDLY(hr))
284 return hr;
285
286 /* Create the inner shared fs folder. Dont fail on failure. */
287 hr = SHELL32_CoCreateInitSF(pidlRoot,
288 &CLSID_ShellFSFolder,
289 CSIDL_COMMON_DESKTOPDIRECTORY,
290 IID_PPV_ARG(IShellFolder2, &m_SharedDesktopFSFolder));
291 if (FAILED_UNEXPECTEDLY(hr))
292 return hr;
293
294 /* Create the inner reg folder */
295 hr = CRegFolder_CreateInstance(&CLSID_ShellDesktop,
296 pidlRoot,
297 L"",
298 IID_PPV_ARG(IShellFolder2, &m_regFolder));
299 if (FAILED_UNEXPECTEDLY(hr))
300 return hr;
301
302 /* Cache the path to the user desktop directory */
303 if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
304 return E_UNEXPECTED;
305
306 sPathTarget = (LPWSTR)SHAlloc((wcslen(szMyPath) + 1) * sizeof(WCHAR));
307 if (!sPathTarget)
308 return E_OUTOFMEMORY;
309
310 wcscpy(sPathTarget, szMyPath);
311 return S_OK;
312 }
313
314 HRESULT CDesktopFolder::_GetSFFromPidl(LPCITEMIDLIST pidl, IShellFolder2** psf)
315 {
316 WCHAR szFileName[MAX_PATH];
317
318 if (_ILIsSpecialFolder(pidl))
319 return m_regFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf));
320
321 lstrcpynW(szFileName, sPathTarget, MAX_PATH - 1);
322 PathAddBackslashW(szFileName);
323 int cLen = wcslen(szFileName);
324
325 if (!_ILSimpleGetTextW(pidl, szFileName + cLen, MAX_PATH - cLen))
326 return E_FAIL;
327
328 if (GetFileAttributes(szFileName) == INVALID_FILE_ATTRIBUTES)
329 return m_SharedDesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf));
330 else
331 return m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf));
332 }
333
334 /**************************************************************************
335 * CDesktopFolder::ParseDisplayName
336 *
337 * NOTES
338 * "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
339 * to MyComputer
340 */
341 HRESULT WINAPI CDesktopFolder::ParseDisplayName(
342 HWND hwndOwner,
343 LPBC pbc,
344 LPOLESTR lpszDisplayName,
345 DWORD *pchEaten,
346 PIDLIST_RELATIVE *ppidl,
347 DWORD *pdwAttributes)
348 {
349 LPCWSTR szNext = NULL;
350 LPITEMIDLIST pidlTemp = NULL;
351 PARSEDURLW urldata;
352 HRESULT hr = S_OK;
353
354 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
355 this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
356 pchEaten, ppidl, pdwAttributes);
357
358 if (!ppidl)
359 return E_INVALIDARG;
360
361 *ppidl = NULL;
362
363 if (!lpszDisplayName)
364 return E_INVALIDARG;
365
366 if (pchEaten)
367 *pchEaten = 0; /* strange but like the original */
368
369 urldata.cbSize = sizeof(urldata);
370
371 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
372 {
373 return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
374 }
375 else if (PathGetDriveNumberW (lpszDisplayName) >= 0)
376 {
377 /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
378 pidlTemp = _ILCreateMyComputer ();
379 szNext = lpszDisplayName;
380 }
381 else if (PathIsUNCW(lpszDisplayName))
382 {
383 pidlTemp = _ILCreateNetwork();
384 szNext = lpszDisplayName;
385 }
386 else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
387 {
388 *ppidl = pidlTemp;
389 return S_OK;
390 }
391 else if (SUCCEEDED(ParseURLW(lpszDisplayName, &urldata)))
392 {
393 if (urldata.nScheme == URL_SCHEME_SHELL) /* handle shell: urls */
394 {
395 TRACE ("-- shell url: %s\n", debugstr_w(urldata.pszSuffix));
396 pidlTemp = _ILCreateGuidFromStrW(urldata.pszSuffix + 2);
397 }
398 else
399 return IEParseDisplayNameWithBCW(CP_ACP, lpszDisplayName, pbc, ppidl);
400 }
401 else
402 {
403 if (*lpszDisplayName)
404 {
405 /* it's a filesystem path on the desktop. Let a FSFolder parse it */
406 hr = m_DesktopFSFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
407 if (SUCCEEDED(hr))
408 return hr;
409
410 return m_SharedDesktopFSFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
411 }
412 else
413 pidlTemp = _ILCreateMyComputer();
414
415 szNext = NULL;
416 }
417
418 if (SUCCEEDED(hr) && pidlTemp)
419 {
420 if (szNext && *szNext)
421 {
422 hr = SHELL32_ParseNextElement(this, hwndOwner, pbc,
423 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
424 }
425 else
426 {
427 if (pdwAttributes && *pdwAttributes)
428 {
429 GetAttributesOf(1, &pidlTemp, pdwAttributes);
430 }
431 }
432 }
433
434 if (SUCCEEDED(hr))
435 *ppidl = pidlTemp;
436 else
437 *ppidl = NULL;
438
439 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
440
441 return hr;
442 }
443
444 /**************************************************************************
445 * CDesktopFolder::EnumObjects
446 */
447 HRESULT WINAPI CDesktopFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
448 {
449 CComPtr<IEnumIDList> pDesktopEnumerator;
450 CComPtr<IEnumIDList> pCommonDesktopEnumerator;
451 HRESULT hr;
452
453 hr = m_DesktopFSFolder->EnumObjects(hwndOwner, dwFlags, &pDesktopEnumerator);
454 if (FAILED(hr))
455 ERR("EnumObjects for desktop fs folder failed\n");
456
457 hr = m_SharedDesktopFSFolder->EnumObjects(hwndOwner, dwFlags, &pCommonDesktopEnumerator);
458 if (FAILED(hr))
459 ERR("EnumObjects for shared desktop fs folder failed\n");
460
461 return ShellObjectCreatorInit<CDesktopFolderEnum>(hwndOwner, dwFlags, pDesktopEnumerator, pCommonDesktopEnumerator, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
462 }
463
464 /**************************************************************************
465 * CDesktopFolder::BindToObject
466 */
467 HRESULT WINAPI CDesktopFolder::BindToObject(
468 PCUIDLIST_RELATIVE pidl,
469 LPBC pbcReserved,
470 REFIID riid,
471 LPVOID *ppvOut)
472 {
473 if (!pidl)
474 return E_INVALIDARG;
475
476 CComPtr<IShellFolder2> psf;
477 HRESULT hr = _GetSFFromPidl(pidl, &psf);
478 if (FAILED_UNEXPECTEDLY(hr))
479 return hr;
480
481 return psf->BindToObject(pidl, pbcReserved, riid, ppvOut);
482 }
483
484 /**************************************************************************
485 * CDesktopFolder::BindToStorage
486 */
487 HRESULT WINAPI CDesktopFolder::BindToStorage(
488 PCUIDLIST_RELATIVE pidl,
489 LPBC pbcReserved,
490 REFIID riid,
491 LPVOID *ppvOut)
492 {
493 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
494 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
495
496 *ppvOut = NULL;
497 return E_NOTIMPL;
498 }
499
500 /**************************************************************************
501 * CDesktopFolder::CompareIDs
502 */
503 HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
504 {
505 bool bIsDesktopFolder1, bIsDesktopFolder2;
506
507 if (!pidl1 || !pidl2)
508 {
509 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2);
510 return E_INVALIDARG;
511 }
512
513 bIsDesktopFolder1 = _ILIsDesktop(pidl1);
514 bIsDesktopFolder2 = _ILIsDesktop(pidl2);
515 if (bIsDesktopFolder1 || bIsDesktopFolder2)
516 return MAKE_COMPARE_HRESULT(bIsDesktopFolder1 - bIsDesktopFolder2);
517
518 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
519 return m_regFolder->CompareIDs(lParam, pidl1, pidl2);
520
521 return m_DesktopFSFolder->CompareIDs(lParam, pidl1, pidl2);
522 }
523
524 /**************************************************************************
525 * CDesktopFolder::CreateViewObject
526 */
527 HRESULT WINAPI CDesktopFolder::CreateViewObject(
528 HWND hwndOwner,
529 REFIID riid,
530 LPVOID *ppvOut)
531 {
532 HRESULT hr = E_INVALIDARG;
533
534 TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
535 this, hwndOwner, shdebugstr_guid (&riid), ppvOut);
536
537 if (!ppvOut)
538 return hr;
539
540 *ppvOut = NULL;
541
542 if (IsEqualIID (riid, IID_IDropTarget))
543 {
544 hr = m_DesktopFSFolder->CreateViewObject(hwndOwner, riid, ppvOut);
545 }
546 else if (IsEqualIID (riid, IID_IContextMenu))
547 {
548 HKEY hKeys[16];
549 UINT cKeys = 0;
550 AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys);
551
552 DEFCONTEXTMENU dcm;
553 dcm.hwnd = hwndOwner;
554 dcm.pcmcb = this;
555 dcm.pidlFolder = pidlRoot;
556 dcm.psf = this;
557 dcm.cidl = 0;
558 dcm.apidl = NULL;
559 dcm.cKeys = cKeys;
560 dcm.aKeys = hKeys;
561 dcm.punkAssociationInfo = NULL;
562 hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut);
563 }
564 else if (IsEqualIID (riid, IID_IShellView))
565 {
566 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this};
567 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
568 }
569 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
570 return hr;
571 }
572
573 /**************************************************************************
574 * CDesktopFolder::GetAttributesOf
575 */
576 HRESULT WINAPI CDesktopFolder::GetAttributesOf(
577 UINT cidl,
578 PCUITEMID_CHILD_ARRAY apidl,
579 DWORD *rgfInOut)
580 {
581 HRESULT hr = S_OK;
582
583 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
584 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
585
586 if (cidl && !apidl)
587 return E_INVALIDARG;
588
589 if (*rgfInOut == 0)
590 *rgfInOut = ~0;
591
592 if(cidl == 0)
593 *rgfInOut &= dwDesktopAttributes;
594 else
595 {
596 /* TODO: always add SFGAO_CANLINK */
597 for (UINT i = 0; i < cidl; ++i)
598 {
599 pdump(*apidl);
600 if (_ILIsDesktop(*apidl))
601 *rgfInOut &= dwDesktopAttributes;
602 else if (_ILIsMyComputer(apidl[i]))
603 *rgfInOut &= dwMyComputerAttributes;
604 else if (_ILIsNetHood(apidl[i]))
605 *rgfInOut &= dwMyNetPlacesAttributes;
606 else if (_ILIsFolder(apidl[i]) || _ILIsValue(apidl[i]) || _ILIsSpecialFolder(apidl[i]))
607 {
608 CComPtr<IShellFolder2> psf;
609 HRESULT hr = _GetSFFromPidl(apidl[i], &psf);
610 if (FAILED_UNEXPECTEDLY(hr))
611 continue;
612
613 psf->GetAttributesOf(1, &apidl[i], rgfInOut);
614 }
615 else
616 ERR("Got an unknown pidl type!!!\n");
617 }
618 }
619 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
620 *rgfInOut &= ~SFGAO_VALIDATE;
621
622 TRACE("-- result=0x%08x\n", *rgfInOut);
623
624 return hr;
625 }
626
627 /**************************************************************************
628 * CDesktopFolder::GetUIObjectOf
629 *
630 * PARAMETERS
631 * HWND hwndOwner, //[in ] Parent window for any output
632 * UINT cidl, //[in ] array size
633 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
634 * REFIID riid, //[in ] Requested Interface
635 * UINT* prgfInOut, //[ ] reserved
636 * LPVOID* ppvObject) //[out] Resulting Interface
637 *
638 */
639 HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
640 HWND hwndOwner,
641 UINT cidl,
642 PCUITEMID_CHILD_ARRAY apidl,
643 REFIID riid,
644 UINT *prgfInOut,
645 LPVOID *ppvOut)
646 {
647 LPVOID pObj = NULL;
648 HRESULT hr = E_INVALIDARG;
649
650 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
651 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
652
653 if (!ppvOut)
654 return hr;
655
656 *ppvOut = NULL;
657
658 if (cidl == 1 && !_ILIsSpecialFolder(apidl[0]))
659 {
660 CComPtr<IShellFolder2> psf;
661 HRESULT hr = _GetSFFromPidl(apidl[0], &psf);
662 if (FAILED_UNEXPECTEDLY(hr))
663 return hr;
664
665 return psf->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut);
666 }
667
668 if (IsEqualIID (riid, IID_IContextMenu))
669 {
670 if (_ILIsSpecialFolder(apidl[0]))
671 {
672 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
673 }
674 else
675 {
676 /* Do not use the context menu of the CFSFolder here. */
677 /* We need to pass a pointer of the CDesktopFolder so as the data object that the context menu gets is rooted to the desktop */
678 /* Otherwise operations like that involve items from both user and shared desktop will not work */
679 HKEY hKeys[16];
680 UINT cKeys = 0;
681 AddFSClassKeysToArray(apidl[0], hKeys, &cKeys);
682
683 DEFCONTEXTMENU dcm;
684 dcm.hwnd = hwndOwner;
685 dcm.pcmcb = this;
686 dcm.pidlFolder = pidlRoot;
687 dcm.psf = this;
688 dcm.cidl = cidl;
689 dcm.apidl = apidl;
690 dcm.cKeys = cKeys;
691 dcm.aKeys = hKeys;
692 dcm.punkAssociationInfo = NULL;
693 hr = SHCreateDefaultContextMenu (&dcm, riid, &pObj);
694 }
695 }
696 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
697 {
698 hr = IDataObject_Constructor( hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
699 }
700 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
701 {
702 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
703 }
704 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1))
705 {
706 CComPtr<IShellFolder> psfChild;
707 hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild));
708 if (FAILED_UNEXPECTEDLY(hr))
709 return hr;
710
711 return psfChild->CreateViewObject(NULL, riid, ppvOut);
712 }
713 else
714 hr = E_NOINTERFACE;
715
716 if (SUCCEEDED(hr) && !pObj)
717 hr = E_OUTOFMEMORY;
718
719 *ppvOut = pObj;
720 TRACE ("(%p)->hr=0x%08x\n", this, hr);
721 return hr;
722 }
723
724 /**************************************************************************
725 * CDesktopFolder::GetDisplayNameOf
726 *
727 * NOTES
728 * special case: pidl = null gives desktop-name back
729 */
730 HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
731 {
732 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
733 pdump (pidl);
734
735 if (!strRet)
736 return E_INVALIDARG;
737
738 if (!_ILIsPidlSimple (pidl))
739 {
740 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
741 }
742 else if (_ILIsDesktop(pidl))
743 {
744 if ((GET_SHGDN_RELATION(dwFlags) == SHGDN_NORMAL) && (GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING))
745 return SHSetStrRet(strRet, sPathTarget);
746 else
747 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet);
748 }
749
750 /* file system folder or file rooted at the desktop */
751 CComPtr<IShellFolder2> psf;
752 HRESULT hr = _GetSFFromPidl(pidl, &psf);
753 if (FAILED_UNEXPECTEDLY(hr))
754 return hr;
755
756 return psf->GetDisplayNameOf(pidl, dwFlags, strRet);
757 }
758
759 /**************************************************************************
760 * CDesktopFolder::SetNameOf
761 * Changes the name of a file object or subfolder, possibly changing its item
762 * identifier in the process.
763 *
764 * PARAMETERS
765 * HWND hwndOwner, //[in ] Owner window for output
766 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
767 * LPCOLESTR lpszName, //[in ] the items new display name
768 * DWORD dwFlags, //[in ] SHGNO formatting flags
769 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
770 */
771 HRESULT WINAPI CDesktopFolder::SetNameOf(
772 HWND hwndOwner,
773 PCUITEMID_CHILD pidl, /* simple pidl */
774 LPCOLESTR lpName,
775 DWORD dwFlags,
776 PITEMID_CHILD *pPidlOut)
777 {
778 CComPtr<IShellFolder2> psf;
779 HRESULT hr = _GetSFFromPidl(pidl, &psf);
780 if (FAILED_UNEXPECTEDLY(hr))
781 return hr;
782
783 return psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
784 }
785
786 HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid)
787 {
788 FIXME ("(%p)\n", this);
789 return E_NOTIMPL;
790 }
791
792 HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum)
793 {
794 FIXME ("(%p)\n", this);
795 return E_NOTIMPL;
796 }
797
798 HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
799 {
800 TRACE ("(%p)\n", this);
801
802 if (pSort)
803 *pSort = 0;
804 if (pDisplay)
805 *pDisplay = 0;
806
807 return S_OK;
808 }
809
810 HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
811 {
812 TRACE ("(%p)\n", this);
813
814 if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
815 return E_INVALIDARG;
816
817 *pcsFlags = DesktopSFHeader[iColumn].pcsFlags;
818
819 return S_OK;
820 }
821
822 HRESULT WINAPI CDesktopFolder::GetDetailsEx(
823 PCUITEMID_CHILD pidl,
824 const SHCOLUMNID *pscid,
825 VARIANT *pv)
826 {
827 FIXME ("(%p)\n", this);
828
829 return E_NOTIMPL;
830 }
831
832 HRESULT WINAPI CDesktopFolder::GetDetailsOf(
833 PCUITEMID_CHILD pidl,
834 UINT iColumn,
835 SHELLDETAILS *psd)
836 {
837 if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
838 return E_INVALIDARG;
839
840 if (!pidl)
841 {
842 psd->fmt = DesktopSFHeader[iColumn].fmt;
843 psd->cxChar = DesktopSFHeader[iColumn].cxChar;
844 return SHSetStrRet(&psd->str, DesktopSFHeader[iColumn].colnameid);
845 }
846
847 CComPtr<IShellFolder2> psf;
848 HRESULT hr = _GetSFFromPidl(pidl, &psf);
849 if (FAILED_UNEXPECTEDLY(hr))
850 return hr;
851
852 hr = psf->GetDetailsOf(pidl, iColumn, psd);
853 if (FAILED_UNEXPECTEDLY(hr))
854 return hr;
855
856 return hr;
857 }
858
859 HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
860 {
861 FIXME ("(%p)\n", this);
862 return E_NOTIMPL;
863 }
864
865 HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId)
866 {
867 TRACE ("(%p)\n", this);
868
869 if (!lpClassId)
870 return E_POINTER;
871
872 *lpClassId = CLSID_ShellDesktop;
873
874 return S_OK;
875 }
876
877 HRESULT WINAPI CDesktopFolder::Initialize(LPCITEMIDLIST pidl)
878 {
879 TRACE ("(%p)->(%p)\n", this, pidl);
880
881 return E_INVALIDARG;
882 }
883
884 HRESULT WINAPI CDesktopFolder::GetCurFolder(LPITEMIDLIST * pidl)
885 {
886 TRACE ("(%p)->(%p)\n", this, pidl);
887
888 if (!pidl)
889 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */
890 *pidl = ILClone (pidlRoot);
891 return S_OK;
892 }
893
894 HRESULT WINAPI CDesktopFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
895 {
896 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND)
897 return S_OK;
898
899 /* no data object means no selection */
900 if (!pdtobj)
901 {
902 if (uMsg == DFM_INVOKECOMMAND && wParam == DFM_CMD_PROPERTIES)
903 {
904 if (32 >= (UINT)ShellExecuteW(hwndOwner, L"open", L"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL))
905 return E_FAIL;
906 return S_OK;
907 }
908 else if (uMsg == DFM_MERGECONTEXTMENU)
909 {
910 QCMINFO *pqcminfo = (QCMINFO *)lParam;
911 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
912 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, FCIDM_SHVIEW_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
913 }
914
915 return S_OK;
916 }
917
918 PIDLIST_ABSOLUTE pidlFolder;
919 PUITEMID_CHILD *apidl;
920 UINT cidl;
921 HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
922 if (FAILED_UNEXPECTEDLY(hr))
923 return hr;
924
925 if (cidl > 1)
926 ERR("SHMultiFileProperties is not yet implemented\n");
927
928 STRRET strFile;
929 hr = GetDisplayNameOf(apidl[0], SHGDN_FORPARSING, &strFile);
930 if (SUCCEEDED(hr))
931 {
932 hr = SH_ShowPropertiesDialog(strFile.pOleStr, pidlFolder, apidl);
933 if (FAILED(hr))
934 ERR("SH_ShowPropertiesDialog failed\n");
935 }
936 else
937 {
938 ERR("Failed to get display name\n");
939 }
940
941 SHFree(pidlFolder);
942 _ILFreeaPidl(apidl, cidl);
943
944 return hr;
945 }
946
947 /*************************************************************************
948 * SHGetDesktopFolder [SHELL32.@]
949 */
950 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
951 {
952 HRESULT hres = S_OK;
953 TRACE("\n");
954
955 if(!psf) return E_INVALIDARG;
956 *psf = NULL;
957 hres = CDesktopFolder::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellFolder, psf));
958
959 TRACE("-- %p->(%p)\n",psf, *psf);
960 return hres;
961 }