diff --git a/modules/rostests/apitests/shell32/ShellExecuteEx.cpp b/modules/rostests/apitests/shell32/ShellExecuteEx.cpp index 73afcd1e2e5..72661ab389f 100644 --- a/modules/rostests/apitests/shell32/ShellExecuteEx.cpp +++ b/modules/rostests/apitests/shell32/ShellExecuteEx.cpp @@ -3,9 +3,12 @@ * LICENSE: GPLv2+ - See COPYING in the top level directory * PURPOSE: Testing ShellExecuteEx * PROGRAMMER: Yaroslav Veremenko + * Katayama Hirofumi MZ */ #include "shelltest.h" +#include +#include #define ok_ShellExecuteEx (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : TestShellExecuteEx @@ -81,7 +84,7 @@ TestShellExecuteEx(const WCHAR* Name, BOOL ExpectedResult) } } -START_TEST(ShellExecuteEx) +static void DoAppPathTest(void) { ok_ShellExecuteEx(L"iexplore", TRUE); ok_ShellExecuteEx(L"iexplore.exe", TRUE); @@ -100,3 +103,269 @@ START_TEST(ShellExecuteEx) DeleteAppPathRegKey(L"iexplore.bat.exe"); } } + +typedef struct TEST_ENTRY +{ + INT lineno; + BOOL ret; + BOOL bProcessHandle; + LPCSTR file; + LPCSTR params; + LPCSTR curdir; +} TEST_ENTRY; + +static char s_sub_program[MAX_PATH]; +static char s_win_test_exe[MAX_PATH]; +static char s_sys_test_exe[MAX_PATH]; +static char s_win_bat_file[MAX_PATH]; +static char s_sys_bat_file[MAX_PATH]; +static char s_win_txt_file[MAX_PATH]; +static char s_sys_txt_file[MAX_PATH]; + +#define DONT_CARE 0x0BADF00D + +static const TEST_ENTRY s_entries_1[] = +{ + { __LINE__, TRUE, TRUE, "test program" }, + { __LINE__, TRUE, TRUE, "test program.bat" }, + { __LINE__, TRUE, TRUE, "test program.exe" }, + { __LINE__, FALSE, FALSE, " test program" }, + { __LINE__, FALSE, FALSE, " test program.bat" }, + { __LINE__, FALSE, FALSE, " test program.exe" }, + { __LINE__, FALSE, FALSE, "test program " }, + { __LINE__, TRUE, TRUE, "test program.bat " }, + { __LINE__, TRUE, TRUE, "test program.exe " }, + { __LINE__, TRUE, TRUE, "test program", "TEST" }, + { __LINE__, TRUE, TRUE, "test program.bat", "TEST" }, + { __LINE__, TRUE, TRUE, "test program.exe", "TEST" }, + { __LINE__, FALSE, FALSE, ".\\test program.bat" }, + { __LINE__, FALSE, FALSE, ".\\test program.exe" }, + { __LINE__, TRUE, TRUE, "\"test program\"" }, + { __LINE__, TRUE, TRUE, "\"test program.bat\"" }, + { __LINE__, TRUE, TRUE, "\"test program.exe\"" }, + { __LINE__, FALSE, FALSE, "\"test program\" TEST" }, + { __LINE__, FALSE, FALSE, "\"test program.bat\" TEST" }, + { __LINE__, FALSE, FALSE, "\"test program.exe\" TEST" }, + { __LINE__, FALSE, FALSE, " \"test program\"" }, + { __LINE__, FALSE, FALSE, " \"test program.bat\"" }, + { __LINE__, FALSE, FALSE, " \"test program.exe\"" }, + { __LINE__, FALSE, FALSE, "\"test program\" " }, + { __LINE__, FALSE, FALSE, "\"test program.bat\" " }, + { __LINE__, FALSE, FALSE, "\"test program.exe\" " }, + { __LINE__, FALSE, FALSE, "\".\\test program.bat\"" }, + { __LINE__, FALSE, FALSE, "\".\\test program.exe\"" }, + { __LINE__, TRUE, TRUE, s_win_test_exe }, + { __LINE__, TRUE, TRUE, s_sys_test_exe }, + { __LINE__, TRUE, TRUE, s_win_bat_file }, + { __LINE__, TRUE, TRUE, s_sys_bat_file }, + { __LINE__, TRUE, TRUE, s_win_bat_file, "TEST" }, + { __LINE__, TRUE, TRUE, s_sys_bat_file, "TEST" }, + { __LINE__, FALSE, FALSE, "invalid program" }, + { __LINE__, FALSE, FALSE, "invalid program.bat" }, + { __LINE__, FALSE, FALSE, "invalid program.exe" }, + { __LINE__, TRUE, TRUE, "test_file.txt" }, + { __LINE__, TRUE, TRUE, "test_file.txt", "parameters parameters" }, + { __LINE__, TRUE, TRUE, "test_file.txt", "parameters parameters", "." }, + { __LINE__, TRUE, TRUE, "shell32_apitest_sub.exe" }, + { __LINE__, TRUE, TRUE, ".\\shell32_apitest_sub.exe" }, + { __LINE__, TRUE, TRUE, "\"shell32_apitest_sub.exe\"" }, + { __LINE__, TRUE, TRUE, "\".\\shell32_apitest_sub.exe\"" }, + { __LINE__, TRUE, DONT_CARE, "https://google.com" }, + { __LINE__, TRUE, FALSE, "::{450d8fba-ad25-11d0-98a8-0800361b1103}" }, + { __LINE__, TRUE, FALSE, "shell:::{450d8fba-ad25-11d0-98a8-0800361b1103}" }, + { __LINE__, TRUE, FALSE, "shell:sendto" }, +}; + +static const TEST_ENTRY s_entries_2[] = +{ + { __LINE__, TRUE, TRUE, "test program" }, + { __LINE__, TRUE, TRUE, "test program", "TEST" }, + { __LINE__, TRUE, TRUE, "\"test program\"" }, + { __LINE__, TRUE, TRUE, s_win_test_exe }, + { __LINE__, TRUE, TRUE, s_sys_test_exe }, + { __LINE__, FALSE, FALSE, s_win_bat_file }, + { __LINE__, FALSE, FALSE, s_sys_bat_file }, + { __LINE__, FALSE, FALSE, s_win_bat_file, "TEST" }, + { __LINE__, FALSE, FALSE, s_sys_bat_file, "TEST" }, +}; + +typedef struct OPENWNDS +{ + UINT count; + HWND *phwnd; +} OPENWNDS; + +static OPENWNDS s_wi0 = { 0 }, s_wi1 = { 0 }; + +static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) +{ + OPENWNDS *info = (OPENWNDS *)lParam; + info->phwnd = (HWND *)realloc(info->phwnd, (info->count + 1) * sizeof(HWND)); + if (!info->phwnd) + return FALSE; + info->phwnd[info->count] = hwnd; + ++(info->count); + return TRUE; +} + +static VOID DoTestEntry(const TEST_ENTRY *pEntry) +{ + SHELLEXECUTEINFOA info = { sizeof(info) }; + info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI; + info.nShow = SW_SHOWNORMAL; + info.lpFile = pEntry->file; + info.lpParameters = pEntry->params; + info.lpDirectory = pEntry->curdir; + BOOL ret = ShellExecuteExA(&info); + ok(ret == pEntry->ret, "Line %u: ret expected %d, got %d\n", + pEntry->lineno, pEntry->ret, ret); + if (!pEntry->ret) + return; + + if ((UINT)pEntry->bProcessHandle != DONT_CARE) + { + if (pEntry->bProcessHandle) + { + ok(!!info.hProcess, "Line %u: hProcess expected non-NULL\n", pEntry->lineno); + } + else + { + ok(!info.hProcess, "Line %u: hProcess expected NULL\n", pEntry->lineno); + return; + } + } + + WaitForInputIdle(info.hProcess, INFINITE); + + // close newly opened windows + EnumWindows(EnumWindowsProc, (LPARAM)&s_wi1); + for (UINT i1 = 0; i1 < s_wi1.count; ++i1) + { + BOOL bFound = FALSE; + for (UINT i0 = 0; i0 < s_wi0.count; ++i0) + { + if (s_wi1.phwnd[i1] == s_wi0.phwnd[i0]) + { + bFound = TRUE; + break; + } + } + if (!bFound) + PostMessageW(s_wi1.phwnd[i1], WM_CLOSE, 0, 0); + } + free(s_wi1.phwnd); + ZeroMemory(&s_wi1, sizeof(s_wi1)); + + WaitForSingleObject(info.hProcess, INFINITE); + CloseHandle(info.hProcess); +} + +static BOOL +GetSubProgramPath(void) +{ + GetModuleFileNameA(NULL, s_sub_program, _countof(s_sub_program)); + PathRemoveFileSpecA(s_sub_program); + PathAppendA(s_sub_program, "shell32_apitest_sub.exe"); + + if (!PathFileExistsA(s_sub_program)) + { + PathRemoveFileSpecA(s_sub_program); + PathAppendA(s_sub_program, "testdata\\shell32_apitest_sub.exe"); + + if (!PathFileExistsA(s_sub_program)) + { + return FALSE; + } + } + + return TRUE; +} + +static void DoTestEntries(void) +{ + if (!GetSubProgramPath()) + { + skip("shell32_apitest_sub.exe is not found\n"); + return; + } + + // s_win_test_exe + GetWindowsDirectoryA(s_win_test_exe, _countof(s_win_test_exe)); + PathAppendA(s_win_test_exe, "test program.exe"); + BOOL ret = CopyFileA(s_sub_program, s_win_test_exe, FALSE); + if (!ret) + { + skip("Please retry with admin rights\n"); + return; + } + + // record open windows + if (!EnumWindows(EnumWindowsProc, (LPARAM)&s_wi0)) + { + skip("EnumWindows failed\n"); + DeleteFileA(s_win_test_exe); + free(s_wi0.phwnd); + return; + } + + // s_sys_test_exe + GetSystemDirectoryA(s_sys_test_exe, _countof(s_sys_test_exe)); + PathAppendA(s_sys_test_exe, "test program.exe"); + ok_int(CopyFileA(s_sub_program, s_sys_test_exe, FALSE), TRUE); + + // s_win_bat_file + GetWindowsDirectoryA(s_win_bat_file, _countof(s_win_bat_file)); + PathAppendA(s_win_bat_file, "test program.bat"); + FILE *fp = fopen(s_win_bat_file, "wb"); + fprintf(fp, "exit /b 3"); + fclose(fp); + ok_int(PathFileExistsA(s_win_bat_file), TRUE); + + // s_sys_bat_file + GetSystemDirectoryA(s_sys_bat_file, _countof(s_sys_bat_file)); + PathAppendA(s_sys_bat_file, "test program.bat"); + fp = fopen(s_sys_bat_file, "wb"); + fprintf(fp, "exit /b 4"); + fclose(fp); + ok_int(PathFileExistsA(s_sys_bat_file), TRUE); + + // s_win_txt_file + GetWindowsDirectoryA(s_win_txt_file, _countof(s_win_txt_file)); + PathAppendA(s_win_txt_file, "test_file.txt"); + fp = fopen(s_win_txt_file, "wb"); + fclose(fp); + ok_int(PathFileExistsA(s_win_txt_file), TRUE); + + // s_sys_txt_file + GetSystemDirectoryA(s_sys_txt_file, _countof(s_sys_txt_file)); + PathAppendA(s_sys_txt_file, "test_file.txt"); + fp = fopen(s_sys_txt_file, "wb"); + fclose(fp); + ok_int(PathFileExistsA(s_sys_txt_file), TRUE); + + for (UINT iTest = 0; iTest < _countof(s_entries_1); ++iTest) + { + DoTestEntry(&s_entries_1[iTest]); + } + + DeleteFileA(s_win_bat_file); + DeleteFileA(s_sys_bat_file); + + for (UINT iTest = 0; iTest < _countof(s_entries_2); ++iTest) + { + DoTestEntry(&s_entries_2[iTest]); + } + + DeleteFileA(s_win_test_exe); + DeleteFileA(s_sys_test_exe); + DeleteFileA(s_win_txt_file); + DeleteFileA(s_sys_txt_file); + + free(s_wi0.phwnd); +} + +START_TEST(ShellExecuteEx) +{ + DoAppPathTest(); + DoTestEntries(); +} diff --git a/modules/rostests/apitests/shell32/shell32_apitest_sub.cpp b/modules/rostests/apitests/shell32/shell32_apitest_sub.cpp index c0d3cc4d83e..127ecaf687f 100644 --- a/modules/rostests/apitests/shell32/shell32_apitest_sub.cpp +++ b/modules/rostests/apitests/shell32/shell32_apitest_sub.cpp @@ -262,7 +262,7 @@ wWinMain(HINSTANCE hInstance, LPWSTR lpCmdLine, INT nCmdShow) { - if (lstrcmpiW(lpCmdLine, L"") == 0) + if (lstrcmpiW(lpCmdLine, L"") == 0 || lstrcmpiW(lpCmdLine, L"TEST") == 0) return 0; s_nMode = _wtoi(lpCmdLine);