diff --git a/dll/win32/shell32/shlexec.cpp b/dll/win32/shell32/shlexec.cpp index 80d4dd012c7..e6986e6b2ed 100644 --- a/dll/win32/shell32/shlexec.cpp +++ b/dll/win32/shell32/shlexec.cpp @@ -1983,21 +1983,48 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) else *wszParameters = L'\0'; + // Get the working directory WCHAR dirBuffer[MAX_PATH]; LPWSTR wszDir = dirBuffer; + wszDir[0] = UNICODE_NULL; CHeapPtr wszDirAlloc; - if (sei_tmp.lpDirectory) + if (sei_tmp.lpDirectory && *sei_tmp.lpDirectory) { - len = lstrlenW(sei_tmp.lpDirectory) + 1; - if (len > _countof(dirBuffer)) + if (sei_tmp.fMask & SEE_MASK_DOENVSUBST) { - wszDirAlloc.Allocate(len); - wszDir = wszDirAlloc; + LPWSTR tmp = expand_environment(sei_tmp.lpDirectory); + if (tmp) + { + wszDirAlloc.Attach(tmp); + wszDir = wszDirAlloc; + } + } + else + { + __SHCloneStrW(&wszDirAlloc, sei_tmp.lpDirectory); + if (wszDirAlloc) + wszDir = wszDirAlloc; + } + } + if (!wszDir[0]) + { + ::GetCurrentDirectoryW(_countof(dirBuffer), dirBuffer); + wszDir = dirBuffer; + } + // NOTE: ShellExecute should accept the invalid working directory for historical reason. + if (!PathIsDirectoryW(wszDir)) + { + INT iDrive = PathGetDriveNumberW(wszDir); + if (iDrive >= 0) + { + PathStripToRootW(wszDir); + if (!PathIsDirectoryW(wszDir)) + { + ::GetWindowsDirectoryW(dirBuffer, _countof(dirBuffer)); + wszDir = dirBuffer; + } } - strcpyW(wszDir, sei_tmp.lpDirectory); } - else - *wszDir = L'\0'; /* adjust string pointers to point to the new buffers */ sei_tmp.lpFile = wszApplicationName; @@ -2128,16 +2155,6 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) } } - if (*sei_tmp.lpDirectory) - { - LPWSTR tmp = expand_environment(sei_tmp.lpDirectory); - if (tmp) - { - wszDirAlloc.Attach(tmp); - sei_tmp.lpDirectory = wszDir = wszDirAlloc; - } - } - /* Else, try to execute the filename */ TRACE("execute: %s,%s,%s\n", debugstr_w(wszApplicationName), debugstr_w(wszParameters), debugstr_w(wszDir)); diff --git a/modules/rostests/apitests/shell32/ShellExecuteEx.cpp b/modules/rostests/apitests/shell32/ShellExecuteEx.cpp index 6d742c3ded7..2c26b33be37 100644 --- a/modules/rostests/apitests/shell32/ShellExecuteEx.cpp +++ b/modules/rostests/apitests/shell32/ShellExecuteEx.cpp @@ -14,6 +14,7 @@ #include #include #include +#include "shell32_apitest_sub.h" static WCHAR s_win_dir[MAX_PATH]; static WCHAR s_sys_dir[MAX_PATH]; @@ -440,6 +441,31 @@ static void TEST_AppPath(void) } } +static void test_DoInvalidDir(void) +{ + WCHAR szSubProgram[MAX_PATH]; + if (!FindSubProgram(szSubProgram, _countof(szSubProgram))) + { + skip("shell32_apitest_sub.exe not found\n"); + return; + } + + DWORD dwExitCode; + SHELLEXECUTEINFOW sei = { sizeof(sei), SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS }; + sei.lpFile = szSubProgram; + sei.lpParameters = L"TEST"; + sei.nShow = SW_SHOWNORMAL; + + // Test invalid path on sei.lpDirectory + WCHAR szInvalidPath[MAX_PATH] = L"M:\\This is an invalid path\n"; + sei.lpDirectory = szInvalidPath; + ok_int(ShellExecuteExW(&sei), TRUE); + WaitForSingleObject(sei.hProcess, 20 * 1000); + GetExitCodeProcess(sei.hProcess, &dwExitCode); + ok_long(dwExitCode, 0); + CloseHandle(sei.hProcess); +} + START_TEST(ShellExecuteEx) { #ifdef _WIN64 @@ -454,6 +480,7 @@ START_TEST(ShellExecuteEx) TEST_DoTestEntries(); test_properties(); test_sei_lpIDList(); + test_DoInvalidDir(); TEST_End(); }