ReactOS 0.4.15-dev-8434-g155a7c7
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
37
38/*************************************************************************
39 * IContextMenu_Invoke [SHLWAPI.207]
40 *
41 * Used by Win:SHELL32!CISFBand::_TrySimpleInvoke.
42 */
46 _In_ IContextMenu *pContextMenu,
48 _In_ LPCSTR lpVerb,
50{
51 CMINVOKECOMMANDINFO info;
52 BOOL ret = FALSE;
53 INT iDefItem = 0;
54 HMENU hMenu = NULL;
55 HCURSOR hOldCursor;
56
57 TRACE("(%p, %p, %s, %u)\n", pContextMenu, hwnd, debugstr_a(lpVerb), uFlags);
58
59 if (!pContextMenu)
60 return FALSE;
61
62 hOldCursor = SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_WAIT));
63
64 ZeroMemory(&info, sizeof(info));
65 info.cbSize = sizeof(info);
66 info.hwnd = hwnd;
67 info.nShow = SW_NORMAL;
68 info.lpVerb = lpVerb;
69
70 if (IS_INTRESOURCE(lpVerb))
71 {
72 hMenu = CreatePopupMenu();
73 if (hMenu)
74 {
75 pContextMenu->QueryContextMenu(hMenu, 0, 1, MAXSHORT, uFlags | CMF_DEFAULTONLY);
76 iDefItem = GetMenuDefaultItem(hMenu, 0, 0);
77 if (iDefItem != -1)
78 info.lpVerb = MAKEINTRESOURCEA(iDefItem - 1);
79 }
80 }
81
82 if (iDefItem != -1 || info.lpVerb)
83 {
84 if (!hwnd)
85 info.fMask |= CMIC_MASK_FLAG_NO_UI;
86 ret = SUCCEEDED(pContextMenu->InvokeCommand(&info));
87 }
88
89 /* Invoking itself doesn't need the menu object, but getting the command info
90 needs the menu. */
91 if (hMenu)
92 DestroyMenu(hMenu);
93
94 SetCursor(hOldCursor);
95
96 return ret;
97}
98
99/*************************************************************************
100 * PathFileExistsDefExtAndAttributesW [SHLWAPI.511]
101 *
102 * @param pszPath The path string.
103 * @param dwWhich The WHICH_... flags.
104 * @param pdwFileAttributes A pointer to the file attributes. Optional.
105 * @return TRUE if successful.
106 */
109 _Inout_ LPWSTR pszPath,
110 _In_ DWORD dwWhich,
111 _Out_opt_ LPDWORD pdwFileAttributes)
112{
113 TRACE("(%s, 0x%lX, %p)\n", debugstr_w(pszPath), dwWhich, pdwFileAttributes);
114
115 if (pdwFileAttributes)
116 *pdwFileAttributes = INVALID_FILE_ATTRIBUTES;
117
118 if (!pszPath)
119 return FALSE;
120
121 if (!dwWhich || (*PathFindExtensionW(pszPath) && (dwWhich & WHICH_OPTIONAL)))
122 return PathFileExistsAndAttributesW(pszPath, pdwFileAttributes);
123
124 if (!PathFileExistsDefExtW(pszPath, dwWhich))
125 {
126 if (pdwFileAttributes)
127 *pdwFileAttributes = INVALID_FILE_ATTRIBUTES;
128 return FALSE;
129 }
130
131 if (pdwFileAttributes)
132 *pdwFileAttributes = GetFileAttributesW(pszPath);
133
134 return TRUE;
135}
136
137static inline BOOL
139{
140 return (hr == E_FAIL || hr == E_INVALIDARG || hr == E_NOTIMPL);
141}
142
143// Used for IShellFolder_GetDisplayNameOf
145{
146 SHGDNF uRemove;
147 SHGDNF uAdd;
149};
150static const RETRY_DATA g_RetryData[] =
151{
152 { SHGDN_FOREDITING, SHGDN_NORMAL, SFGDNO_RETRYALWAYS },
153 { SHGDN_FORADDRESSBAR, SHGDN_NORMAL, SFGDNO_RETRYALWAYS },
154 { SHGDN_NORMAL, SHGDN_FORPARSING, SFGDNO_RETRYALWAYS },
155 { SHGDN_FORPARSING, SHGDN_NORMAL, SFGDNO_RETRYWITHFORPARSING },
156 { SHGDN_INFOLDER, SHGDN_NORMAL, SFGDNO_RETRYALWAYS },
157};
158
159/*************************************************************************
160 * IShellFolder_GetDisplayNameOf [SHLWAPI.316]
161 *
162 * @note Don't confuse with <shobjidl.h> inline function of the same name.
163 * If the original call fails with the given uFlags, this function will
164 * retry with other flags to attempt retrieving any meaningful description.
165 */
168 _In_ IShellFolder *psf,
169 _In_ LPCITEMIDLIST pidl,
170 _In_ SHGDNF uFlags,
172 _In_ DWORD dwRetryFlags) // dwRetryFlags is an additional parameter
173{
174 HRESULT hr;
175
176 TRACE("(%p)->(%p, 0x%lX, %p, 0x%lX)\n", psf, pidl, uFlags, lpName, dwRetryFlags);
177
178 hr = psf->GetDisplayNameOf(pidl, uFlags, lpName);
180 return hr;
181
182 dwRetryFlags |= SFGDNO_RETRYALWAYS;
183
184 if ((uFlags & SHGDN_FORPARSING) == 0)
185 dwRetryFlags |= SFGDNO_RETRYWITHFORPARSING;
186
187 // Retry with other flags to get successful results
188 for (SIZE_T iEntry = 0; iEntry < _countof(g_RetryData); ++iEntry)
189 {
190 const RETRY_DATA *pData = &g_RetryData[iEntry];
191 if (!(dwRetryFlags & pData->dwRetryFlags))
192 continue;
193
194 SHGDNF uNewFlags = ((uFlags & ~pData->uRemove) | pData->uAdd);
195 if (uNewFlags == uFlags)
196 continue;
197
198 hr = psf->GetDisplayNameOf(pidl, uNewFlags, lpName);
200 break;
201
202 uFlags = uNewFlags; // Update flags every time
203 }
204
205 return hr;
206}
207
208/*************************************************************************
209 * IShellFolder_ParseDisplayName [SHLWAPI.317]
210 *
211 * @note Don't confuse with <shobjidl.h> inline function of the same name.
212 * This function is safer than IShellFolder::ParseDisplayName.
213 */
216 _In_ IShellFolder *psf,
217 _In_opt_ HWND hwndOwner,
218 _In_opt_ LPBC pbcReserved,
219 _In_ LPOLESTR lpszDisplayName,
220 _Out_opt_ ULONG *pchEaten,
222 _Out_opt_ ULONG *pdwAttributes)
223{
224 ULONG dummy1, dummy2;
225
226 TRACE("(%p)->(%p, %p, %s, %p, %p, %p)\n", psf, hwndOwner, pbcReserved,
227 debugstr_w(lpszDisplayName), pchEaten, ppidl, pdwAttributes);
228
229 if (!pdwAttributes)
230 {
231 dummy1 = 0;
232 pdwAttributes = &dummy1;
233 }
234
235 if (!pchEaten)
236 {
237 dummy2 = 0;
238 pchEaten = &dummy2;
239 }
240
241 if (ppidl)
242 *ppidl = NULL;
243
244 return psf->ParseDisplayName(hwndOwner, pbcReserved, lpszDisplayName, pchEaten,
245 ppidl, pdwAttributes);
246}
247
248/*************************************************************************
249 * IShellFolder_CompareIDs [SHLWAPI.551]
250 *
251 * @note Don't confuse with <shobjidl.h> inline function of the same name.
252 * This function tries IShellFolder2 if possible.
253 */
256 _In_ IShellFolder *psf,
260{
261 TRACE("(%p, %p, %p, %p)\n", psf, lParam, pidl1, pidl2);
262
263 if (lParam & ~(SIZE_T)SHCIDS_COLUMNMASK)
264 {
265 /* Try as IShellFolder2 if possible */
266 HRESULT hr = psf->QueryInterface(IID_IShellFolder2, (void **)&psf);
267 if (FAILED(hr))
268 lParam &= SHCIDS_COLUMNMASK;
269 else
270 psf->Release();
271 }
272
273 return psf->CompareIDs(lParam, pidl1, pidl2);
274}
#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
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:652
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
EXTERN_C BOOL WINAPI IContextMenu_Invoke(_In_ IContextMenu *pContextMenu, _In_ HWND hwnd, _In_ LPCSTR lpVerb, _In_ UINT uFlags)
Definition: utils.cpp:45
static const RETRY_DATA g_RetryData[]
Definition: utils.cpp:150
#define IShellFolder_ParseDisplayName
Definition: utils.cpp:14
#define IShellFolder_CompareIDs
Definition: utils.cpp:15
BOOL WINAPI PathFileExistsDefExtAndAttributesW(_Inout_ LPWSTR pszPath, _In_ DWORD dwWhich, _Out_opt_ LPDWORD pdwFileAttributes)
Definition: utils.cpp:108
#define IShellFolder_GetDisplayNameOf
Definition: utils.cpp:13
static BOOL SHLWAPI_IsBogusHRESULT(HRESULT hr)
Definition: utils.cpp:138
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
HRESULT QueryInterface([in] REFIID riid, [out, iid_is(riid)] void **ppvObject)
nsrefcnt Release()
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#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
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:147
SHGDNF uRemove
Definition: utils.cpp:146
DWORD dwRetryFlags
Definition: utils.cpp:148
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1830
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
int ret
#define ZeroMemory
Definition: winbase.h:1712
_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 SW_NORMAL
Definition: winuser.h:769
const char * LPCSTR
Definition: xmlstorage.h:183
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185