cmd: DIR command outputs free space for the path.
[wine.git] / dlls / shell32 / shfldr_desktop.c
blob49de36aa741a2398dad50a7deb76a04e97dad509
2 /*
3 * Virtual Desktop Folder
5 * Copyright 1997 Marcus Meissner
6 * Copyright 1998, 1999, 2002 Juergen Schmied
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.
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.
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
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <stdio.h>
28 #define COBJMACROS
29 #include "winerror.h"
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "wingdi.h"
34 #include "winuser.h"
36 #include "ole2.h"
37 #include "shlguid.h"
39 #include "wininet.h"
40 #include "pidl.h"
41 #include "shell32_main.h"
42 #include "shresdef.h"
43 #include "shlwapi.h"
44 #include "shellfolder.h"
45 #include "wine/debug.h"
46 #include "debughlp.h"
47 #include "shfldr.h"
49 WINE_DEFAULT_DEBUG_CHANNEL (shell);
51 /* Undocumented functions from shdocvw */
52 extern HRESULT WINAPI IEParseDisplayNameWithBCW(DWORD codepage, LPCWSTR lpszDisplayName, LPBC pbc, LPITEMIDLIST *ppidl);
54 /***********************************************************************
55 * Desktopfolder implementation
58 typedef struct {
59 IShellFolder2 IShellFolder2_iface;
60 IPersistFolder2 IPersistFolder2_iface;
61 LONG ref;
63 /* both paths are parsible from the desktop */
64 LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
65 LPITEMIDLIST pidlRoot; /* absolute pidl */
67 UINT cfShellIDList; /* clipboardformat for IDropTarget */
68 BOOL fAcceptFmt; /* flag for pending Drop */
69 } IDesktopFolderImpl;
71 static IDesktopFolderImpl *cached_sf;
73 static inline IDesktopFolderImpl *impl_from_IShellFolder2(IShellFolder2 *iface)
75 return CONTAINING_RECORD(iface, IDesktopFolderImpl, IShellFolder2_iface);
78 static inline IDesktopFolderImpl *impl_from_IPersistFolder2( IPersistFolder2 *iface )
80 return CONTAINING_RECORD(iface, IDesktopFolderImpl, IPersistFolder2_iface);
83 static const shvheader desktop_header[] =
85 { &FMTID_Storage, PID_STG_NAME, IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15 },
86 { &FMTID_Storage, PID_STG_SIZE, IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10 },
87 { &FMTID_Storage, PID_STG_STORAGETYPE, IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10 },
88 { &FMTID_Storage, PID_STG_WRITETIME, IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12 },
89 { &FMTID_Storage, PID_STG_ATTRIBUTES, IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5 },
92 /**************************************************************************
93 * ISF_Desktop_fnQueryInterface
96 static HRESULT WINAPI ISF_Desktop_fnQueryInterface(
97 IShellFolder2 * iface, REFIID riid, LPVOID * ppvObj)
99 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
101 TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
103 if (!ppvObj) return E_POINTER;
105 *ppvObj = NULL;
107 if (IsEqualIID (riid, &IID_IUnknown) ||
108 IsEqualIID (riid, &IID_IShellFolder) ||
109 IsEqualIID (riid, &IID_IShellFolder2))
111 *ppvObj = &This->IShellFolder2_iface;
113 else if (IsEqualIID (riid, &IID_IPersist) ||
114 IsEqualIID (riid, &IID_IPersistFolder) ||
115 IsEqualIID (riid, &IID_IPersistFolder2))
117 *ppvObj = &This->IPersistFolder2_iface;
120 if (*ppvObj)
122 IUnknown_AddRef ((IUnknown *) (*ppvObj));
123 TRACE ("-- Interface: (%p)->(%p)\n", ppvObj, *ppvObj);
124 return S_OK;
126 TRACE ("-- Interface: E_NOINTERFACE\n");
127 return E_NOINTERFACE;
130 static ULONG WINAPI ISF_Desktop_fnAddRef (IShellFolder2 * iface)
132 return 2; /* non-heap based object */
135 static ULONG WINAPI ISF_Desktop_fnRelease (IShellFolder2 * iface)
137 return 1; /* non-heap based object */
140 /**************************************************************************
141 * ISF_Desktop_fnParseDisplayName
143 * NOTES
144 * "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
145 * to MyComputer
147 static HRESULT WINAPI ISF_Desktop_fnParseDisplayName (IShellFolder2 * iface,
148 HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
149 DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
151 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
152 WCHAR c, szElement[MAX_PATH];
153 LPCWSTR szNext = NULL;
154 LPITEMIDLIST pidlTemp = NULL;
155 PARSEDURLW urldata;
156 HRESULT hr = S_OK;
157 CLSID clsid;
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);
163 if (!ppidl) return E_INVALIDARG;
164 *ppidl = 0;
166 if (!lpszDisplayName) return E_INVALIDARG;
168 if (pchEaten)
169 *pchEaten = 0; /* strange but like the original */
171 urldata.cbSize = sizeof(urldata);
173 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
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);
180 /* we can't use PathGetDriveNumberW because we can't have the \\?\ prefix */
181 else if ((c = towupper(lpszDisplayName[0])) >= 'A' && c <= 'Z' && lpszDisplayName[1] == ':')
183 /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
184 pidlTemp = _ILCreateMyComputer ();
185 szNext = lpszDisplayName;
187 else if (!wcsncmp( lpszDisplayName, L"\\\\?\\unix\\", 9 ))
189 pidlTemp = _ILCreateGuid(PT_GUID, &CLSID_UnixDosFolder);
190 szNext = lpszDisplayName;
192 else if (PathIsUNCW(lpszDisplayName))
194 pidlTemp = _ILCreateNetwork();
195 szNext = lpszDisplayName;
197 else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
199 *ppidl = pidlTemp;
200 return S_OK;
202 else if (SUCCEEDED(ParseURLW(lpszDisplayName, &urldata)))
204 if (urldata.nScheme == URL_SCHEME_SHELL) /* handle shell: urls */
206 TRACE ("-- shell url: %s\n", debugstr_w(urldata.pszSuffix));
207 SHCLSIDFromStringW (urldata.pszSuffix+2, &clsid);
208 pidlTemp = _ILCreateGuid (PT_GUID, &clsid);
210 else
211 return IEParseDisplayNameWithBCW(CP_ACP,lpszDisplayName,pbc,ppidl);
213 else
215 /* it's a filesystem path on the desktop. Let a FSFolder parse it */
217 if (*lpszDisplayName)
219 if (*lpszDisplayName == '/')
221 /* UNIX paths should be parsed by unixfs */
222 IShellFolder *unixFS;
223 hr = UnixFolder_Constructor(NULL, &IID_IShellFolder, (LPVOID*)&unixFS);
224 if (SUCCEEDED(hr))
226 hr = IShellFolder_ParseDisplayName(unixFS, NULL, NULL,
227 lpszDisplayName, NULL, &pidlTemp, NULL);
228 IShellFolder_Release(unixFS);
231 else
233 /* build a complete path to create a simple pidl */
234 WCHAR szPath[MAX_PATH];
235 LPWSTR pathPtr;
237 lstrcpynW(szPath, This->sPathTarget, MAX_PATH);
238 pathPtr = PathAddBackslashW(szPath);
239 if (pathPtr)
241 lstrcpynW(pathPtr, lpszDisplayName, MAX_PATH - (pathPtr - szPath));
242 hr = _ILCreateFromPathW(szPath, &pidlTemp);
244 else
246 /* should never reach here, but for completeness */
247 hr = E_NOT_SUFFICIENT_BUFFER;
251 else
252 pidlTemp = _ILCreateMyComputer();
254 szNext = NULL;
257 if (SUCCEEDED(hr) && pidlTemp)
259 if (szNext && *szNext)
261 hr = SHELL32_ParseNextElement(iface, hwndOwner, pbc,
262 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
264 else
266 if (pdwAttributes && *pdwAttributes)
267 hr = SHELL32_GetItemAttributes(iface, pidlTemp, pdwAttributes);
271 *ppidl = pidlTemp;
273 TRACE ("(%p)->(-- ret=0x%08lx)\n", This, hr);
275 return hr;
278 static void add_shell_namespace_extensions(IEnumIDListImpl *list, HKEY root)
280 WCHAR guid[39], clsidkeyW[60];
281 DWORD size, i = 0;
282 HKEY hkey;
284 if (RegOpenKeyExW(root, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\Namespace", 0, KEY_READ, &hkey))
285 return;
287 size = ARRAY_SIZE(guid);
288 while (!RegEnumKeyExW(hkey, i++, guid, &size, 0, NULL, NULL, NULL))
290 DWORD attributes, value_size = sizeof(attributes);
292 /* Check if extension is configured as nonenumerable */
293 swprintf(clsidkeyW, ARRAY_SIZE(clsidkeyW), L"CLSID\\%s\\ShellFolder", guid);
294 RegGetValueW(HKEY_CLASSES_ROOT, clsidkeyW, L"Attributes", RRF_RT_REG_DWORD | RRF_ZEROONFAILURE,
295 NULL, &attributes, &value_size);
297 if (!(attributes & SFGAO_NONENUMERATED))
298 AddToEnumList(list, _ILCreateGuidFromStrW(guid));
299 size = ARRAY_SIZE(guid);
302 RegCloseKey(hkey);
305 /**************************************************************************
306 * CreateDesktopEnumList()
308 static BOOL CreateDesktopEnumList(IEnumIDListImpl *list, DWORD dwFlags)
310 BOOL ret = TRUE;
311 WCHAR szPath[MAX_PATH];
313 TRACE("(%p)->(flags=0x%08lx)\n", list, dwFlags);
315 /* enumerate the root folders */
316 if (dwFlags & SHCONTF_FOLDERS)
318 ret = AddToEnumList(list, _ILCreateMyComputer());
319 add_shell_namespace_extensions(list, HKEY_LOCAL_MACHINE);
320 add_shell_namespace_extensions(list, HKEY_CURRENT_USER);
323 /* enumerate the elements in %windir%\desktop */
324 ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
325 ret = ret && CreateFolderEnumList(list, szPath, dwFlags);
327 return ret;
330 /**************************************************************************
331 * ISF_Desktop_fnEnumObjects
333 static HRESULT WINAPI ISF_Desktop_fnEnumObjects (IShellFolder2 * iface,
334 HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
336 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
337 IEnumIDListImpl *list;
339 TRACE ("(%p)->(HWND=%p flags=0x%08lx pplist=%p)\n",
340 This, hwndOwner, dwFlags, ppEnumIDList);
342 if (!(list = IEnumIDList_Constructor()))
343 return E_OUTOFMEMORY;
344 CreateDesktopEnumList(list, dwFlags);
345 *ppEnumIDList = &list->IEnumIDList_iface;
347 TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);
349 return S_OK;
352 /**************************************************************************
353 * ISF_Desktop_fnBindToObject
355 static HRESULT WINAPI ISF_Desktop_fnBindToObject (IShellFolder2 * iface,
356 LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
358 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
360 TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n",
361 This, pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
363 return SHELL32_BindToChild( This->pidlRoot, &CLSID_ShellFSFolder, This->sPathTarget, pidl, riid, ppvOut );
366 /**************************************************************************
367 * ISF_Desktop_fnBindToStorage
369 static HRESULT WINAPI ISF_Desktop_fnBindToStorage (IShellFolder2 * iface,
370 LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
372 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
374 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
375 This, pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
377 *ppvOut = NULL;
378 return E_NOTIMPL;
381 /**************************************************************************
382 * ISF_Desktop_fnCompareIDs
384 static HRESULT WINAPI ISF_Desktop_fnCompareIDs (IShellFolder2 *iface,
385 LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
387 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
388 HRESULT hr;
390 TRACE ("(%p)->(0x%08Ix,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
391 hr = SHELL32_CompareIDs(iface, lParam, pidl1, pidl2);
392 TRACE ("-- 0x%08lx\n", hr);
393 return hr;
396 /**************************************************************************
397 * ISF_Desktop_fnCreateViewObject
399 static HRESULT WINAPI ISF_Desktop_fnCreateViewObject (IShellFolder2 * iface,
400 HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
402 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
403 LPSHELLVIEW pShellView;
404 HRESULT hr = E_INVALIDARG;
406 TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
407 This, hwndOwner, shdebugstr_guid (riid), ppvOut);
409 if (!ppvOut)
410 return E_INVALIDARG;
412 *ppvOut = NULL;
414 if (IsEqualIID (riid, &IID_IDropTarget))
416 WARN ("IDropTarget not implemented\n");
417 hr = E_NOTIMPL;
419 else if (IsEqualIID (riid, &IID_IContextMenu))
421 hr = BackgroundMenu_Constructor((IShellFolder*)iface, TRUE, riid, ppvOut);
423 else if (IsEqualIID (riid, &IID_IShellView))
425 pShellView = IShellView_Constructor ((IShellFolder *) iface);
426 if (pShellView)
428 hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
429 IShellView_Release (pShellView);
432 TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
433 return hr;
436 /**************************************************************************
437 * ISF_Desktop_fnGetAttributesOf
439 static HRESULT WINAPI ISF_Desktop_fnGetAttributesOf (IShellFolder2 * iface,
440 UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
442 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
444 static const DWORD dwDesktopAttributes =
445 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
446 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER;
447 static const DWORD dwMyComputerAttributes =
448 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET |
449 SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
451 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08lx))\n",
452 This, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
454 if (!rgfInOut)
455 return E_INVALIDARG;
456 if (cidl && !apidl)
457 return E_INVALIDARG;
459 if (*rgfInOut == 0)
460 *rgfInOut = ~0;
462 if(cidl == 0) {
463 *rgfInOut &= dwDesktopAttributes;
464 } else {
465 while (cidl > 0 && *apidl) {
466 pdump (*apidl);
467 if (_ILIsDesktop(*apidl)) {
468 *rgfInOut &= dwDesktopAttributes;
469 } else if (_ILIsMyComputer(*apidl)) {
470 *rgfInOut &= dwMyComputerAttributes;
471 } else {
472 SHELL32_GetItemAttributes(iface, *apidl, rgfInOut);
474 apidl++;
475 cidl--;
478 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
479 *rgfInOut &= ~SFGAO_VALIDATE;
481 TRACE ("-- result=0x%08lx\n", *rgfInOut);
483 return S_OK;
486 /**************************************************************************
487 * ISF_Desktop_fnGetUIObjectOf
489 * PARAMETERS
490 * HWND hwndOwner, //[in ] Parent window for any output
491 * UINT cidl, //[in ] array size
492 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
493 * REFIID riid, //[in ] Requested Interface
494 * UINT* prgfInOut, //[ ] reserved
495 * LPVOID* ppvObject) //[out] Resulting Interface
498 static HRESULT WINAPI ISF_Desktop_fnGetUIObjectOf (IShellFolder2 * iface,
499 HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
500 REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
502 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
504 LPITEMIDLIST pidl;
505 IUnknown *pObj = NULL;
506 HRESULT hr = E_INVALIDARG;
508 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
509 This, hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);
511 if (!ppvOut)
512 return E_INVALIDARG;
514 *ppvOut = NULL;
516 if (IsEqualIID (riid, &IID_IContextMenu))
518 if (cidl > 0)
519 return ItemMenu_Constructor((IShellFolder*)iface, This->pidlRoot, apidl, cidl, riid, ppvOut);
520 else
521 return BackgroundMenu_Constructor((IShellFolder*)iface, TRUE, riid, ppvOut);
523 else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1))
525 pObj = (LPUNKNOWN) IDataObject_Constructor( hwndOwner,
526 This->pidlRoot, apidl, cidl);
527 hr = S_OK;
529 else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1))
531 pidl = ILCombine (This->pidlRoot, apidl[0]);
532 pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
533 ILFree(pidl);
534 hr = S_OK;
536 else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1))
538 pidl = ILCombine (This->pidlRoot, apidl[0]);
539 pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
540 ILFree(pidl);
541 hr = S_OK;
543 else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1))
545 hr = IShellFolder2_QueryInterface (iface,
546 &IID_IDropTarget, (LPVOID *) & pObj);
548 else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
549 IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1))
551 pidl = ILCombine (This->pidlRoot, apidl[0]);
552 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, &pObj);
553 ILFree(pidl);
555 else
556 hr = E_NOINTERFACE;
558 if (SUCCEEDED(hr) && !pObj)
559 hr = E_OUTOFMEMORY;
561 *ppvOut = pObj;
562 TRACE ("(%p)->hr=0x%08lx\n", This, hr);
563 return hr;
566 /**************************************************************************
567 * ISF_Desktop_fnGetDisplayNameOf
569 * NOTES
570 * special case: pidl = null gives desktop-name back
572 static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf (IShellFolder2 * iface,
573 LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
575 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
576 HRESULT hr = S_OK;
577 LPWSTR pszPath;
579 TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", This, pidl, dwFlags, strRet);
580 pdump (pidl);
582 if (!strRet)
583 return E_INVALIDARG;
585 pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
586 if (!pszPath)
587 return E_OUTOFMEMORY;
589 if (_ILIsDesktop (pidl))
591 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
592 (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
593 lstrcpyW(pszPath, This->sPathTarget);
594 else
595 HCR_GetClassNameW(&CLSID_ShellDesktop, pszPath, MAX_PATH);
597 else if (_ILIsPidlSimple (pidl))
599 GUID const *clsid;
601 if ((clsid = _ILGetGUIDPointer (pidl)))
603 if ((GET_SHGDN_FOR (dwFlags) & (SHGDN_FORPARSING | SHGDN_FORADDRESSBAR)) == SHGDN_FORPARSING)
605 BOOL bWantsForParsing;
608 * We can only get a filesystem path from a shellfolder if the
609 * value WantsFORPARSING in CLSID\\{...}\\shellfolder exists.
611 * Exception: The MyComputer folder doesn't have this key,
612 * but any other filesystem backed folder it needs it.
614 if (IsEqualIID (clsid, &CLSID_MyComputer))
616 bWantsForParsing = TRUE;
618 else
620 /* get the "WantsFORPARSING" flag from the registry */
621 WCHAR szRegPath[100];
622 LONG r;
624 lstrcpyW (szRegPath, L"CLSID\\");
625 SHELL32_GUIDToStringW (clsid, &szRegPath[6]);
626 lstrcatW (szRegPath, L"\\shellfolder");
627 r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath, L"WantsForParsing", NULL, NULL, NULL);
628 if (r == ERROR_SUCCESS)
629 bWantsForParsing = TRUE;
630 else
631 bWantsForParsing = FALSE;
634 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
635 bWantsForParsing)
638 * we need the filesystem path to the destination folder.
639 * Only the folder itself can know it
641 hr = SHELL32_GetDisplayNameOfChild (iface, pidl, dwFlags,
642 pszPath,
643 MAX_PATH);
645 else
647 /* parsing name like ::{...} */
648 pszPath[0] = ':';
649 pszPath[1] = ':';
650 SHELL32_GUIDToStringW (clsid, &pszPath[2]);
653 else
655 /* user friendly name */
656 HCR_GetClassNameW (clsid, pszPath, MAX_PATH);
659 else
661 int cLen = 0;
663 /* file system folder or file rooted at the desktop */
664 if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
665 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
667 lstrcpynW(pszPath, This->sPathTarget, MAX_PATH - 1);
668 PathAddBackslashW(pszPath);
669 cLen = lstrlenW(pszPath);
672 _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
674 if (!_ILIsFolder(pidl))
675 SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
678 else
680 /* a complex pidl, let the subfolder do the work */
681 hr = SHELL32_GetDisplayNameOfChild (iface, pidl, dwFlags,
682 pszPath, MAX_PATH);
685 if (SUCCEEDED(hr))
687 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
688 if (GetVersion() & 0x80000000)
690 strRet->uType = STRRET_CSTR;
691 if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->cStr, MAX_PATH,
692 NULL, NULL))
693 strRet->cStr[0] = '\0';
694 CoTaskMemFree(pszPath);
696 else
698 strRet->uType = STRRET_WSTR;
699 strRet->pOleStr = pszPath;
702 else
703 CoTaskMemFree(pszPath);
705 TRACE ("-- (%p)->(%s,0x%08lx)\n", This,
706 strRet->uType == STRRET_CSTR ? strRet->cStr :
707 debugstr_w(strRet->pOleStr), hr);
708 return hr;
711 /**************************************************************************
712 * ISF_Desktop_fnSetNameOf
713 * Changes the name of a file object or subfolder, possibly changing its item
714 * identifier in the process.
716 * PARAMETERS
717 * HWND hwndOwner, //[in ] Owner window for output
718 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
719 * LPCOLESTR lpszName, //[in ] the items new display name
720 * DWORD dwFlags, //[in ] SHGNO formatting flags
721 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
723 static HRESULT WINAPI ISF_Desktop_fnSetNameOf (IShellFolder2 * iface,
724 HWND hwndOwner, LPCITEMIDLIST pidl, /* simple pidl */
725 LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
727 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
729 FIXME ("(%p)->(%p,pidl=%p,%s,%lu,%p) stub\n", This, hwndOwner, pidl,
730 debugstr_w (lpName), dwFlags, pPidlOut);
732 return E_FAIL;
735 static HRESULT WINAPI ISF_Desktop_fnGetDefaultSearchGUID(IShellFolder2 *iface, GUID *guid)
737 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
738 TRACE("(%p)->(%p)\n", This, guid);
739 return E_NOTIMPL;
742 static HRESULT WINAPI ISF_Desktop_fnEnumSearches (IShellFolder2 *iface,
743 IEnumExtraSearch ** ppenum)
745 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
746 FIXME ("(%p)->(%p) stub\n", This, ppenum);
747 return E_NOTIMPL;
750 static HRESULT WINAPI ISF_Desktop_fnGetDefaultColumn(IShellFolder2 *iface, DWORD reserved, ULONG *sort, ULONG *display)
752 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
754 TRACE ("(%p)->(%#lx, %p, %p)\n", This, reserved, sort, display);
756 return E_NOTIMPL;
759 static HRESULT WINAPI ISF_Desktop_fnGetDefaultColumnState (
760 IShellFolder2 * iface, UINT iColumn, DWORD * pcsFlags)
762 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
764 TRACE ("(%p)->(%d %p)\n", This, iColumn, pcsFlags);
766 if (!pcsFlags || iColumn >= ARRAY_SIZE(desktop_header))
767 return E_INVALIDARG;
769 *pcsFlags = desktop_header[iColumn].pcsFlags;
771 return S_OK;
774 static HRESULT WINAPI ISF_Desktop_fnGetDetailsEx (IShellFolder2 * iface,
775 LPCITEMIDLIST pidl, const SHCOLUMNID * pscid, VARIANT * pv)
777 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
778 FIXME ("(%p)->(%p %p %p) stub\n", This, pidl, pscid, pv);
779 return E_NOTIMPL;
782 static HRESULT WINAPI ISF_Desktop_fnGetDetailsOf (IShellFolder2 * iface,
783 LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS * psd)
785 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
787 TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
789 if (!psd || iColumn >= ARRAY_SIZE(desktop_header))
790 return E_INVALIDARG;
792 if (!pidl)
793 return SHELL32_GetColumnDetails(desktop_header, iColumn, psd);
795 return shellfolder_get_file_details( iface, pidl, desktop_header, iColumn, psd );
798 static HRESULT WINAPI ISF_Desktop_fnMapColumnToSCID(IShellFolder2 *iface, UINT column, SHCOLUMNID *scid)
800 IDesktopFolderImpl *This = impl_from_IShellFolder2(iface);
802 TRACE("(%p)->(%u %p)\n", This, column, scid);
804 if (column >= ARRAY_SIZE(desktop_header))
805 return E_INVALIDARG;
807 return shellfolder_map_column_to_scid(desktop_header, column, scid);
810 static const IShellFolder2Vtbl vt_MCFldr_ShellFolder2 =
812 ISF_Desktop_fnQueryInterface,
813 ISF_Desktop_fnAddRef,
814 ISF_Desktop_fnRelease,
815 ISF_Desktop_fnParseDisplayName,
816 ISF_Desktop_fnEnumObjects,
817 ISF_Desktop_fnBindToObject,
818 ISF_Desktop_fnBindToStorage,
819 ISF_Desktop_fnCompareIDs,
820 ISF_Desktop_fnCreateViewObject,
821 ISF_Desktop_fnGetAttributesOf,
822 ISF_Desktop_fnGetUIObjectOf,
823 ISF_Desktop_fnGetDisplayNameOf,
824 ISF_Desktop_fnSetNameOf,
825 /* ShellFolder2 */
826 ISF_Desktop_fnGetDefaultSearchGUID,
827 ISF_Desktop_fnEnumSearches,
828 ISF_Desktop_fnGetDefaultColumn,
829 ISF_Desktop_fnGetDefaultColumnState,
830 ISF_Desktop_fnGetDetailsEx,
831 ISF_Desktop_fnGetDetailsOf,
832 ISF_Desktop_fnMapColumnToSCID
835 /**************************************************************************
836 * IPersist
838 static HRESULT WINAPI ISF_Desktop_IPersistFolder2_fnQueryInterface(
839 IPersistFolder2 *iface, REFIID riid, LPVOID *ppvObj)
841 IDesktopFolderImpl *This = impl_from_IPersistFolder2( iface );
842 return IShellFolder2_QueryInterface(&This->IShellFolder2_iface, riid, ppvObj);
845 static ULONG WINAPI ISF_Desktop_IPersistFolder2_fnAddRef(
846 IPersistFolder2 *iface)
848 IDesktopFolderImpl *This = impl_from_IPersistFolder2( iface );
849 return IShellFolder2_AddRef(&This->IShellFolder2_iface);
852 static ULONG WINAPI ISF_Desktop_IPersistFolder2_fnRelease(
853 IPersistFolder2 *iface)
855 IDesktopFolderImpl *This = impl_from_IPersistFolder2( iface );
856 return IShellFolder2_Release(&This->IShellFolder2_iface);
859 static HRESULT WINAPI ISF_Desktop_IPersistFolder2_fnGetClassID(
860 IPersistFolder2 *iface, CLSID *clsid)
862 *clsid = CLSID_ShellDesktop;
863 return S_OK;
865 static HRESULT WINAPI ISF_Desktop_IPersistFolder2_fnInitialize(
866 IPersistFolder2 *iface, LPCITEMIDLIST pidl)
868 IDesktopFolderImpl *This = impl_from_IPersistFolder2( iface );
869 FIXME ("(%p)->(%p) stub\n", This, pidl);
870 return E_NOTIMPL;
872 static HRESULT WINAPI ISF_Desktop_IPersistFolder2_fnGetCurFolder(
873 IPersistFolder2 *iface, LPITEMIDLIST *ppidl)
875 IDesktopFolderImpl *This = impl_from_IPersistFolder2( iface );
876 *ppidl = ILClone(This->pidlRoot);
877 return S_OK;
880 static const IPersistFolder2Vtbl vt_IPersistFolder2 =
882 ISF_Desktop_IPersistFolder2_fnQueryInterface,
883 ISF_Desktop_IPersistFolder2_fnAddRef,
884 ISF_Desktop_IPersistFolder2_fnRelease,
885 ISF_Desktop_IPersistFolder2_fnGetClassID,
886 ISF_Desktop_IPersistFolder2_fnInitialize,
887 ISF_Desktop_IPersistFolder2_fnGetCurFolder
890 void release_desktop_folder(void)
892 if (!cached_sf) return;
893 SHFree(cached_sf->pidlRoot);
894 SHFree(cached_sf->sPathTarget);
895 LocalFree(cached_sf);
898 /**************************************************************************
899 * ISF_Desktop_Constructor
901 HRESULT WINAPI ISF_Desktop_Constructor (
902 IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
904 WCHAR szMyPath[MAX_PATH];
906 TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
908 if (!ppv)
909 return E_POINTER;
910 if (pUnkOuter)
911 return CLASS_E_NOAGGREGATION;
913 if (!cached_sf)
915 IDesktopFolderImpl *sf;
917 if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, FALSE ))
918 return E_UNEXPECTED;
920 sf = LocalAlloc( LMEM_ZEROINIT, sizeof (IDesktopFolderImpl) );
921 if (!sf)
922 return E_OUTOFMEMORY;
924 sf->ref = 1;
925 sf->IShellFolder2_iface.lpVtbl = &vt_MCFldr_ShellFolder2;
926 sf->IPersistFolder2_iface.lpVtbl = &vt_IPersistFolder2;
927 sf->pidlRoot = _ILCreateDesktop(); /* my qualified pidl */
928 sf->sPathTarget = SHAlloc( (lstrlenW(szMyPath) + 1)*sizeof(WCHAR) );
929 lstrcpyW( sf->sPathTarget, szMyPath );
931 if (InterlockedCompareExchangePointer((void *)&cached_sf, sf, NULL) != NULL)
933 /* some other thread already been here */
934 SHFree( sf->pidlRoot );
935 SHFree( sf->sPathTarget );
936 LocalFree( sf );
940 return IShellFolder2_QueryInterface( &cached_sf->IShellFolder2_iface, riid, ppv );
943 static HRESULT WINAPI active_desktop_QueryInterface(IActiveDesktop *iface, REFIID riid, void **obj)
945 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
947 *obj = NULL;
949 if (IsEqualIID(riid, &IID_IActiveDesktop)
950 || IsEqualIID(riid, &IID_IUnknown))
952 *obj = iface;
955 if (*obj)
957 IUnknown_AddRef((IUnknown *)*obj);
958 return S_OK;
961 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
962 *obj = NULL;
963 return E_NOINTERFACE;
966 static ULONG WINAPI active_desktop_AddRef(IActiveDesktop *iface)
968 return 2;
971 static ULONG WINAPI active_desktop_Release(IActiveDesktop *iface)
973 return 1;
976 static HRESULT WINAPI active_desktop_ApplyChanges(IActiveDesktop *iface, DWORD flags)
978 FIXME("%p, %#lx.\n", iface, flags);
980 return E_NOTIMPL;
983 static HRESULT WINAPI active_desktop_GetWallpaper(IActiveDesktop *iface, PWSTR wallpaper, UINT length, DWORD flags)
985 FIXME("%p, %p, %u, %#lx.\n", iface, wallpaper, length, flags);
987 return E_NOTIMPL;
990 static HRESULT WINAPI active_desktop_SetWallpaper(IActiveDesktop *iface, PCWSTR wallpaper, DWORD reserved)
992 FIXME("%p, %s, %#lx.\n", iface, debugstr_w(wallpaper), reserved);
994 return E_NOTIMPL;
997 static HRESULT WINAPI active_desktop_GetWallpaperOptions(IActiveDesktop *iface, LPWALLPAPEROPT options, DWORD reserved)
999 FIXME("%p, %p, %#lx.\n", iface, options, reserved);
1001 return E_NOTIMPL;
1004 static HRESULT WINAPI active_desktop_SetWallpaperOptions(IActiveDesktop *iface, LPCWALLPAPEROPT options, DWORD reserved)
1006 FIXME("%p, %p, %#lx.\n", iface, options, reserved);
1008 return E_NOTIMPL;
1011 static HRESULT WINAPI active_desktop_GetPattern(IActiveDesktop *iface, PWSTR pattern, UINT length, DWORD reserved)
1013 FIXME("%p, %p, %u, %#lx.\n", iface, pattern, length, reserved);
1015 return E_NOTIMPL;
1018 static HRESULT WINAPI active_desktop_SetPattern(IActiveDesktop *iface, PCWSTR pattern, DWORD reserved)
1020 FIXME("%p, %s, %#lx.\n", iface, debugstr_w(pattern), reserved);
1022 return E_NOTIMPL;
1025 static HRESULT WINAPI active_desktop_GetDesktopItemOptions(IActiveDesktop *iface, LPCOMPONENTSOPT options, DWORD reserved)
1027 FIXME("%p, %p, %#lx.\n", iface, options, reserved);
1029 return E_NOTIMPL;
1032 static HRESULT WINAPI active_desktop_SetDesktopItemOptions(IActiveDesktop *iface, LPCCOMPONENTSOPT options, DWORD reserved)
1034 FIXME("%p, %p, %#lx.\n", iface, options, reserved);
1036 return E_NOTIMPL;
1039 static HRESULT WINAPI active_desktop_AddDesktopItem(IActiveDesktop *iface, LPCCOMPONENT component, DWORD reserved)
1041 FIXME("%p, %p, %#lx.\n", iface, component, reserved);
1043 return E_NOTIMPL;
1046 static HRESULT WINAPI active_desktop_AddDesktopItemWithUI(IActiveDesktop *iface, HWND hwnd, LPCOMPONENT component, DWORD reserved)
1048 FIXME("%p, %p, %p, %#lx.\n", iface, hwnd, component, reserved);
1050 return E_NOTIMPL;
1053 static HRESULT WINAPI active_desktop_ModifyDesktopItem(IActiveDesktop *iface, LPCCOMPONENT component, DWORD flags)
1055 FIXME("%p, %p, %#lx.\n", iface, component, flags);
1057 return E_NOTIMPL;
1060 static HRESULT WINAPI active_desktop_RemoveDesktopItem(IActiveDesktop *iface, LPCCOMPONENT component, DWORD reserved)
1062 FIXME("%p, %p, %#lx.\n", iface, component, reserved);
1064 return E_NOTIMPL;
1067 static HRESULT WINAPI active_desktop_GetDesktopItemCount(IActiveDesktop *iface, int *count, DWORD reserved)
1069 FIXME("%p, %p, %#lx.\n", iface, count, reserved);
1071 return E_NOTIMPL;
1074 static HRESULT WINAPI active_desktop_GetDesktopItem(IActiveDesktop *iface, int index, LPCOMPONENT component, DWORD reserved)
1076 FIXME("%p, %d, %p, %#lx.\n", iface, index, component, reserved);
1078 return E_NOTIMPL;
1081 static HRESULT WINAPI active_desktop_GetDesktopItemByID(IActiveDesktop *iface, ULONG_PTR id, LPCOMPONENT component, DWORD reserved)
1083 FIXME("%p, %Ix, %p, %#lx.\n", iface, id, component, reserved);
1085 return E_NOTIMPL;
1088 static HRESULT WINAPI active_desktop_GenerateDesktopItemHtml(IActiveDesktop *iface, PCWSTR filename, LPCOMPONENT component, DWORD reserved)
1090 FIXME("%p, %s, %p, %#lx.\n", iface, debugstr_w(filename), component, reserved);
1092 return E_NOTIMPL;
1095 static HRESULT WINAPI active_desktop_AddUrl(IActiveDesktop *iface, HWND hwnd, PCWSTR source, LPCOMPONENT component, DWORD flags)
1097 FIXME("%p, %p, %s, %p, %#lx.\n", iface, hwnd, debugstr_w(source), component, flags);
1099 return E_NOTIMPL;
1102 static HRESULT WINAPI active_desktop_GetDesktopItemBySource(IActiveDesktop *iface, PCWSTR source, LPCOMPONENT component, DWORD reserved)
1104 FIXME("%p, %s, %p, %#lx.\n", iface, debugstr_w(source), component, reserved);
1106 return E_NOTIMPL;
1109 static const IActiveDesktopVtbl active_desktop_vtbl =
1111 active_desktop_QueryInterface,
1112 active_desktop_AddRef,
1113 active_desktop_Release,
1114 active_desktop_ApplyChanges,
1115 active_desktop_GetWallpaper,
1116 active_desktop_SetWallpaper,
1117 active_desktop_GetWallpaperOptions,
1118 active_desktop_SetWallpaperOptions,
1119 active_desktop_GetPattern,
1120 active_desktop_SetPattern,
1121 active_desktop_GetDesktopItemOptions,
1122 active_desktop_SetDesktopItemOptions,
1123 active_desktop_AddDesktopItem,
1124 active_desktop_AddDesktopItemWithUI,
1125 active_desktop_ModifyDesktopItem,
1126 active_desktop_RemoveDesktopItem,
1127 active_desktop_GetDesktopItemCount,
1128 active_desktop_GetDesktopItem,
1129 active_desktop_GetDesktopItemByID,
1130 active_desktop_GenerateDesktopItemHtml,
1131 active_desktop_AddUrl,
1132 active_desktop_GetDesktopItemBySource,
1135 HRESULT WINAPI ActiveDesktop_Constructor(IUnknown *outer, REFIID riid, void **obj)
1137 static IActiveDesktop object = { &active_desktop_vtbl };
1138 HRESULT hr;
1140 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), obj);
1142 if (outer)
1143 return CLASS_E_NOAGGREGATION;
1145 hr = IUnknown_QueryInterface(&object, riid, obj);
1146 IUnknown_Release(&object);
1148 return hr;