mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 18:52:57 +00:00
[SHELL32_APITEST] Add RealShellExecuteEx testcase (#6647)
Follow-up to #5849. JIRA issue: CORE-19278 - Add closewnd.cpp, closewnd.h, and RealShellExecuteEx.cpp files. - In closewnd.cpp, close newly-opened windows. - Add RealShellExecuteEx testcase.
This commit is contained in:
parent
ad748b0b3b
commit
436cfa94c9
6 changed files with 257 additions and 67 deletions
|
@ -2,6 +2,7 @@
|
||||||
spec2def(shell32_apitest.exe shell32_apitest.spec)
|
spec2def(shell32_apitest.exe shell32_apitest.spec)
|
||||||
|
|
||||||
list(APPEND SOURCE
|
list(APPEND SOURCE
|
||||||
|
closewnd.cpp
|
||||||
AddCommas.cpp
|
AddCommas.cpp
|
||||||
CFSFolder.cpp
|
CFSFolder.cpp
|
||||||
CheckEscapes.cpp
|
CheckEscapes.cpp
|
||||||
|
@ -22,6 +23,7 @@ list(APPEND SOURCE
|
||||||
PathIsEqualOrSubFolder.cpp
|
PathIsEqualOrSubFolder.cpp
|
||||||
PathIsTemporary.cpp
|
PathIsTemporary.cpp
|
||||||
PathResolve.cpp
|
PathResolve.cpp
|
||||||
|
RealShellExecuteEx.cpp
|
||||||
SHAppBarMessage.cpp
|
SHAppBarMessage.cpp
|
||||||
SHChangeNotify.cpp
|
SHChangeNotify.cpp
|
||||||
SHCreateDataObject.cpp
|
SHCreateDataObject.cpp
|
||||||
|
|
136
modules/rostests/apitests/shell32/RealShellExecuteEx.cpp
Normal file
136
modules/rostests/apitests/shell32/RealShellExecuteEx.cpp
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS API tests
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: Test for RealShellExecuteExA/W
|
||||||
|
* COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "shelltest.h"
|
||||||
|
#include "closewnd.h"
|
||||||
|
#include <versionhelpers.h>
|
||||||
|
|
||||||
|
BOOL IsWindowsServer2003SP2OrGreater(void)
|
||||||
|
{
|
||||||
|
return IsWindowsVersionOrGreater(5, 2, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef HINSTANCE (WINAPI *FN_RealShellExecuteExA)(
|
||||||
|
_In_opt_ HWND hwnd,
|
||||||
|
_In_opt_ LPCSTR lpOperation,
|
||||||
|
_In_opt_ LPCSTR lpFile,
|
||||||
|
_In_opt_ LPCSTR lpParameters,
|
||||||
|
_In_opt_ LPCSTR lpDirectory,
|
||||||
|
_In_opt_ LPSTR lpReturn,
|
||||||
|
_In_opt_ LPCSTR lpTitle,
|
||||||
|
_In_opt_ LPVOID lpReserved,
|
||||||
|
_In_ INT nCmdShow,
|
||||||
|
_Out_opt_ PHANDLE lphProcess,
|
||||||
|
_In_ DWORD dwFlags);
|
||||||
|
|
||||||
|
typedef HINSTANCE (WINAPI *FN_RealShellExecuteExW)(
|
||||||
|
_In_opt_ HWND hwnd,
|
||||||
|
_In_opt_ LPCWSTR lpOperation,
|
||||||
|
_In_opt_ LPCWSTR lpFile,
|
||||||
|
_In_opt_ LPCWSTR lpParameters,
|
||||||
|
_In_opt_ LPCWSTR lpDirectory,
|
||||||
|
_In_opt_ LPWSTR lpReturn,
|
||||||
|
_In_opt_ LPCWSTR lpTitle,
|
||||||
|
_In_opt_ LPVOID lpReserved,
|
||||||
|
_In_ INT nCmdShow,
|
||||||
|
_Out_opt_ PHANDLE lphProcess,
|
||||||
|
_In_ DWORD dwFlags);
|
||||||
|
|
||||||
|
static HINSTANCE s_hSHELL32 = NULL;
|
||||||
|
static FN_RealShellExecuteExA s_fnRealShellExecuteExA = NULL;
|
||||||
|
static FN_RealShellExecuteExW s_fnRealShellExecuteExW = NULL;
|
||||||
|
|
||||||
|
static WINDOW_LIST s_List1, s_List2;
|
||||||
|
|
||||||
|
static void TEST_Start(void)
|
||||||
|
{
|
||||||
|
GetWindowList(&s_List1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TEST_End(void)
|
||||||
|
{
|
||||||
|
Sleep(500);
|
||||||
|
GetWindowList(&s_List2);
|
||||||
|
CloseNewWindows(&s_List1, &s_List2);
|
||||||
|
FreeWindowList(&s_List1);
|
||||||
|
FreeWindowList(&s_List2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TEST_RealShellExecuteExA(void)
|
||||||
|
{
|
||||||
|
TEST_Start();
|
||||||
|
|
||||||
|
INT_PTR ret;
|
||||||
|
|
||||||
|
ret = (INT_PTR)s_fnRealShellExecuteExA(
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
"notepad.exe",
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
SW_SHOWDEFAULT,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
if (IsWindowsServer2003SP2OrGreater())
|
||||||
|
ok_long((LONG)ret, 42);
|
||||||
|
else
|
||||||
|
ok_long((LONG)ret, 2);
|
||||||
|
|
||||||
|
TEST_End();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TEST_RealShellExecuteExW(void)
|
||||||
|
{
|
||||||
|
TEST_Start();
|
||||||
|
|
||||||
|
INT_PTR ret;
|
||||||
|
|
||||||
|
ret = (INT_PTR)s_fnRealShellExecuteExW(
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
L"notepad.exe",
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
SW_SHOWDEFAULT,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
ok_long((LONG)ret, 42);
|
||||||
|
|
||||||
|
TEST_End();
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST(RealShellExecuteEx)
|
||||||
|
{
|
||||||
|
if (IsWindowsVistaOrGreater())
|
||||||
|
{
|
||||||
|
skip("Vista+\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_hSHELL32 = LoadLibraryW(L"shell32.dll");
|
||||||
|
|
||||||
|
s_fnRealShellExecuteExA = (FN_RealShellExecuteExA)GetProcAddress(s_hSHELL32, MAKEINTRESOURCEA(266));
|
||||||
|
s_fnRealShellExecuteExW = (FN_RealShellExecuteExW)GetProcAddress(s_hSHELL32, MAKEINTRESOURCEA(267));
|
||||||
|
|
||||||
|
if (!s_fnRealShellExecuteExA || !s_fnRealShellExecuteExW)
|
||||||
|
{
|
||||||
|
skip("RealShellExecuteExA/W not found: %p, %p\n",
|
||||||
|
s_fnRealShellExecuteExA, s_fnRealShellExecuteExW);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_RealShellExecuteExA();
|
||||||
|
TEST_RealShellExecuteExW();
|
||||||
|
|
||||||
|
FreeLibrary(s_hSHELL32);
|
||||||
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "shelltest.h"
|
#include "shelltest.h"
|
||||||
|
#include "closewnd.h"
|
||||||
#include <pstypes.h>
|
#include <pstypes.h>
|
||||||
#include <psfuncs.h>
|
#include <psfuncs.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -149,7 +150,8 @@ getCommandLineFromProcess(HANDLE hProcess)
|
||||||
static void TEST_DoTestEntryStruct(const TEST_ENTRY *pEntry)
|
static void TEST_DoTestEntryStruct(const TEST_ENTRY *pEntry)
|
||||||
{
|
{
|
||||||
SHELLEXECUTEINFOW info = { sizeof(info) };
|
SHELLEXECUTEINFOW info = { sizeof(info) };
|
||||||
info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_WAITFORINPUTIDLE | SEE_MASK_FLAG_NO_UI;
|
info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_WAITFORINPUTIDLE |
|
||||||
|
SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC;
|
||||||
info.hwnd = NULL;
|
info.hwnd = NULL;
|
||||||
info.lpVerb = NULL;
|
info.lpVerb = NULL;
|
||||||
info.lpFile = pEntry->lpFile;
|
info.lpFile = pEntry->lpFile;
|
||||||
|
@ -212,67 +214,6 @@ enableTokenPrivilege(LPCWSTR pszPrivilege)
|
||||||
return AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL);
|
return AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct WINDOW_LIST
|
|
||||||
{
|
|
||||||
SIZE_T m_chWnds;
|
|
||||||
HWND *m_phWnds;
|
|
||||||
} WINDOW_LIST, *PWINDOW_LIST;
|
|
||||||
|
|
||||||
static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
|
|
||||||
{
|
|
||||||
if (!IsWindowVisible(hwnd))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
PWINDOW_LIST pList = (PWINDOW_LIST)lParam;
|
|
||||||
SIZE_T cb = (pList->m_chWnds + 1) * sizeof(HWND);
|
|
||||||
HWND *phWnds = (HWND *)realloc(pList->m_phWnds, cb);
|
|
||||||
if (!phWnds)
|
|
||||||
return FALSE;
|
|
||||||
phWnds[pList->m_chWnds++] = hwnd;
|
|
||||||
pList->m_phWnds = phWnds;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void TEST_GetWindowList(PWINDOW_LIST pList)
|
|
||||||
{
|
|
||||||
EnumWindows(EnumWindowsProc, (LPARAM)pList);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TEST_CloseNewWindows(PWINDOW_LIST List1, PWINDOW_LIST List2)
|
|
||||||
{
|
|
||||||
for (SIZE_T i2 = 0; i2 < List2->m_chWnds; ++i2)
|
|
||||||
{
|
|
||||||
BOOL bFoundInList1 = FALSE;
|
|
||||||
HWND hWnd = List2->m_phWnds[i2];
|
|
||||||
for (SIZE_T i1 = 0; i1 < List1->m_chWnds; ++i1)
|
|
||||||
{
|
|
||||||
if (hWnd == List1->m_phWnds[i1])
|
|
||||||
{
|
|
||||||
bFoundInList1 = TRUE;
|
|
||||||
goto Escape;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Escape:
|
|
||||||
if (!bFoundInList1)
|
|
||||||
{
|
|
||||||
for (INT i = 0; i < 5; ++i)
|
|
||||||
{
|
|
||||||
if (!IsWindow(hWnd))
|
|
||||||
break;
|
|
||||||
|
|
||||||
SwitchToThisWindow(hWnd, TRUE);
|
|
||||||
|
|
||||||
// Alt+F4
|
|
||||||
keybd_event(VK_MENU, 0x38, 0, 0);
|
|
||||||
keybd_event(VK_F4, 0x3E, 0, 0);
|
|
||||||
keybd_event(VK_F4, 0x3E, KEYEVENTF_KEYUP, 0);
|
|
||||||
keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0);
|
|
||||||
Sleep(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static WINDOW_LIST s_List1, s_List2;
|
static WINDOW_LIST s_List1, s_List2;
|
||||||
|
|
||||||
static BOOL TEST_Start(void)
|
static BOOL TEST_Start(void)
|
||||||
|
@ -364,7 +305,7 @@ static BOOL TEST_Start(void)
|
||||||
StringCchPrintfW(s_sys_test_exe_cmdline, _countof(s_sys_test_exe_cmdline),
|
StringCchPrintfW(s_sys_test_exe_cmdline, _countof(s_sys_test_exe_cmdline),
|
||||||
L"\"%s\" ", s_sys_test_exe);
|
L"\"%s\" ", s_sys_test_exe);
|
||||||
|
|
||||||
TEST_GetWindowList(&s_List1);
|
GetWindowList(&s_List1);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -372,10 +313,10 @@ static BOOL TEST_Start(void)
|
||||||
static void TEST_End(void)
|
static void TEST_End(void)
|
||||||
{
|
{
|
||||||
Sleep(500);
|
Sleep(500);
|
||||||
TEST_GetWindowList(&s_List2);
|
GetWindowList(&s_List2);
|
||||||
TEST_CloseNewWindows(&s_List1, &s_List2);
|
CloseNewWindows(&s_List1, &s_List2);
|
||||||
free(s_List1.m_phWnds);
|
FreeWindowList(&s_List1);
|
||||||
free(s_List2.m_phWnds);
|
FreeWindowList(&s_List2);
|
||||||
|
|
||||||
DeleteFileW(s_win_test_exe);
|
DeleteFileW(s_win_test_exe);
|
||||||
DeleteFileW(s_sys_test_exe);
|
DeleteFileW(s_sys_test_exe);
|
||||||
|
|
90
modules/rostests/apitests/shell32/closewnd.cpp
Normal file
90
modules/rostests/apitests/shell32/closewnd.cpp
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS API tests
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: Close windows after tests
|
||||||
|
* COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "shelltest.h"
|
||||||
|
#include "closewnd.h"
|
||||||
|
|
||||||
|
void FreeWindowList(PWINDOW_LIST pList)
|
||||||
|
{
|
||||||
|
free(pList->m_phWnds);
|
||||||
|
pList->m_phWnds = NULL;
|
||||||
|
pList->m_chWnds = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (!IsWindowVisible(hwnd))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
PWINDOW_LIST pList = (PWINDOW_LIST)lParam;
|
||||||
|
SIZE_T cb = (pList->m_chWnds + 1) * sizeof(HWND);
|
||||||
|
HWND *phWnds = (HWND *)realloc(pList->m_phWnds, cb);
|
||||||
|
if (!phWnds)
|
||||||
|
return FALSE;
|
||||||
|
phWnds[pList->m_chWnds++] = hwnd;
|
||||||
|
pList->m_phWnds = phWnds;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetWindowList(PWINDOW_LIST pList)
|
||||||
|
{
|
||||||
|
pList->m_phWnds = NULL;
|
||||||
|
pList->m_chWnds = 0;
|
||||||
|
EnumWindows(EnumWindowsProc, (LPARAM)pList);
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2)
|
||||||
|
{
|
||||||
|
for (SIZE_T i2 = 0; i2 < List2->m_chWnds; ++i2)
|
||||||
|
{
|
||||||
|
HWND hWnd = List2->m_phWnds[i2];
|
||||||
|
if (!IsWindowEnabled(hWnd) || !IsWindowVisible(hWnd))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BOOL bFoundInList1 = FALSE;
|
||||||
|
for (SIZE_T i1 = 0; i1 < List1->m_chWnds; ++i1)
|
||||||
|
{
|
||||||
|
if (hWnd == List1->m_phWnds[i1])
|
||||||
|
{
|
||||||
|
bFoundInList1 = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bFoundInList1)
|
||||||
|
return hWnd;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TRIALS_COUNT 8
|
||||||
|
|
||||||
|
void CloseNewWindows(PWINDOW_LIST List1, PWINDOW_LIST List2)
|
||||||
|
{
|
||||||
|
INT cDiff = List2->m_chWnds - List1->m_chWnds;
|
||||||
|
for (INT j = 0; j < cDiff; ++j)
|
||||||
|
{
|
||||||
|
HWND hWnd = FindNewWindow(List1, List2);
|
||||||
|
if (!hWnd)
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (INT i = 0; i < TRIALS_COUNT; ++i)
|
||||||
|
{
|
||||||
|
if (!IsWindow(hWnd))
|
||||||
|
break;
|
||||||
|
|
||||||
|
SwitchToThisWindow(hWnd, TRUE);
|
||||||
|
|
||||||
|
// Alt+F4
|
||||||
|
keybd_event(VK_MENU, 0x38, 0, 0);
|
||||||
|
keybd_event(VK_F4, 0x3E, 0, 0);
|
||||||
|
keybd_event(VK_F4, 0x3E, KEYEVENTF_KEYUP, 0);
|
||||||
|
keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0);
|
||||||
|
Sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
modules/rostests/apitests/shell32/closewnd.h
Normal file
19
modules/rostests/apitests/shell32/closewnd.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS API tests
|
||||||
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||||
|
* PURPOSE: Close windows after tests
|
||||||
|
* COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct WINDOW_LIST
|
||||||
|
{
|
||||||
|
SIZE_T m_chWnds;
|
||||||
|
HWND *m_phWnds;
|
||||||
|
} WINDOW_LIST, *PWINDOW_LIST;
|
||||||
|
|
||||||
|
void GetWindowList(PWINDOW_LIST pList);
|
||||||
|
HWND FindNewWindow(PWINDOW_LIST List1, PWINDOW_LIST List2);
|
||||||
|
void CloseNewWindows(PWINDOW_LIST List1, PWINDOW_LIST List2);
|
||||||
|
void FreeWindowList(PWINDOW_LIST pList);
|
|
@ -24,6 +24,7 @@ extern void func_OpenAs_RunDLL(void);
|
||||||
extern void func_PathIsEqualOrSubFolder(void);
|
extern void func_PathIsEqualOrSubFolder(void);
|
||||||
extern void func_PathIsTemporary(void);
|
extern void func_PathIsTemporary(void);
|
||||||
extern void func_PathResolve(void);
|
extern void func_PathResolve(void);
|
||||||
|
extern void func_RealShellExecuteEx(void);
|
||||||
extern void func_SHAppBarMessage(void);
|
extern void func_SHAppBarMessage(void);
|
||||||
extern void func_SHChangeNotify(void);
|
extern void func_SHChangeNotify(void);
|
||||||
extern void func_SHCreateDataObject(void);
|
extern void func_SHCreateDataObject(void);
|
||||||
|
@ -63,6 +64,7 @@ const struct test winetest_testlist[] =
|
||||||
{ "PathIsEqualOrSubFolder", func_PathIsEqualOrSubFolder },
|
{ "PathIsEqualOrSubFolder", func_PathIsEqualOrSubFolder },
|
||||||
{ "PathIsTemporary", func_PathIsTemporary },
|
{ "PathIsTemporary", func_PathIsTemporary },
|
||||||
{ "PathResolve", func_PathResolve },
|
{ "PathResolve", func_PathResolve },
|
||||||
|
{ "RealShellExecuteEx", func_RealShellExecuteEx },
|
||||||
{ "SHAppBarMessage", func_SHAppBarMessage },
|
{ "SHAppBarMessage", func_SHAppBarMessage },
|
||||||
{ "SHChangeNotify", func_SHChangeNotify },
|
{ "SHChangeNotify", func_SHChangeNotify },
|
||||||
{ "SHCreateDataObject", func_SHCreateDataObject },
|
{ "SHCreateDataObject", func_SHCreateDataObject },
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue