Follow up to !5342. This adds the last missing piece for fixing how `ShellExecute` finds files, and restore the ability of running native unix programs with `ShellExecute`
-- v8: shell32: Restore the ability of running native unix programs with ShellExecute
From: Yuxuan Shui yshui@codeweavers.com
--- dlls/shell32/shlexec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index f09b6d4daf3..804aa38a904 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -637,7 +637,7 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, lstrcpyW(xlpFile, lpFile); if (PathResolveAW(xlpFile, (const void **)search_paths, PRF_TRYPROGRAMEXTENSIONS | PRF_VERIFYEXISTS)) { - TRACE("SearchPathW returned non-zero\n"); + TRACE("PathResolveAW returned non-zero\n"); lpFile = xlpFile; /* The file was found in lpPath or one of the directories in the system-wide search path */ }
From: Yuxuan Shui yshui@codeweavers.com
So that the path returned by SHELL_FindExecutable would be fully qualified, otherwise CreateProcess will do its own path resolution which is not what we want. --- dlls/shell32/shlexec.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index 804aa38a904..9704f9d8f06 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -1797,10 +1797,10 @@ static BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
if (*sei_tmp.lpDirectory) { + LPWSTR buf; len = ExpandEnvironmentStringsW(sei_tmp.lpDirectory, NULL, 0); if (len > 0) { - LPWSTR buf; len++; buf = malloc(len * sizeof(WCHAR)); ExpandEnvironmentStringsW(sei_tmp.lpDirectory, buf, len); @@ -1809,6 +1809,18 @@ static BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) wszDir = buf; sei_tmp.lpDirectory = wszDir; } + + len = GetFullPathNameW(sei_tmp.lpDirectory, 0, NULL, NULL); + if (len > 0) + { + len++; + buf = malloc(len * sizeof(WCHAR)); + GetFullPathNameW(sei_tmp.lpDirectory, len, buf, NULL); + if (wszDir != dirBuffer) + free(wszDir); + wszDir = buf; + sei_tmp.lpDirectory = wszDir; + } }
/* Else, try to execute the filename */
From: Yuxuan Shui yshui@codeweavers.com
For ShellExecute, if the specified file is found, we will try running it anyway, even if it doesn't have a "program" extension.
Windows associations will take precedence over this. --- dlls/shell32/shlexec.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index 9704f9d8f06..d2fe3caed88 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -579,6 +579,7 @@ static UINT SHELL_FindExecutableByVerb(LPCWSTR lpVerb, LPWSTR key, LPWSTR classn * * Utility for code sharing between FindExecutable and ShellExecute * in: + * lpPath the path to search for the file * lpFile the name of a file * lpVerb the operation on it (open) * out: @@ -639,6 +640,7 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, { 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 @@ -696,7 +698,6 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb,
if (wcsicmp(tok, &extension[1]) == 0) /* have to skip the leading "." */ { - lstrcpyW(lpResult, xlpFile); /* Need to perhaps check that the file has a path * attached */ TRACE("found %s\n", debugstr_w(lpResult)); @@ -781,7 +782,7 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, } }
- TRACE("returning %s\n", debugstr_w(lpResult)); + TRACE("returning path %s, retval %d\n", debugstr_w(lpResult), retval); return retval; }
@@ -1817,7 +1818,7 @@ static BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) buf = malloc(len * sizeof(WCHAR)); GetFullPathNameW(sei_tmp.lpDirectory, len, buf, NULL); if (wszDir != dirBuffer) - free(wszDir); + free(wszDir); wszDir = buf; sei_tmp.lpDirectory = wszDir; } @@ -1885,6 +1886,22 @@ static BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) lstrcatW(lpstrTmpFile, lpFile); retval = (UINT_PTR)ShellExecuteW(sei_tmp.hwnd, sei_tmp.lpVerb, lpstrTmpFile, NULL, NULL, 0); } + else if (retval == SE_ERR_NOASSOC && SHGetFileInfoW(wcmd, 0, NULL, 0, SHGFI_EXETYPE) == 0) + { + /* File found, but no association. And no other cases fit, this could be a + unix programs, try running it. We have to do this in a "catch-all" fashion because + unix program can have any extensions. However, things get more complicated because + the file we find could be a Windows executable without the proper extensions, it could + be seen as unexpected if we start it, so we special case it here. */ + UINT exec_retval; + TRACE("No association found, trying as Unix binary %s\n", debugstr_w(wcmd)); + exec_retval = SHELL_quote_and_execute( wcmd, wszParameters, wszKeyname, + wszApplicationName, env, &sei_tmp, + sei, execfunc ); + TRACE("Unix binary returned %u\n", exec_retval); + if (exec_retval > 32) + retval = exec_retval; + }
end: TRACE("retval %Iu\n", retval);
This merge request was approved by Huw Davies.