msi/tests: Skip some source tests if a required product key cannot be created.
[wine] / dlls / shell32 / shfldr_desktop.c
1
2 /*
3  *    Virtual Desktop Folder
4  *
5  *    Copyright 1997            Marcus Meissner
6  *    Copyright 1998, 1999, 2002    Juergen Schmied
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 "config.h"
24 #include "wine/port.h"
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30
31 #define COBJMACROS
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34
35 #include "winerror.h"
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winreg.h"
39 #include "wingdi.h"
40 #include "winuser.h"
41
42 #include "ole2.h"
43 #include "shlguid.h"
44
45 #include "enumidlist.h"
46 #include "pidl.h"
47 #include "undocshell.h"
48 #include "shell32_main.h"
49 #include "shresdef.h"
50 #include "shlwapi.h"
51 #include "shellfolder.h"
52 #include "wine/debug.h"
53 #include "debughlp.h"
54 #include "shfldr.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL (shell);
57
58 /* Undocumented functions from shdocvw */
59 extern HRESULT WINAPI IEParseDisplayNameWithBCW(DWORD codepage, LPCWSTR lpszDisplayName, LPBC pbc, LPITEMIDLIST *ppidl);
60
61
62 /***********************************************************************
63 *     Desktopfolder implementation
64 */
65
66 typedef struct {
67     const IShellFolder2Vtbl *lpVtbl;
68     const IPersistVtbl *lpVtblIPersist;
69     LONG ref;
70
71     /* both paths are parsible from the desktop */
72     LPWSTR sPathTarget;     /* complete path to target used for enumeration and ChangeNotify */
73     LPITEMIDLIST pidlRoot;  /* absolute pidl */
74
75     UINT cfShellIDList;        /* clipboardformat for IDropTarget */
76     BOOL fAcceptFmt;        /* flag for pending Drop */
77 } IDesktopFolderImpl;
78
79 static inline IDesktopFolderImpl *impl_from_IPersist( IPersist *iface )
80 {
81     return (IDesktopFolderImpl *)((char*)iface - FIELD_OFFSET(IDesktopFolderImpl, lpVtblIPersist));
82 }
83
84 static const shvheader desktop_header[] = {
85     {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
86     {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
87     {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
88     {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
89     {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
90 };
91
92 #define DESKTOPSHELLVIEWCOLUMNS sizeof(desktop_header)/sizeof(shvheader)
93
94 /**************************************************************************
95  *    ISF_Desktop_fnQueryInterface
96  *
97  * NOTES supports not IPersistFolder
98  */
99 static HRESULT WINAPI ISF_Desktop_fnQueryInterface(
100                 IShellFolder2 * iface, REFIID riid, LPVOID * ppvObj)
101 {
102     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
103
104     TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
105
106     *ppvObj = NULL;
107
108     if (IsEqualIID (riid, &IID_IUnknown) ||
109         IsEqualIID (riid, &IID_IShellFolder) ||
110         IsEqualIID (riid, &IID_IShellFolder2))
111     {
112         *ppvObj = This;
113     }
114     else if (IsEqualIID (riid, &IID_IPersist))
115     {
116         *ppvObj = &This->lpVtblIPersist;
117     }
118
119     if (*ppvObj)
120     {
121         IUnknown_AddRef ((IUnknown *) (*ppvObj));
122         TRACE ("-- Interface: (%p)->(%p)\n", ppvObj, *ppvObj);
123         return S_OK;
124     }
125     TRACE ("-- Interface: E_NOINTERFACE\n");
126     return E_NOINTERFACE;
127 }
128
129 static ULONG WINAPI ISF_Desktop_fnAddRef (IShellFolder2 * iface)
130 {
131     return 2; /* non-heap based object */
132 }
133
134 static ULONG WINAPI ISF_Desktop_fnRelease (IShellFolder2 * iface)
135 {
136     return 1; /* non-heap based object */
137 }
138
139 /**************************************************************************
140  *    ISF_Desktop_fnParseDisplayName
141  *
142  * NOTES
143  *    "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
144  *    to MyComputer
145  */
146 static HRESULT WINAPI ISF_Desktop_fnParseDisplayName (IShellFolder2 * iface,
147                 HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
148                 DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
149 {
150     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
151     IShellFolder *shell_folder = (IShellFolder*)iface;
152     WCHAR szElement[MAX_PATH];
153     LPCWSTR szNext = NULL;
154     LPITEMIDLIST pidlTemp = NULL;
155     PARSEDURLW urldata;
156     HRESULT hr = S_OK;
157     CLSID clsid;
158
159     TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
160            This, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
161            pchEaten, ppidl, pdwAttributes);
162
163     if (!ppidl) return E_INVALIDARG;
164     *ppidl = 0;
165
166     if (!lpszDisplayName) return E_INVALIDARG;
167
168     if (pchEaten)
169         *pchEaten = 0;        /* strange but like the original */
170
171     urldata.cbSize = sizeof(urldata);
172
173     if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
174     {
175         szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
176         TRACE ("-- element: %s\n", debugstr_w (szElement));
177         SHCLSIDFromStringW (szElement + 2, &clsid);
178         pidlTemp = _ILCreateGuid (PT_GUID, &clsid);
179     }
180     else if (PathGetDriveNumberW (lpszDisplayName) >= 0)
181     {
182         /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
183         if (UNIXFS_is_rooted_at_desktop()) 
184             pidlTemp = _ILCreateGuid(PT_GUID, &CLSID_UnixDosFolder);
185         else
186             pidlTemp = _ILCreateMyComputer ();
187         szNext = lpszDisplayName;
188     }
189     else if (PathIsUNCW(lpszDisplayName))
190     {
191         pidlTemp = _ILCreateNetwork();
192         szNext = lpszDisplayName;
193     }
194     else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
195     {
196         *ppidl = pidlTemp;
197         return S_OK;
198     }
199     else if (SUCCEEDED(ParseURLW(lpszDisplayName, &urldata)))
200     {
201         if (urldata.nScheme == URL_SCHEME_SHELL) /* handle shell: urls */
202         {
203             TRACE ("-- shell url: %s\n", debugstr_w(urldata.pszSuffix));
204             SHCLSIDFromStringW (urldata.pszSuffix+2, &clsid);
205             pidlTemp = _ILCreateGuid (PT_GUID, &clsid);
206         }
207         else
208             return IEParseDisplayNameWithBCW(CP_ACP,lpszDisplayName,pbc,ppidl);
209     }
210     else
211     {
212         /* it's a filesystem path on the desktop. Let a FSFolder parse it */
213
214         if (*lpszDisplayName)
215         {
216             if (*lpszDisplayName == '/')
217             {
218                 /* UNIX paths should be parsed by unixfs */
219                 IShellFolder *unixFS;
220                 hr = UnixFolder_Constructor(NULL, &IID_IShellFolder, (LPVOID*)&unixFS);
221                 if (SUCCEEDED(hr))
222                 {
223                     hr = IShellFolder_ParseDisplayName(unixFS, NULL, NULL,
224                             lpszDisplayName, NULL, &pidlTemp, NULL);
225                     IShellFolder_Release(unixFS);
226                 }
227             }
228             else
229             {
230                 /* build a complete path to create a simple pidl */
231                 WCHAR szPath[MAX_PATH];
232                 LPWSTR pathPtr;
233
234                 lstrcpynW(szPath, This->sPathTarget, MAX_PATH);
235                 pathPtr = PathAddBackslashW(szPath);
236                 if (pathPtr)
237                 {
238                     lstrcpynW(pathPtr, lpszDisplayName, MAX_PATH - (pathPtr - szPath));
239                     hr = _ILCreateFromPathW(szPath, &pidlTemp);
240                 }
241                 else
242                 {
243                     /* should never reach here, but for completeness */
244                     hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
245                 }
246             }
247         }
248         else
249             pidlTemp = _ILCreateMyComputer();
250
251         szNext = NULL;
252     }
253
254     if (SUCCEEDED(hr) && pidlTemp)
255     {
256         if (szNext && *szNext)
257         {
258             hr = SHELL32_ParseNextElement(iface, hwndOwner, pbc,
259                     &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
260         }
261         else
262         {
263             if (pdwAttributes && *pdwAttributes)
264                 hr = SHELL32_GetItemAttributes(shell_folder, pidlTemp, pdwAttributes);
265         }
266     }
267
268     *ppidl = pidlTemp;
269
270     TRACE ("(%p)->(-- ret=0x%08x)\n", This, hr);
271
272     return hr;
273 }
274
275 /**************************************************************************
276  *  CreateDesktopEnumList()
277  */
278 static const WCHAR Desktop_NameSpaceW[] = { 'S','O','F','T','W','A','R','E',
279  '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
280  'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
281  'o','r','e','r','\\','D','e','s','k','t','o','p','\\','N','a','m','e','s','p',
282  'a','c','e','\0' };
283
284 static BOOL CreateDesktopEnumList(IEnumIDList *list, DWORD dwFlags)
285 {
286     BOOL ret = TRUE;
287     WCHAR szPath[MAX_PATH];
288
289     TRACE("(%p)->(flags=0x%08x)\n", list, dwFlags);
290
291     /* enumerate the root folders */
292     if (dwFlags & SHCONTF_FOLDERS)
293     {
294         HKEY hkey;
295         UINT i;
296
297         /* create the pidl for This item */
298         ret = AddToEnumList(list, _ILCreateMyComputer());
299
300         for (i=0; i<2; i++) {
301             if (ret && !RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
302                                       Desktop_NameSpaceW, 0, KEY_READ, &hkey))
303             {
304                 WCHAR iid[50];
305                 int i=0;
306
307                 while (ret)
308                 {
309                     DWORD size;
310                     LONG r;
311
312                     size = sizeof (iid) / sizeof (iid[0]);
313                     r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
314                     if (ERROR_SUCCESS == r)
315                     {
316                         ret = AddToEnumList(list, _ILCreateGuidFromStrW(iid));
317                         i++;
318                     }
319                     else if (ERROR_NO_MORE_ITEMS == r)
320                         break;
321                     else
322                         ret = FALSE;
323                 }
324                 RegCloseKey(hkey);
325             }
326         }
327     }
328
329     /* enumerate the elements in %windir%\desktop */
330     SHGetSpecialFolderPathW(0, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
331     ret = ret && CreateFolderEnumList(list, szPath, dwFlags);
332
333     return ret;
334 }
335
336 /**************************************************************************
337  *        ISF_Desktop_fnEnumObjects
338  */
339 static HRESULT WINAPI ISF_Desktop_fnEnumObjects (IShellFolder2 * iface,
340                 HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
341 {
342     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
343
344     TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n",
345            This, hwndOwner, dwFlags, ppEnumIDList);
346
347     *ppEnumIDList = IEnumIDList_Constructor();
348     if (*ppEnumIDList)
349         CreateDesktopEnumList(*ppEnumIDList, dwFlags);
350
351     TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);
352
353     return *ppEnumIDList ? S_OK : E_OUTOFMEMORY;
354 }
355
356 /**************************************************************************
357  *        ISF_Desktop_fnBindToObject
358  */
359 static HRESULT WINAPI ISF_Desktop_fnBindToObject (IShellFolder2 * iface,
360                 LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
361 {
362     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
363
364     TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n",
365            This, pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
366
367     return SHELL32_BindToChild( This->pidlRoot, This->sPathTarget, pidl, riid, ppvOut );
368 }
369
370 /**************************************************************************
371  *    ISF_Desktop_fnBindToStorage
372  */
373 static HRESULT WINAPI ISF_Desktop_fnBindToStorage (IShellFolder2 * iface,
374                 LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
375 {
376     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
377
378     FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
379            This, pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
380
381     *ppvOut = NULL;
382     return E_NOTIMPL;
383 }
384
385 /**************************************************************************
386  *     ISF_Desktop_fnCompareIDs
387  */
388 static HRESULT WINAPI ISF_Desktop_fnCompareIDs (IShellFolder2 *iface,
389                         LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
390 {
391     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
392     IShellFolder *shell_folder = (IShellFolder*)iface;
393     HRESULT hr;
394
395     TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
396     hr = SHELL32_CompareIDs ( shell_folder, lParam, pidl1, pidl2);
397     TRACE ("-- 0x%08x\n", hr);
398     return hr;
399 }
400
401 /**************************************************************************
402  *    ISF_Desktop_fnCreateViewObject
403  */
404 static HRESULT WINAPI ISF_Desktop_fnCreateViewObject (IShellFolder2 * iface,
405                               HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
406 {
407     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
408     LPSHELLVIEW pShellView;
409     HRESULT hr = E_INVALIDARG;
410
411     TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
412            This, hwndOwner, shdebugstr_guid (riid), ppvOut);
413
414     if (!ppvOut)
415         return E_INVALIDARG;
416
417     *ppvOut = NULL;
418
419     if (IsEqualIID (riid, &IID_IDropTarget))
420     {
421         WARN ("IDropTarget not implemented\n");
422         hr = E_NOTIMPL;
423     }
424     else if (IsEqualIID (riid, &IID_IContextMenu))
425     {
426         WARN ("IContextMenu not implemented\n");
427         hr = E_NOTIMPL;
428     }
429     else if (IsEqualIID (riid, &IID_IShellView))
430     {
431         pShellView = IShellView_Constructor ((IShellFolder *) iface);
432         if (pShellView)
433         {
434             hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
435             IShellView_Release (pShellView);
436         }
437     }
438     TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
439     return hr;
440 }
441
442 /**************************************************************************
443  *  ISF_Desktop_fnGetAttributesOf
444  */
445 static HRESULT WINAPI ISF_Desktop_fnGetAttributesOf (IShellFolder2 * iface,
446                 UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
447 {
448     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
449     IShellFolder *shell_folder = (IShellFolder*)iface;
450
451     static const DWORD dwDesktopAttributes = 
452         SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
453         SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER;
454     static const DWORD dwMyComputerAttributes = 
455         SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET |
456         SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
457
458     TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
459            This, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
460
461     if (!rgfInOut)
462         return E_INVALIDARG;
463     if (cidl && !apidl)
464         return E_INVALIDARG;
465
466     if (*rgfInOut == 0)
467         *rgfInOut = ~0;
468     
469     if(cidl == 0) {
470         *rgfInOut &= dwDesktopAttributes; 
471     } else {
472         while (cidl > 0 && *apidl) {
473             pdump (*apidl);
474             if (_ILIsDesktop(*apidl)) { 
475                 *rgfInOut &= dwDesktopAttributes;
476             } else if (_ILIsMyComputer(*apidl)) {
477                 *rgfInOut &= dwMyComputerAttributes;
478             } else {
479                 SHELL32_GetItemAttributes ( shell_folder, *apidl, rgfInOut);
480             }
481             apidl++;
482             cidl--;
483         }
484     }
485     /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
486     *rgfInOut &= ~SFGAO_VALIDATE;
487
488     TRACE ("-- result=0x%08x\n", *rgfInOut);
489
490     return S_OK;
491 }
492
493 /**************************************************************************
494  *    ISF_Desktop_fnGetUIObjectOf
495  *
496  * PARAMETERS
497  *  HWND           hwndOwner, //[in ] Parent window for any output
498  *  UINT           cidl,      //[in ] array size
499  *  LPCITEMIDLIST* apidl,     //[in ] simple pidl array
500  *  REFIID         riid,      //[in ] Requested Interface
501  *  UINT*          prgfInOut, //[   ] reserved
502  *  LPVOID*        ppvObject) //[out] Resulting Interface
503  *
504  */
505 static HRESULT WINAPI ISF_Desktop_fnGetUIObjectOf (IShellFolder2 * iface,
506                 HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
507                 REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
508 {
509     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
510
511     LPITEMIDLIST pidl;
512     IUnknown *pObj = NULL;
513     HRESULT hr = E_INVALIDARG;
514
515     TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
516        This, hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);
517
518     if (!ppvOut)
519         return E_INVALIDARG;
520
521     *ppvOut = NULL;
522
523     if (IsEqualIID (riid, &IID_IContextMenu))
524     {
525         if (cidl > 0)
526             pObj = (LPUNKNOWN) ISvItemCm_Constructor( (IShellFolder *) iface, This->pidlRoot, apidl, cidl);
527         else
528             pObj = (LPUNKNOWN) ISvBgCm_Constructor( (IShellFolder *) iface, TRUE);
529         hr = S_OK;
530     }
531     else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1))
532     {
533         pObj = (LPUNKNOWN) IDataObject_Constructor( hwndOwner,
534                                                   This->pidlRoot, apidl, cidl);
535         hr = S_OK;
536     }
537     else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1))
538     {
539         pidl = ILCombine (This->pidlRoot, apidl[0]);
540         pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
541         SHFree (pidl);
542         hr = S_OK;
543     }
544     else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1))
545     {
546         pidl = ILCombine (This->pidlRoot, apidl[0]);
547         pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
548         SHFree (pidl);
549         hr = S_OK;
550     }
551     else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1))
552     {
553         hr = IShellFolder_QueryInterface (iface,
554                                           &IID_IDropTarget, (LPVOID *) & pObj);
555     }
556     else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
557               IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1))
558     {
559         pidl = ILCombine (This->pidlRoot, apidl[0]);
560         hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
561         SHFree (pidl);
562     }
563     else
564         hr = E_NOINTERFACE;
565
566     if (SUCCEEDED(hr) && !pObj)
567         hr = E_OUTOFMEMORY;
568
569     *ppvOut = pObj;
570     TRACE ("(%p)->hr=0x%08x\n", This, hr);
571     return hr;
572 }
573
574 /**************************************************************************
575  *    ISF_Desktop_fnGetDisplayNameOf
576  *
577  * NOTES
578  *    special case: pidl = null gives desktop-name back
579  */
580 static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf (IShellFolder2 * iface,
581                 LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
582 {
583     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
584     HRESULT hr = S_OK;
585     LPWSTR pszPath;
586
587     TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet);
588     pdump (pidl);
589
590     if (!strRet)
591         return E_INVALIDARG;
592
593     pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
594     if (!pszPath)
595         return E_OUTOFMEMORY;
596
597     if (_ILIsDesktop (pidl))
598     {
599         if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
600             (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
601             strcpyW(pszPath, This->sPathTarget);
602         else
603             HCR_GetClassNameW(&CLSID_ShellDesktop, pszPath, MAX_PATH);
604     }
605     else if (_ILIsPidlSimple (pidl))
606     {
607         GUID const *clsid;
608
609         if ((clsid = _ILGetGUIDPointer (pidl)))
610         {
611             if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
612             {
613                 int bWantsForParsing;
614
615                 /*
616                  * We can only get a filesystem path from a shellfolder if the
617                  *  value WantsFORPARSING in CLSID\\{...}\\shellfolder exists.
618                  *
619                  * Exception: The MyComputer folder doesn't have this key,
620                  *   but any other filesystem backed folder it needs it.
621                  */
622                 if (IsEqualIID (clsid, &CLSID_MyComputer))
623                 {
624                     bWantsForParsing = TRUE;
625                 }
626                 else
627                 {
628                     /* get the "WantsFORPARSING" flag from the registry */
629                     static const WCHAR clsidW[] =
630                      { 'C','L','S','I','D','\\',0 };
631                     static const WCHAR shellfolderW[] =
632                      { '\\','s','h','e','l','l','f','o','l','d','e','r',0 };
633                     static const WCHAR wantsForParsingW[] =
634                      { 'W','a','n','t','s','F','o','r','P','a','r','s','i','n',
635                      'g',0 };
636                     WCHAR szRegPath[100];
637                     LONG r;
638
639                     lstrcpyW (szRegPath, clsidW);
640                     SHELL32_GUIDToStringW (clsid, &szRegPath[6]);
641                     lstrcatW (szRegPath, shellfolderW);
642                     r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath,
643                                     wantsForParsingW, NULL, NULL, NULL);
644                     if (r == ERROR_SUCCESS)
645                         bWantsForParsing = TRUE;
646                     else
647                         bWantsForParsing = FALSE;
648                 }
649
650                 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
651                      bWantsForParsing)
652                 {
653                     /*
654                      * we need the filesystem path to the destination folder.
655                      * Only the folder itself can know it
656                      */
657                     hr = SHELL32_GetDisplayNameOfChild (iface, pidl, dwFlags,
658                                                         pszPath,
659                                                         MAX_PATH);
660                 }
661                 else
662                 {
663                     /* parsing name like ::{...} */
664                     pszPath[0] = ':';
665                     pszPath[1] = ':';
666                     SHELL32_GUIDToStringW (clsid, &pszPath[2]);
667                 }
668             }
669             else
670             {
671                 /* user friendly name */
672                 HCR_GetClassNameW (clsid, pszPath, MAX_PATH);
673             }
674         }
675         else
676         {
677             int cLen = 0;
678
679             /* file system folder or file rooted at the desktop */
680             if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
681                 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
682             {
683                 lstrcpynW(pszPath, This->sPathTarget, MAX_PATH - 1);
684                 PathAddBackslashW(pszPath);
685                 cLen = lstrlenW(pszPath);
686             }
687
688             _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
689
690             if (!_ILIsFolder(pidl))
691                 SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
692         }
693     }
694     else
695     {
696         /* a complex pidl, let the subfolder do the work */
697         hr = SHELL32_GetDisplayNameOfChild (iface, pidl, dwFlags,
698                                             pszPath, MAX_PATH);
699     }
700
701     if (SUCCEEDED(hr))
702     {
703         /* Win9x always returns ANSI strings, NT always returns Unicode strings */
704         if (GetVersion() & 0x80000000)
705         {
706             strRet->uType = STRRET_CSTR;
707             if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->u.cStr, MAX_PATH,
708                                      NULL, NULL))
709                 strRet->u.cStr[0] = '\0';
710             CoTaskMemFree(pszPath);
711         }
712         else
713         {
714             strRet->uType = STRRET_WSTR;
715             strRet->u.pOleStr = pszPath;
716         }
717     }
718     else
719         CoTaskMemFree(pszPath);
720
721     TRACE ("-- (%p)->(%s,0x%08x)\n", This,
722     strRet->uType == STRRET_CSTR ? strRet->u.cStr :
723     debugstr_w(strRet->u.pOleStr), hr);
724     return hr;
725 }
726
727 /**************************************************************************
728  *  ISF_Desktop_fnSetNameOf
729  *  Changes the name of a file object or subfolder, possibly changing its item
730  *  identifier in the process.
731  *
732  * PARAMETERS
733  *  HWND          hwndOwner,  //[in ] Owner window for output
734  *  LPCITEMIDLIST pidl,       //[in ] simple pidl of item to change
735  *  LPCOLESTR     lpszName,   //[in ] the items new display name
736  *  DWORD         dwFlags,    //[in ] SHGNO formatting flags
737  *  LPITEMIDLIST* ppidlOut)   //[out] simple pidl returned
738  */
739 static HRESULT WINAPI ISF_Desktop_fnSetNameOf (IShellFolder2 * iface,
740                 HWND hwndOwner, LPCITEMIDLIST pidl,    /* simple pidl */
741                 LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
742 {
743     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
744
745     FIXME ("(%p)->(%p,pidl=%p,%s,%u,%p) stub\n", This, hwndOwner, pidl,
746            debugstr_w (lpName), dwFlags, pPidlOut);
747
748     return E_FAIL;
749 }
750
751 static HRESULT WINAPI ISF_Desktop_fnGetDefaultSearchGUID(IShellFolder2 *iface,
752                 GUID * pguid)
753 {
754     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
755     FIXME ("(%p)->(%p) stub\n", This, pguid);
756     return E_NOTIMPL;
757 }
758
759 static HRESULT WINAPI ISF_Desktop_fnEnumSearches (IShellFolder2 *iface,
760                 IEnumExtraSearch ** ppenum)
761 {
762     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
763     FIXME ("(%p)->(%p) stub\n", This, ppenum);
764     return E_NOTIMPL;
765 }
766
767 static HRESULT WINAPI ISF_Desktop_fnGetDefaultColumn (IShellFolder2 * iface,
768                 DWORD reserved, ULONG * pSort, ULONG * pDisplay)
769 {
770     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
771
772     TRACE ("(%p)->(%d %p %p)\n", This, reserved, pSort, pDisplay);
773
774     if (pSort)
775         *pSort = 0;
776     if (pDisplay)
777         *pDisplay = 0;
778
779     return S_OK;
780 }
781 static HRESULT WINAPI ISF_Desktop_fnGetDefaultColumnState (
782                 IShellFolder2 * iface, UINT iColumn, DWORD * pcsFlags)
783 {
784     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
785
786     TRACE ("(%p)->(%d %p)\n", This, iColumn, pcsFlags);
787
788     if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
789     return E_INVALIDARG;
790
791     *pcsFlags = desktop_header[iColumn].pcsFlags;
792
793     return S_OK;
794 }
795
796 static HRESULT WINAPI ISF_Desktop_fnGetDetailsEx (IShellFolder2 * iface,
797                 LPCITEMIDLIST pidl, const SHCOLUMNID * pscid, VARIANT * pv)
798 {
799     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
800     FIXME ("(%p)->(%p %p %p) stub\n", This, pidl, pscid, pv);
801     return E_NOTIMPL;
802 }
803
804 static HRESULT WINAPI ISF_Desktop_fnGetDetailsOf (IShellFolder2 * iface,
805                 LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS * psd)
806 {
807     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
808
809     HRESULT hr = S_OK;
810
811     TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
812
813     if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
814         return E_INVALIDARG;
815
816     if (!pidl)
817         return SHELL32_GetColumnDetails(desktop_header, iColumn, psd);
818
819     /* the data from the pidl */
820     psd->str.uType = STRRET_CSTR;
821     switch (iColumn)
822     {
823     case 0:        /* name */
824         hr = IShellFolder_GetDisplayNameOf(iface, pidl,
825                    SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
826         break;
827     case 1:        /* size */
828         _ILGetFileSize (pidl, psd->str.u.cStr, MAX_PATH);
829         break;
830     case 2:        /* type */
831         _ILGetFileType (pidl, psd->str.u.cStr, MAX_PATH);
832         break;
833     case 3:        /* date */
834         _ILGetFileDate (pidl, psd->str.u.cStr, MAX_PATH);
835         break;
836     case 4:        /* attributes */
837         _ILGetFileAttributes (pidl, psd->str.u.cStr, MAX_PATH);
838         break;
839     }
840
841     return hr;
842 }
843
844 static HRESULT WINAPI ISF_Desktop_fnMapColumnToSCID (
845                 IShellFolder2 * iface, UINT column, SHCOLUMNID * pscid)
846 {
847     IDesktopFolderImpl *This = (IDesktopFolderImpl *)iface;
848     FIXME ("(%p)->(%d %p) stub\n", This, column, pscid);
849     return E_NOTIMPL;
850 }
851
852 static const IShellFolder2Vtbl vt_MCFldr_ShellFolder2 =
853 {
854     ISF_Desktop_fnQueryInterface,
855     ISF_Desktop_fnAddRef,
856     ISF_Desktop_fnRelease,
857     ISF_Desktop_fnParseDisplayName,
858     ISF_Desktop_fnEnumObjects,
859     ISF_Desktop_fnBindToObject,
860     ISF_Desktop_fnBindToStorage,
861     ISF_Desktop_fnCompareIDs,
862     ISF_Desktop_fnCreateViewObject,
863     ISF_Desktop_fnGetAttributesOf,
864     ISF_Desktop_fnGetUIObjectOf,
865     ISF_Desktop_fnGetDisplayNameOf,
866     ISF_Desktop_fnSetNameOf,
867     /* ShellFolder2 */
868     ISF_Desktop_fnGetDefaultSearchGUID,
869     ISF_Desktop_fnEnumSearches,
870     ISF_Desktop_fnGetDefaultColumn,
871     ISF_Desktop_fnGetDefaultColumnState,
872     ISF_Desktop_fnGetDetailsEx,
873     ISF_Desktop_fnGetDetailsOf,
874     ISF_Desktop_fnMapColumnToSCID
875 };
876
877 /**************************************************************************
878  *    IPersist
879  */
880 static HRESULT WINAPI ISF_Desktop_IPersist_fnQueryInterface(
881     IPersist *iface, REFIID riid, LPVOID *ppvObj)
882 {
883     IDesktopFolderImpl *This = impl_from_IPersist( iface );
884     return IShellFolder2_QueryInterface((IShellFolder2*)This, riid, ppvObj);
885 }
886
887 static ULONG WINAPI ISF_Desktop_IPersist_fnAddRef(IPersist *iface)
888 {
889     IDesktopFolderImpl *This = impl_from_IPersist( iface );
890     return IShellFolder2_AddRef((IShellFolder2*)This);
891 }
892
893 static ULONG WINAPI ISF_Desktop_IPersist_fnRelease(IPersist *iface)
894 {
895     IDesktopFolderImpl *This = impl_from_IPersist( iface );
896     return IShellFolder2_Release((IShellFolder2*)This);
897 }
898
899 static HRESULT WINAPI ISF_Desktop_IPersist_fnGetClassID(IPersist *iface, CLSID *clsid)
900 {
901     *clsid = CLSID_ShellDesktop;
902     return S_OK;
903 }
904
905 static const IPersistVtbl vt_IPersist =
906 {
907     ISF_Desktop_IPersist_fnQueryInterface,
908     ISF_Desktop_IPersist_fnAddRef,
909     ISF_Desktop_IPersist_fnRelease,
910     ISF_Desktop_IPersist_fnGetClassID
911 };
912
913 /**************************************************************************
914  *    ISF_Desktop_Constructor
915  */
916 HRESULT WINAPI ISF_Desktop_Constructor (
917                 IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
918 {
919     static IDesktopFolderImpl *cached_sf;
920     WCHAR szMyPath[MAX_PATH];
921
922     TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
923
924     if (!ppv)
925         return E_POINTER;
926     if (pUnkOuter)
927         return CLASS_E_NOAGGREGATION;
928
929     if (!cached_sf)
930     {
931         IDesktopFolderImpl *sf;
932
933         if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
934             return E_UNEXPECTED;
935
936         sf = LocalAlloc( LMEM_ZEROINIT, sizeof (IDesktopFolderImpl) );
937         if (!sf)
938             return E_OUTOFMEMORY;
939
940         sf->ref = 1;
941         sf->lpVtbl = &vt_MCFldr_ShellFolder2;
942         sf->lpVtblIPersist = &vt_IPersist;
943         sf->pidlRoot = _ILCreateDesktop();    /* my qualified pidl */
944         sf->sPathTarget = SHAlloc( (lstrlenW(szMyPath) + 1)*sizeof(WCHAR) );
945         lstrcpyW( sf->sPathTarget, szMyPath );
946
947         if (InterlockedCompareExchangePointer((void *)&cached_sf, sf, NULL) != NULL)
948         {
949             /* some other thread already been here */
950             SHFree( sf->pidlRoot );
951             SHFree( sf->sPathTarget );
952             LocalFree( sf );
953         }
954     }
955
956     return IUnknown_QueryInterface( (IShellFolder2*)cached_sf, riid, ppv );
957 }