07678efb05c239124b4e9ce16a91eaf542126117
[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_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
67 {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
68 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10},
69 {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 12},
70 };
71
72 #define DESKTOPSHELLVIEWCOLUMNS 4
73
74 static const DWORD dwDesktopAttributes =
75 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
76 SFGAO_STORAGEANCESTOR | SFGAO_HASPROPSHEET | SFGAO_STORAGE | SFGAO_CANLINK;
77 static const DWORD dwMyComputerAttributes =
78 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
79 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
80 static DWORD dwMyNetPlacesAttributes =
81 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
82 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
83
84
85 CDesktopFolderEnum::CDesktopFolderEnum()
86 {
87 }
88
89 CDesktopFolderEnum::~CDesktopFolderEnum()
90 {
91 }
92
93 static const WCHAR ClassicStartMenuW[] = L"SOFTWARE\\Microsoft\\Windows\\"
94 L"CurrentVersion\\Explorer\\HideDesktopIcons\\ClassicStartMenu";
95
96 static INT
97 IsNamespaceExtensionHidden(const WCHAR *iid)
98 {
99 DWORD Result, dwResult;
100 dwResult = sizeof(DWORD);
101
102 if (RegGetValueW(HKEY_CURRENT_USER, /* FIXME use NewStartPanel when activated */
103 ClassicStartMenuW,
104 iid,
105 RRF_RT_DWORD,
106 NULL,
107 &Result,
108 &dwResult) != ERROR_SUCCESS)
109 {
110 return -1;
111 }
112
113 return Result;
114 }
115
116 /**************************************************************************
117 * CreateDesktopEnumList()
118 */
119
120 HRESULT WINAPI CDesktopFolderEnum::Initialize(CDesktopFolder *desktopFolder, HWND hwndOwner, DWORD dwFlags)
121 {
122 BOOL ret = TRUE;
123 WCHAR szPath[MAX_PATH];
124
125 static const WCHAR MyDocumentsClassString[] = L"{450D8FBA-AD25-11D0-98A8-0800361B1103}";
126 static const WCHAR Desktop_NameSpaceW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\Namespace";
127
128 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
129
130 /* enumerate the root folders */
131 if (dwFlags & SHCONTF_FOLDERS)
132 {
133 HKEY hkey;
134 UINT i;
135 DWORD dwResult;
136
137 /* create the pidl for This item */
138 if (IsNamespaceExtensionHidden(MyDocumentsClassString) < 1)
139 {
140 ret = AddToEnumList(_ILCreateMyDocuments());
141 }
142 ret = AddToEnumList(_ILCreateMyComputer());
143
144 for (i = 0; i < 2; i++)
145 {
146 if (i == 0)
147 dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
148 else
149 dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
150
151 if (dwResult == ERROR_SUCCESS)
152 {
153 WCHAR iid[50];
154 LPITEMIDLIST pidl;
155 int i = 0;
156
157 while (ret)
158 {
159 DWORD size;
160 LONG r;
161
162 size = sizeof (iid) / sizeof (iid[0]);
163 r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
164 if (ERROR_SUCCESS == r)
165 {
166 if (IsNamespaceExtensionHidden(iid) < 1)
167 {
168 pidl = _ILCreateGuidFromStrW(iid);
169 if (pidl != NULL)
170 {
171 if (!HasItemWithCLSID(pidl))
172 {
173 ret = AddToEnumList(pidl);
174 }
175 else
176 {
177 SHFree(pidl);
178 }
179 }
180 }
181 }
182 else if (ERROR_NO_MORE_ITEMS == r)
183 break;
184 else
185 ret = FALSE;
186 i++;
187 }
188 RegCloseKey(hkey);
189 }
190 }
191 for (i = 0; i < 2; i++)
192 {
193 if (i == 0)
194 dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, ClassicStartMenuW, 0, KEY_READ, &hkey);
195 else
196 dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, ClassicStartMenuW, 0, KEY_READ, &hkey);
197
198 if (dwResult == ERROR_SUCCESS)
199 {
200 DWORD j = 0, dwVal, Val, dwType, dwIID;
201 LONG r;
202 WCHAR iid[50];
203
204 while(ret)
205 {
206 dwVal = sizeof(Val);
207 dwIID = sizeof(iid) / sizeof(WCHAR);
208
209 r = RegEnumValueW(hkey, j++, iid, &dwIID, NULL, &dwType, (LPBYTE)&Val, &dwVal);
210 if (r == ERROR_SUCCESS)
211 {
212 if (Val == 0 && dwType == REG_DWORD)
213 {
214 LPITEMIDLIST pidl = _ILCreateGuidFromStrW(iid);
215 if (pidl != NULL)
216 {
217 if (!HasItemWithCLSID(pidl))
218 {
219 AddToEnumList(pidl);
220 }
221 else
222 {
223 SHFree(pidl);
224 }
225 }
226 }
227 }
228 else if (ERROR_NO_MORE_ITEMS == r)
229 break;
230 else
231 ret = FALSE;
232 }
233 RegCloseKey(hkey);
234 }
235
236 }
237 }
238
239 /* enumerate the elements in %windir%\desktop */
240 ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
241 ret = ret && CreateFolderEnumList(szPath, dwFlags);
242
243 ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
244 ret = ret && CreateFolderEnumList(szPath, dwFlags);
245
246 return ret ? S_OK : E_FAIL;
247 }
248
249 CDesktopFolder::CDesktopFolder() :
250 sPathTarget(NULL),
251 pidlRoot(NULL)
252 {
253 }
254
255 CDesktopFolder::~CDesktopFolder()
256 {
257 }
258
259 HRESULT WINAPI CDesktopFolder::FinalConstruct()
260 {
261 WCHAR szMyPath[MAX_PATH];
262 HRESULT hr;
263
264 /* Create the root pidl */
265 pidlRoot = _ILCreateDesktop();
266 if (!pidlRoot)
267 return E_OUTOFMEMORY;
268
269 /* Create the inner fs folder */
270 hr = SHELL32_CoCreateInitSF(pidlRoot,
271 NULL,
272 NULL,
273 &CLSID_ShellFSFolder,
274 CSIDL_DESKTOPDIRECTORY,
275 IID_PPV_ARG(IShellFolder2, &m_DesktopFSFolder));
276 if (FAILED_UNEXPECTEDLY(hr))
277 return hr;
278
279 /* Create the inner shared fs folder. Dont fail on failure. */
280 hr = SHELL32_CoCreateInitSF(pidlRoot,
281 NULL,
282 NULL,
283 &CLSID_ShellFSFolder,
284 CSIDL_COMMON_DESKTOPDIRECTORY,
285 IID_PPV_ARG(IShellFolder2, &m_SharedDesktopFSFolder));
286 if (FAILED_UNEXPECTEDLY(hr))
287 return hr;
288
289 /* Create the inner reg folder */
290 hr = CRegFolder_CreateInstance(&CLSID_ShellDesktop,
291 pidlRoot,
292 L"",
293 IID_PPV_ARG(IShellFolder2, &m_regFolder));
294 if (FAILED_UNEXPECTEDLY(hr))
295 return hr;
296
297 /* Cache the path to the user desktop directory */
298 if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
299 return E_UNEXPECTED;
300
301 sPathTarget = (LPWSTR)SHAlloc((wcslen(szMyPath) + 1) * sizeof(WCHAR));
302 if (!sPathTarget)
303 return E_OUTOFMEMORY;
304
305 wcscpy(sPathTarget, szMyPath);
306 return S_OK;
307 }
308
309 HRESULT CDesktopFolder::_GetSFFromPidl(LPCITEMIDLIST pidl, IShellFolder2** psf)
310 {
311 WCHAR szFileName[MAX_PATH];
312
313 if (_ILIsSpecialFolder(pidl))
314 return m_regFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf));
315
316 lstrcpynW(szFileName, sPathTarget, MAX_PATH - 1);
317 PathAddBackslashW(szFileName);
318 int cLen = wcslen(szFileName);
319
320 if (!_ILSimpleGetTextW(pidl, szFileName + cLen, MAX_PATH - cLen))
321 return E_FAIL;
322
323 if (GetFileAttributes(szFileName) == INVALID_FILE_ATTRIBUTES)
324 return m_SharedDesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf));
325 else
326 return m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf));
327 }
328
329 /**************************************************************************
330 * CDesktopFolder::ParseDisplayName
331 *
332 * NOTES
333 * "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
334 * to MyComputer
335 */
336 HRESULT WINAPI CDesktopFolder::ParseDisplayName(
337 HWND hwndOwner,
338 LPBC pbc,
339 LPOLESTR lpszDisplayName,
340 DWORD *pchEaten,
341 PIDLIST_RELATIVE *ppidl,
342 DWORD *pdwAttributes)
343 {
344 LPCWSTR szNext = NULL;
345 LPITEMIDLIST pidlTemp = NULL;
346 PARSEDURLW urldata;
347 HRESULT hr = S_OK;
348
349 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
350 this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
351 pchEaten, ppidl, pdwAttributes);
352
353 if (!ppidl)
354 return E_INVALIDARG;
355
356 *ppidl = NULL;
357
358 if (!lpszDisplayName)
359 return E_INVALIDARG;
360
361 if (pchEaten)
362 *pchEaten = 0; /* strange but like the original */
363
364 urldata.cbSize = sizeof(urldata);
365
366 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
367 {
368 return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
369 }
370 else if (PathGetDriveNumberW (lpszDisplayName) >= 0)
371 {
372 /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
373 pidlTemp = _ILCreateMyComputer ();
374 szNext = lpszDisplayName;
375 }
376 else if (PathIsUNCW(lpszDisplayName))
377 {
378 pidlTemp = _ILCreateNetwork();
379 szNext = lpszDisplayName;
380 }
381 else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
382 {
383 *ppidl = pidlTemp;
384 return S_OK;
385 }
386 else if (SUCCEEDED(ParseURLW(lpszDisplayName, &urldata)))
387 {
388 if (urldata.nScheme == URL_SCHEME_SHELL) /* handle shell: urls */
389 {
390 TRACE ("-- shell url: %s\n", debugstr_w(urldata.pszSuffix));
391 pidlTemp = _ILCreateGuidFromStrW(urldata.pszSuffix + 2);
392 }
393 else
394 return IEParseDisplayNameWithBCW(CP_ACP, lpszDisplayName, pbc, ppidl);
395 }
396 else
397 {
398 if (*lpszDisplayName)
399 {
400 /* it's a filesystem path on the desktop. Let a FSFolder parse it */
401 hr = m_DesktopFSFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
402 if (SUCCEEDED(hr))
403 return hr;
404
405 return m_SharedDesktopFSFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
406 }
407 else
408 pidlTemp = _ILCreateMyComputer();
409
410 szNext = NULL;
411 }
412
413 if (SUCCEEDED(hr) && pidlTemp)
414 {
415 if (szNext && *szNext)
416 {
417 hr = SHELL32_ParseNextElement(this, hwndOwner, pbc,
418 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
419 }
420 else
421 {
422 if (pdwAttributes && *pdwAttributes)
423 {
424 GetAttributesOf(1, &pidlTemp, pdwAttributes);
425 }
426 }
427 }
428
429 if (SUCCEEDED(hr))
430 *ppidl = pidlTemp;
431 else
432 *ppidl = NULL;
433
434 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
435
436 return hr;
437 }
438
439 /**************************************************************************
440 * CDesktopFolder::EnumObjects
441 */
442 HRESULT WINAPI CDesktopFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
443 {
444 return ShellObjectCreatorInit<CDesktopFolderEnum>(this, hwndOwner, dwFlags, IID_IEnumIDList, ppEnumIDList);
445 }
446
447 /**************************************************************************
448 * CDesktopFolder::BindToObject
449 */
450 HRESULT WINAPI CDesktopFolder::BindToObject(
451 PCUIDLIST_RELATIVE pidl,
452 LPBC pbcReserved,
453 REFIID riid,
454 LPVOID *ppvOut)
455 {
456 if (!pidl)
457 return E_INVALIDARG;
458
459 CComPtr<IShellFolder2> psf;
460 HRESULT hr = _GetSFFromPidl(pidl, &psf);
461 if (FAILED_UNEXPECTEDLY(hr))
462 return hr;
463
464 return psf->BindToObject(pidl, pbcReserved, riid, ppvOut);
465 }
466
467 /**************************************************************************
468 * CDesktopFolder::BindToStorage
469 */
470 HRESULT WINAPI CDesktopFolder::BindToStorage(
471 PCUIDLIST_RELATIVE pidl,
472 LPBC pbcReserved,
473 REFIID riid,
474 LPVOID *ppvOut)
475 {
476 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
477 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
478
479 *ppvOut = NULL;
480 return E_NOTIMPL;
481 }
482
483 /**************************************************************************
484 * CDesktopFolder::CompareIDs
485 */
486 HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
487 {
488 bool bIsDesktopFolder1, bIsDesktopFolder2;
489
490 if (!pidl1 || !pidl2)
491 {
492 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2);
493 return E_INVALIDARG;
494 }
495
496 bIsDesktopFolder1 = _ILIsDesktop(pidl1);
497 bIsDesktopFolder2 = _ILIsDesktop(pidl2);
498 if (bIsDesktopFolder1 || bIsDesktopFolder2)
499 return MAKE_COMPARE_HRESULT(bIsDesktopFolder1 - bIsDesktopFolder2);
500
501 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
502 return m_regFolder->CompareIDs(lParam, pidl1, pidl2);
503
504 return m_DesktopFSFolder->CompareIDs(lParam, pidl1, pidl2);
505 }
506
507 /**************************************************************************
508 * CDesktopFolder::CreateViewObject
509 */
510 HRESULT WINAPI CDesktopFolder::CreateViewObject(
511 HWND hwndOwner,
512 REFIID riid,
513 LPVOID *ppvOut)
514 {
515 CComPtr<IShellView> pShellView;
516 HRESULT hr = E_INVALIDARG;
517
518 TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
519 this, hwndOwner, shdebugstr_guid (&riid), ppvOut);
520
521 if (!ppvOut)
522 return hr;
523
524 *ppvOut = NULL;
525
526 if (IsEqualIID (riid, IID_IDropTarget))
527 {
528 hr = m_DesktopFSFolder->CreateViewObject(hwndOwner, riid, ppvOut);
529 }
530 else if (IsEqualIID (riid, IID_IContextMenu))
531 {
532 HKEY hKeys[16];
533 UINT cKeys = 0;
534 AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys);
535
536 DEFCONTEXTMENU dcm;
537 dcm.hwnd = hwndOwner;
538 dcm.pcmcb = this;
539 dcm.pidlFolder = pidlRoot;
540 dcm.psf = this;
541 dcm.cidl = 0;
542 dcm.apidl = NULL;
543 dcm.cKeys = cKeys;
544 dcm.aKeys = hKeys;
545 dcm.punkAssociationInfo = NULL;
546 hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut);
547 }
548 else if (IsEqualIID (riid, IID_IShellView))
549 {
550 hr = IShellView_Constructor((IShellFolder *)this, &pShellView);
551 if (pShellView)
552 hr = pShellView->QueryInterface(riid, 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
690 hr = E_NOINTERFACE;
691
692 if (SUCCEEDED(hr) && !pObj)
693 hr = E_OUTOFMEMORY;
694
695 *ppvOut = pObj;
696 TRACE ("(%p)->hr=0x%08x\n", this, hr);
697 return hr;
698 }
699
700 /**************************************************************************
701 * CDesktopFolder::GetDisplayNameOf
702 *
703 * NOTES
704 * special case: pidl = null gives desktop-name back
705 */
706 HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
707 {
708 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
709 pdump (pidl);
710
711 if (!strRet)
712 return E_INVALIDARG;
713
714 if (!_ILIsPidlSimple (pidl))
715 {
716 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
717 }
718 else if (_ILIsDesktop(pidl))
719 {
720 if ((GET_SHGDN_RELATION(dwFlags) == SHGDN_NORMAL) && (GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING))
721 return SHSetStrRet(strRet, sPathTarget);
722 else
723 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet);
724 }
725
726 /* file system folder or file rooted at the desktop */
727 CComPtr<IShellFolder2> psf;
728 HRESULT hr = _GetSFFromPidl(pidl, &psf);
729 if (FAILED_UNEXPECTEDLY(hr))
730 return hr;
731
732 return psf->GetDisplayNameOf(pidl, dwFlags, strRet);
733 }
734
735 /**************************************************************************
736 * CDesktopFolder::SetNameOf
737 * Changes the name of a file object or subfolder, possibly changing its item
738 * identifier in the process.
739 *
740 * PARAMETERS
741 * HWND hwndOwner, //[in ] Owner window for output
742 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
743 * LPCOLESTR lpszName, //[in ] the items new display name
744 * DWORD dwFlags, //[in ] SHGNO formatting flags
745 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
746 */
747 HRESULT WINAPI CDesktopFolder::SetNameOf(
748 HWND hwndOwner,
749 PCUITEMID_CHILD pidl, /* simple pidl */
750 LPCOLESTR lpName,
751 DWORD dwFlags,
752 PITEMID_CHILD *pPidlOut)
753 {
754 CComPtr<IShellFolder2> psf;
755 HRESULT hr = _GetSFFromPidl(pidl, &psf);
756 if (FAILED_UNEXPECTEDLY(hr))
757 return hr;
758
759 return psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
760 }
761
762 HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid)
763 {
764 FIXME ("(%p)\n", this);
765 return E_NOTIMPL;
766 }
767
768 HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum)
769 {
770 FIXME ("(%p)\n", this);
771 return E_NOTIMPL;
772 }
773
774 HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
775 {
776 TRACE ("(%p)\n", this);
777
778 if (pSort)
779 *pSort = 0;
780 if (pDisplay)
781 *pDisplay = 0;
782
783 return S_OK;
784 }
785
786 HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
787 {
788 TRACE ("(%p)\n", this);
789
790 if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
791 return E_INVALIDARG;
792
793 *pcsFlags = DesktopSFHeader[iColumn].pcsFlags;
794
795 return S_OK;
796 }
797
798 HRESULT WINAPI CDesktopFolder::GetDetailsEx(
799 PCUITEMID_CHILD pidl,
800 const SHCOLUMNID *pscid,
801 VARIANT *pv)
802 {
803 FIXME ("(%p)\n", this);
804
805 return E_NOTIMPL;
806 }
807
808 HRESULT WINAPI CDesktopFolder::GetDetailsOf(
809 PCUITEMID_CHILD pidl,
810 UINT iColumn,
811 SHELLDETAILS *psd)
812 {
813 if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
814 return E_INVALIDARG;
815
816 if (!pidl)
817 {
818 psd->fmt = DesktopSFHeader[iColumn].fmt;
819 psd->cxChar = DesktopSFHeader[iColumn].cxChar;
820 return SHSetStrRet(&psd->str, DesktopSFHeader[iColumn].colnameid);
821 }
822
823 CComPtr<IShellFolder2> psf;
824 HRESULT hr = _GetSFFromPidl(pidl, &psf);
825 if (FAILED_UNEXPECTEDLY(hr))
826 return hr;
827
828 hr = psf->GetDetailsOf(pidl, iColumn, psd);
829 if (FAILED_UNEXPECTEDLY(hr))
830 return hr;
831
832 return hr;
833 }
834
835 HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
836 {
837 FIXME ("(%p)\n", this);
838 return E_NOTIMPL;
839 }
840
841 HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId)
842 {
843 TRACE ("(%p)\n", this);
844
845 if (!lpClassId)
846 return E_POINTER;
847
848 *lpClassId = CLSID_ShellDesktop;
849
850 return S_OK;
851 }
852
853 HRESULT WINAPI CDesktopFolder::Initialize(LPCITEMIDLIST pidl)
854 {
855 TRACE ("(%p)->(%p)\n", this, pidl);
856
857 return E_INVALIDARG;
858 }
859
860 HRESULT WINAPI CDesktopFolder::GetCurFolder(LPITEMIDLIST * pidl)
861 {
862 TRACE ("(%p)->(%p)\n", this, pidl);
863
864 if (!pidl)
865 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */
866 *pidl = ILClone (pidlRoot);
867 return S_OK;
868 }
869
870 HRESULT WINAPI CDesktopFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
871 {
872 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND)
873 return S_OK;
874
875 /* no data object means no selection */
876 if (!pdtobj)
877 {
878 if (uMsg == DFM_INVOKECOMMAND && wParam == DFM_CMD_PROPERTIES)
879 {
880 if (32 >= (UINT)ShellExecuteW(hwndOwner, L"open", L"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL))
881 return E_FAIL;
882 return S_OK;
883 }
884 else if (uMsg == DFM_MERGECONTEXTMENU)
885 {
886 QCMINFO *pqcminfo = (QCMINFO *)lParam;
887 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
888 _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, FCIDM_SHVIEW_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
889 }
890
891 return S_OK;
892 }
893
894 PIDLIST_ABSOLUTE pidlFolder;
895 PUITEMID_CHILD *apidl;
896 UINT cidl;
897 HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
898 if (FAILED_UNEXPECTEDLY(hr))
899 return hr;
900
901 if (cidl > 1)
902 ERR("SHMultiFileProperties is not yet implemented\n");
903
904 STRRET strFile;
905 hr = GetDisplayNameOf(apidl[0], SHGDN_FORPARSING, &strFile);
906 if (SUCCEEDED(hr))
907 {
908 hr = SH_ShowPropertiesDialog(strFile.pOleStr, pidlFolder, apidl);
909 if (FAILED(hr))
910 ERR("SH_ShowPropertiesDialog failed\n");
911 }
912 else
913 {
914 ERR("Failed to get display name\n");
915 }
916
917 SHFree(pidlFolder);
918 _ILFreeaPidl(apidl, cidl);
919
920 return hr;
921 }
922
923 /*************************************************************************
924 * SHGetDesktopFolder [SHELL32.@]
925 */
926 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
927 {
928 HRESULT hres = S_OK;
929 TRACE("\n");
930
931 if(!psf) return E_INVALIDARG;
932 *psf = NULL;
933 hres = CDesktopFolder::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellFolder, psf));
934
935 TRACE("-- %p->(%p)\n",psf, *psf);
936 return hres;
937 }