2 * Virtual Desktop Folder
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 * Copyright 2009 Andrew Hill
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
25 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
28 CDesktopFolder should create two file system folders internally, one representing the
29 user's desktop folder, and the other representing the common desktop folder. It should
30 also create a CRegFolder to represent the virtual items that exist only in the registry.
31 The CRegFolder is aggregated by the CDesktopFolder, and queries for the CLSID_IShellFolder,
32 CLSID_IShellFolder2, or CLSID_IShellIconOverlay interfaces prefer the CRegFolder
34 The CDesktopFolderEnum class should create two enumerators, one for each of the file
35 system folders, and enumerate the contents of each folder. Since the CRegFolder
36 implementation of IShellFolder::EnumObjects enumerates the virtual items, the
37 CDesktopFolderEnum is only responsible for returning the physical items.
38 CDesktopFolderEnum is incorrect where it filters My Computer from the enumeration
39 if the new start menu is used. The CDesktopViewCallback is responsible for filtering
40 it from the view by handling the IncludeObject query to return S_FALSE. The enumerator
41 always shows My Computer.
44 /* Undocumented functions from shdocvw */
45 extern "C" HRESULT WINAPI
IEParseDisplayNameWithBCW(DWORD codepage
, LPCWSTR lpszDisplayName
, LPBC pbc
, LPITEMIDLIST
*ppidl
);
47 /***********************************************************************
48 * Desktopfolder implementation
53 class CDesktopFolderEnum
:
54 public IEnumIDListImpl
57 // CComPtr fDesktopEnumerator;
58 // CComPtr fCommonDesktopEnumerator;
61 ~CDesktopFolderEnum();
62 HRESULT WINAPI
Initialize(CDesktopFolder
*desktopFolder
, HWND hwndOwner
, DWORD dwFlags
);
64 BEGIN_COM_MAP(CDesktopFolderEnum
)
65 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
69 int SHELL_ConfirmMsgBox(HWND hWnd
, LPWSTR lpszText
, LPWSTR lpszCaption
, HICON hIcon
, BOOL bYesToAll
);
71 static const shvheader DesktopSFHeader
[] = {
72 {IDS_SHV_COLUMN1
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 15},
73 {IDS_SHV_COLUMN2
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
74 {IDS_SHV_COLUMN3
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
75 {IDS_SHV_COLUMN4
, SHCOLSTATE_TYPE_DATE
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 12},
76 {IDS_SHV_COLUMN5
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 5}
79 #define DESKTOPSHELLVIEWCOLUMNS 5
81 CDesktopFolderEnum::CDesktopFolderEnum()
85 CDesktopFolderEnum::~CDesktopFolderEnum()
89 static const WCHAR ClassicStartMenuW
[] = L
"SOFTWARE\\Microsoft\\Windows\\"
90 L
"CurrentVersion\\Explorer\\HideDesktopIcons\\ClassicStartMenu";
93 IsNamespaceExtensionHidden(const WCHAR
*iid
)
95 DWORD Result
, dwResult
;
96 dwResult
= sizeof(DWORD
);
98 if (RegGetValueW(HKEY_CURRENT_USER
, /* FIXME use NewStartPanel when activated */
104 &dwResult
) != ERROR_SUCCESS
)
113 SetNamespaceExtensionVisibleStatus(const WCHAR
* iid
, DWORD dwStatus
)
117 if (RegOpenKeyExW(HKEY_CURRENT_USER
, ClassicStartMenuW
, 0, KEY_WRITE
, &hKey
) == ERROR_SUCCESS
)
119 RegSetValueExW(hKey
, iid
, 0, REG_DWORD
, (LPBYTE
)&dwStatus
, sizeof(DWORD
));
124 /**************************************************************************
125 * CreateDesktopEnumList()
128 HRESULT WINAPI
CDesktopFolderEnum::Initialize(CDesktopFolder
*desktopFolder
, HWND hwndOwner
, DWORD dwFlags
)
131 WCHAR szPath
[MAX_PATH
];
133 static const WCHAR MyDocumentsClassString
[] = L
"{450D8FBA-AD25-11D0-98A8-0800361B1103}";
134 static const WCHAR Desktop_NameSpaceW
[] = L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\Namespace";
136 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags
);
138 /* enumerate the root folders */
139 if (dwFlags
& SHCONTF_FOLDERS
)
145 /* create the pidl for This item */
146 if (IsNamespaceExtensionHidden(MyDocumentsClassString
) < 1)
148 ret
= AddToEnumList(_ILCreateMyDocuments());
150 ret
= AddToEnumList(_ILCreateMyComputer());
152 for (i
= 0; i
< 2; i
++)
155 dwResult
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, Desktop_NameSpaceW
, 0, KEY_READ
, &hkey
);
157 dwResult
= RegOpenKeyExW(HKEY_CURRENT_USER
, Desktop_NameSpaceW
, 0, KEY_READ
, &hkey
);
159 if (dwResult
== ERROR_SUCCESS
)
170 size
= sizeof (iid
) / sizeof (iid
[0]);
171 r
= RegEnumKeyExW(hkey
, i
, iid
, &size
, 0, NULL
, NULL
, NULL
);
172 if (ERROR_SUCCESS
== r
)
174 if (IsNamespaceExtensionHidden(iid
) < 1)
176 pidl
= _ILCreateGuidFromStrW(iid
);
179 if (!HasItemWithCLSID(pidl
))
181 ret
= AddToEnumList(pidl
);
190 else if (ERROR_NO_MORE_ITEMS
== r
)
199 for (i
= 0; i
< 2; i
++)
202 dwResult
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, ClassicStartMenuW
, 0, KEY_READ
, &hkey
);
204 dwResult
= RegOpenKeyExW(HKEY_CURRENT_USER
, ClassicStartMenuW
, 0, KEY_READ
, &hkey
);
206 if (dwResult
== ERROR_SUCCESS
)
208 DWORD j
= 0, dwVal
, Val
, dwType
, dwIID
;
215 dwIID
= sizeof(iid
) / sizeof(WCHAR
);
217 r
= RegEnumValueW(hkey
, j
++, iid
, &dwIID
, NULL
, &dwType
, (LPBYTE
)&Val
, &dwVal
);
218 if (r
== ERROR_SUCCESS
)
220 if (Val
== 0 && dwType
== REG_DWORD
)
222 LPITEMIDLIST pidl
= _ILCreateGuidFromStrW(iid
);
225 if (!HasItemWithCLSID(pidl
))
236 else if (ERROR_NO_MORE_ITEMS
== r
)
247 /* enumerate the elements in %windir%\desktop */
248 ret
= ret
&& SHGetSpecialFolderPathW(0, szPath
, CSIDL_DESKTOPDIRECTORY
, FALSE
);
249 ret
= ret
&& CreateFolderEnumList(szPath
, dwFlags
);
251 ret
= ret
&& SHGetSpecialFolderPathW(0, szPath
, CSIDL_COMMON_DESKTOPDIRECTORY
, FALSE
);
252 ret
= ret
&& CreateFolderEnumList(szPath
, dwFlags
);
254 return ret
? S_OK
: E_FAIL
;
257 CDesktopFolder::CDesktopFolder()
263 CDesktopFolder::~CDesktopFolder()
267 HRESULT WINAPI
CDesktopFolder::FinalConstruct()
269 WCHAR szMyPath
[MAX_PATH
];
271 if (!SHGetSpecialFolderPathW( 0, szMyPath
, CSIDL_DESKTOPDIRECTORY
, TRUE
))
274 pidlRoot
= _ILCreateDesktop(); /* my qualified pidl */
275 sPathTarget
= (LPWSTR
)SHAlloc((wcslen(szMyPath
) + 1) * sizeof(WCHAR
));
276 wcscpy(sPathTarget
, szMyPath
);
280 /**************************************************************************
281 * CDesktopFolder::ParseDisplayName
284 * "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
287 HRESULT WINAPI
CDesktopFolder::ParseDisplayName(
290 LPOLESTR lpszDisplayName
,
293 DWORD
*pdwAttributes
)
295 WCHAR szElement
[MAX_PATH
];
296 LPCWSTR szNext
= NULL
;
297 LPITEMIDLIST pidlTemp
= NULL
;
302 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
303 this, hwndOwner
, pbc
, lpszDisplayName
, debugstr_w(lpszDisplayName
),
304 pchEaten
, ppidl
, pdwAttributes
);
309 if (!lpszDisplayName
)
318 *pchEaten
= 0; /* strange but like the original */
320 urldata
.cbSize
= sizeof(urldata
);
322 if (lpszDisplayName
[0] == ':' && lpszDisplayName
[1] == ':')
324 szNext
= GetNextElementW (lpszDisplayName
, szElement
, MAX_PATH
);
325 TRACE ("-- element: %s\n", debugstr_w (szElement
));
326 CLSIDFromString (szElement
+ 2, &clsid
);
327 pidlTemp
= _ILCreateGuid (PT_GUID
, clsid
);
329 else if (PathGetDriveNumberW (lpszDisplayName
) >= 0)
331 /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
332 pidlTemp
= _ILCreateMyComputer ();
333 szNext
= lpszDisplayName
;
335 else if (PathIsUNCW(lpszDisplayName
))
337 pidlTemp
= _ILCreateNetwork();
338 szNext
= lpszDisplayName
;
340 else if( (pidlTemp
= SHELL32_CreatePidlFromBindCtx(pbc
, lpszDisplayName
)) )
345 else if (SUCCEEDED(ParseURLW(lpszDisplayName
, &urldata
)))
347 if (urldata
.nScheme
== URL_SCHEME_SHELL
) /* handle shell: urls */
349 TRACE ("-- shell url: %s\n", debugstr_w(urldata
.pszSuffix
));
350 SHCLSIDFromStringW (urldata
.pszSuffix
+ 2, &clsid
);
351 pidlTemp
= _ILCreateGuid (PT_GUID
, clsid
);
354 return IEParseDisplayNameWithBCW(CP_ACP
, lpszDisplayName
, pbc
, ppidl
);
358 /* it's a filesystem path on the desktop. Let a FSFolder parse it */
360 if (*lpszDisplayName
)
362 WCHAR szPath
[MAX_PATH
];
365 /* build a complete path to create a simple pidl */
366 lstrcpynW(szPath
, sPathTarget
, MAX_PATH
);
367 pathPtr
= PathAddBackslashW(szPath
);
370 lstrcpynW(pathPtr
, lpszDisplayName
, MAX_PATH
- (pathPtr
- szPath
));
371 hr
= _ILCreateFromPathW(szPath
, &pidlTemp
);
375 /* should never reach here, but for completeness */
376 hr
= HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
);
380 pidlTemp
= _ILCreateMyComputer();
385 if (SUCCEEDED(hr
) && pidlTemp
)
387 if (szNext
&& *szNext
)
389 hr
= SHELL32_ParseNextElement(this, hwndOwner
, pbc
,
390 &pidlTemp
, (LPOLESTR
) szNext
, pchEaten
, pdwAttributes
);
394 if (pdwAttributes
&& *pdwAttributes
)
395 hr
= SHELL32_GetItemAttributes((IShellFolder
*)this,
396 pidlTemp
, pdwAttributes
);
405 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr
);
410 /**************************************************************************
411 * CDesktopFolder::EnumObjects
413 HRESULT WINAPI
CDesktopFolder::EnumObjects(
416 LPENUMIDLIST
*ppEnumIDList
)
418 CComObject
<CDesktopFolderEnum
> *theEnumerator
;
419 CComPtr
<IEnumIDList
> result
;
422 TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner
, dwFlags
, ppEnumIDList
);
424 if (ppEnumIDList
== NULL
)
426 *ppEnumIDList
= NULL
;
428 ATLTRY (theEnumerator
= new CComObject
<CDesktopFolderEnum
>);
430 if (theEnumerator
== NULL
)
431 return E_OUTOFMEMORY
;
433 hResult
= theEnumerator
->QueryInterface (IID_IEnumIDList
, (void **)&result
);
434 if (FAILED (hResult
))
436 delete theEnumerator
;
440 hResult
= theEnumerator
->Initialize (this, hwndOwner
, dwFlags
);
441 if (FAILED (hResult
))
443 *ppEnumIDList
= result
.Detach ();
445 TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList
);
450 /**************************************************************************
451 * CDesktopFolder::BindToObject
453 HRESULT WINAPI
CDesktopFolder::BindToObject(
459 TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n",
460 this, pidl
, pbcReserved
, shdebugstr_guid (&riid
), ppvOut
);
462 return SHELL32_BindToChild( pidlRoot
, sPathTarget
, pidl
, riid
, ppvOut
);
465 /**************************************************************************
466 * CDesktopFolder::BindToStorage
468 HRESULT WINAPI
CDesktopFolder::BindToStorage(
474 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
475 this, pidl
, pbcReserved
, shdebugstr_guid (&riid
), ppvOut
);
481 /**************************************************************************
482 * CDesktopFolder::CompareIDs
484 HRESULT WINAPI
CDesktopFolder::CompareIDs(LPARAM lParam
, LPCITEMIDLIST pidl1
, LPCITEMIDLIST pidl2
)
488 TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam
, pidl1
, pidl2
);
489 nReturn
= SHELL32_CompareIDs ((IShellFolder
*)this, lParam
, pidl1
, pidl2
);
490 TRACE ("-- %i\n", nReturn
);
494 /**************************************************************************
495 * CDesktopFolder::CreateViewObject
497 HRESULT WINAPI
CDesktopFolder::CreateViewObject(
502 CComPtr
<IShellView
> pShellView
;
503 HRESULT hr
= E_INVALIDARG
;
505 TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
506 this, hwndOwner
, shdebugstr_guid (&riid
), ppvOut
);
513 if (IsEqualIID (riid
, IID_IDropTarget
))
515 WARN ("IDropTarget not implemented\n");
518 else if (IsEqualIID (riid
, IID_IContextMenu
))
520 WARN ("IContextMenu not implemented\n");
523 else if (IsEqualIID (riid
, IID_IShellView
))
525 hr
= IShellView_Constructor((IShellFolder
*)this, &pShellView
);
527 hr
= pShellView
->QueryInterface(riid
, ppvOut
);
529 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut
);
533 /**************************************************************************
534 * CDesktopFolder::GetAttributesOf
536 HRESULT WINAPI
CDesktopFolder::GetAttributesOf(
538 LPCITEMIDLIST
*apidl
,
542 static const DWORD dwDesktopAttributes
=
543 SFGAO_HASSUBFOLDER
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
| SFGAO_FILESYSANCESTOR
|
544 SFGAO_STORAGEANCESTOR
| SFGAO_HASPROPSHEET
| SFGAO_STORAGE
| SFGAO_CANLINK
;
545 static const DWORD dwMyComputerAttributes
=
546 SFGAO_CANRENAME
| SFGAO_CANDELETE
| SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
|
547 SFGAO_FILESYSANCESTOR
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_CANLINK
;
548 static DWORD dwMyNetPlacesAttributes
=
549 SFGAO_CANRENAME
| SFGAO_CANDELETE
| SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
|
550 SFGAO_FILESYSANCESTOR
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_CANLINK
;
552 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
553 this, cidl
, apidl
, rgfInOut
, rgfInOut
? *rgfInOut
: 0);
562 *rgfInOut
&= dwDesktopAttributes
;
565 /* TODO: always add SFGAO_CANLINK */
566 for (UINT i
= 0; i
< cidl
; ++i
)
569 if (_ILIsDesktop(*apidl
))
570 *rgfInOut
&= dwDesktopAttributes
;
571 else if (_ILIsMyComputer(apidl
[i
]))
572 *rgfInOut
&= dwMyComputerAttributes
;
573 else if (_ILIsNetHood(apidl
[i
]))
574 *rgfInOut
&= dwMyNetPlacesAttributes
;
576 SHELL32_GetItemAttributes((IShellFolder
*)this, apidl
[i
], rgfInOut
);
579 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
580 *rgfInOut
&= ~SFGAO_VALIDATE
;
582 TRACE("-- result=0x%08x\n", *rgfInOut
);
587 /**************************************************************************
588 * CDesktopFolder::GetUIObjectOf
591 * HWND hwndOwner, //[in ] Parent window for any output
592 * UINT cidl, //[in ] array size
593 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
594 * REFIID riid, //[in ] Requested Interface
595 * UINT* prgfInOut, //[ ] reserved
596 * LPVOID* ppvObject) //[out] Resulting Interface
599 HRESULT WINAPI
CDesktopFolder::GetUIObjectOf(
602 LPCITEMIDLIST
*apidl
,
608 IUnknown
*pObj
= NULL
;
609 HRESULT hr
= E_INVALIDARG
;
611 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
612 this, hwndOwner
, cidl
, apidl
, shdebugstr_guid (&riid
), prgfInOut
, ppvOut
);
619 if (IsEqualIID (riid
, IID_IContextMenu
))
621 hr
= CDefFolderMenu_Create2(pidlRoot
, hwndOwner
, cidl
, apidl
, (IShellFolder
*)this, NULL
, 0, NULL
, (IContextMenu
**)&pObj
);
623 else if (IsEqualIID (riid
, IID_IDataObject
) && (cidl
>= 1))
625 hr
= IDataObject_Constructor( hwndOwner
, pidlRoot
, apidl
, cidl
, (IDataObject
**)&pObj
);
627 else if (IsEqualIID (riid
, IID_IExtractIconA
) && (cidl
== 1))
629 pidl
= ILCombine (pidlRoot
, apidl
[0]);
630 pObj
= (LPUNKNOWN
) IExtractIconA_Constructor (pidl
);
634 else if (IsEqualIID (riid
, IID_IExtractIconW
) && (cidl
== 1))
636 pidl
= ILCombine (pidlRoot
, apidl
[0]);
637 pObj
= (LPUNKNOWN
) IExtractIconW_Constructor (pidl
);
641 else if (IsEqualIID (riid
, IID_IDropTarget
) && (cidl
>= 1))
643 hr
= this->QueryInterface (IID_IDropTarget
, (LPVOID
*)&pObj
);
645 else if ((IsEqualIID(riid
, IID_IShellLinkW
) ||
646 IsEqualIID(riid
, IID_IShellLinkA
)) && (cidl
== 1))
648 pidl
= ILCombine (pidlRoot
, apidl
[0]);
649 hr
= IShellLink_ConstructFromFile(NULL
, riid
, pidl
, (LPVOID
*)&pObj
);
655 if (SUCCEEDED(hr
) && !pObj
)
659 TRACE ("(%p)->hr=0x%08x\n", this, hr
);
663 /**************************************************************************
664 * CDesktopFolder::GetDisplayNameOf
667 * special case: pidl = null gives desktop-name back
669 HRESULT WINAPI
CDesktopFolder::GetDisplayNameOf(LPCITEMIDLIST pidl
, DWORD dwFlags
, LPSTRRET strRet
)
674 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl
, dwFlags
, strRet
);
680 pszPath
= (LPWSTR
)CoTaskMemAlloc((MAX_PATH
+ 1) * sizeof(WCHAR
));
682 return E_OUTOFMEMORY
;
684 if (_ILIsDesktop (pidl
))
686 if ((GET_SHGDN_RELATION (dwFlags
) == SHGDN_NORMAL
) &&
687 (GET_SHGDN_FOR (dwFlags
) & SHGDN_FORPARSING
))
688 wcscpy(pszPath
, sPathTarget
);
690 HCR_GetClassNameW(CLSID_ShellDesktop
, pszPath
, MAX_PATH
);
692 else if (_ILIsPidlSimple (pidl
))
696 if ((clsid
= _ILGetGUIDPointer (pidl
)))
698 if (GET_SHGDN_FOR (dwFlags
) & SHGDN_FORPARSING
)
700 int bWantsForParsing
;
703 * We can only get a filesystem path from a shellfolder if the
704 * value WantsFORPARSING in CLSID\\{...}\\shellfolder exists.
706 * Exception: The MyComputer folder doesn't have this key,
707 * but any other filesystem backed folder it needs it.
709 if (IsEqualIID (*clsid
, CLSID_MyComputer
))
711 bWantsForParsing
= TRUE
;
715 /* get the "WantsFORPARSING" flag from the registry */
716 static const WCHAR clsidW
[] =
717 { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
718 static const WCHAR shellfolderW
[] =
719 { '\\', 's', 'h', 'e', 'l', 'l', 'f', 'o', 'l', 'd', 'e', 'r', 0 };
720 static const WCHAR wantsForParsingW
[] =
721 { 'W', 'a', 'n', 't', 's', 'F', 'o', 'r', 'P', 'a', 'r', 's', 'i', 'n',
724 WCHAR szRegPath
[100];
727 wcscpy (szRegPath
, clsidW
);
728 SHELL32_GUIDToStringW (*clsid
, &szRegPath
[6]);
729 wcscat (szRegPath
, shellfolderW
);
730 r
= SHGetValueW(HKEY_CLASSES_ROOT
, szRegPath
,
731 wantsForParsingW
, NULL
, NULL
, NULL
);
732 if (r
== ERROR_SUCCESS
)
733 bWantsForParsing
= TRUE
;
735 bWantsForParsing
= FALSE
;
738 if ((GET_SHGDN_RELATION (dwFlags
) == SHGDN_NORMAL
) &&
742 * we need the filesystem path to the destination folder.
743 * Only the folder itself can know it
745 hr
= SHELL32_GetDisplayNameOfChild (this, pidl
, dwFlags
,
751 /* parsing name like ::{...} */
754 SHELL32_GUIDToStringW (*clsid
, &pszPath
[2]);
759 /* user friendly name */
760 HCR_GetClassNameW (*clsid
, pszPath
, MAX_PATH
);
767 /* file system folder or file rooted at the desktop */
768 if ((GET_SHGDN_FOR(dwFlags
) == SHGDN_FORPARSING
) &&
769 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
))
771 lstrcpynW(pszPath
, sPathTarget
, MAX_PATH
- 1);
772 PathAddBackslashW(pszPath
);
773 cLen
= wcslen(pszPath
);
776 _ILSimpleGetTextW(pidl
, pszPath
+ cLen
, MAX_PATH
- cLen
);
777 if (!_ILIsFolder(pidl
))
778 SHELL_FS_ProcessDisplayFilename(pszPath
, dwFlags
);
780 if (GetFileAttributes(pszPath
) == INVALID_FILE_ATTRIBUTES
)
782 /* file system folder or file rooted at the AllUsers desktop */
783 if ((GET_SHGDN_FOR(dwFlags
) == SHGDN_FORPARSING
) &&
784 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
))
786 SHGetSpecialFolderPathW(0, pszPath
, CSIDL_COMMON_DESKTOPDIRECTORY
, FALSE
);
787 PathAddBackslashW(pszPath
);
788 cLen
= wcslen(pszPath
);
791 _ILSimpleGetTextW(pidl
, pszPath
+ cLen
, MAX_PATH
- cLen
);
792 if (!_ILIsFolder(pidl
))
793 SHELL_FS_ProcessDisplayFilename(pszPath
, dwFlags
);
799 /* a complex pidl, let the subfolder do the work */
800 hr
= SHELL32_GetDisplayNameOfChild (this, pidl
, dwFlags
,
806 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
807 if (GetVersion() & 0x80000000)
809 strRet
->uType
= STRRET_CSTR
;
810 if (!WideCharToMultiByte(CP_ACP
, 0, pszPath
, -1, strRet
->cStr
, MAX_PATH
,
812 strRet
->cStr
[0] = '\0';
813 CoTaskMemFree(pszPath
);
817 strRet
->uType
= STRRET_WSTR
;
818 strRet
->pOleStr
= pszPath
;
822 CoTaskMemFree(pszPath
);
824 TRACE ("-- (%p)->(%s,0x%08x)\n", this,
825 strRet
->uType
== STRRET_CSTR
? strRet
->cStr
:
826 debugstr_w(strRet
->pOleStr
), hr
);
830 /**************************************************************************
831 * CDesktopFolder::SetNameOf
832 * Changes the name of a file object or subfolder, possibly changing its item
833 * identifier in the process.
836 * HWND hwndOwner, //[in ] Owner window for output
837 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
838 * LPCOLESTR lpszName, //[in ] the items new display name
839 * DWORD dwFlags, //[in ] SHGNO formatting flags
840 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
842 HRESULT WINAPI
CDesktopFolder::SetNameOf(
844 LPCITEMIDLIST pidl
, /* simple pidl */
847 LPITEMIDLIST
*pPidlOut
)
849 CComPtr
<IShellFolder2
> psf
;
851 WCHAR szSrc
[MAX_PATH
+ 1], szDest
[MAX_PATH
+ 1];
853 BOOL bIsFolder
= _ILIsFolder (ILFindLastID (pidl
));
855 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner
, pidl
,
856 debugstr_w (lpName
), dwFlags
, pPidlOut
);
858 if (_ILGetGUIDPointer(pidl
))
860 if (SUCCEEDED(BindToObject(pidl
, NULL
, IID_IShellFolder2
, (LPVOID
*)&psf
)))
862 hr
= psf
->SetNameOf(hwndOwner
, pidl
, lpName
, dwFlags
, pPidlOut
);
867 /* build source path */
868 lstrcpynW(szSrc
, sPathTarget
, MAX_PATH
);
869 ptr
= PathAddBackslashW (szSrc
);
871 _ILSimpleGetTextW (pidl
, ptr
, MAX_PATH
+ 1 - (ptr
- szSrc
));
873 /* build destination path */
874 if (dwFlags
== SHGDN_NORMAL
|| dwFlags
& SHGDN_INFOLDER
) {
875 lstrcpynW(szDest
, sPathTarget
, MAX_PATH
);
876 ptr
= PathAddBackslashW (szDest
);
878 lstrcpynW(ptr
, lpName
, MAX_PATH
+ 1 - (ptr
- szDest
));
880 lstrcpynW(szDest
, lpName
, MAX_PATH
);
882 if(!(dwFlags
& SHGDN_FORPARSING
) && SHELL_FS_HideExtension(szSrc
)) {
883 WCHAR
*ext
= PathFindExtensionW(szSrc
);
885 INT len
= wcslen(szDest
);
886 lstrcpynW(szDest
+ len
, ext
, MAX_PATH
- len
);
890 if (!memcmp(szSrc
, szDest
, (wcslen(szDest
) + 1) * sizeof(WCHAR
)))
892 /* src and destination is the same */
895 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
900 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc
), debugstr_w(szDest
));
901 if (MoveFileW (szSrc
, szDest
))
906 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
908 SHChangeNotify (bIsFolder
? SHCNE_RENAMEFOLDER
: SHCNE_RENAMEITEM
,
909 SHCNF_PATHW
, szSrc
, szDest
);
916 HRESULT WINAPI
CDesktopFolder::GetDefaultSearchGUID(GUID
*pguid
)
918 FIXME ("(%p)\n", this);
922 HRESULT WINAPI
CDesktopFolder::EnumSearches(IEnumExtraSearch
**ppenum
)
924 FIXME ("(%p)\n", this);
928 HRESULT WINAPI
CDesktopFolder::GetDefaultColumn(DWORD dwRes
, ULONG
*pSort
, ULONG
*pDisplay
)
930 TRACE ("(%p)\n", this);
940 HRESULT WINAPI
CDesktopFolder::GetDefaultColumnState(UINT iColumn
, DWORD
*pcsFlags
)
942 TRACE ("(%p)\n", this);
944 if (!pcsFlags
|| iColumn
>= DESKTOPSHELLVIEWCOLUMNS
)
947 *pcsFlags
= DesktopSFHeader
[iColumn
].pcsFlags
;
952 HRESULT WINAPI
CDesktopFolder::GetDetailsEx(
954 const SHCOLUMNID
*pscid
,
957 FIXME ("(%p)\n", this);
962 HRESULT WINAPI
CDesktopFolder::GetDetailsOf(
969 TRACE ("(%p)->(%p %i %p)\n", this, pidl
, iColumn
, psd
);
971 if (!psd
|| iColumn
>= DESKTOPSHELLVIEWCOLUMNS
)
976 psd
->fmt
= DesktopSFHeader
[iColumn
].fmt
;
977 psd
->cxChar
= DesktopSFHeader
[iColumn
].cxChar
;
978 psd
->str
.uType
= STRRET_CSTR
;
979 LoadStringA (shell32_hInstance
, DesktopSFHeader
[iColumn
].colnameid
,
980 psd
->str
.cStr
, MAX_PATH
);
984 /* the data from the pidl */
985 psd
->str
.uType
= STRRET_CSTR
;
989 hr
= GetDisplayNameOf(pidl
,
990 SHGDN_NORMAL
| SHGDN_INFOLDER
, &psd
->str
);
993 _ILGetFileSize (pidl
, psd
->str
.cStr
, MAX_PATH
);
996 _ILGetFileType (pidl
, psd
->str
.cStr
, MAX_PATH
);
999 _ILGetFileDate (pidl
, psd
->str
.cStr
, MAX_PATH
);
1001 case 4: /* attributes */
1002 _ILGetFileAttributes (pidl
, psd
->str
.cStr
, MAX_PATH
);
1009 HRESULT WINAPI
CDesktopFolder::MapColumnToSCID(UINT column
, SHCOLUMNID
*pscid
)
1011 FIXME ("(%p)\n", this);
1015 HRESULT WINAPI
CDesktopFolder::GetClassID(CLSID
*lpClassId
)
1017 TRACE ("(%p)\n", this);
1022 *lpClassId
= CLSID_ShellDesktop
;
1027 HRESULT WINAPI
CDesktopFolder::Initialize(LPCITEMIDLIST pidl
)
1029 TRACE ("(%p)->(%p)\n", this, pidl
);
1034 HRESULT WINAPI
CDesktopFolder::GetCurFolder(LPITEMIDLIST
* pidl
)
1036 TRACE ("(%p)->(%p)\n", this, pidl
);
1038 if (!pidl
) return E_POINTER
;
1039 *pidl
= ILClone (pidlRoot
);
1043 HRESULT WINAPI
CDesktopFolder::GetUniqueName(LPWSTR pwszName
, UINT uLen
)
1045 CComPtr
<IEnumIDList
> penum
;
1047 WCHAR wszText
[MAX_PATH
];
1048 WCHAR wszNewFolder
[25];
1049 const WCHAR wszFormat
[] = {'%', 's', ' ', '%', 'd', 0 };
1051 LoadStringW(shell32_hInstance
, IDS_NEWFOLDER
, wszNewFolder
, sizeof(wszNewFolder
) / sizeof(WCHAR
));
1053 TRACE ("(%p)(%p %u)\n", this, pwszName
, uLen
);
1055 if (uLen
< sizeof(wszNewFolder
) / sizeof(WCHAR
) + 3)
1058 lstrcpynW (pwszName
, wszNewFolder
, uLen
);
1061 SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
| SHCONTF_INCLUDEHIDDEN
, &penum
);
1069 while (S_OK
== penum
->Next(1, &pidl
, &dwFetched
) &&
1071 _ILSimpleGetTextW (pidl
, wszText
, MAX_PATH
);
1072 if (0 == lstrcmpiW (wszText
, pwszName
)) {
1073 _snwprintf (pwszName
, uLen
, wszFormat
, wszNewFolder
, i
++);
1086 HRESULT WINAPI
CDesktopFolder::AddFolder(HWND hwnd
, LPCWSTR pwszName
, LPITEMIDLIST
*ppidlOut
)
1088 WCHAR wszNewDir
[MAX_PATH
];
1090 HRESULT hres
= E_FAIL
;
1092 TRACE ("(%p)(%s %p)\n", this, debugstr_w(pwszName
), ppidlOut
);
1096 lstrcpynW(wszNewDir
, sPathTarget
, MAX_PATH
);
1097 PathAppendW(wszNewDir
, pwszName
);
1098 bRes
= CreateDirectoryW (wszNewDir
, NULL
);
1101 SHChangeNotify (SHCNE_MKDIR
, SHCNF_PATHW
, wszNewDir
, NULL
);
1104 hres
= _ILCreateFromPathW(wszNewDir
, ppidlOut
);
1110 HRESULT WINAPI
CDesktopFolder::DeleteItems(UINT cidl
, LPCITEMIDLIST
*apidl
)
1114 WCHAR wszPath
[MAX_PATH
];
1115 WCHAR wszCaption
[50];
1116 WCHAR
*wszPathsList
;
1118 WCHAR
*wszCurrentPath
;
1119 UINT bRestoreWithDeskCpl
= FALSE
;
1122 TRACE ("(%p)(%u %p)\n", this, cidl
, apidl
);
1123 if (cidl
== 0) return S_OK
;
1125 for(i
= 0; i
< cidl
; i
++)
1127 if (_ILIsMyComputer(apidl
[i
]))
1128 bRestoreWithDeskCpl
++;
1129 else if (_ILIsNetHood(apidl
[i
]))
1130 bRestoreWithDeskCpl
++;
1131 else if (_ILIsMyDocuments(apidl
[i
]))
1132 bRestoreWithDeskCpl
++;
1135 if (bRestoreWithDeskCpl
)
1137 /* FIXME use FormatMessage
1138 * use a similar message resource as in windows
1140 LoadStringW(shell32_hInstance
, IDS_DELETEMULTIPLE_TEXT
, wszPath
, sizeof(wszPath
) / sizeof(WCHAR
));
1141 wszPath
[(sizeof(wszPath
)/sizeof(WCHAR
))-1] = 0;
1143 LoadStringW(shell32_hInstance
, IDS_DELETEITEM_CAPTION
, wszCaption
, sizeof(wszCaption
) / sizeof(WCHAR
));
1144 wszCaption
[(sizeof(wszCaption
)/sizeof(WCHAR
))-1] = 0;
1146 res
= SHELL_ConfirmMsgBox(GetActiveWindow(), wszPath
, wszCaption
, NULL
, cidl
> 1);
1147 if (res
== IDC_YESTOALL
|| res
== IDYES
)
1149 for(i
= 0; i
< cidl
; i
++)
1151 if (_ILIsMyComputer(apidl
[i
]))
1152 SetNamespaceExtensionVisibleStatus(L
"{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 0x1);
1153 else if (_ILIsNetHood(apidl
[i
]))
1154 SetNamespaceExtensionVisibleStatus(L
"{208D2C60-3AEA-1069-A2D7-08002B30309D}", 0x1);
1155 else if (_ILIsMyDocuments(apidl
[i
]))
1156 SetNamespaceExtensionVisibleStatus(L
"{450D8FBA-AD25-11D0-98A8-0800361B1103}", 0x1);
1161 lstrcpynW(wszPath
, sPathTarget
, MAX_PATH
);
1165 PathAddBackslashW(wszPath
);
1166 wszPathsList
= BuildPathsList(wszPath
, cidl
, apidl
);
1168 ZeroMemory(&op
, sizeof(op
));
1169 op
.hwnd
= GetActiveWindow();
1170 op
.wFunc
= FO_DELETE
;
1171 op
.pFrom
= wszPathsList
;
1172 op
.fFlags
= FOF_ALLOWUNDO
;
1173 if (SHFileOperationW(&op
))
1175 WARN("SHFileOperation failed\n");
1181 /* we currently need to manually send the notifies */
1182 wszCurrentPath
= wszPathsList
;
1183 for (i
= 0; i
< cidl
; i
++)
1187 if (_ILIsFolder(apidl
[i
]))
1188 wEventId
= SHCNE_RMDIR
;
1189 else if (_ILIsValue(apidl
[i
]))
1190 wEventId
= SHCNE_DELETE
;
1194 /* check if file exists */
1195 if (GetFileAttributesW(wszCurrentPath
) == INVALID_FILE_ATTRIBUTES
)
1197 LPITEMIDLIST pidl
= ILCombine(pidlRoot
, apidl
[i
]);
1198 SHChangeNotify(wEventId
, SHCNF_IDLIST
, pidl
, NULL
);
1202 wszCurrentPath
+= wcslen(wszCurrentPath
) + 1;
1204 HeapFree(GetProcessHeap(), 0, wszPathsList
);
1208 HRESULT WINAPI
CDesktopFolder::CopyItems(IShellFolder
*pSFFrom
, UINT cidl
, LPCITEMIDLIST
*apidl
)
1210 CComPtr
<IPersistFolder2
> ppf2
;
1211 WCHAR szSrcPath
[MAX_PATH
];
1212 WCHAR szTargetPath
[MAX_PATH
];
1215 LPWSTR pszSrc
, pszTarget
, pszSrcList
, pszTargetList
, pszFileName
;
1219 TRACE ("(%p)->(%p,%u,%p)\n", this, pSFFrom
, cidl
, apidl
);
1221 pSFFrom
->QueryInterface(IID_IPersistFolder2
, (LPVOID
*)&ppf2
);
1224 if (FAILED(ppf2
->GetCurFolder(&pidl
)))
1227 if (FAILED(pSFFrom
->GetDisplayNameOf(pidl
, SHGDN_FORPARSING
, &strRet
)))
1233 if (FAILED(StrRetToBufW(&strRet
, pidl
, szSrcPath
, MAX_PATH
)))
1240 pszSrc
= PathAddBackslashW (szSrcPath
);
1242 wcscpy(szTargetPath
, sPathTarget
);
1243 pszTarget
= PathAddBackslashW (szTargetPath
);
1245 pszSrcList
= BuildPathsList(szSrcPath
, cidl
, apidl
);
1246 pszTargetList
= BuildPathsList(szTargetPath
, cidl
, apidl
);
1248 if (!pszSrcList
|| !pszTargetList
)
1251 HeapFree(GetProcessHeap(), 0, pszSrcList
);
1254 HeapFree(GetProcessHeap(), 0, pszTargetList
);
1257 return E_OUTOFMEMORY
;
1259 ZeroMemory(&op
, sizeof(op
));
1262 /* remove trailing backslash */
1265 op
.pFrom
= szSrcPath
;
1269 op
.pFrom
= pszSrcList
;
1272 if (!pszTargetList
[0])
1274 /* remove trailing backslash */
1275 if (pszTarget
- szTargetPath
> 3)
1278 pszTarget
[0] = L
'\0';
1282 pszTarget
[1] = L
'\0';
1285 op
.pTo
= szTargetPath
;
1289 op
.pTo
= pszTargetList
;
1291 op
.hwnd
= GetActiveWindow();
1293 op
.fFlags
= FOF_ALLOWUNDO
| FOF_NOCONFIRMMKDIR
;
1295 res
= SHFileOperationW(&op
);
1297 if (res
== DE_SAMEFILE
)
1299 length
= wcslen(szTargetPath
);
1302 pszFileName
= wcsrchr(pszSrcList
, '\\');
1305 if (LoadStringW(shell32_hInstance
, IDS_COPY_OF
, pszTarget
, MAX_PATH
- length
))
1307 wcscat(szTargetPath
, L
" ");
1310 wcscat(szTargetPath
, pszFileName
);
1311 op
.pTo
= szTargetPath
;
1313 res
= SHFileOperationW(&op
);
1317 HeapFree(GetProcessHeap(), 0, pszSrcList
);
1318 HeapFree(GetProcessHeap(), 0, pszTargetList
);