ReactOS 0.4.17-dev-116-ga4b6fe9
SHInvokeCommandsOnContextMenu.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Tests for SHInvokeCommandsOnContextMenu
5 * COPYRIGHT: Copyright 2026 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 */
7
8#include <apitest.h>
9#include <windows.h>
10#include <shlwapi.h>
11#include <objbase.h>
12#include <shellapi.h>
13#include <shobjidl.h>
14
16 DWORD, PCSTR *, UINT);
17
19
21{
25
29
34
35 STDMETHODIMP_(ULONG) AddRef() override { return 1; }
36 STDMETHODIMP_(ULONG) Release() override { return 1; }
38 {
39 return E_NOINTERFACE;
40 }
41
44 {
47
49 return queryResult;
50
51 if (defaultItemId != (UINT)-1)
52 {
53 AppendMenuA(hmenu, MF_STRING, idCmdFirst + defaultItemId - 1, "Item");
54 SetMenuDefaultItem(hmenu, idCmdFirst + defaultItemId - 1, FALSE);
55 }
56 return queryResult;
57 }
58
60 {
62 const CMINVOKECOMMANDINFOEX* iciex = reinterpret_cast<const CMINVOKECOMMANDINFOEX*>(pici);
63
64 lastFMask = iciex->fMask;
65 lastHadUnicode = !!(iciex->fMask & CMIC_MASK_UNICODE);
66
67 if (HIWORD(iciex->lpVerb))
68 lstrcpyA(lastVerb, iciex->lpVerb);
69 else
71
72 if (lastHadUnicode && iciex->lpVerbW && HIWORD(iciex->lpVerbW))
73 lstrcpyW(lastVerbW, iciex->lpVerbW);
74 else
76
77 return invokeResult;
78 }
79
81 {
82 return E_NOTIMPL;
83 }
84};
85
86struct MockSite : public IUnknown
87{
88 STDMETHODIMP_(ULONG) AddRef() override { return 1; }
89 STDMETHODIMP_(ULONG) Release() override { return 1; }
91 {
92 return E_NOINTERFACE;
93 }
94};
95
97{
98protected:
100
101public:
103 {
105 }
107 {
109 }
110};
111
113{
116 ok_hr(hr, E_FAIL);
117 ok_int(cm.queryCalled, 1);
118 ok_int(cm.invokeCalled, 0);
119}
120
122{
124 cm.defaultItemId = 1;
125 cm.invokeResult = S_OK;
126
128 ok_hr(hr, S_OK);
129 ok_int(cm.queryCalled, 1);
130 ok_int(cm.invokeCalled, 1);
131}
132
134{
136 cm.defaultItemId = 1;
138 ok_int(!!(cm.lastQueryFlags & CMF_DEFAULTONLY), TRUE);
139}
140
142{
143 const char* verbs[] = { "open" };
146 ok_int(!!(cm.lastQueryFlags & CMF_DEFAULTONLY), FALSE);
147}
148
149static void SingleVerb_Success(void)
150{
151 const char* verbs[] = { "open" };
153 cm.invokeResult = S_OK;
154
156 ok_hr(hr, S_OK);
157 ok_int(cm.invokeCalled, 1);
158 ok_str(cm.lastVerb, "open");
159}
160
162{
163 const char* verbs[] = { "open", "print" };
165 cm.invokeResult = S_OK;
166
168 ok_hr(hr, S_OK);
169 ok_int(cm.invokeCalled, 1);
170 ok_str(cm.lastVerb, "open");
171}
172
173static void Cancelled_BreaksLoop(void)
174{
175 const char* verbs[] = { "open", "print" };
178
181 ok_int(cm.invokeCalled, 1);
182}
183
185{
186 const char* verbs[] = { "open" };
188 cm.invokeResult = S_OK;
189
192 ok_wstr(cm.lastVerbW, L"open");
193}
194
196{
198 const char* verbs[] = { "open" };
200 cm.invokeResult = S_OK;
201
203 ok_int(!!(cm.lastFMask & kMask), TRUE);
204}
205
207{
212
213 // IUnknown
214 STDMETHODIMP_(ULONG) AddRef() override { return 1; }
215 STDMETHODIMP_(ULONG) Release() override { return 1; }
217 {
218 if (riid == IID_IObjectWithSite) { *ppv = static_cast<IObjectWithSite*>(this); return S_OK; }
219 return E_NOINTERFACE;
220 }
221
222 // IObjectWithSite
224 {
225 if (pSite) siteSet = true;
226 else siteClear= true;
227 site = pSite;
228 return S_OK;
229 }
230 STDMETHODIMP GetSite(REFIID, void**) override { return E_NOTIMPL; }
231
232 // IContextMenu
234 {
235 ++queryCnt;
236 return S_OK;
237 }
240};
241
243{
245 MockSite mySite;
246
247 const char* verbs[] = { "open" };
249
250 ok_int(target.siteSet, TRUE);
251 ok_int(target.siteClear, TRUE);
252}
253
255{
257 cm.queryResult = E_FAIL;
258 cm.invokeResult = S_OK;
259 const char* verbs[] = { "open" };
260
262 ok_int(FAILED(hr), TRUE);
263 ok_int(cm.invokeCalled, 0);
264}
265
267{
270 {
271 capturedHwnd = pici->hwnd;
272 return S_OK;
273 }
274};
275
277{
278 HwndCaptureMock mock;
279 const char* verbs[] = { "open" };
280 HWND fakeHwnd = reinterpret_cast<HWND>(static_cast<ULONG_PTR>(0xDEADBEEF));
281
282 g_fnSHInvokeCommandsOnContextMenu(fakeHwnd, NULL, &mock, 0, verbs, 1);
283 ok_ptr(mock.capturedHwnd, fakeHwnd);
284}
285
287{
288 HINSTANCE hSHLWAPI = LoadLibraryW(L"shlwapi");
289 if (!hSHLWAPI)
290 {
291 skip("shlwapi not found\n");
292 return;
293 }
294
298 {
299 skip("SHInvokeCommandsOnContextMenu not found\n");
300 FreeLibrary(hSHLWAPI);
301 return;
302 }
303
316
317 FreeLibrary(hSHLWAPI);
318}
#define ok_hr(status, expected)
Definition: ACListISF.cpp:31
static void FMask_IsPassedToInvokeCommand(void)
static FN_SHInvokeCommandsOnContextMenu g_fnSHInvokeCommandsOnContextMenu
static void ZeroVerbs_QueryReceivesCMF_DEFAULTONLY(void)
static void PunkSite_SetAndClearedAroundCall(void)
static void NonZeroVerbs_QueryDoesNotReceiveCMF_DEFAULTONLY(void)
HRESULT(WINAPI * FN_SHInvokeCommandsOnContextMenu)(HWND, IUnknown *, IContextMenu *, DWORD, PCSTR *, UINT)
static void Hwnd_IsPassedToInvokeCommand(void)
static void Cancelled_BreaksLoop(void)
static void ZeroVerbs_WithDefaultItem_InvokesOnce(void)
static void MultipleVerbs_StopsOnFirstSuccess(void)
static void QueryFails_InvokeNotCalled(void)
static void ZeroVerbs_NoDefaultItem_ReturnsEFail(void)
static void AsciiVerb_SetsUnicodeMaskAndVerbW(void)
static void SingleVerb_Success(void)
#define ok_str(x, y)
Definition: atltest.h:127
#define skip(...)
Definition: atltest.h:64
#define ok_wstr(x, y)
Definition: atltest.h:130
#define START_TEST(x)
Definition: atltest.h:75
#define ok_int(expression, result)
Definition: atltest.h:134
#define ok_ptr(expression, result)
Definition: atltest.h:108
#define STDMETHODIMP
Definition: basetyps.h:43
Verb verbs[]
Definition: certutil.cpp:21
#define E_NOTIMPL
Definition: ddrawi.h:99
#define E_FAIL
Definition: ddrawi.h:102
HRESULT hr
Definition: delayimp.cpp:573
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
UINT uFlags
Definition: api.c:59
HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(void *reserved, DWORD model)
Definition: combase.c:2803
void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
Definition: combase.c:2842
#define GetProcAddress(x, y)
Definition: compat.h:753
#define FreeLibrary(x)
Definition: compat.h:748
HANDLE HWND
Definition: compat.h:19
#define MAX_PATH
Definition: compat.h:34
#define lstrcpyW
Definition: compat.h:749
#define LoadLibraryW(x)
Definition: compat.h:747
EXTERN_C HRESULT WINAPI SHInvokeCommandsOnContextMenu(_In_opt_ HWND hwnd, _In_opt_ IUnknown *punkSite, _In_ IContextMenu *pCM, _In_ DWORD fMask, _In_reads_opt_(cVerbs) PCSTR *pVerbs, _In_ UINT cVerbs)
Definition: utils.cpp:234
#define L(x)
Definition: resources.c:13
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
REFIID riid
Definition: atlbase.h:39
REFIID LPVOID * ppv
Definition: atlbase.h:39
ULONG AddRef()
ULONG Release()
#define S_OK
Definition: intsafe.h:52
#define FAILED(hr)
Definition: intsafe.h:51
LPSTR WINAPI lstrcpyA(LPSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:100
const IID IID_IObjectWithSite
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:60
static HMENU hmenu
Definition: win.c:78
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
unsigned int UINT
Definition: ndis.h:50
#define DWORD
Definition: nt_native.h:44
#define UNICODE_NULL
#define ANSI_NULL
@ COINIT_APARTMENTTHREADED
Definition: objbase.h:279
short WCHAR
Definition: pedump.c:58
char CHAR
Definition: pedump.c:57
#define REFIID
Definition: guiddef.h:118
#define SEE_MASK_NOASYNC
Definition: shellapi.h:35
#define SEE_MASK_FLAG_NO_UI
Definition: shellapi.h:38
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici) override
STDMETHODIMP QueryInterface(REFIID, void **) override
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici) override
STDMETHODIMP GetCommandString(UINT_PTR, UINT, UINT *, CHAR *, UINT) override
STDMETHODIMP QueryContextMenu(HMENU hmenu, UINT, UINT idCmdFirst, UINT, UINT uFlags) override
STDMETHODIMP_(ULONG) AddRef() override
STDMETHODIMP_(ULONG) Release() override
STDMETHODIMP QueryInterface(REFIID riid, void **ppv) override
STDMETHODIMP_(ULONG) Release() override
STDMETHODIMP SetSite(IUnknown *pSite) override
STDMETHODIMP QueryContextMenu(HMENU, UINT, UINT, UINT, UINT) override
STDMETHODIMP_(ULONG) AddRef() override
STDMETHODIMP GetCommandString(UINT_PTR, UINT, UINT *, CHAR *, UINT) override
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO) override
STDMETHODIMP GetSite(REFIID, void **) override
STDMETHODIMP QueryInterface(REFIID, void **) override
STDMETHODIMP_(ULONG) Release() override
STDMETHODIMP_(ULONG) AddRef() override
Definition: tools.h:99
int32_t INT
Definition: typedefs.h:58
const char * PCSTR
Definition: typedefs.h:52
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
#define HIWORD(l)
Definition: typedefs.h:247
#define HRESULT
Definition: msvc.h:7
#define WINAPI
Definition: msvc.h:6
static HRESULT HRESULT_FROM_WIN32(unsigned int x)
Definition: winerror.h:210
#define E_NOINTERFACE
Definition: winerror.h:3479
#define ERROR_CANCELLED
Definition: winerror.h:1055
BOOL WINAPI SetMenuDefaultItem(_In_ HMENU, _In_ UINT, _In_ UINT)
#define MF_STRING
Definition: winuser.h:138
BOOL WINAPI AppendMenuA(_In_ HMENU, _In_ UINT, _In_ UINT_PTR, _In_opt_ LPCSTR)
#define MAKEINTRESOURCEA(i)
Definition: winuser.h:581