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