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.
-- v3: shell32: Fix ShellExecute for non-filespec paths. shell32: Make sure array passed to PathResolve is big enough.
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..ec266aebd60 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, 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);