4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
7 * IShellFolder2 and related interfaces
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
28 /***************************************************************************
29 * SHELL32_GetCustomFolderAttributeFromPath (internal function)
31 * Gets a value from the folder's desktop.ini file, if one exists.
34 * pwszFolderPath[I] Folder containing the desktop.ini file.
35 * pwszHeading [I] Heading in .ini file.
36 * pwszAttribute [I] Attribute in .ini file.
37 * pwszValue [O] Buffer to store value into.
38 * cchValue [I] Size in characters including NULL of buffer pointed to
42 * TRUE if returned non-NULL value.
45 static BOOL __inline
SHELL32_GetCustomFolderAttributeFromPath(
46 LPWSTR pwszFolderPath
, LPCWSTR pwszHeading
, LPCWSTR pwszAttribute
,
47 LPWSTR pwszValue
, DWORD cchValue
)
49 static const WCHAR wszDesktopIni
[] =
50 {'d','e','s','k','t','o','p','.','i','n','i',0};
51 static const WCHAR wszDefault
[] = {0};
53 PathAddBackslashW(pwszFolderPath
);
54 PathAppendW(pwszFolderPath
, wszDesktopIni
);
55 return GetPrivateProfileStringW(pwszHeading
, pwszAttribute
, wszDefault
,
56 pwszValue
, cchValue
, pwszFolderPath
);
59 /***************************************************************************
60 * GetNextElement (internal function)
62 * Gets a part of a string till the first backslash.
65 * pszNext [IN] string to get the element from
66 * pszOut [IN] pointer to buffer which receives string
67 * dwOut [IN] length of pszOut
70 * LPSTR pointer to first, not yet parsed char
73 LPCWSTR
GetNextElementW (LPCWSTR pszNext
, LPWSTR pszOut
, DWORD dwOut
)
75 LPCWSTR pszTail
= pszNext
;
78 TRACE ("(%s %p 0x%08x)\n", debugstr_w (pszNext
), pszOut
, dwOut
);
82 if (!pszNext
|| !*pszNext
)
85 while (*pszTail
&& (*pszTail
!= (WCHAR
) '\\'))
88 dwCopy
= pszTail
- pszNext
+ 1;
89 lstrcpynW (pszOut
, pszNext
, (dwOut
< dwCopy
) ? dwOut
: dwCopy
);
96 TRACE ("--(%s %s 0x%08x %p)\n", debugstr_w (pszNext
), debugstr_w (pszOut
), dwOut
, pszTail
);
100 HRESULT
SHELL32_ParseNextElement (IShellFolder2
* psf
, HWND hwndOwner
, LPBC pbc
,
101 LPITEMIDLIST
* pidlInOut
, LPOLESTR szNext
, DWORD
* pEaten
, DWORD
* pdwAttributes
)
103 HRESULT hr
= E_INVALIDARG
;
104 LPITEMIDLIST pidlIn
= pidlInOut
? *pidlInOut
: NULL
;
105 LPITEMIDLIST pidlOut
= NULL
;
106 LPITEMIDLIST pidlTemp
= NULL
;
107 CComPtr
<IShellFolder
> psfChild
;
109 TRACE ("(%p, %p, %p, %s)\n", psf
, pbc
, pidlIn
, debugstr_w (szNext
));
111 /* get the shellfolder for the child pidl and let it analyse further */
112 hr
= psf
->BindToObject(pidlIn
, pbc
, IID_PPV_ARG(IShellFolder
, &psfChild
));
116 hr
= psfChild
->ParseDisplayName(hwndOwner
, pbc
, szNext
, pEaten
, &pidlOut
, pdwAttributes
);
120 pidlTemp
= ILCombine (pidlIn
, pidlOut
);
135 *pidlInOut
= pidlTemp
;
137 TRACE ("-- pidl=%p ret=0x%08x\n", pidlInOut
? *pidlInOut
: NULL
, hr
);
141 /***********************************************************************
142 * SHELL32_CoCreateInitSF
144 * Creates a shell folder and initializes it with a pidl and a root folder
145 * via IPersistFolder3 or IPersistFolder.
148 * pathRoot can be NULL for Folders being a drive.
149 * In this case the absolute path is built from pidlChild (eg. C:)
151 HRESULT
SHELL32_CoCreateInitSF (LPCITEMIDLIST pidlRoot
, LPCWSTR pathRoot
,
152 LPCITEMIDLIST pidlChild
, const GUID
* clsid
, int csidl
, REFIID riid
, LPVOID
*ppvOut
)
155 CComPtr
<IShellFolder
> pShellFolder
;
157 TRACE ("%p %s %p\n", pidlRoot
, debugstr_w(pathRoot
), pidlChild
);
159 hr
= SHCoCreateInstance(NULL
, clsid
, NULL
, IID_PPV_ARG(IShellFolder
, &pShellFolder
));
163 LPITEMIDLIST pidlAbsolute
= ILCombine (pidlRoot
, pidlChild
);
164 CComPtr
<IPersistFolder
> ppf
;
165 CComPtr
<IPersistFolder3
> ppf3
;
167 if (SUCCEEDED(pShellFolder
->QueryInterface(IID_PPV_ARG(IPersistFolder3
, &ppf3
))))
169 PERSIST_FOLDER_TARGET_INFO ppfti
;
171 ZeroMemory (&ppfti
, sizeof (ppfti
));
173 /* fill the PERSIST_FOLDER_TARGET_INFO */
174 ppfti
.dwAttributes
= -1;
180 lstrcpynW (ppfti
.szTargetParsingName
, pathRoot
, MAX_PATH
- 1);
181 PathAddBackslashW(ppfti
.szTargetParsingName
); /* FIXME: why have drives a backslash here ? */
186 int len
= wcslen(ppfti
.szTargetParsingName
);
188 if (!_ILSimpleGetTextW(pidlChild
, ppfti
.szTargetParsingName
+ len
, MAX_PATH
- len
))
192 ppf3
->InitializeEx(NULL
, pidlAbsolute
, &ppfti
);
194 else if (SUCCEEDED(pShellFolder
->QueryInterface(IID_PPV_ARG(IPersistFolder
, &ppf
))))
196 ppf
->Initialize(pidlAbsolute
);
198 ILFree (pidlAbsolute
);
200 return pShellFolder
->QueryInterface(riid
, ppvOut
);
203 void SHELL32_GetCLSIDForDirectory(LPCWSTR pathRoot
, LPCITEMIDLIST pidl
, CLSID
* pclsidFolder
)
205 static const WCHAR wszDotShellClassInfo
[] = {
206 '.','S','h','e','l','l','C','l','a','s','s','I','n','f','o',0 };
207 static const WCHAR wszCLSID
[] = {'C','L','S','I','D',0};
208 WCHAR wszCLSIDValue
[CHARS_IN_GUID
], wszFolderPath
[MAX_PATH
], *pwszPathTail
= wszFolderPath
;
210 /* see if folder CLSID should be overridden by desktop.ini file */
212 lstrcpynW(wszFolderPath
, pathRoot
, MAX_PATH
);
213 pwszPathTail
= PathAddBackslashW(wszFolderPath
);
216 _ILSimpleGetTextW(pidl
,pwszPathTail
,MAX_PATH
- (int)(pwszPathTail
- wszFolderPath
));
218 if (SHELL32_GetCustomFolderAttributeFromPath (wszFolderPath
,
219 wszDotShellClassInfo
, wszCLSID
, wszCLSIDValue
, CHARS_IN_GUID
))
220 CLSIDFromString (wszCLSIDValue
, pclsidFolder
);
223 /***********************************************************************
224 * SHELL32_BindToFS [Internal]
226 * Common code for IShellFolder_BindToObject.
229 * pidlRoot [I] The parent shell folder's absolute pidl.
230 * pathRoot [I] Absolute dos path of the parent shell folder.
231 * pidlComplete [I] PIDL of the child. Relative to pidlRoot.
232 * riid [I] GUID of the interface, which ppvOut shall be bound to.
233 * ppvOut [O] A reference to the child's interface (riid).
236 * pidlComplete has to contain at least one non empty SHITEMID.
237 * This function makes special assumptions on the shell namespace, which
238 * means you probably can't use it for your IShellFolder implementation.
240 HRESULT
SHELL32_BindToFS (LPCITEMIDLIST pidlRoot
,
241 LPCWSTR pathRoot
, LPCITEMIDLIST pidlComplete
, REFIID riid
, LPVOID
* ppvOut
)
243 CComPtr
<IShellFolder
> pSF
;
245 LPCITEMIDLIST pidlChild
;
247 if (!pidlRoot
|| !ppvOut
|| !pidlComplete
|| !pidlComplete
->mkid
.cb
)
250 if (_ILIsValue(pidlComplete
))
252 ERR("Binding to file is unimplemented\n");
253 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
255 if (!_ILIsFolder(pidlComplete
))
257 ERR("Got an unknown type of pidl!\n");
263 pidlChild
= (_ILIsPidlSimple (pidlComplete
)) ? pidlComplete
: ILCloneFirst (pidlComplete
);
265 CLSID clsidFolder
= CLSID_ShellFSFolder
;
266 DWORD attributes
= _ILGetFileAttributes(ILFindLastID(pidlChild
), NULL
, 0);
267 if ((attributes
& (FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_READONLY
)) != 0)
268 SHELL32_GetCLSIDForDirectory(pathRoot
, pidlChild
, &clsidFolder
);
270 hr
= SHELL32_CoCreateInitSF (pidlRoot
, pathRoot
, pidlChild
, &clsidFolder
, -1, IID_PPV_ARG(IShellFolder
, &pSF
));
272 if (pidlChild
!= pidlComplete
)
273 ILFree ((LPITEMIDLIST
)pidlChild
);
275 if (SUCCEEDED (hr
)) {
276 if (_ILIsPidlSimple (pidlComplete
)) {
278 hr
= pSF
->QueryInterface(riid
, ppvOut
);
281 hr
= pSF
->BindToObject(ILGetNext (pidlComplete
), NULL
, riid
, ppvOut
);
285 TRACE ("-- returning (%p) %08x\n", *ppvOut
, hr
);
290 /***********************************************************************
291 * SHELL32_GetDisplayNameOfChild
293 * Retrieves the display name of a child object of a shellfolder.
295 * For a pidl eg. [subpidl1][subpidl2][subpidl3]:
296 * - it binds to the child shellfolder [subpidl1]
297 * - asks it for the displayname of [subpidl2][subpidl3]
299 * Is possible the pidl is a simple pidl. In this case it asks the
300 * subfolder for the displayname of an empty pidl. The subfolder
301 * returns the own displayname eg. "::{guid}". This is used for
302 * virtual folders with the registry key WantsFORPARSING set.
304 HRESULT
SHELL32_GetDisplayNameOfChild (IShellFolder2
* psf
,
305 LPCITEMIDLIST pidl
, DWORD dwFlags
, LPSTRRET strRet
)
307 LPITEMIDLIST pidlFirst
= ILCloneFirst(pidl
);
309 return E_OUTOFMEMORY
;
311 CComPtr
<IShellFolder
> psfChild
;
312 HRESULT hr
= psf
->BindToObject(pidlFirst
, NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
315 hr
= psfChild
->GetDisplayNameOf(ILGetNext (pidl
), dwFlags
, strRet
);
322 HRESULT
HCR_GetClassName(REFIID riid
, LPSTRRET strRet
)
325 WCHAR wstrName
[MAX_PATH
+1];
326 bRet
= HCR_GetClassNameW(riid
, wstrName
, MAX_PATH
);
330 return SHSetStrRet(strRet
, wstrName
);
333 /***********************************************************************
334 * SHELL32_GetItemAttributes
338 * folder: 0xE0000177 FILESYSTEM | HASSUBFOLDER | FOLDER
339 * file: 0x40000177 FILESYSTEM
340 * drive: 0xf0000144 FILESYSTEM | HASSUBFOLDER | FOLDER | FILESYSANCESTOR
341 * mycomputer: 0xb0000154 HASSUBFOLDER | FOLDER | FILESYSANCESTOR
342 * (seems to be default for shell extensions if no registry entry exists)
345 * folder: 0xF0400177 FILESYSTEM | HASSUBFOLDER | FOLDER | FILESYSANCESTOR | CANMONIKER
346 * file: 0x40400177 FILESYSTEM | CANMONIKER
347 * drive 0xF0400154 FILESYSTEM | HASSUBFOLDER | FOLDER | FILESYSANCESTOR | CANMONIKER | CANRENAME (LABEL)
349 * According to the MSDN documentation this function should not set flags. It claims only to reset flags when necessary.
350 * However it turns out the native shell32.dll _sets_ flags in several cases - so do we.
353 static const DWORD dwSupportedAttr
=
354 SFGAO_CANCOPY
| /*0x00000001 */
355 SFGAO_CANMOVE
| /*0x00000002 */
356 SFGAO_CANLINK
| /*0x00000004 */
357 SFGAO_CANRENAME
| /*0x00000010 */
358 SFGAO_CANDELETE
| /*0x00000020 */
359 SFGAO_HASPROPSHEET
| /*0x00000040 */
360 SFGAO_DROPTARGET
| /*0x00000100 */
361 SFGAO_LINK
| /*0x00010000 */
362 SFGAO_READONLY
| /*0x00040000 */
363 SFGAO_HIDDEN
| /*0x00080000 */
364 SFGAO_FILESYSANCESTOR
| /*0x10000000 */
365 SFGAO_FOLDER
| /*0x20000000 */
366 SFGAO_FILESYSTEM
| /*0x40000000 */
367 SFGAO_HASSUBFOLDER
; /*0x80000000 */
369 HRESULT
SHELL32_GetFSItemAttributes(IShellFolder
* psf
, LPCITEMIDLIST pidl
, LPDWORD pdwAttributes
)
371 DWORD dwFileAttributes
, dwShellAttributes
;
373 if (!_ILIsFolder(pidl
) && !_ILIsValue(pidl
))
375 ERR("Got wrong type of pidl!\n");
376 *pdwAttributes
&= SFGAO_CANLINK
;
380 if (*pdwAttributes
& ~dwSupportedAttr
)
382 WARN ("attributes 0x%08x not implemented\n", (*pdwAttributes
& ~dwSupportedAttr
));
383 *pdwAttributes
&= dwSupportedAttr
;
386 dwFileAttributes
= _ILGetFileAttributes(pidl
, NULL
, 0);
388 /* Set common attributes */
389 dwShellAttributes
= *pdwAttributes
;
390 dwShellAttributes
|= SFGAO_FILESYSTEM
| SFGAO_DROPTARGET
| SFGAO_HASPROPSHEET
| SFGAO_CANDELETE
|
391 SFGAO_CANRENAME
| SFGAO_CANLINK
| SFGAO_CANMOVE
| SFGAO_CANCOPY
;
393 if (dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
395 dwShellAttributes
|= (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_FILESYSANCESTOR
);
398 dwShellAttributes
&= ~(SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_FILESYSANCESTOR
);
400 if (dwFileAttributes
& FILE_ATTRIBUTE_HIDDEN
)
401 dwShellAttributes
|= SFGAO_HIDDEN
;
403 dwShellAttributes
&= ~SFGAO_HIDDEN
;
405 if (dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
406 dwShellAttributes
|= SFGAO_READONLY
;
408 dwShellAttributes
&= ~SFGAO_READONLY
;
410 if (SFGAO_LINK
& *pdwAttributes
)
414 if (!_ILGetExtension(pidl
, ext
, MAX_PATH
) || lstrcmpiA(ext
, "lnk"))
415 dwShellAttributes
&= ~SFGAO_LINK
;
418 if (SFGAO_HASSUBFOLDER
& *pdwAttributes
)
420 CComPtr
<IShellFolder
> psf2
;
421 if (SUCCEEDED(psf
->BindToObject(pidl
, 0, IID_PPV_ARG(IShellFolder
, &psf2
))))
423 CComPtr
<IEnumIDList
> pEnumIL
;
424 if (SUCCEEDED(psf2
->EnumObjects(0, SHCONTF_FOLDERS
, &pEnumIL
)))
426 if (pEnumIL
->Skip(1) != S_OK
)
427 dwShellAttributes
&= ~SFGAO_HASSUBFOLDER
;
432 *pdwAttributes
&= dwShellAttributes
;
434 TRACE ("-- 0x%08x\n", *pdwAttributes
);
438 HRESULT
SHELL32_CompareChildren(IShellFolder2
* psf
, LPARAM lParam
, LPCITEMIDLIST pidl1
, LPCITEMIDLIST pidl2
)
440 PUIDLIST_RELATIVE nextpidl1
= ILGetNext (pidl1
);
441 PUIDLIST_RELATIVE nextpidl2
= ILGetNext (pidl2
);
443 bool isEmpty1
= _ILIsDesktop(nextpidl1
);
444 bool isEmpty2
= _ILIsDesktop(nextpidl2
);
445 if (isEmpty1
|| isEmpty2
)
446 return MAKE_COMPARE_HRESULT(isEmpty2
- isEmpty1
);
448 PITEMID_CHILD firstpidl
= ILCloneFirst (pidl1
);
450 return E_OUTOFMEMORY
;
452 CComPtr
<IShellFolder
> psf2
;
453 HRESULT hr
= psf
->BindToObject(firstpidl
, 0, IID_PPV_ARG(IShellFolder
, &psf2
));
456 return MAKE_COMPARE_HRESULT(0);
458 return psf2
->CompareIDs(lParam
, nextpidl1
, nextpidl2
);
461 HRESULT
SHELL32_CompareDetails(IShellFolder2
* isf
, LPARAM lParam
, LPCITEMIDLIST pidl1
, LPCITEMIDLIST pidl2
)
464 WCHAR wszItem1
[MAX_PATH
], wszItem2
[MAX_PATH
];
467 hres
= isf
->GetDetailsOf(pidl1
, lParam
, &sd
);
469 return MAKE_COMPARE_HRESULT(1);
471 hres
= StrRetToBufW(&sd
.str
, pidl1
, wszItem1
, MAX_PATH
);
473 return MAKE_COMPARE_HRESULT(1);
475 hres
= isf
->GetDetailsOf(pidl2
, lParam
, &sd
);
477 return MAKE_COMPARE_HRESULT(1);
479 hres
= StrRetToBufW(&sd
.str
, pidl2
, wszItem2
, MAX_PATH
);
481 return MAKE_COMPARE_HRESULT(1);
483 int ret
= wcsicmp(wszItem1
, wszItem2
);
485 return SHELL32_CompareChildren(isf
, lParam
, pidl1
, pidl2
);
487 return MAKE_COMPARE_HRESULT(ret
);
490 void AddClassKeyToArray(const WCHAR
* szClass
, HKEY
* array
, UINT
* cKeys
)
496 LSTATUS result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szClass
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hkey
);
497 if (result
!= ERROR_SUCCESS
)
500 array
[*cKeys
] = hkey
;
504 void AddFSClassKeysToArray(PCUITEMID_CHILD pidl
, HKEY
* array
, UINT
* cKeys
)
506 if (_ILIsValue(pidl
))
508 FileStructW
* pFileData
= _ILGetFileStructW(pidl
);
509 LPWSTR extension
= PathFindExtension(pFileData
->wszName
);
513 AddClassKeyToArray(extension
, array
, cKeys
);
515 WCHAR wszClass
[40], wszClass2
[40];
516 DWORD dwSize
= sizeof(wszClass
);
517 if (RegGetValueW(HKEY_CLASSES_ROOT
, extension
, NULL
, RRF_RT_REG_SZ
, NULL
, wszClass
, &dwSize
) == ERROR_SUCCESS
)
519 swprintf(wszClass2
, L
"%s//%s", extension
, wszClass
);
521 AddClassKeyToArray(wszClass
, array
, cKeys
);
522 AddClassKeyToArray(wszClass2
, array
, cKeys
);
525 swprintf(wszClass2
, L
"SystemFileAssociations//%s", extension
);
526 AddClassKeyToArray(wszClass2
, array
, cKeys
);
528 if (RegGetValueW(HKEY_CLASSES_ROOT
, extension
, L
"PerceivedType ", RRF_RT_REG_SZ
, NULL
, wszClass
, &dwSize
) == ERROR_SUCCESS
)
530 swprintf(wszClass2
, L
"SystemFileAssociations//%s", wszClass
);
531 AddClassKeyToArray(wszClass2
, array
, cKeys
);
535 AddClassKeyToArray(L
"AllFilesystemObjects", array
, cKeys
);
536 AddClassKeyToArray(L
"*", array
, cKeys
);
538 else if (_ILIsFolder(pidl
))
540 AddClassKeyToArray(L
"AllFilesystemObjects", array
, cKeys
);
541 AddClassKeyToArray(L
"Directory", array
, cKeys
);
542 AddClassKeyToArray(L
"Folder", array
, cKeys
);
546 ERR("Got non FS pidl\n");
550 HRESULT
SH_GetApidlFromDataObject(IDataObject
*pDataObject
, PIDLIST_ABSOLUTE
* ppidlfolder
, PUITEMID_CHILD
**apidlItems
, UINT
*pcidl
)
552 UINT cfShellIDList
= RegisterClipboardFormatW(CFSTR_SHELLIDLIST
);
557 InitFormatEtc (fmt
, cfShellIDList
, TYMED_HGLOBAL
);
559 HRESULT hr
= pDataObject
->QueryGetData(&fmt
);
560 if (FAILED_UNEXPECTEDLY(hr
))
564 hr
= pDataObject
->GetData(&fmt
, &medium
);
565 if (FAILED_UNEXPECTEDLY(hr
))
568 /* lock the handle */
569 LPIDA lpcida
= (LPIDA
)GlobalLock(medium
.hGlobal
);
572 ReleaseStgMedium(&medium
);
576 /* convert the data into pidl */
578 LPITEMIDLIST
*apidl
= _ILCopyCidaToaPidl(&pidl
, lpcida
);
581 ReleaseStgMedium(&medium
);
582 return E_OUTOFMEMORY
;
587 *pcidl
= lpcida
->cidl
;
589 ReleaseStgMedium(&medium
);
593 /***********************************************************************
598 HRESULT WINAPI
SHCreateLinks( HWND hWnd
, LPCSTR lpszDir
, IDataObject
* lpDataObject
,
599 UINT uFlags
, LPITEMIDLIST
*lppidlLinks
)
601 FIXME("%p %s %p %08x %p\n", hWnd
, lpszDir
, lpDataObject
, uFlags
, lppidlLinks
);
605 /***********************************************************************
606 * SHOpenFolderAndSelectItems
612 SHOpenFolderAndSelectItems(LPITEMIDLIST pidlFolder
,
614 PCUITEMID_CHILD_ARRAY apidl
,
617 ERR("SHOpenFolderAndSelectItems() is hackplemented\n");
618 PCIDLIST_ABSOLUTE pidlItem
;
621 /* Firefox sends a full pidl here dispite the fact it is a PCUITEMID_CHILD_ARRAY -_- */
622 if (ILGetNext(apidl
[0]) != NULL
)
628 pidlItem
= ILCombine(pidlFolder
, apidl
[0]);
633 pidlItem
= pidlFolder
;
636 CComPtr
<IShellFolder
> psfDesktop
;
638 HRESULT hr
= SHGetDesktopFolder(&psfDesktop
);
639 if (FAILED_UNEXPECTEDLY(hr
))
643 hr
= psfDesktop
->GetDisplayNameOf(pidlItem
, SHGDN_FORPARSING
, &strret
);
644 if (FAILED_UNEXPECTEDLY(hr
))
647 WCHAR wszBuf
[MAX_PATH
];
648 hr
= StrRetToBufW(&strret
, pidlItem
, wszBuf
, _countof(wszBuf
));
649 if (FAILED_UNEXPECTEDLY(hr
))
652 WCHAR wszParams
[MAX_PATH
];
653 wcscpy(wszParams
, L
"/select,");
654 wcscat(wszParams
, wszBuf
);
656 SHELLEXECUTEINFOW sei
;
657 memset(&sei
, 0, sizeof sei
);
658 sei
.cbSize
= sizeof sei
;
659 sei
.fMask
= SEE_MASK_WAITFORINPUTIDLE
;
660 sei
.lpFile
= L
"explorer.exe";
661 sei
.lpParameters
= wszParams
;
663 if (ShellExecuteExW(&sei
))