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