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 #include "CFSFolder.h" // Only for CFSFolder::*FSColumn* helpers!
25 
26 WINE_DEFAULT_DEBUG_CHANNEL(shell);
27 
28 extern BOOL SHELL32_IsShellFolderNamespaceItemHidden(LPCWSTR SubKey, REFCLSID Clsid);
29 
30 static const REQUIREDREGITEM g_RequiredItems[] =
31 {
32     { CLSID_MyComputer, "sysdm.cpl", 0x50 },
33     { CLSID_NetworkPlaces, "ncpa.cpl", 0x58 },
34     { CLSID_Internet, "inetcpl.cpl", 0x68 },
35 };
36 static const REGFOLDERINFO g_RegFolderInfo =
37 {
38     PT_DESKTOP_REGITEM,
39     _countof(g_RequiredItems), g_RequiredItems,
40     CLSID_ShellDesktop,
41     L"",
42     L"Desktop",
43 };
44 
IsSelf(UINT cidl,PCUITEMID_CHILD_ARRAY apidl)45 static BOOL IsSelf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl)
46 {
47     return cidl == 0 || (cidl == 1 && apidl && _ILIsEmpty(apidl[0]));
48 }
49 
IsRegItem(PCUITEMID_CHILD pidl)50 static const CLSID* IsRegItem(PCUITEMID_CHILD pidl)
51 {
52     if (pidl && pidl->mkid.cb == 2 + 2 + sizeof(CLSID) && pidl->mkid.abID[0] == PT_GUID)
53         return (const CLSID*)(&pidl->mkid.abID[2]);
54     return NULL;
55 }
56 
57 STDMETHODIMP
ShellUrlParseDisplayName(HWND hwndOwner,LPBC pbc,LPOLESTR lpszDisplayName,DWORD * pchEaten,PIDLIST_RELATIVE * ppidl,DWORD * pdwAttributes)58 CDesktopFolder::ShellUrlParseDisplayName(
59     HWND hwndOwner,
60     LPBC pbc,
61     LPOLESTR lpszDisplayName,
62     DWORD *pchEaten,
63     PIDLIST_RELATIVE *ppidl,
64     DWORD *pdwAttributes)
65 {
66     LPWSTR pch;
67     INT cch, csidl;
68     HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
69     PARSEDURLW ParsedURL = { sizeof(ParsedURL) };
70 
71     ::ParseURLW(lpszDisplayName, &ParsedURL);
72 
73     DWORD attrs = (pdwAttributes ? *pdwAttributes : 0) | SFGAO_STREAM;
74     if (ParsedURL.pszSuffix[0] == L':' && ParsedURL.pszSuffix[1] == L':') // It begins from "::"
75     {
76         CComPtr<IShellFolder> psfDesktop;
77         hr = SHGetDesktopFolder(&psfDesktop);
78         if (SUCCEEDED(hr))
79         {
80             CComPtr<IBindCtx> pBindCtx;
81             hr = ::CreateBindCtx(0, &pBindCtx);
82             if (SUCCEEDED(hr))
83             {
84                 BIND_OPTS BindOps = { sizeof(BindOps) };
85                 BindOps.grfMode = STGM_CREATE;
86                 pBindCtx->SetBindOptions(&BindOps);
87                 hr = psfDesktop->ParseDisplayName(hwndOwner, pBindCtx,
88                                                   (LPWSTR)ParsedURL.pszSuffix,
89                                                   pchEaten, ppidl, &attrs);
90             }
91         }
92     }
93     else
94     {
95         csidl = Shell_ParseSpecialFolder(ParsedURL.pszSuffix, &pch, &cch);
96         if (csidl == -1)
97         {
98             ERR("\n");
99             return hr;
100         }
101 
102         CComHeapPtr<ITEMIDLIST> pidlLocation;
103         hr = SHGetFolderLocation(hwndOwner, (csidl | CSIDL_FLAG_CREATE), NULL, 0, &pidlLocation);
104         if (FAILED_UNEXPECTEDLY(hr))
105             return hr;
106 
107         if (pch && *pch)
108         {
109             CComPtr<IShellFolder> psfFolder;
110             hr = SHBindToObject(NULL, pidlLocation, IID_PPV_ARG(IShellFolder, &psfFolder));
111             if (SUCCEEDED(hr))
112             {
113                 CComHeapPtr<ITEMIDLIST> pidlNew;
114                 hr = psfFolder->ParseDisplayName(hwndOwner, pbc, pch, pchEaten, &pidlNew, &attrs);
115                 if (SUCCEEDED(hr))
116                 {
117                     hr = SHILCombine(pidlLocation, pidlNew, ppidl);
118                     if (pchEaten)
119                         *pchEaten += cch;
120                 }
121             }
122         }
123         else
124         {
125             if (attrs)
126                 hr = SHGetNameAndFlagsW(pidlLocation, 0, NULL, 0, &attrs);
127 
128             if (SUCCEEDED(hr))
129             {
130                 if (pchEaten)
131                     *pchEaten = cch;
132                 *ppidl = pidlLocation.Detach();
133             }
134         }
135     }
136 
137     // FIXME: SHWindowsPolicy
138     if (SUCCEEDED(hr) && (attrs & SFGAO_STREAM) &&
139         !BindCtx_ContainsObject(pbc, STR_PARSE_SHELL_PROTOCOL_TO_FILE_OBJECTS))
140     {
141         ILFree(*ppidl);
142         *ppidl = NULL;
143         hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
144     }
145 
146     if (pdwAttributes)
147         *pdwAttributes = attrs;
148 
149     // FIXME: SHWindowsPolicy
150     if (FAILED(hr) && !Shell_FailForceReturn(hr))
151         hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
152 
153     return hr;
154 }
155 
156 STDMETHODIMP
HttpUrlParseDisplayName(HWND hwndOwner,LPBC pbc,LPOLESTR lpszDisplayName,DWORD * pchEaten,PIDLIST_RELATIVE * ppidl,DWORD * pdwAttributes)157 CDesktopFolder::HttpUrlParseDisplayName(
158     HWND hwndOwner,
159     LPBC pbc,
160     LPOLESTR lpszDisplayName,
161     DWORD *pchEaten,
162     PIDLIST_RELATIVE *ppidl,
163     DWORD *pdwAttributes)
164 {
165     FIXME("\n");
166     return E_NOTIMPL; // FIXME
167 }
168 
169 /*
170 CDesktopFolder should create two file system folders internally, one representing the
171 user's desktop folder, and the other representing the common desktop folder. It should
172 also create a CRegFolder to represent the virtual items that exist only in the registry.
173 The CRegFolder is aggregated by the CDesktopFolder, and queries for the CLSID_IShellFolder,
174 CLSID_IShellFolder2, or CLSID_IShellIconOverlay interfaces prefer the CRegFolder
175 implementation.
176 The CDesktopFolderEnum class should create two enumerators, one for each of the file
177 system folders, and enumerate the contents of each folder. Since the CRegFolder
178 implementation of IShellFolder::EnumObjects enumerates the virtual items, the
179 CDesktopFolderEnum is only responsible for returning the physical items.
180 CDesktopFolderViewCB is responsible for filtering hidden regitems.
181 The enumerator always shows My Computer.
182 */
183 
184 /* Undocumented functions from shdocvw */
185 extern "C" HRESULT WINAPI IEParseDisplayNameWithBCW(DWORD codepage, LPCWSTR lpszDisplayName, LPBC pbc, LPITEMIDLIST *ppidl);
186 
187 class CDesktopFolderEnum :
188     public CEnumIDListBase
189 {
190     private:
191 //    CComPtr                                fDesktopEnumerator;
192 //    CComPtr                                fCommonDesktopEnumerator;
193     public:
194 
Initialize(IShellFolder * pRegFolder,SHCONTF dwFlags,IEnumIDList * pRegEnumerator,IEnumIDList * pDesktopEnumerator,IEnumIDList * pCommonDesktopEnumerator)195         HRESULT WINAPI Initialize(IShellFolder *pRegFolder, SHCONTF dwFlags, IEnumIDList *pRegEnumerator,
196                                   IEnumIDList *pDesktopEnumerator, IEnumIDList *pCommonDesktopEnumerator)
197         {
198             TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
199 
200             AppendItemsFromEnumerator(pRegEnumerator);
201 
202             /* Enumerate the items in the two fs folders */
203             AppendItemsFromEnumerator(pDesktopEnumerator);
204             AppendItemsFromEnumerator(pCommonDesktopEnumerator);
205 
206             return S_OK;
207         }
208 
209         BEGIN_COM_MAP(CDesktopFolderEnum)
210         COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
211         END_COM_MAP()
212 };
213 
214 int SHELL_ConfirmMsgBox(HWND hWnd, LPWSTR lpszText, LPWSTR lpszCaption, HICON hIcon, BOOL bYesToAll);
215 
216 static const DWORD dwDesktopAttributes =
217     SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
218     SFGAO_STORAGEANCESTOR | SFGAO_HASPROPSHEET | SFGAO_STORAGE;
219 static const DWORD dwMyComputerAttributes =
220     SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
221     SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
222 static DWORD dwMyNetPlacesAttributes =
223     SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
224     SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
225 
CDesktopFolder()226 CDesktopFolder::CDesktopFolder() :
227     sPathTarget(NULL),
228     pidlRoot(NULL)
229 {
230 }
231 
~CDesktopFolder()232 CDesktopFolder::~CDesktopFolder()
233 {
234 }
235 
FinalConstruct()236 HRESULT WINAPI CDesktopFolder::FinalConstruct()
237 {
238     WCHAR szMyPath[MAX_PATH];
239     HRESULT hr;
240 
241     /* Create the root pidl */
242     pidlRoot = _ILCreateDesktop();
243     if (!pidlRoot)
244         return E_OUTOFMEMORY;
245 
246     /* Create the inner fs folder */
247     hr = SHELL32_CoCreateInitSF(pidlRoot,
248                                 &CLSID_ShellFSFolder,
249                                 CSIDL_DESKTOPDIRECTORY,
250                                 IID_PPV_ARG(IShellFolder2, &m_DesktopFSFolder));
251     if (FAILED_UNEXPECTEDLY(hr))
252         return hr;
253 
254     /* Create the inner shared fs folder. Dont fail on failure. */
255     hr = SHELL32_CoCreateInitSF(pidlRoot,
256                                 &CLSID_ShellFSFolder,
257                                 CSIDL_COMMON_DESKTOPDIRECTORY,
258                                 IID_PPV_ARG(IShellFolder2, &m_SharedDesktopFSFolder));
259     if (FAILED_UNEXPECTEDLY(hr))
260         return hr;
261 
262     /* Create the inner reg folder */
263     REGFOLDERINITDATA RegInit = { static_cast<IShellFolder*>(this), &g_RegFolderInfo };
264     hr = CRegFolder_CreateInstance(&RegInit,
265                                    pidlRoot,
266                                    IID_PPV_ARG(IShellFolder2, &m_regFolder));
267     if (FAILED_UNEXPECTEDLY(hr))
268         return hr;
269 
270     /* Cache the path to the user desktop directory */
271     if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
272         return E_UNEXPECTED;
273 
274     sPathTarget = (LPWSTR)SHAlloc((wcslen(szMyPath) + 1) * sizeof(WCHAR));
275     if (!sPathTarget)
276         return E_OUTOFMEMORY;
277 
278     wcscpy(sPathTarget, szMyPath);
279     return S_OK;
280 }
281 
_GetSFFromPidl(LPCITEMIDLIST pidl,IShellFolder2 ** psf)282 HRESULT CDesktopFolder::_GetSFFromPidl(LPCITEMIDLIST pidl, IShellFolder2** psf)
283 {
284     WCHAR szFileName[MAX_PATH];
285 
286     if (_ILIsSpecialFolder(pidl))
287         return m_regFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf));
288 
289     lstrcpynW(szFileName, sPathTarget, MAX_PATH - 1);
290     PathAddBackslashW(szFileName);
291     int cLen = wcslen(szFileName);
292 
293     if (!_ILSimpleGetTextW(pidl, szFileName + cLen, MAX_PATH - cLen))
294         return E_FAIL;
295 
296     if (GetFileAttributes(szFileName) == INVALID_FILE_ATTRIBUTES)
297         return m_SharedDesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf));
298     else
299         return m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf));
300 }
301 
_ParseDisplayNameByParent(HWND hwndOwner,LPBC pbc,LPOLESTR lpszDisplayName,DWORD * pchEaten,PIDLIST_RELATIVE * ppidl,DWORD * pdwAttributes)302 HRESULT CDesktopFolder::_ParseDisplayNameByParent(
303     HWND hwndOwner,
304     LPBC pbc,
305     LPOLESTR lpszDisplayName,
306     DWORD *pchEaten,
307     PIDLIST_RELATIVE *ppidl,
308     DWORD *pdwAttributes)
309 {
310     if (pchEaten)
311         *pchEaten = 0;
312 
313     CComHeapPtr<ITEMIDLIST> pidlParent;
314     BOOL bPath = FALSE;
315     WCHAR wch = *lpszDisplayName;
316     if (((L'A' <= wch && wch <= L'Z') || (L'a' <= wch && wch <= L'z')) &&
317         (lpszDisplayName[1] == L':'))
318     {
319         // "C:..."
320         bPath = TRUE;
321         pidlParent.Attach(_ILCreateMyComputer());
322     }
323     else if (PathIsUNCW(lpszDisplayName)) // "\\\\..."
324     {
325         bPath = TRUE;
326         pidlParent.Attach(_ILCreateNetwork());
327     }
328 
329     if (bPath)
330     {
331         if (!pidlParent)
332             return E_OUTOFMEMORY;
333 
334         CComPtr<IShellFolder> pParentFolder;
335         SHBindToObject(NULL, pidlParent, IID_PPV_ARG(IShellFolder, &pParentFolder));
336 
337         CComHeapPtr<ITEMIDLIST> pidlChild;
338         HRESULT hr = pParentFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName,
339                                                      pchEaten, &pidlChild, pdwAttributes);
340         if (FAILED(hr))
341             return hr;
342 
343         *ppidl = ILCombine(pidlParent, pidlChild);
344         return (*ppidl ? S_OK : E_OUTOFMEMORY);
345     }
346 
347     if (!UrlIsW(lpszDisplayName, URLIS_URL) || SHSkipJunctionBinding(pbc, NULL))
348         return E_INVALIDARG;
349 
350     // Now lpszDisplayName is a URL
351     PARSEDURLW ParsedURL = { sizeof(ParsedURL) };
352     ::ParseURLW(lpszDisplayName, &ParsedURL);
353 
354     switch (ParsedURL.nScheme)
355     {
356         case URL_SCHEME_FILE: // "file:..."
357         {
358             // Convert "file://..." to a normal path
359             WCHAR szPath[MAX_PATH];
360             DWORD cchPath = _countof(szPath);
361             HRESULT hr = PathCreateFromUrlW(lpszDisplayName, szPath, &cchPath, 0);
362             if (FAILED_UNEXPECTEDLY(hr))
363                 return hr;
364 
365             CComPtr<IShellFolder> psfDesktop;
366             hr = SHGetDesktopFolder(&psfDesktop);
367             if (FAILED_UNEXPECTEDLY(hr))
368                 return hr;
369 
370             // Parse by desktop folder
371             return psfDesktop->ParseDisplayName(hwndOwner, pbc, szPath, pchEaten, ppidl,
372                                                 pdwAttributes);
373         }
374         case URL_SCHEME_HTTP:  // "http:..."
375         case URL_SCHEME_HTTPS: // "https:..."
376         {
377             if (!BindCtx_ContainsObject(pbc, STR_PARSE_PREFER_FOLDER_BROWSING))
378                 return E_INVALIDARG;
379 
380             return HttpUrlParseDisplayName(hwndOwner,
381                                            pbc,
382                                            lpszDisplayName,
383                                            pchEaten,
384                                            ppidl,
385                                            pdwAttributes);
386         }
387         case URL_SCHEME_SHELL: // "shell:..."
388         {
389             return ShellUrlParseDisplayName(hwndOwner,
390                                             pbc,
391                                             lpszDisplayName,
392                                             pchEaten,
393                                             ppidl,
394                                             pdwAttributes);
395         }
396         case URL_SCHEME_MSSHELLROOTED:
397         case URL_SCHEME_MSSHELLIDLIST:
398         {
399             WARN("We don't support 'ms-shell-rooted:' and 'ms-shell-idlist:' schemes\n");
400             break;
401         }
402         default:
403         {
404             TRACE("Scheme: %u\n", ParsedURL.nScheme);
405             break;
406         }
407     }
408 
409     return E_INVALIDARG;
410 }
411 
412 /**************************************************************************
413  *    CDesktopFolder::ParseDisplayName
414  *
415  * NOTES
416  *    "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
417  *    to MyComputer
418  */
ParseDisplayName(HWND hwndOwner,LPBC pbc,LPOLESTR lpszDisplayName,DWORD * pchEaten,PIDLIST_RELATIVE * ppidl,DWORD * pdwAttributes)419 HRESULT WINAPI CDesktopFolder::ParseDisplayName(
420     HWND hwndOwner,
421     LPBC pbc,
422     LPOLESTR lpszDisplayName,
423     DWORD *pchEaten,
424     PIDLIST_RELATIVE *ppidl,
425     DWORD *pdwAttributes)
426 {
427     TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
428            this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
429            pchEaten, ppidl, pdwAttributes);
430 
431     if (!ppidl)
432         return E_INVALIDARG;
433 
434     *ppidl = NULL;
435 
436     if (!lpszDisplayName)
437         return E_INVALIDARG;
438 
439     if (!*lpszDisplayName)
440     {
441         *ppidl = _ILCreateMyComputer();
442         return (*ppidl ? S_OK : E_OUTOFMEMORY);
443     }
444 
445     if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
446     {
447         return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl,
448                                              pdwAttributes);
449     }
450 
451     HRESULT hr = _ParseDisplayNameByParent(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl,
452                                            pdwAttributes);
453     if (SUCCEEDED(hr))
454     {
455         if (BindCtx_ContainsObject(pbc, STR_PARSE_TRANSLATE_ALIASES))
456         {
457             CComHeapPtr<ITEMIDLIST> pidlAlias;
458             if (SUCCEEDED(Shell_TranslateIDListAlias(*ppidl, NULL, &pidlAlias, 0xFFFF)))
459             {
460                 ILFree(*ppidl);
461                 *ppidl = pidlAlias.Detach();
462             }
463         }
464 
465         TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
466         return hr;
467     }
468 
469     if (Shell_FailForceReturn(hr))
470         return hr;
471 
472     if (BindCtx_ContainsObject(pbc, STR_DONT_PARSE_RELATIVE))
473         return E_INVALIDARG;
474 
475     if (SHIsFileSysBindCtx(pbc, NULL) == S_OK)
476         return hr;
477 
478     BIND_OPTS BindOps = { sizeof(BindOps) };
479     BOOL bCreate = FALSE;
480     if (pbc && SUCCEEDED(pbc->GetBindOptions(&BindOps)) && (BindOps.grfMode & STGM_CREATE))
481     {
482         BindOps.grfMode &= ~STGM_CREATE;
483         bCreate = TRUE;
484         pbc->SetBindOptions(&BindOps);
485     }
486 
487     if (m_DesktopFSFolder)
488     {
489         hr = m_DesktopFSFolder->ParseDisplayName(hwndOwner,
490                                                  pbc,
491                                                  lpszDisplayName,
492                                                  pchEaten,
493                                                  ppidl,
494                                                  pdwAttributes);
495     }
496 
497     if (FAILED(hr) && m_SharedDesktopFSFolder)
498     {
499         hr = m_SharedDesktopFSFolder->ParseDisplayName(hwndOwner,
500                                                        pbc,
501                                                        lpszDisplayName,
502                                                        pchEaten,
503                                                        ppidl,
504                                                        pdwAttributes);
505     }
506 
507     if (FAILED(hr) && bCreate && m_DesktopFSFolder)
508     {
509         BindOps.grfMode |= STGM_CREATE;
510         pbc->SetBindOptions(&BindOps);
511         hr = m_DesktopFSFolder->ParseDisplayName(hwndOwner,
512                                                  pbc,
513                                                  lpszDisplayName,
514                                                  pchEaten,
515                                                  ppidl,
516                                                  pdwAttributes);
517     }
518 
519     TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
520 
521     return hr;
522 }
523 
524 /**************************************************************************
525  *        CDesktopFolder::EnumObjects
526  */
EnumObjects(HWND hwndOwner,DWORD dwFlags,LPENUMIDLIST * ppEnumIDList)527 HRESULT WINAPI CDesktopFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
528 {
529     CComPtr<IEnumIDList> pRegEnumerator;
530     CComPtr<IEnumIDList> pDesktopEnumerator;
531     CComPtr<IEnumIDList> pCommonDesktopEnumerator;
532     HRESULT hr;
533 
534     hr = m_regFolder->EnumObjects(hwndOwner, dwFlags, &pRegEnumerator);
535     if (FAILED(hr))
536         ERR("EnumObjects for reg folder failed\n");
537 
538     hr = m_DesktopFSFolder->EnumObjects(hwndOwner, dwFlags, &pDesktopEnumerator);
539     if (FAILED(hr))
540         ERR("EnumObjects for desktop fs folder failed\n");
541 
542     hr = m_SharedDesktopFSFolder->EnumObjects(hwndOwner, dwFlags, &pCommonDesktopEnumerator);
543     if (FAILED(hr))
544         ERR("EnumObjects for shared desktop fs folder failed\n");
545 
546     return ShellObjectCreatorInit<CDesktopFolderEnum>(m_regFolder, dwFlags, pRegEnumerator, pDesktopEnumerator,
547                                                       pCommonDesktopEnumerator, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
548 }
549 
550 /**************************************************************************
551  *        CDesktopFolder::BindToObject
552  */
BindToObject(PCUIDLIST_RELATIVE pidl,LPBC pbcReserved,REFIID riid,LPVOID * ppvOut)553 HRESULT WINAPI CDesktopFolder::BindToObject(
554     PCUIDLIST_RELATIVE pidl,
555     LPBC pbcReserved,
556     REFIID riid,
557     LPVOID *ppvOut)
558 {
559     if (!pidl)
560         return E_INVALIDARG;
561 
562     CComPtr<IShellFolder2> psf;
563     HRESULT hr = _GetSFFromPidl(pidl, &psf);
564     if (FAILED_UNEXPECTEDLY(hr))
565         return hr;
566 
567     return psf->BindToObject(pidl, pbcReserved, riid, ppvOut);
568 }
569 
570 /**************************************************************************
571  *    CDesktopFolder::BindToStorage
572  */
BindToStorage(PCUIDLIST_RELATIVE pidl,LPBC pbcReserved,REFIID riid,LPVOID * ppvOut)573 HRESULT WINAPI CDesktopFolder::BindToStorage(
574     PCUIDLIST_RELATIVE pidl,
575     LPBC pbcReserved,
576     REFIID riid,
577     LPVOID *ppvOut)
578 {
579     FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
580            this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
581 
582     *ppvOut = NULL;
583     return E_NOTIMPL;
584 }
585 
586 /**************************************************************************
587  *     CDesktopFolder::CompareIDs
588  */
CompareIDs(LPARAM lParam,PCUIDLIST_RELATIVE pidl1,PCUIDLIST_RELATIVE pidl2)589 HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
590 {
591     bool bIsDesktopFolder1, bIsDesktopFolder2;
592 
593     if (!pidl1 || !pidl2)
594     {
595         ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2);
596         return E_INVALIDARG;
597     }
598 
599     bIsDesktopFolder1 = _ILIsDesktop(pidl1);
600     bIsDesktopFolder2 = _ILIsDesktop(pidl2);
601     if (bIsDesktopFolder1 || bIsDesktopFolder2)
602         return MAKE_COMPARE_HRESULT(bIsDesktopFolder1 - bIsDesktopFolder2);
603 
604     if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
605         return m_regFolder->CompareIDs(lParam, pidl1, pidl2);
606 
607     return m_DesktopFSFolder->CompareIDs(lParam, pidl1, pidl2);
608 }
609 
610 /**************************************************************************
611  *    CDesktopFolder::CreateViewObject
612  */
CreateViewObject(HWND hwndOwner,REFIID riid,LPVOID * ppvOut)613 HRESULT WINAPI CDesktopFolder::CreateViewObject(
614     HWND hwndOwner,
615     REFIID riid,
616     LPVOID *ppvOut)
617 {
618     HRESULT hr = E_INVALIDARG;
619 
620     TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
621            this, hwndOwner, shdebugstr_guid (&riid), ppvOut);
622 
623     if (!ppvOut)
624         return hr;
625 
626     *ppvOut = NULL;
627 
628     if (IsEqualIID (riid, IID_IDropTarget))
629     {
630         hr = m_DesktopFSFolder->CreateViewObject(hwndOwner, riid, ppvOut);
631     }
632     else if (IsEqualIID (riid, IID_IContextMenu))
633     {
634             HKEY hKeys[16];
635             UINT cKeys = 0;
636             AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys);
637 
638             DEFCONTEXTMENU dcm;
639             dcm.hwnd = hwndOwner;
640             dcm.pcmcb = this;
641             dcm.pidlFolder = pidlRoot;
642             dcm.psf = this;
643             dcm.cidl = 0;
644             dcm.apidl = NULL;
645             dcm.cKeys = cKeys;
646             dcm.aKeys = hKeys;
647             dcm.punkAssociationInfo = NULL;
648             hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut);
649     }
650     else if (IsEqualIID (riid, IID_IShellView))
651     {
652         CComPtr<CDesktopFolderViewCB> sfviewcb;
653         if (SUCCEEDED(hr = ShellObjectCreator(sfviewcb)))
654         {
655             SFV_CREATE create = { sizeof(create), this, NULL, sfviewcb };
656             hr = SHCreateShellFolderView(&create, (IShellView**)ppvOut);
657             if (SUCCEEDED(hr))
658                 sfviewcb->Initialize((IShellView*)*ppvOut);
659         }
660     }
661     TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
662     return hr;
663 }
664 
665 /**************************************************************************
666  *  CDesktopFolder::GetAttributesOf
667  */
GetAttributesOf(UINT cidl,PCUITEMID_CHILD_ARRAY apidl,DWORD * rgfInOut)668 HRESULT WINAPI CDesktopFolder::GetAttributesOf(
669     UINT cidl,
670     PCUITEMID_CHILD_ARRAY apidl,
671     DWORD *rgfInOut)
672 {
673     HRESULT hr = S_OK;
674 
675     TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
676           this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
677 
678     if (cidl && !apidl)
679         return E_INVALIDARG;
680 
681     if (*rgfInOut == 0)
682         *rgfInOut = ~0;
683 
684     if(cidl == 0)
685         *rgfInOut &= dwDesktopAttributes;
686     else
687     {
688         /* TODO: always add SFGAO_CANLINK */
689         for (UINT i = 0; i < cidl; ++i)
690         {
691             pdump(*apidl);
692             if (_ILIsDesktop(*apidl))
693                 *rgfInOut &= dwDesktopAttributes;
694             else if (_ILIsMyComputer(apidl[i]))
695                 *rgfInOut &= dwMyComputerAttributes;
696             else if (_ILIsNetHood(apidl[i]))
697                 *rgfInOut &= dwMyNetPlacesAttributes;
698             else if (_ILIsFolder(apidl[i]) || _ILIsValue(apidl[i]) || _ILIsSpecialFolder(apidl[i]))
699             {
700                 CComPtr<IShellFolder2> psf;
701                 HRESULT hr = _GetSFFromPidl(apidl[i], &psf);
702                 if (FAILED_UNEXPECTEDLY(hr))
703                     continue;
704 
705                 psf->GetAttributesOf(1, &apidl[i], rgfInOut);
706             }
707             else
708                 ERR("Got an unknown pidl type!!!\n");
709         }
710     }
711     /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
712     *rgfInOut &= ~SFGAO_VALIDATE;
713 
714     TRACE("-- result=0x%08x\n", *rgfInOut);
715 
716     return hr;
717 }
718 
719 /**************************************************************************
720  *    CDesktopFolder::GetUIObjectOf
721  *
722  * PARAMETERS
723  *  HWND           hwndOwner, //[in ] Parent window for any output
724  *  UINT           cidl,      //[in ] array size
725  *  LPCITEMIDLIST* apidl,     //[in ] simple pidl array
726  *  REFIID         riid,      //[in ] Requested Interface
727  *  UINT*          prgfInOut, //[   ] reserved
728  *  LPVOID*        ppvObject) //[out] Resulting Interface
729  *
730  */
GetUIObjectOf(HWND hwndOwner,UINT cidl,PCUITEMID_CHILD_ARRAY apidl,REFIID riid,UINT * prgfInOut,LPVOID * ppvOut)731 HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
732     HWND hwndOwner,
733     UINT cidl,
734     PCUITEMID_CHILD_ARRAY apidl,
735     REFIID riid,
736     UINT *prgfInOut,
737     LPVOID *ppvOut)
738 {
739     LPVOID pObj = NULL;
740     HRESULT hr = E_INVALIDARG;
741 
742     TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
743            this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
744 
745     if (!ppvOut)
746         return hr;
747     *ppvOut = NULL;
748 
749     BOOL self = IsSelf(cidl, apidl);
750     if (cidl == 1 && !_ILIsSpecialFolder(apidl[0]) && !self)
751     {
752         CComPtr<IShellFolder2> psf;
753         HRESULT hr = _GetSFFromPidl(apidl[0], &psf);
754         if (FAILED_UNEXPECTEDLY(hr))
755             return hr;
756 
757         return psf->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut);
758     }
759 
760     if (IsEqualIID (riid, IID_IContextMenu))
761     {
762         // FIXME: m_regFolder vs AddFSClassKeysToArray is incorrect when the selection includes both regitems and FS items
763         if (!self && cidl > 0 && _ILIsSpecialFolder(apidl[0]))
764         {
765             hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
766         }
767         else
768         {
769             /* Do not use the context menu of the CFSFolder here. */
770             /* We need to pass a pointer of the CDesktopFolder so as the data object that the context menu gets is rooted to the desktop */
771             /* Otherwise operations like that involve items from both user and shared desktop will not work */
772             HKEY hKeys[16];
773             UINT cKeys = 0;
774             if (self)
775             {
776                 AddClsidKeyToArray(CLSID_ShellDesktop, hKeys, &cKeys);
777                 AddClassKeyToArray(L"Folder", hKeys, &cKeys);
778             }
779             else if (cidl > 0)
780             {
781                 AddFSClassKeysToArray(cidl, apidl, hKeys, &cKeys);
782             }
783 
784             DEFCONTEXTMENU dcm;
785             dcm.hwnd = hwndOwner;
786             dcm.pcmcb = this;
787             dcm.pidlFolder = pidlRoot;
788             dcm.psf = this;
789             dcm.cidl = cidl;
790             dcm.apidl = apidl;
791             dcm.cKeys = cKeys;
792             dcm.aKeys = hKeys;
793             dcm.punkAssociationInfo = NULL;
794             hr = SHCreateDefaultContextMenu (&dcm, riid, &pObj);
795         }
796     }
797     else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
798     {
799         hr = IDataObject_Constructor( hwndOwner, pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj);
800     }
801     else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
802     {
803         hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
804     }
805     else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1))
806     {
807         CComPtr<IShellFolder> psfChild;
808         hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild));
809         if (FAILED_UNEXPECTEDLY(hr))
810             return hr;
811 
812         return psfChild->CreateViewObject(NULL, riid, ppvOut);
813     }
814     else
815         hr = E_NOINTERFACE;
816 
817     if (SUCCEEDED(hr) && !pObj)
818         hr = E_OUTOFMEMORY;
819 
820     *ppvOut = pObj;
821     TRACE ("(%p)->hr=0x%08x\n", this, hr);
822     return hr;
823 }
824 
825 /**************************************************************************
826  *    CDesktopFolder::GetDisplayNameOf
827  *
828  * NOTES
829  *    special case: pidl = null gives desktop-name back
830  */
GetDisplayNameOf(PCUITEMID_CHILD pidl,DWORD dwFlags,LPSTRRET strRet)831 HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
832 {
833     TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
834     pdump (pidl);
835 
836     if (!strRet)
837         return E_INVALIDARG;
838 
839     if (!_ILIsPidlSimple (pidl))
840     {
841         return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
842     }
843     else if (_ILIsDesktop(pidl))
844     {
845         if (IS_SHGDN_DESKTOPABSOLUTEPARSING(dwFlags))
846             return SHSetStrRet(strRet, sPathTarget);
847         else
848             return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet);
849     }
850 
851     /* file system folder or file rooted at the desktop */
852     CComPtr<IShellFolder2> psf;
853     HRESULT hr = _GetSFFromPidl(pidl, &psf);
854     if (FAILED_UNEXPECTEDLY(hr))
855         return hr;
856 
857     return psf->GetDisplayNameOf(pidl, dwFlags, strRet);
858 }
859 
860 /**************************************************************************
861  *  CDesktopFolder::SetNameOf
862  *  Changes the name of a file object or subfolder, possibly changing its item
863  *  identifier in the process.
864  *
865  * PARAMETERS
866  *  HWND          hwndOwner,  //[in ] Owner window for output
867  *  LPCITEMIDLIST pidl,       //[in ] simple pidl of item to change
868  *  LPCOLESTR     lpszName,   //[in ] the items new display name
869  *  DWORD         dwFlags,    //[in ] SHGNO formatting flags
870  *  LPITEMIDLIST* ppidlOut)   //[out] simple pidl returned
871  */
SetNameOf(HWND hwndOwner,PCUITEMID_CHILD pidl,LPCOLESTR lpName,DWORD dwFlags,PITEMID_CHILD * pPidlOut)872 HRESULT WINAPI CDesktopFolder::SetNameOf(
873     HWND hwndOwner,
874     PCUITEMID_CHILD pidl,    /* simple pidl */
875     LPCOLESTR lpName,
876     DWORD dwFlags,
877     PITEMID_CHILD *pPidlOut)
878 {
879     CComPtr<IShellFolder2> psf;
880     HRESULT hr = _GetSFFromPidl(pidl, &psf);
881     if (FAILED_UNEXPECTEDLY(hr))
882         return hr;
883 
884     return psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
885 }
886 
GetDefaultSearchGUID(GUID * pguid)887 HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid)
888 {
889     FIXME ("(%p)\n", this);
890     return E_NOTIMPL;
891 }
892 
EnumSearches(IEnumExtraSearch ** ppenum)893 HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum)
894 {
895     FIXME ("(%p)\n", this);
896     return E_NOTIMPL;
897 }
898 
GetDefaultColumn(DWORD dwRes,ULONG * pSort,ULONG * pDisplay)899 HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
900 {
901     TRACE ("(%p)\n", this);
902 
903     if (pSort)
904         *pSort = 0;
905     if (pDisplay)
906         *pDisplay = 0;
907 
908     return S_OK;
909 }
910 
GetDefaultColumnState(UINT iColumn,SHCOLSTATEF * pcsFlags)911 HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags)
912 {
913     HRESULT hr;
914     TRACE ("(%p)\n", this);
915 
916     if (!pcsFlags)
917         return E_INVALIDARG;
918 
919     hr = CFSFolder::GetDefaultFSColumnState(iColumn, *pcsFlags);
920     /*
921     // CDesktopFolder may override the flags if desired (future)
922     switch(iColumn)
923     {
924     case SHFSF_COL_FATTS:
925         *pcsFlags &= ~SHCOLSTATE_ONBYDEFAULT;
926         break;
927     }
928     */
929     return hr;
930 }
931 
GetDetailsEx(PCUITEMID_CHILD pidl,const SHCOLUMNID * pscid,VARIANT * pv)932 HRESULT WINAPI CDesktopFolder::GetDetailsEx(
933     PCUITEMID_CHILD pidl,
934     const SHCOLUMNID *pscid,
935     VARIANT *pv)
936 {
937     FIXME ("(%p)\n", this);
938 
939     return E_NOTIMPL;
940 }
941 
942 /*************************************************************************
943  * Column info functions.
944  * CFSFolder.h provides defaults for us.
945  */
GetColumnDetails(UINT iColumn,SHELLDETAILS & sd)946 HRESULT CDesktopFolder::GetColumnDetails(UINT iColumn, SHELLDETAILS &sd)
947 {
948     /* CDesktopFolder may override the flags and/or name if desired */
949     return CFSFolder::GetFSColumnDetails(iColumn, sd);
950 }
951 
GetDetailsOf(PCUITEMID_CHILD pidl,UINT iColumn,SHELLDETAILS * psd)952 HRESULT WINAPI CDesktopFolder::GetDetailsOf(
953     PCUITEMID_CHILD pidl,
954     UINT iColumn,
955     SHELLDETAILS *psd)
956 {
957     if (!psd)
958         return E_INVALIDARG;
959 
960     if (!pidl)
961     {
962         return GetColumnDetails(iColumn, *psd);
963     }
964 
965     CComPtr<IShellFolder2> psf;
966     HRESULT hr = _GetSFFromPidl(pidl, &psf);
967     if (FAILED_UNEXPECTEDLY(hr))
968         return hr;
969 
970     hr =  psf->GetDetailsOf(pidl, iColumn, psd);
971     if (FAILED_UNEXPECTEDLY(hr))
972         return hr;
973 
974     return hr;
975 }
976 
MapColumnToSCID(UINT column,SHCOLUMNID * pscid)977 HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
978 {
979     FIXME ("(%p)\n", this);
980     return E_NOTIMPL;
981 }
982 
GetClassID(CLSID * lpClassId)983 HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId)
984 {
985     TRACE ("(%p)\n", this);
986 
987     if (!lpClassId)
988         return E_POINTER;
989 
990     *lpClassId = CLSID_ShellDesktop;
991 
992     return S_OK;
993 }
994 
Initialize(PCIDLIST_ABSOLUTE pidl)995 HRESULT WINAPI CDesktopFolder::Initialize(PCIDLIST_ABSOLUTE pidl)
996 {
997     TRACE ("(%p)->(%p)\n", this, pidl);
998 
999     if (!pidl)
1000         return S_OK;
1001 
1002     return E_INVALIDARG;
1003 }
1004 
GetCurFolder(PIDLIST_ABSOLUTE * pidl)1005 HRESULT WINAPI CDesktopFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl)
1006 {
1007     TRACE ("(%p)->(%p)\n", this, pidl);
1008 
1009     if (!pidl)
1010         return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */
1011     *pidl = ILClone (pidlRoot);
1012     return S_OK;
1013 }
1014 
CallBack(IShellFolder * psf,HWND hwndOwner,IDataObject * pdtobj,UINT uMsg,WPARAM wParam,LPARAM lParam)1015 HRESULT WINAPI CDesktopFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
1016 {
1017     enum { IDC_PROPERTIES };
1018     if (uMsg == DFM_INVOKECOMMAND && wParam == (pdtobj ? DFM_CMD_PROPERTIES : IDC_PROPERTIES))
1019     {
1020         return SHELL_ExecuteControlPanelCPL(hwndOwner, L"desk.cpl") ? S_OK : E_FAIL;
1021     }
1022     else if (uMsg == DFM_MERGECONTEXTMENU && !pdtobj) // Add Properties item when called for directory background
1023     {
1024         QCMINFO *pqcminfo = (QCMINFO *)lParam;
1025         HMENU hpopup = CreatePopupMenu();
1026         _InsertMenuItemW(hpopup, 0, TRUE, IDC_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
1027         pqcminfo->idCmdFirst = Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR);
1028         DestroyMenu(hpopup);
1029         return S_OK;
1030     }
1031     return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg);
1032 }
1033 
1034 /*************************************************************************
1035  * CDesktopFolderViewCB
1036  */
1037 
IsProgmanHostedBrowser(IShellView * psv)1038 bool CDesktopFolderViewCB::IsProgmanHostedBrowser(IShellView *psv)
1039 {
1040     FOLDERSETTINGS settings;
1041     return SUCCEEDED(psv->GetCurrentInfo(&settings)) && (settings.fFlags & FWF_DESKTOP);
1042 }
1043 
IsProgmanHostedBrowser()1044 bool CDesktopFolderViewCB::IsProgmanHostedBrowser()
1045 {
1046     enum { Uninitialized = 0, NotHosted, IsHosted };
1047     C_ASSERT(Uninitialized == 0);
1048     if (m_IsProgmanHosted == Uninitialized)
1049         m_IsProgmanHosted = m_pShellView && IsProgmanHostedBrowser(m_pShellView) ? IsHosted : NotHosted;
1050     return m_IsProgmanHosted == IsHosted;
1051 }
1052 
ShouldShow(IShellFolder * psf,PCIDLIST_ABSOLUTE pidlFolder,PCUITEMID_CHILD pidlItem)1053 HRESULT WINAPI CDesktopFolderViewCB::ShouldShow(IShellFolder *psf, PCIDLIST_ABSOLUTE pidlFolder, PCUITEMID_CHILD pidlItem)
1054 {
1055     const CLSID* pClsid;
1056     if (IsProgmanHostedBrowser() && (pClsid = IsRegItem(pidlItem)) != NULL)
1057     {
1058         const BOOL NewStart = SHELL_GetSetting(SSF_STARTPANELON, fStartPanelOn);
1059         LPCWSTR SubKey = NewStart ? L"HideDesktopIcons\\NewStartPanel" : L"HideDesktopIcons\\ClassicStartMenu";
1060         return SHELL32_IsShellFolderNamespaceItemHidden(SubKey, *pClsid) ? S_FALSE : S_OK;
1061     }
1062     return S_OK;
1063 }
1064 
MessageSFVCB(UINT uMsg,WPARAM wParam,LPARAM lParam)1065 HRESULT WINAPI CDesktopFolderViewCB::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
1066 {
1067     switch (uMsg)
1068     {
1069         case SFVM_VIEWRELEASE:
1070             m_pShellView = NULL;
1071             return S_OK;
1072         case SFVM_GETCOMMANDDIR:
1073         {
1074             WCHAR buf[MAX_PATH];
1075             if (SHGetSpecialFolderPathW(NULL, buf, CSIDL_DESKTOPDIRECTORY, TRUE))
1076                 return StringCchCopyW((PWSTR)lParam, wParam, buf);
1077             break;
1078         }
1079     }
1080     return E_NOTIMPL;
1081 }
1082 
1083 /*************************************************************************
1084  * SHGetDesktopFolder            [SHELL32.@]
1085  */
SHGetDesktopFolder(IShellFolder ** psf)1086 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
1087 {
1088     HRESULT    hres = S_OK;
1089     TRACE("\n");
1090 
1091     if(!psf) return E_INVALIDARG;
1092     *psf = NULL;
1093     hres = CDesktopFolder::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellFolder, psf));
1094 
1095     TRACE("-- %p->(%p)\n",psf, *psf);
1096     return hres;
1097 }
1098