ReactOS 0.4.16-dev-2-g02a6913
utils.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Shell
3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4 * PURPOSE: Implement shell light-weight utility functions
5 * COPYRIGHT: Copyright 2023-2024 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 */
7
8#define _ATL_NO_EXCEPTIONS
9
10/*
11 * HACK! These functions are conflicting with <shobjidl.h> inline functions...
12 */
13#define IShellFolder_GetDisplayNameOf _disabled_IShellFolder_GetDisplayNameOf_
14#define IShellFolder_ParseDisplayName _disabled_IShellFolder_ParseDisplayName_
15#define IShellFolder_CompareIDs _disabled_IShellFolder_CompareIDs_
16
17#include "precomp.h"
18#include <shellapi.h>
19#include <shlwapi.h>
20#include <shlobj_undoc.h>
21#include <shlguid_undoc.h>
22#include <atlstr.h>
23
24/*
25 * HACK!
26 */
27#undef IShellFolder_GetDisplayNameOf
28#undef IShellFolder_ParseDisplayName
29#undef IShellFolder_CompareIDs
30
31#define SHLWAPI_ISHELLFOLDER_HELPERS /* HACK! */
32#include <shlwapi_undoc.h>
33
34#include <strsafe.h>
35
36#ifndef FAILED_UNEXPECTEDLY
37#define FAILED_UNEXPECTEDLY FAILED /* FIXME: Make shellutils.h usable without ATL */
38#endif
39
41
42static inline WORD
44{
47}
48
49static HRESULT
53 _In_ IContextMenu* pCM,
54 _In_ UINT fCMIC,
55 _In_ UINT fCMF,
56 _In_opt_ LPCSTR pszVerb,
57 _In_opt_ LPCWSTR pwszDir,
58 _In_ bool ForceQCM)
59{
60 CMINVOKECOMMANDINFOEX info = { sizeof(info), fCMIC, hWnd, pszVerb };
61 INT iDefItem = 0;
62 HMENU hMenu = NULL;
63 HCURSOR hOldCursor;
64 HRESULT hr = S_OK;
65 WCHAR wideverb[MAX_PATH];
66
67 if (!pCM)
68 return E_INVALIDARG;
69
70 hOldCursor = SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_WAIT));
71 info.nShow = SW_NORMAL;
72 if (pUnk)
74
75 if (IS_INTRESOURCE(pszVerb))
76 {
77 hMenu = CreatePopupMenu();
78 if (hMenu)
79 {
80 hr = pCM->QueryContextMenu(hMenu, 0, 1, MAXSHORT, fCMF | CMF_DEFAULTONLY);
81 iDefItem = GetMenuDefaultItem(hMenu, 0, 0);
82 if (iDefItem != -1)
83 info.lpVerb = MAKEINTRESOURCEA(iDefItem - 1);
84 }
85 info.lpVerbW = MAKEINTRESOURCEW(info.lpVerb);
86 }
87 else
88 {
90 {
91 info.fMask |= CMF_OPTIMIZEFORINVOKE;
92 }
93 if (pszVerb && SHAnsiToUnicode(pszVerb, wideverb, _countof(wideverb)))
94 {
95 info.fMask |= CMIC_MASK_UNICODE;
96 info.lpVerbW = wideverb;
97 }
98 if (ForceQCM)
99 {
100 hMenu = CreatePopupMenu();
101 hr = pCM->QueryContextMenu(hMenu, 0, 1, MAXSHORT, fCMF);
102 }
103 }
104
105 SetCursor(hOldCursor);
106
107 if (!FAILED_UNEXPECTEDLY(hr) && (iDefItem != -1 || info.lpVerb))
108 {
109 if (!hWnd)
110 info.fMask |= CMIC_MASK_FLAG_NO_UI;
111
113 if (pwszDir)
114 {
115 info.fMask |= CMIC_MASK_UNICODE;
116 info.lpDirectoryW = pwszDir;
117 if (SHUnicodeToAnsi(pwszDir, dir, _countof(dir)))
118 info.lpDirectory = dir;
119 }
120
121 hr = pCM->InvokeCommand((LPCMINVOKECOMMANDINFO)&info);
122 if (FAILED_UNEXPECTEDLY(hr)) { /* Diagnostic message */ }
123 }
124
125 if (pUnk)
127 if (hMenu)
128 DestroyMenu(hMenu);
129
130 return hr;
131}
132
133/*************************************************************************
134 * SHInvokeCommandOnContextMenuEx [SHLWAPI.639]
135 */
141 _In_ IContextMenu* pCM,
142 _In_ UINT fCMIC,
143 _In_ UINT fCMF,
144 _In_opt_ LPCSTR pszVerb,
145 _In_opt_ LPCWSTR pwszDir)
146{
147 return SHInvokeCommandOnContextMenuInternal(hWnd, pUnk, pCM, fCMIC, fCMF, pszVerb, pwszDir, true);
148}
149
150/*************************************************************************
151 * SHInvokeCommandOnContextMenu [SHLWAPI.540]
152 */
158 _In_ IContextMenu* pCM,
159 _In_ UINT fCMIC,
160 _In_opt_ LPCSTR pszVerb)
161{
162 return SHInvokeCommandOnContextMenuEx(hWnd, pUnk, pCM, fCMIC, CMF_EXTENDEDVERBS, pszVerb, NULL);
163}
164
165/*************************************************************************
166 * SHInvokeCommandWithFlagsAndSite [SHLWAPI.571]
167 */
173 _In_ IShellFolder* pShellFolder,
174 _In_ LPCITEMIDLIST pidl,
175 _In_ UINT fCMIC,
176 _In_opt_ LPCSTR pszVerb)
177{
179 if (pShellFolder)
180 {
181 IContextMenu *pCM;
182 hr = pShellFolder->GetUIObjectOf(hWnd, 1, &pidl, IID_IContextMenu, NULL, (void**)&pCM);
183 if (SUCCEEDED(hr))
184 {
185 fCMIC |= CMIC_MASK_FLAG_LOG_USAGE;
186 hr = SHInvokeCommandOnContextMenuEx(hWnd, pUnk, pCM, fCMIC, 0, pszVerb, NULL);
187 pCM->Release();
188 }
189 }
190 return hr;
191}
192
193
194/*************************************************************************
195 * IContextMenu_Invoke [SHLWAPI.207]
196 *
197 * Used by Win:SHELL32!CISFBand::_TrySimpleInvoke.
198 */
202 _In_ IContextMenu *pContextMenu,
203 _In_ HWND hwnd,
204 _In_ LPCSTR lpVerb,
206{
207 TRACE("(%p, %p, %s, %u)\n", pContextMenu, hwnd, debugstr_a(lpVerb), uFlags);
209 uFlags, lpVerb, NULL, false);
210 return !FAILED_UNEXPECTEDLY(hr);
211}
212
213/*************************************************************************
214 * PathFileExistsDefExtAndAttributesW [SHLWAPI.511]
215 *
216 * @param pszPath The path string.
217 * @param dwWhich The WHICH_... flags.
218 * @param pdwFileAttributes A pointer to the file attributes. Optional.
219 * @return TRUE if successful.
220 */
223 _Inout_ LPWSTR pszPath,
224 _In_ DWORD dwWhich,
225 _Out_opt_ LPDWORD pdwFileAttributes)
226{
227 TRACE("(%s, 0x%lX, %p)\n", debugstr_w(pszPath), dwWhich, pdwFileAttributes);
228
229 if (pdwFileAttributes)
230 *pdwFileAttributes = INVALID_FILE_ATTRIBUTES;
231
232 if (!pszPath)
233 return FALSE;
234
235 if (!dwWhich || (*PathFindExtensionW(pszPath) && (dwWhich & WHICH_OPTIONAL)))
236 return PathFileExistsAndAttributesW(pszPath, pdwFileAttributes);
237
238 if (!PathFileExistsDefExtW(pszPath, dwWhich))
239 {
240 if (pdwFileAttributes)
241 *pdwFileAttributes = INVALID_FILE_ATTRIBUTES;
242 return FALSE;
243 }
244
245 if (pdwFileAttributes)
246 *pdwFileAttributes = GetFileAttributesW(pszPath);
247
248 return TRUE;
249}
250
251static inline BOOL
253{
254 return (hr == E_FAIL || hr == E_INVALIDARG || hr == E_NOTIMPL);
255}
256
257// Used for IShellFolder_GetDisplayNameOf
259{
260 SHGDNF uRemove;
261 SHGDNF uAdd;
263};
264static const RETRY_DATA g_RetryData[] =
265{
266 { SHGDN_FOREDITING, SHGDN_NORMAL, SFGDNO_RETRYALWAYS },
267 { SHGDN_FORADDRESSBAR, SHGDN_NORMAL, SFGDNO_RETRYALWAYS },
268 { SHGDN_NORMAL, SHGDN_FORPARSING, SFGDNO_RETRYALWAYS },
269 { SHGDN_FORPARSING, SHGDN_NORMAL, SFGDNO_RETRYWITHFORPARSING },
270 { SHGDN_INFOLDER, SHGDN_NORMAL, SFGDNO_RETRYALWAYS },
271};
272
273/*************************************************************************
274 * IShellFolder_GetDisplayNameOf [SHLWAPI.316]
275 *
276 * @note Don't confuse with <shobjidl.h> inline function of the same name.
277 * If the original call fails with the given uFlags, this function will
278 * retry with other flags to attempt retrieving any meaningful description.
279 */
282 _In_ IShellFolder *psf,
283 _In_ LPCITEMIDLIST pidl,
284 _In_ SHGDNF uFlags,
286 _In_ DWORD dwRetryFlags) // dwRetryFlags is an additional parameter
287{
288 HRESULT hr;
289
290 TRACE("(%p)->(%p, 0x%lX, %p, 0x%lX)\n", psf, pidl, uFlags, lpName, dwRetryFlags);
291
292 hr = psf->GetDisplayNameOf(pidl, uFlags, lpName);
294 return hr;
295
296 dwRetryFlags |= SFGDNO_RETRYALWAYS;
297
298 if ((uFlags & SHGDN_FORPARSING) == 0)
299 dwRetryFlags |= SFGDNO_RETRYWITHFORPARSING;
300
301 // Retry with other flags to get successful results
302 for (SIZE_T iEntry = 0; iEntry < _countof(g_RetryData); ++iEntry)
303 {
304 const RETRY_DATA *pData = &g_RetryData[iEntry];
305 if (!(dwRetryFlags & pData->dwRetryFlags))
306 continue;
307
308 SHGDNF uNewFlags = ((uFlags & ~pData->uRemove) | pData->uAdd);
309 if (uNewFlags == uFlags)
310 continue;
311
312 hr = psf->GetDisplayNameOf(pidl, uNewFlags, lpName);
314 break;
315
316 uFlags = uNewFlags; // Update flags every time
317 }
318
319 return hr;
320}
321
322/*************************************************************************
323 * IShellFolder_ParseDisplayName [SHLWAPI.317]
324 *
325 * @note Don't confuse with <shobjidl.h> inline function of the same name.
326 * This function is safer than IShellFolder::ParseDisplayName.
327 */
330 _In_ IShellFolder *psf,
331 _In_opt_ HWND hwndOwner,
332 _In_opt_ LPBC pbcReserved,
333 _In_ LPOLESTR lpszDisplayName,
334 _Out_opt_ ULONG *pchEaten,
336 _Out_opt_ ULONG *pdwAttributes)
337{
338 ULONG dummy1, dummy2;
339
340 TRACE("(%p)->(%p, %p, %s, %p, %p, %p)\n", psf, hwndOwner, pbcReserved,
341 debugstr_w(lpszDisplayName), pchEaten, ppidl, pdwAttributes);
342
343 if (!pdwAttributes)
344 {
345 dummy1 = 0;
346 pdwAttributes = &dummy1;
347 }
348
349 if (!pchEaten)
350 {
351 dummy2 = 0;
352 pchEaten = &dummy2;
353 }
354
355 if (ppidl)
356 *ppidl = NULL;
357
358 return psf->ParseDisplayName(hwndOwner, pbcReserved, lpszDisplayName, pchEaten,
359 ppidl, pdwAttributes);
360}
361
362/*************************************************************************
363 * IShellFolder_CompareIDs [SHLWAPI.551]
364 *
365 * @note Don't confuse with <shobjidl.h> inline function of the same name.
366 * This function tries IShellFolder2 if possible.
367 */
370 _In_ IShellFolder *psf,
374{
375 TRACE("(%p, %p, %p, %p)\n", psf, lParam, pidl1, pidl2);
376
377 if (lParam & ~(SIZE_T)SHCIDS_COLUMNMASK)
378 {
379 /* Try as IShellFolder2 if possible */
380 HRESULT hr = psf->QueryInterface(IID_IShellFolder2, (void **)&psf);
381 if (FAILED(hr))
382 lParam &= SHCIDS_COLUMNMASK;
383 else
384 psf->Release();
385 }
386
387 return psf->CompareIDs(lParam, pidl1, pidl2);
388}
unsigned int dir
Definition: maze.c:112
HWND hWnd
Definition: settings.c:17
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
void shell(int argc, const char *argv[])
Definition: cmds.c:1231
#define EXTERN_C
Definition: basetyps.h:12
LPARAM lParam
Definition: combotst.c:139
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_NOTIMPL
Definition: ddrawi.h:99
#define E_FAIL
Definition: ddrawi.h:102
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
UINT uFlags
Definition: api.c:59
#define MAX_PATH
Definition: compat.h:34
static const WCHAR version[]
Definition: asmname.c:66
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:652
HRESULT WINAPI IUnknown_SetSite(IUnknown *obj, IUnknown *site)
Definition: ordinal.c:1411
LPWSTR WINAPI PathFindExtensionW(LPCWSTR lpszPath)
Definition: path.c:447
BOOL WINAPI PathFileExistsAndAttributesW(LPCWSTR lpszPath, DWORD *dwAttr)
Definition: path.c:1832
BOOL WINAPI PathFileExistsDefExtW(LPWSTR lpszPath, DWORD dwWhich)
Definition: path.c:1117
DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
Definition: string.c:2667
INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
Definition: string.c:2791
EXTERN_C HRESULT WINAPI SHInvokeCommandOnContextMenu(_In_opt_ HWND hWnd, _In_opt_ IUnknown *pUnk, _In_ IContextMenu *pCM, _In_ UINT fCMIC, _In_opt_ LPCSTR pszVerb)
Definition: utils.cpp:155
EXTERN_C HRESULT WINAPI SHInvokeCommandWithFlagsAndSite(_In_opt_ HWND hWnd, _In_opt_ IUnknown *pUnk, _In_ IShellFolder *pShellFolder, _In_ LPCITEMIDLIST pidl, _In_ UINT fCMIC, _In_opt_ LPCSTR pszVerb)
Definition: utils.cpp:170
EXTERN_C HRESULT WINAPI SHInvokeCommandOnContextMenuEx(_In_opt_ HWND hWnd, _In_opt_ IUnknown *pUnk, _In_ IContextMenu *pCM, _In_ UINT fCMIC, _In_ UINT fCMF, _In_opt_ LPCSTR pszVerb, _In_opt_ LPCWSTR pwszDir)
Definition: utils.cpp:138
EXTERN_C BOOL WINAPI IContextMenu_Invoke(_In_ IContextMenu *pContextMenu, _In_ HWND hwnd, _In_ LPCSTR lpVerb, _In_ UINT uFlags)
Definition: utils.cpp:201
static const RETRY_DATA g_RetryData[]
Definition: utils.cpp:264
static HRESULT SHInvokeCommandOnContextMenuInternal(_In_opt_ HWND hWnd, _In_opt_ IUnknown *pUnk, _In_ IContextMenu *pCM, _In_ UINT fCMIC, _In_ UINT fCMF, _In_opt_ LPCSTR pszVerb, _In_opt_ LPCWSTR pwszDir, _In_ bool ForceQCM)
Definition: utils.cpp:50
#define FAILED_UNEXPECTEDLY
Definition: utils.cpp:37
#define IShellFolder_ParseDisplayName
Definition: utils.cpp:14
#define IShellFolder_CompareIDs
Definition: utils.cpp:15
static WORD GetVersionMajorMinor()
Definition: utils.cpp:43
BOOL WINAPI PathFileExistsDefExtAndAttributesW(_Inout_ LPWSTR pszPath, _In_ DWORD dwWhich, _Out_opt_ LPDWORD pdwFileAttributes)
Definition: utils.cpp:222
#define IShellFolder_GetDisplayNameOf
Definition: utils.cpp:13
static BOOL SHLWAPI_IsBogusHRESULT(HRESULT hr)
Definition: utils.cpp:252
static void *static void *static LPDIRECTPLAY IUnknown * pUnk
Definition: dplayx.c:30
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
HRESULT QueryInterface([in] REFIID riid, [out, iid_is(riid)] void **ppvObject)
ULONG Release()
nsrefcnt Release()
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define LOBYTE(W)
Definition: jmemdos.c:487
#define HIBYTE(W)
Definition: jmemdos.c:486
#define debugstr_a
Definition: kernel32.h:31
#define debugstr_w
Definition: kernel32.h:32
static LPOLESTR
Definition: stg_prop.c:27
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:63
#define _Out_opt_
Definition: ms_sal.h:346
#define _Inout_
Definition: ms_sal.h:378
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
unsigned int UINT
Definition: ndis.h:50
interface IBindCtx * LPBC
Definition: objfwd.h:18
DWORD WINAPI GetVersion()
Definition: redirtest.c:5
#define _WIN32_WINNT_WIN7
Definition: sdkddkver.h:28
HRESULT hr
Definition: shlfolder.c:183
#define WHICH_OPTIONAL
const ITEMIDLIST_RELATIVE UNALIGNED * PCUIDLIST_RELATIVE
Definition: shtypes.idl:57
const ITEMIDLIST UNALIGNED * LPCITEMIDLIST
Definition: shtypes.idl:42
#define _countof(array)
Definition: sndvol32.h:70
#define TRACE(s)
Definition: solgame.cpp:4
SHGDNF uAdd
Definition: utils.cpp:261
SHGDNF uRemove
Definition: utils.cpp:260
DWORD dwRetryFlags
Definition: utils.cpp:262
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1830
#define MAKEWORD(a, b)
Definition: typedefs.h:248
ULONG_PTR SIZE_T
Definition: typedefs.h:80
uint32_t * LPDWORD
Definition: typedefs.h:59
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG
Definition: typedefs.h:59
#define MAXSHORT
Definition: umtypes.h:114
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
_In_ LPCSTR lpName
Definition: winbase.h:2789
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LPARAM
Definition: windef.h:208
HICON HCURSOR
Definition: windef.h:299
#define WINAPI
Definition: msvc.h:6
HMENU WINAPI CreatePopupMenu(void)
Definition: menu.c:838
UINT WINAPI GetMenuDefaultItem(_In_ HMENU hMenu, _In_ UINT fByPos, _In_ UINT gmdiFlags)
#define IS_INTRESOURCE(i)
Definition: winuser.h:580
HCURSOR WINAPI SetCursor(_In_opt_ HCURSOR)
HCURSOR WINAPI LoadCursorW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2149
#define MAKEINTRESOURCEA(i)
Definition: winuser.h:581
BOOL WINAPI DestroyMenu(_In_ HMENU)
#define IDC_WAIT
Definition: winuser.h:689
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
#define SW_NORMAL
Definition: winuser.h:772
const char * LPCSTR
Definition: xmlstorage.h:183
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
char CHAR
Definition: xmlstorage.h:175