Reactos
at master 369 lines 11 kB view raw
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 IsQSForward 5 * COPYRIGHT: Copyright 2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 6 */ 7 8#include <apitest.h> 9#include <docobj.h> 10#include <shlobj.h> 11#include <shlwapi.h> 12#include <shlwapi_undoc.h> 13#include <pseh/pseh2.h> 14#include <versionhelpers.h> 15 16static const BOOL g_bWin8 = IsWindows8OrGreater(); 17 18static HRESULT 19IsQSForwardMockup(_In_opt_ const GUID *pguidCmdGroup, _In_ ULONG cCmds, _In_ OLECMD *prgCmds) 20{ 21 DWORD cmdFlags = 0; 22 OLECMDID cmdID; 23 ULONG iCmd; 24 enum { 25 CMD_FLAG_SUPPORTED_BASIC = 0x1, 26 CMD_FLAG_SUPPORTED_ADVANCED = 0x2, 27 CMD_FLAG_NOT_SUPPORTED = 0x4, 28 }; 29 30 //TRACE("(%s, %lu, %p)\n", wine_dbgstr_guid(pguidCmdGroup), cCmds, prgCmds); 31 32 if ((LONG)cCmds <= 0) 33 return OLECMDERR_E_NOTSUPPORTED; 34 35 if (!pguidCmdGroup) 36 { 37 for (iCmd = 0; iCmd < cCmds; ++iCmd) 38 { 39 cmdID = (OLECMDID)prgCmds[iCmd].cmdID; 40 if (cmdID <= OLECMDID_PROPERTIES) 41 { 42 cmdFlags |= CMD_FLAG_NOT_SUPPORTED; // Not supported 43 continue; 44 } 45 46 if (cmdID <= OLECMDID_PASTE || cmdID == OLECMDID_SELECTALL) 47 { 48 cmdFlags |= CMD_FLAG_SUPPORTED_BASIC; 49 continue; 50 } 51 52 if (cmdID <= OLECMDID_UPDATECOMMANDS || 53 (OLECMDID_HIDETOOLBARS <= cmdID && cmdID != OLECMDID_ENABLE_INTERACTION)) 54 { 55 cmdFlags |= CMD_FLAG_NOT_SUPPORTED; // Not supported 56 continue; 57 } 58 59 cmdFlags |= CMD_FLAG_SUPPORTED_ADVANCED; 60 } 61 } 62 else 63 { 64 if (!IsEqualGUID(CGID_Explorer, *pguidCmdGroup)) 65 { 66 if (g_bWin8) 67 return OLECMDERR_E_UNKNOWNGROUP; 68 else 69 return OLECMDERR_E_NOTSUPPORTED; 70 } 71 72 for (iCmd = 0; iCmd < cCmds; ++iCmd) 73 { 74 cmdID = (OLECMDID)prgCmds[iCmd].cmdID; 75 if (cmdID == OLECMDID_SELECTALL || 76 (OLECMDID_SHOWFIND <= cmdID && cmdID <= OLECMDID_SHOWPRINT)) 77 { 78 cmdFlags |= CMD_FLAG_SUPPORTED_BASIC; 79 break; 80 } 81 } 82 } 83 84 if (!cmdFlags || (cmdFlags & CMD_FLAG_NOT_SUPPORTED)) 85 return OLECMDERR_E_NOTSUPPORTED; // Not supported 86 87 return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, cmdFlags); 88} 89 90static HRESULT 91MayQSForwardMockup( 92 _In_ IUnknown *lpUnknown, 93 _In_ INT nUnknown, 94 _In_opt_ const GUID *riidCmdGrp, 95 _In_ ULONG cCmds, 96 _Inout_ OLECMD *prgCmds, 97 _Inout_ OLECMDTEXT *pCmdText) 98{ 99 //TRACE("(%p, %d, %s, %d, %p, %p)\n", 100 // lpUnknown, nUnknown, wine_dbgstr_guid(riidCmdGrp), cCmds, prgCmds, pCmdText); 101 102 HRESULT hr = IsQSForwardMockup(riidCmdGrp, cCmds, prgCmds); 103 if (FAILED(hr) || !HRESULT_CODE(hr) || nUnknown <= 0) 104 return OLECMDERR_E_NOTSUPPORTED; 105 106 return IUnknown_QueryStatus(lpUnknown, *riidCmdGrp, cCmds, prgCmds, pCmdText); 107} 108 109static HRESULT 110MayExecForwardMockup( 111 _In_ IUnknown *lpUnknown, 112 _In_ INT nUnknown, 113 _In_opt_ const GUID *pguidCmdGroup, 114 _In_ DWORD nCmdID, 115 _In_ DWORD nCmdexecopt, 116 _In_ VARIANT *pvaIn, 117 _Inout_ VARIANT *pvaOut) 118{ 119 //TRACE("(%p, %d, %s, %d, %d, %p, %p)\n", lpUnknown, nUnknown, 120 // wine_dbgstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut); 121 122 OLECMD cmd = { nCmdID }; 123 HRESULT hr = IsQSForwardMockup(pguidCmdGroup, 1, &cmd); 124 if (FAILED(hr) || !HRESULT_CODE(hr) || nUnknown <= 0) 125 return OLECMDERR_E_NOTSUPPORTED; 126 127 return IUnknown_Exec(lpUnknown, *pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); 128} 129 130static BOOL g_bQueryStatus = FALSE; 131static BOOL g_bExec = FALSE; 132 133class CDummyClass : public IOleCommandTarget 134{ 135public: 136 CDummyClass() { } 137 virtual ~CDummyClass() { } 138 139 // ** IUnknown methods ** 140 STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj) override 141 { 142 if (!ppvObj) 143 return E_POINTER; 144 *ppvObj = NULL; 145 if (riid == IID_IUnknown || riid == IID_IOleCommandTarget) 146 *ppvObj = this; 147 if (*ppvObj) 148 { 149 AddRef(); 150 return S_OK; 151 } 152 return E_NOINTERFACE; 153 } 154 STDMETHODIMP_(ULONG) AddRef() override 155 { 156 return 2; 157 } 158 STDMETHODIMP_(ULONG) Release() override 159 { 160 return 2; 161 } 162 163 // ** IOleCommandTarget methods ** 164 STDMETHODIMP QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText) override 165 { 166 g_bQueryStatus = TRUE; 167 return 0xBEEFCAFE; 168 } 169 STDMETHODIMP Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) override 170 { 171 g_bExec = TRUE; 172 return 0x2BAD2BAD; 173 } 174 175 static void *operator new(size_t size) 176 { 177 return LocalAlloc(LPTR, size); 178 } 179 static void operator delete(void *ptr) 180 { 181 LocalFree(ptr); 182 } 183 static void operator delete(void *ptr, size_t size) 184 { 185 LocalFree(ptr); 186 } 187}; 188 189static VOID TEST_IsQSForward(VOID) 190{ 191 OLECMD cmds[2]; 192 LONG cmdID, cmdID2; 193 HRESULT ret1, ret2; 194 ULONG cCmds; 195 BOOL bExcept1, bExcept2; 196 const GUID *pGUID; 197 enum { LOW_VALUE = -1, HIGH_VALUE = OLECMDID_CLOSE }; 198 199 cmds[0].cmdf = 0; 200 201 cCmds = 0; 202 pGUID = NULL; 203 for (cmdID = LOW_VALUE; cmdID <= HIGH_VALUE; ++cmdID) 204 { 205 cmds[0].cmdID = cmdID; 206 207 ret1 = IsQSForward(*pGUID, cCmds, cmds); 208 ret2 = IsQSForwardMockup(pGUID, cCmds, cmds); 209 ok(ret1 == ret2, "cmdID: %ld (%ld vs %ld)\n", cmdID, ret1, ret2); 210 211 ret1 = IsQSForward(*pGUID, cCmds, NULL); 212 ret2 = IsQSForwardMockup(pGUID, cCmds, NULL); 213 ok(ret1 == ret2, "cmdID: %ld (%ld vs %ld)\n", cmdID, ret1, ret2); 214 } 215 216 cCmds = 1; 217 for (cmdID = LOW_VALUE; cmdID <= HIGH_VALUE; ++cmdID) 218 { 219 cmds[0].cmdID = cmdID; 220 221 pGUID = NULL; 222 ret1 = IsQSForward(*pGUID, cCmds, cmds); 223 ret2 = IsQSForwardMockup(pGUID, cCmds, cmds); 224 ok(ret1 == ret2, "cmdID: %ld (%ld vs %ld)\n", cmdID, ret1, ret2); 225 226 ret1 = ret2 = 0xDEADFACE; 227 bExcept1 = bExcept2 = FALSE; 228 229 _SEH2_TRY 230 { 231 ret1 = IsQSForward(*pGUID, cCmds, NULL); 232 } 233 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 234 { 235 bExcept1 = TRUE; 236 } 237 _SEH2_END; 238 239 _SEH2_TRY 240 { 241 ret2 = IsQSForwardMockup(pGUID, cCmds, NULL); 242 } 243 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 244 { 245 bExcept2 = TRUE; 246 } 247 _SEH2_END; 248 249 ok(ret1 == ret2, "cmdID: %ld (%ld vs %ld)\n", cmdID, ret1, ret2); 250 ok((bExcept1 && bExcept2), "cmdID: %ld (%d vs %d)\n", cmdID, bExcept1, bExcept2); 251 252 pGUID = &CGID_Explorer; 253 ret1 = IsQSForward(*pGUID, cCmds, cmds); 254 ret2 = IsQSForwardMockup(pGUID, cCmds, cmds); 255 ok(ret1 == ret2, "cmdID: %ld (%ld vs %ld)\n", cmdID, ret1, ret2); 256 257 pGUID = &IID_IUnknown; 258 ret1 = IsQSForward(*pGUID, cCmds, cmds); 259 ret2 = IsQSForwardMockup(pGUID, cCmds, cmds); 260 ok(ret1 == ret2, "cmdID: %ld (%ld vs %ld)\n", cmdID, ret1, ret2); 261 } 262 263 cCmds = 2; 264 for (cmdID = LOW_VALUE; cmdID <= HIGH_VALUE; ++cmdID) 265 { 266 cmds[0].cmdID = cmdID; 267 268 pGUID = NULL; 269 for (cmdID2 = LOW_VALUE; cmdID2 <= HIGH_VALUE; ++cmdID2) 270 { 271 cmds[1].cmdID = cmdID2; 272 ret1 = IsQSForward(*pGUID, cCmds, cmds); 273 ret2 = IsQSForwardMockup(pGUID, cCmds, cmds); 274 ok(ret1 == ret2, "cmdID: %ld (%ld vs %ld)\n", cmdID, ret1, ret2); 275 } 276 277 pGUID = &CGID_Explorer; 278 for (cmdID2 = LOW_VALUE; cmdID2 <= HIGH_VALUE; ++cmdID2) 279 { 280 cmds[1].cmdID = cmdID2; 281 ret1 = IsQSForward(*pGUID, cCmds, cmds); 282 ret2 = IsQSForwardMockup(pGUID, cCmds, cmds); 283 ok(ret1 == ret2, "cmdID: %ld (%ld vs %ld)\n", cmdID, ret1, ret2); 284 } 285 } 286} 287 288static VOID TEST_MayQSForwardMockup(VOID) 289{ 290 CDummyClass dummy; 291 LONG cmdID; 292 OLECMD cmds[1]; 293 OLECMDTEXT cmdText; 294 HRESULT ret1, ret2; 295 296 // Testing OLECMDID_PROPERTIES support 297 cmds[0].cmdID = cmdID = OLECMDID_PROPERTIES; 298 299 g_bQueryStatus = g_bExec = FALSE; 300 ret1 = MayQSForward(&dummy, 1, CGID_Explorer, _countof(cmds), cmds, &cmdText); 301 ok_int(g_bQueryStatus, FALSE); 302 ok_int(g_bExec, FALSE); 303 304 g_bQueryStatus = g_bExec = FALSE; 305 ret2 = MayQSForwardMockup(&dummy, 1, &CGID_Explorer, _countof(cmds), cmds, &cmdText); 306 ok_int(g_bQueryStatus, FALSE); 307 ok_int(g_bExec, FALSE); 308 309 ok(ret1 == ret2, "cmdID: %ld (%ld vs %ld)\n", cmdID, ret1, ret2); 310 311 // Testing OLECMDID_SHOWFIND support 312 cmds[0].cmdID = cmdID = OLECMDID_SHOWFIND; 313 314 g_bQueryStatus = g_bExec = FALSE; 315 ret1 = MayQSForward(&dummy, 1, CGID_Explorer, _countof(cmds), cmds, &cmdText); 316 ok_int(g_bQueryStatus, TRUE); 317 ok_int(g_bExec, FALSE); 318 319 g_bQueryStatus = g_bExec = FALSE; 320 ret2 = MayQSForwardMockup(&dummy, 1, &CGID_Explorer, _countof(cmds), cmds, &cmdText); 321 ok_int(g_bQueryStatus, TRUE); 322 ok_int(g_bExec, FALSE); 323 324 ok(ret1 == ret2, "cmdID: %ld (%ld vs %ld)\n", cmdID, ret1, ret2); 325} 326 327static VOID TEST_MayExecForwardMockup(VOID) 328{ 329 CDummyClass dummy; 330 LONG cmdID; 331 HRESULT ret1, ret2; 332 333 // Testing OLECMDID_PROPERTIES support 334 cmdID = OLECMDID_PROPERTIES; 335 336 g_bQueryStatus = g_bExec = FALSE; 337 ret1 = MayExecForward(&dummy, 1, CGID_Explorer, cmdID, 0, NULL, NULL); 338 ok_int(g_bQueryStatus, FALSE); 339 ok_int(g_bExec, FALSE); 340 341 g_bQueryStatus = g_bExec = FALSE; 342 ret2 = MayExecForwardMockup(&dummy, 1, &CGID_Explorer, cmdID, 0, NULL, NULL); 343 ok_int(g_bQueryStatus, FALSE); 344 ok_int(g_bExec, FALSE); 345 346 ok(ret1 == ret2, "cmdID: %ld (%ld vs %ld)\n", cmdID, ret1, ret2); 347 348 // Testing OLECMDID_SHOWFIND support 349 cmdID = OLECMDID_SHOWFIND; 350 351 g_bQueryStatus = g_bExec = FALSE; 352 ret1 = MayExecForward(&dummy, 1, CGID_Explorer, cmdID, 0, NULL, NULL); 353 ok_int(g_bQueryStatus, FALSE); 354 ok_int(g_bExec, TRUE); 355 356 g_bQueryStatus = g_bExec = FALSE; 357 ret2 = MayExecForwardMockup(&dummy, 1, &CGID_Explorer, cmdID, 0, NULL, NULL); 358 ok_int(g_bQueryStatus, FALSE); 359 ok_int(g_bExec, TRUE); 360 361 ok(ret1 == ret2, "cmdID: %ld (%ld vs %ld)\n", cmdID, ret1, ret2); 362} 363 364START_TEST(IsQSForward) 365{ 366 TEST_IsQSForward(); 367 TEST_MayQSForwardMockup(); 368 TEST_MayExecForwardMockup(); 369}