https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c35a84985abcc05b0b537…
commit c35a84985abcc05b0b5376bf97928bea3ea62bde
Author:     Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Tue Jun 8 08:07:37 2021 +0900
Commit:     GitHub <noreply(a)github.com>
CommitDate: Tue Jun 8 08:07:37 2021 +0900
    [SHELL32_APITEST] Strengthen ShellExecuteEx testcase (#3731)
    Investigate shell32!ShellExecuteEx function more. CORE-17351, CORE-16898, CORE-17612
---
 .../rostests/apitests/shell32/ShellExecuteEx.cpp   | 271 ++++++++++++++++++++-
 .../apitests/shell32/shell32_apitest_sub.cpp       |   2 +-
 2 files changed, 271 insertions(+), 2 deletions(-)
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 <yaroslav(a)veremenko.info>
+ *                  Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
  */
 #include "shelltest.h"
+#include <shlwapi.h>
+#include <stdio.h>
 #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);