diff --git a/dll/win32/shell32/shlexec.cpp b/dll/win32/shell32/shlexec.cpp index 292c8db8292..ed66c540efd 100644 --- a/dll/win32/shell32/shlexec.cpp +++ b/dll/win32/shell32/shlexec.cpp @@ -2124,6 +2124,39 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) *end = L'\0'; lpFile = wfileName; } + /* We have to test sei instead of sei_tmp because sei_tmp had its + * input fMask modifed above in SHELL_translate_idlist. + * This code is needed to handle the case where we only have an + * lpIDList with multiple CLSID/PIDL's (not 'My Computer' only) */ + else if ((sei->fMask & SEE_MASK_IDLIST) == SEE_MASK_IDLIST) + { + WCHAR buffer[MAX_PATH], xlpFile[MAX_PATH]; + LPWSTR space, s; + + LPWSTR beg = wszApplicationName; + for(s = beg; (space = const_cast(strchrW(s, L' '))); s = space + 1) + { + int idx = space - sei_tmp.lpFile; + memcpy(buffer, sei_tmp.lpFile, idx * sizeof(WCHAR)); + buffer[idx] = '\0'; + + if (SearchPathW(*sei_tmp.lpDirectory ? sei_tmp.lpDirectory : NULL, + buffer, L".exe", _countof(xlpFile), xlpFile, NULL)) + { + /* separate out command from parameter string */ + LPCWSTR p = space + 1; + + while(isspaceW(*p)) + ++p; + + strcpyW(wszParameters, p); + *space = L'\0'; + + break; + } + } + lpFile = sei_tmp.lpFile; + } else { lpFile = sei_tmp.lpFile; diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt b/modules/rostests/apitests/shell32/CMakeLists.txt index 53c87297d89..e6a2a2fdf78 100644 --- a/modules/rostests/apitests/shell32/CMakeLists.txt +++ b/modules/rostests/apitests/shell32/CMakeLists.txt @@ -60,3 +60,9 @@ target_link_libraries(shell32_apitest_sub cpprt atl_classes) set_module_type(shell32_apitest_sub win32gui UNICODE) add_importlibs(shell32_apitest_sub msvcrt kernel32 user32 shell32 shlwapi ole32) add_rostests_file(TARGET shell32_apitest_sub SUBDIR testdata) + +# cleanup.exe +add_executable(cleanup cleanup.c) +set_module_type(cleanup win32cui UNICODE) +add_importlibs(cleanup msvcrt kernel32 user32 shell32 shlwapi ole32) +add_rostests_file(TARGET cleanup) diff --git a/modules/rostests/apitests/shell32/ShellExecuteEx.cpp b/modules/rostests/apitests/shell32/ShellExecuteEx.cpp index d239467d859..962c97c02a5 100644 --- a/modules/rostests/apitests/shell32/ShellExecuteEx.cpp +++ b/modules/rostests/apitests/shell32/ShellExecuteEx.cpp @@ -467,6 +467,54 @@ static void test_properties() ok_ptr(info.hInstApp, (HINSTANCE)2); } +static void test_sei_lpIDList() +{ + /* This tests ShellExecuteEx with lpIDList for explorer C:\ */ + + /* ITEMIDLIST for CLSID of 'My Computer' followed by PIDL for 'C:\' */ + BYTE lpitemidlist[30] = { 0x14, 0, 0x1f, 0, 0xe0, 0x4f, 0xd0, 0x20, 0xea, + 0x3a, 0x69, 0x10, 0xa2, 0xd8, 0x08, 0, 0x2b, 0x30, 0x30, 0x9d, // My Computer + 0x8, 0, 0x23, 0x43, 0x3a, 0x5c, 0x5c, 0, 0, 0,}; // C:\\ + NUL-NUL ending + BYTE *lpBytes; + lpBytes = lpitemidlist; + + SHELLEXECUTEINFOW ShellExecInfo; + BOOL Result; + STARTUPINFOW si; + PROCESS_INFORMATION pi; + HWND hWnd; + + ZeroMemory( &si, sizeof(si) ); + si.cb = sizeof(si); + ZeroMemory( &pi, sizeof(pi) ); + + ZeroMemory(&ShellExecInfo, sizeof(ShellExecInfo)); + ShellExecInfo.cbSize = sizeof(ShellExecInfo); + ShellExecInfo.fMask = SEE_MASK_IDLIST; + ShellExecInfo.hwnd = NULL; + ShellExecInfo.nShow = SW_SHOWNORMAL; + ShellExecInfo.lpFile = NULL; + ShellExecInfo.lpDirectory = NULL; + ShellExecInfo.lpIDList = lpBytes; + + /* Start the cleanup.exe program which closes the popup error box on + * our current failure, so we get results and don't hang this test. + * This program is unique to this present failure case of ReactOS. */ + CreateProcessW( L"cleanup.exe", + NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + + Result = ShellExecuteExW(&ShellExecInfo); + ok(Result == TRUE, "ShellExecuteEx lpIDList 'C:\\' failed.\n"); + trace("sei_lpIDList returned: %s.\n", Result ? "SUCCESS" : "FAILURE"); + if (Result) + { + Sleep(700); + // Terminate Window + hWnd = FindWindowW(L"CabinetWClass", L"Local Disk (C:)"); + PostMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0); + } +} + START_TEST(ShellExecuteEx) { DoAppPathTest(); @@ -475,4 +523,7 @@ START_TEST(ShellExecuteEx) DoWaitForWindow(CLASSNAME, CLASSNAME, TRUE, TRUE); Sleep(100); + + test_sei_lpIDList(); + } diff --git a/modules/rostests/apitests/shell32/cleanup.c b/modules/rostests/apitests/shell32/cleanup.c new file mode 100644 index 00000000000..dc6ae4c3317 --- /dev/null +++ b/modules/rostests/apitests/shell32/cleanup.c @@ -0,0 +1,29 @@ +/* + * PROJECT: ReactOS API tests + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Looks for a failure messagebox on ShellExecuteExW and cancels it to avoid test hang + * COPYRIGHT: Copyright 2023 Doug Lyons + */ + +#include +#include + +int wmain(int argc, WCHAR *argv[]) +{ + HWND hWnd; + INT i; + + printf("cleanup is running\n"); + for (i=0;i<5;i++) + { + hWnd = FindWindowW(L"#32770", L"Error"); + if (hWnd) + { + PostMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0); + ExitProcess(0); + } + Sleep(1000); + } + return 0; +} +