I was going to reimplement path resolution in ShellExecute, but half way through I realized that's very unnecessary.
Since what I wanted is a version of `PathResolve` that behaves differently _only_ for filespec paths, I ended up duplicating a lot of code, then I realized I can still pass filespec paths onto `PathResolve` and only deal with non-filespec paths.
-- v4: shell32: Fix ShellExecute for non-filespec paths.
From: Yuxuan Shui yshui@codeweavers.com
--- dlls/shell32/shlexec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index d2fe3caed88..f0cf27c5098 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -599,7 +599,7 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, WCHAR wBuffer[256]; /* Used to GetProfileString */ UINT retval = SE_ERR_NOASSOC; WCHAR *tok; /* token pointer */ - WCHAR xlpFile[256]; /* result of SearchPath */ + WCHAR xlpFile[MAX_PATH]; /* result of SearchPath */ DWORD attribs; /* file attributes */ WCHAR curdir[MAX_PATH]; const WCHAR *search_paths[3] = {0}; @@ -634,7 +634,7 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, } else search_paths[0] = curdir; - GetCurrentDirectoryW(MAX_PATH, curdir); + GetCurrentDirectoryW(ARRAY_SIZE(curdir), curdir); lstrcpyW(xlpFile, lpFile); if (PathResolveAW(xlpFile, (const void **)search_paths, PRF_TRYPROGRAMEXTENSIONS | PRF_VERIFYEXISTS)) {
From: Yuxuan Shui yshui@codeweavers.com
--- dlls/shell32/shlexec.c | 60 ++++++++++++++++++++++++++++-------- dlls/shell32/tests/shlexec.c | 13 +++++++- 2 files changed, 59 insertions(+), 14 deletions(-)
diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index f0cf27c5098..828c7168a34 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -49,6 +49,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(exec); typedef UINT_PTR (*SHELL_ExecuteW32)(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, const SHELLEXECUTEINFOW *sei, LPSHELLEXECUTEINFOW sei_out); extern BOOL WINAPI PathResolveAW(void *path, const void **paths, DWORD flags); +extern BOOL WINAPI PathFileExistsDefExtW(LPWSTR lpszPath,DWORD dwWhich);
static inline BOOL isSpace(WCHAR c) { @@ -627,24 +628,57 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, return 33; }
- if (lpPath && *lpPath) + GetCurrentDirectoryW(ARRAY_SIZE(curdir), curdir); + if (!PathIsFileSpecW(lpFile)) { - search_paths[0] = lpPath; - search_paths[1] = curdir; + BOOL found = FALSE; + if (lpPath && *lpPath) + { + TRACE("ASDF %s\n", debugstr_w(lpPath)); + PathCombineW(xlpFile, lpPath, lpFile); + if (PathFileExistsDefExtW(xlpFile, 0xbf)) + { + GetFullPathNameW(xlpFile, ARRAY_SIZE(xlpFile), xlpFile, NULL); + found = TRUE; + } + } + if (!found) + { + lstrcpyW(xlpFile, lpFile); + if (PathFileExistsDefExtW(xlpFile, 0xbf)) + { + GetFullPathNameW(xlpFile, ARRAY_SIZE(xlpFile), xlpFile, NULL); + found = TRUE; + } + } + if (found) + { + lpFile = xlpFile; + lstrcpyW(lpResult, xlpFile); + } + else + xlpFile[0] = '\0'; } else - search_paths[0] = curdir; - GetCurrentDirectoryW(ARRAY_SIZE(curdir), curdir); - lstrcpyW(xlpFile, lpFile); - if (PathResolveAW(xlpFile, (const void **)search_paths, PRF_TRYPROGRAMEXTENSIONS | PRF_VERIFYEXISTS)) { - TRACE("PathResolveAW returned non-zero\n"); - lpFile = xlpFile; - lstrcpyW(lpResult, xlpFile); - /* The file was found in lpPath or one of the directories in the system-wide search path */ + if (lpPath && *lpPath) + { + search_paths[0] = lpPath; + search_paths[1] = curdir; + } + else + search_paths[0] = curdir; + lstrcpyW(xlpFile, lpFile); + if (PathResolveAW(xlpFile, (const void **)search_paths, PRF_TRYPROGRAMEXTENSIONS | PRF_VERIFYEXISTS)) + { + TRACE("PathResolveAW returned non-zero\n"); + lpFile = xlpFile; + lstrcpyW(lpResult, xlpFile); + /* The file was found in lpPath or one of the directories in the system-wide search path */ + } + else + xlpFile[0] = '\0'; } - else - xlpFile[0] = '\0';
attribs = GetFileAttributesW(lpFile); if (attribs!=INVALID_FILE_ATTRIBUTES && (attribs&FILE_ATTRIBUTE_DIRECTORY)) diff --git a/dlls/shell32/tests/shlexec.c b/dlls/shell32/tests/shlexec.c index 0f537d829f4..bd32ece8705 100644 --- a/dlls/shell32/tests/shlexec.c +++ b/dlls/shell32/tests/shlexec.c @@ -2267,9 +2267,11 @@ static void test_exes(void) char filename[2 * MAX_PATH + 17]; char params[1024]; char curdir[MAX_PATH]; - char *basename = strrchr(argv0, '\') + 1; + char relative_basename[MAX_PATH]; + char *basename = strrchr(argv0, '\') + 1, *dirname = strdup(argv0); INT_PTR rc;
+ *strrchr(dirname, '\') = '\0'; sprintf(params, "shlexec "%s" Exec", child_file);
/* We need NOZONECHECKS on Win2003 to block a dialog */ @@ -2279,6 +2281,15 @@ static void test_exes(void) okChildInt("argcA", 4); okChildString("argvA3", "Exec");
+ /* Check non-filespec paths */ + snprintf(relative_basename, ARRAY_SIZE(relative_basename), ".\\%s", basename); + rc=shell_execute_ex(SEE_MASK_NOZONECHECKS | SEE_MASK_FLAG_NO_UI, NULL, relative_basename, params, + dirname, NULL); + okShell(rc > 32, "returned %Iu\n", rc); + okChildInt("argcA", 4); + okChildString("argvA3", "Exec"); + free(dirname); + rc=shell_execute_ex(SEE_MASK_NOZONECHECKS | SEE_MASK_CLASSNAME | SEE_MASK_FLAG_NO_UI, NULL, argv0, params, NULL, ".exe"); okShell(rc > 32, "returned %Iu\n", rc);
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=145939
Your paranoid android.
=== w1064v1507 (32 bit report) ===
shell32: shlexec.c:1148: Test failed: ShellExecute(file="C:\Users\winetest\AppData\Local\Temp\wtShlexecDir\drawback_nonexist.noassoc foo.shlexec") WaitForSingleObject returned 258 shlexec.c:1148: Test failed: ShellExecute(file="C:\Users\winetest\AppData\Local\Temp\wtShlexecDir\drawback_nonexist.noassoc foo.shlexec") ShlexecVar expected 'Present', but key not found or empty