ReactOS 0.4.16-dev-983-g23ad936
util.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Picture and Fax Viewer
3 * LICENSE: GPL-2.0 (https://spdx.org/licenses/GPL-2.0)
4 * PURPOSE: Utility routines
5 * COPYRIGHT: Copyright 2025 Whindmar Saksit <whindsaks@proton.me>
6 */
7
8#include "shimgvw.h"
9#include <windowsx.h>
10#include <shlobj.h>
11#include <shellapi.h>
12#include <shellutils.h>
13#include <shlwapi_undoc.h>
14
16
17static int
19{
20 MENUITEMINFOW mii;
21 mii.cbSize = FIELD_OFFSET(MENUITEMINFOW, hbmpItem); /* USER32 version agnostic */
22 mii.fMask = MIIM_ID;
23 mii.cch = 0;
24 return GetMenuItemInfoW(hMenu, Pos, TRUE, &mii) ? mii.wID : -1;
25}
26
27static BOOL
29{
30 MENUITEMINFOW mii;
31 mii.cbSize = FIELD_OFFSET(MENUITEMINFOW, hbmpItem); /* USER32 version agnostic */
32 mii.fMask = MIIM_FTYPE;
33 mii.cch = 0;
34 return GetMenuItemInfoW(hMenu, Pos, TRUE, &mii) && (mii.fType & MFT_SEPARATOR);
35}
36
37static BOOL
39{
40 WCHAR buf[MAX_PATH * 3];
43 return hr == S_OK && *Assoc == L'.' && StrStrW(buf, L",ImageView_Fullscreen");
44}
45
46static void
47ModifyShellContextMenu(IContextMenu *pCM, HMENU hMenu, UINT CmdIdFirst, PCWSTR Assoc)
48{
49 HRESULT hr;
50 for (UINT i = 0, c = GetMenuItemCount(hMenu); i < c; ++i)
51 {
52 WCHAR buf[200];
53 UINT id = GetMenuItemIdByPos(hMenu, i);
54 if (id == (UINT)-1)
55 continue;
56
58 /* Note: We just ask for the wide string because all the items we care about come from shell32 and it handles both */
59 hr = IContextMenu_GetCommandString(pCM, id - CmdIdFirst, GCS_VERBW, NULL, (char*)buf, _countof(buf));
60 if (SUCCEEDED(hr))
61 {
63 if (IsSelfShellVerb(Assoc, buf))
64 ++remove;
65 else if (!lstrcmpiW(L"cut", buf) || !lstrcmpiW(L"paste", buf) || !lstrcmpiW(L"pastelink", buf) ||
66 !lstrcmpiW(L"delete", buf) || !lstrcmpiW(L"link", buf))
67 ++remove;
68
69 if (remove && DeleteMenu(hMenu, i, MF_BYPOSITION))
70 {
71 if (i-- > 0)
72 {
73 if (IsMenuSeparator(hMenu, i) && IsMenuSeparator(hMenu, i + 1))
74 DeleteMenu(hMenu, i, MF_BYPOSITION);
75 }
76 }
77 }
78 }
79
80 while (IsMenuSeparator(hMenu, 0) && DeleteMenu(hMenu, 0, MF_BYPOSITION)) {}
81}
82
83static LRESULT CALLBACK
85{
86 LRESULT lRes = 0;
88 lRes = DefWindowProc(hwnd, uMsg, wParam, lParam);
89 return lRes;
90}
91
92static void
94{
95 enum { first = 1, last = 0x7fff };
96 HRESULT hr;
97 HMENU hMenu = CreatePopupMenu();
98 UINT cmf = GetKeyState(VK_SHIFT) < 0 ? CMF_EXTENDEDVERBS : 0;
99
101 if ((int)lParam == -1)
102 {
103 RECT rect;
105 pt.x = (rect.left + rect.right) / 2;
106 pt.y = rect.top;
107 }
108
109 g_pContextMenu = pCM;
111 if (!hwnd)
112 goto die;
113 hr = IContextMenu_QueryContextMenu(pCM, hMenu, 0, first, last, cmf | CMF_NODEFAULT);
114 if (SUCCEEDED(hr))
115 {
116 UINT id;
118 id = TrackPopupMenuEx(hMenu, TPM_RETURNCMD, pt.x, pt.y, hwnd, NULL);
119 if (id)
120 {
121 UINT flags = (GetKeyState(VK_SHIFT) < 0 ? CMIC_MASK_SHIFT_DOWN : 0) |
122 (GetKeyState(VK_CONTROL) < 0 ? CMIC_MASK_CONTROL_DOWN : 0);
123 CMINVOKECOMMANDINFO ici = { sizeof(ici), flags, hwnd, MAKEINTRESOURCEA(id - first) };
124 ici.nShow = SW_SHOW;
125 hr = IContextMenu_InvokeCommand(pCM, &ici);
126 }
127 }
129die:
130 DestroyMenu(hMenu);
132}
133
136{
138 IShellFolder *pSF;
139 PCUITEMID_CHILD pidlItem;
141 *ppv = NULL;
142 if (pidl && SUCCEEDED(SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &pSF), &pidlItem)))
143 {
144 hr = IShellFolder_GetUIObjectOf(pSF, hwnd, 1, &pidlItem, riid, NULL, ppv);
145 IShellFolder_Release(pSF);
146 }
147 SHFree(pidl);
148 return hr;
149}
150
151void
153{
154 IContextMenu *pCM;
156 if (SUCCEEDED(hr))
157 {
159 IContextMenu_Release(pCM);
160 }
161}
162
163typedef struct _ENABLECOMMANDDATA
164{
171
172static DWORD CALLBACK
174{
175 enum { first = 1, last = 0x7fff };
176 ENABLECOMMANDDATA *pData = ThreadParam;
177 IContextMenu *pCM;
179 if (SUCCEEDED(hr))
180 {
181 HMENU hMenu = CreatePopupMenu();
182 hr = IContextMenu_QueryContextMenu(pCM, hMenu, 0, first, last, CMF_NORMAL);
183 if (SUCCEEDED(hr))
184 {
185 for (UINT i = 0, c = GetMenuItemCount(hMenu); i < c; ++i)
186 {
187 WCHAR buf[200];
188 UINT id = GetMenuItemIdByPos(hMenu, i);
189 if (id == (UINT)-1)
190 continue;
191
192 *buf = UNICODE_NULL;
193 hr = IContextMenu_GetCommandString(pCM, id - first, GCS_VERBW, NULL, (char*)buf, _countof(buf));
194 if (SUCCEEDED(hr) && !lstrcmpiW(buf, pData->Verb))
195 {
196 PostMessageW(pData->hwnd, WM_UPDATECOMMANDSTATE, MAKELONG(pData->CmdId, TRUE), pData->ImageId);
197 break;
198 }
199 }
200 }
201 DestroyMenu(hMenu);
202 IContextMenu_Release(pCM);
203 }
204 SHFree(pData);
205 return 0;
206}
207
208void
210{
211 const SIZE_T cch = lstrlenW(File) + 1;
213 if (pData)
214 {
215 pData->hwnd = hwnd;
216 pData->Verb = Verb; // Note: This assumes the string is valid for the lifetime of the thread.
217 pData->CmdId = CmdId;
218 pData->ImageId = ImageId;
219 CopyMemory(pData->File, File, cch * sizeof(*File));
221 }
222}
223
224void
226{
228 if (!*File)
229 return;
230
231 sei.hwnd = hwnd;
232 sei.lpVerb = Verb;
233 sei.lpFile = File;
234 sei.nShow = SW_SHOW;
235 if (!ShellExecuteExW(&sei))
236 {
237 DPRINT1("ShellExecuteExW(%ls, %ls) failed with code %ld\n", Verb, File, GetLastError());
238 }
239 else if (Quit)
240 {
241 // Destroy the window to quit the application
243 }
244}
245
246UINT
248{
249 return SHELL_ErrorBox(hwnd, Error);
250}
251
252void
254{
256}
#define DPRINT1
Definition: precomp.h:8
BOOL Error
Definition: chkdsk.c:66
Definition: File.h:16
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
ush Pos
Definition: deflate.h:92
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
Definition: string.c:590
#define ERROR_NOT_SUPPORTED
Definition: compat.h:100
#define MAX_PATH
Definition: compat.h:34
#define CALLBACK
Definition: compat.h:35
#define lstrlenW
Definition: compat.h:750
int WINAPI lstrcmpiW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4262
void WINAPI SHFree(LPVOID pv)
Definition: shellole.c:326
LPVOID WINAPI SHAlloc(SIZE_T len)
Definition: shellole.c:304
void EnableCommandIfVerbExists(UINT ImageId, HWND hwnd, UINT CmdId, PCWSTR Verb, PCWSTR File)
Definition: util.c:209
static void ModifyShellContextMenu(IContextMenu *pCM, HMENU hMenu, UINT CmdIdFirst, PCWSTR Assoc)
Definition: util.c:47
static LRESULT CALLBACK ShellContextMenuWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: util.c:84
void ShellExecuteVerb(HWND hwnd, PCWSTR Verb, PCWSTR File, BOOL Quit)
Definition: util.c:225
static BOOL IsMenuSeparator(HMENU hMenu, UINT Pos)
Definition: util.c:28
void DoShellContextMenuOnFile(HWND hwnd, PCWSTR File, LPARAM lParam)
Definition: util.c:152
IContextMenu * g_pContextMenu
Definition: util.c:15
static BOOL IsSelfShellVerb(PCWSTR Assoc, PCWSTR Verb)
Definition: util.c:38
static int GetMenuItemIdByPos(HMENU hMenu, UINT Pos)
Definition: util.c:18
static DWORD CALLBACK EnableCommandIfVerbExistsProc(LPVOID ThreadParam)
Definition: util.c:173
void DisplayHelp(HWND hwnd)
Definition: util.c:253
UINT ErrorBox(HWND hwnd, UINT Error)
Definition: util.c:247
struct _ENABLECOMMANDDATA ENABLECOMMANDDATA
HRESULT GetUIObjectOfPath(HWND hwnd, PCWSTR File, REFIID riid, void **ppv)
Definition: util.c:135
static void DoShellContextMenu(HWND hwnd, IContextMenu *pCM, PCWSTR File, LPARAM lParam)
Definition: util.c:93
HRESULT WINAPI AssocQueryStringW(ASSOCF cfFlags, ASSOCSTR str, LPCWSTR pszAssoc, LPCWSTR pszExtra, LPWSTR pszOut, DWORD *pcchOut)
Definition: assoc.c:436
HWND WINAPI SHCreateWorkerWindowW(WNDPROC wndProc, HWND hWndParent, DWORD dwExStyle, DWORD dwStyle, HMENU hMenu, LONG_PTR wnd_extra)
Definition: ordinal.c:3004
LPWSTR WINAPI PathFindExtensionW(LPCWSTR lpszPath)
Definition: path.c:447
BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE pfnThreadProc, VOID *pData, DWORD dwFlags, LPTHREAD_START_ROUTINE pfnCallback)
Definition: thread.c:356
#define pt(x, y)
Definition: drawing.c:79
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
const GLubyte * c
Definition: glext.h:8905
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLbitfield flags
Definition: glext.h:7161
const GLint * first
Definition: glext.h:5794
GLuint id
Definition: glext.h:5910
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
REFIID riid
Definition: atlbase.h:39
REFIID LPVOID * ppv
Definition: atlbase.h:39
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define c
Definition: ke_i.h:80
#define die(str)
Definition: mkdosfs.c:347
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
static DWORD DWORD void LPSTR DWORD cch
Definition: str.c:202
static UINT UINT last
Definition: font.c:45
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:63
int remove
Definition: msacm.c:1366
unsigned int UINT
Definition: ndis.h:50
#define UNICODE_NULL
#define L(x)
Definition: ntvdm.h:50
#define WS_CHILD
Definition: pedump.c:617
#define WS_VISIBLE
Definition: pedump.c:620
HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast)
Definition: pidl.c:1462
#define REFIID
Definition: guiddef.h:118
#define DefWindowProc
Definition: ros2win.h:31
HRESULT WINAPI SHForwardContextMenuMsg(IUnknown *pUnk, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult, BOOL useIContextMenu2)
Definition: rosordinal.c:11
#define SEE_MASK_ASYNCOK
Definition: shellapi.h:54
#define SEE_MASK_INVOKEIDLIST
Definition: shellapi.h:28
#define SHELL_ErrorBox
Definition: shellutils.h:126
#define WM_UPDATECOMMANDSTATE
Definition: shimgvw.h:33
BOOL WINAPI DECLSPEC_HOTPATCH ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:2452
HRESULT hr
Definition: shlfolder.c:183
#define ILCreateFromPath
Definition: shlobj.h:2514
@ ASSOCSTR_COMMAND
Definition: shlwapi.h:612
@ ASSOCF_NOTRUNCATE
Definition: shlwapi.h:597
#define CTF_COINIT
Definition: shlwapi.h:1981
#define CTF_INSIST
Definition: shlwapi.h:1978
const ITEMID_CHILD UNALIGNED * PCUITEMID_CHILD
Definition: shtypes.idl:70
#define _countof(array)
Definition: sndvol32.h:70
& rect
Definition: startmenu.cpp:1413
PCWSTR Verb
Definition: util.c:166
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1830
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define ANYSIZE_ARRAY
Definition: typedefs.h:46
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define MAKELONG(a, b)
Definition: typedefs.h:249
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define CopyMemory
Definition: winbase.h:1741
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
UINT_PTR WPARAM
Definition: windef.h:207
#define GET_Y_LPARAM(lp)
Definition: windowsx.h:300
#define GET_X_LPARAM(lp)
Definition: windowsx.h:299
#define HRESULT_FROM_WIN32(x)
Definition: winerror.h:92
HMENU WINAPI CreatePopupMenu(void)
Definition: menu.c:838
#define MIIM_ID
Definition: winuser.h:733
int WINAPI GetMenuItemCount(_In_opt_ HMENU)
BOOL WINAPI PostMessageW(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
BOOL WINAPI GetWindowRect(_In_ HWND, _Out_ LPRECT)
#define MIIM_FTYPE
Definition: winuser.h:740
#define VK_CONTROL
Definition: winuser.h:2214
BOOL WINAPI DeleteMenu(_In_ HMENU, _In_ UINT, _In_ UINT)
#define MFT_SEPARATOR
Definition: winuser.h:755
BOOL WINAPI TrackPopupMenuEx(_In_ HMENU, _In_ UINT, _In_ int, _In_ int, _In_ HWND, _In_opt_ LPTPMPARAMS)
#define MF_BYPOSITION
Definition: winuser.h:203
#define MAKEINTRESOURCEA(i)
Definition: winuser.h:581
BOOL WINAPI DestroyMenu(_In_ HMENU)
BOOL WINAPI GetMenuItemInfoW(_In_ HMENU, _In_ UINT, _In_ BOOL, _Inout_ LPMENUITEMINFOW)
#define VK_SHIFT
Definition: winuser.h:2213
#define SW_SHOW
Definition: winuser.h:786
#define TPM_RETURNCMD
Definition: winuser.h:2398
BOOL WINAPI DestroyWindow(_In_ HWND)
SHORT WINAPI GetKeyState(_In_ int)
#define IID_PPV_ARG(Itype, ppType)
__wchar_t WCHAR
Definition: xmlstorage.h:180