From 0bad544aab9e2c9ee93bbabac0386e02c58a39c0 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 20 May 2024 09:51:07 +0100 Subject: [PATCH] shell32: Fix ShellExecute for non-filespec paths. --- dlls/shell32/shlexec.c | 62 ++++++++++++++++++++++++++++-------- dlls/shell32/tests/shlexec.c | 13 +++++++- 2 files changed, 60 insertions(+), 15 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) - { - search_paths[0] = lpPath; - search_paths[1] = curdir; - } - else - search_paths[0] = curdir; GetCurrentDirectoryW(ARRAY_SIZE(curdir), curdir); - lstrcpyW(xlpFile, lpFile); - if (PathResolveAW(xlpFile, (const void **)search_paths, PRF_TRYPROGRAMEXTENSIONS | PRF_VERIFYEXISTS)) + if (!PathIsFileSpecW(lpFile)) { - 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 */ + 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 - xlpFile[0] = '\0'; + { + 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'; + } 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);