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`
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
When ShellExecute is called with the expressed intention to run a file without an extension (i.e. by putting a trailing dot in the file name), honor that and try running the file as a program. --- dlls/shell32/shlexec.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index 9704f9d8f06..b437f98e6e6 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -601,6 +601,7 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, WCHAR xlpFile[256]; /* result of SearchPath */ DWORD attribs; /* file attributes */ WCHAR curdir[MAX_PATH]; + BOOL has_trailing_dot; const WCHAR *search_paths[3] = {0};
TRACE("%s\n", debugstr_w(lpFile)); @@ -626,6 +627,7 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, return 33; }
+ has_trailing_dot = lpFile[lstrlenW(lpFile) - 1] == '.'; if (lpPath && *lpPath) { search_paths[0] = lpPath; @@ -663,10 +665,18 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, /* .\FILE.EXE :( */ TRACE("xlpFile=%s,extension=%s\n", debugstr_w(xlpFile), debugstr_w(extension));
- if (extension == NULL || extension[1]==0) + if (extension == NULL) { - WARN("Returning SE_ERR_NOASSOC\n"); - return SE_ERR_NOASSOC; + if (!has_trailing_dot) + { + WARN("Returning SE_ERR_NOASSOC\n"); + return SE_ERR_NOASSOC; + } + + /* Special wine extension to support running a native unix program, + * if the file name has an trailing dot. */ + lstrcpyW(lpResult, xlpFile); + return 33; }
/* Three places to check: */
Would it be possible to add some tests?
On Wed Mar 27 14:24:44 2024 +0000, Huw Davies wrote:
Would it be possible to add some tests?
What's the best way to add tests that only run on wine? Can't test running unix programs on Windows, also feels odd to use `broken` here.
This is still failing for me.
ShellExecute( NULL, NULL, "linuxbinary", "1", "c:\temp", SW_SHOW);
On Fri Mar 29 18:13:51 2024 +0000, Alistair Leslie-Hughes wrote:
This is still failing for me. ShellExecute( NULL, NULL, "linuxbinary", "1", "c:\temp", SW_SHOW);
what about "linuxbinary." ?