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`
-- v7: 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 | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index 9704f9d8f06..91b5e10cbea 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; }
@@ -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 programs 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 is still not working for me
So, calling this from my application. ShellExecute( NULL, NULL, "linuxbinary", "1", "C:\Temp\Application\linux", SW_SHOW);
Produces. 0024:trace:shell:PathFindOnPathExW (L"linuxbin",077D78A4,000000bf) 0024:trace:shell:PathFileExistsDefExtW (L"C:\Temp\Application\linux\linuxbin",191) 0024:trace:shell:PathFileExistsDefExtW (L"C:\Temp\Application\linuxbin",191) 0024:trace:shell:SHLWAPI_PathFindInOtherDirs (L"linuxbin",000000bf) 0024:trace:shell:PathFileExistsDefExtW (L"C:\windows\system32\linuxbin",191 .....
The first call to PathFileExistsDefExtW, is the exact location but for some reason it wants to continue looking though every search path.
On Wed Apr 24 13:55:44 2024 +0000, Alistair Leslie-Hughes wrote:
This is still not working for me So, calling this from my application. ShellExecute( NULL, NULL, "linuxbinary", "1", "C:\Temp\Application\linux", SW_SHOW); Produces. 0024:trace:shell:PathFindOnPathExW (L"linuxbin",077D78A4,000000bf) 0024:trace:shell:PathFileExistsDefExtW (L"C:\Temp\Application\linux\linuxbin",191) 0024:trace:shell:PathFileExistsDefExtW (L"C:\Temp\Application\linuxbin",191) 0024:trace:shell:SHLWAPI_PathFindInOtherDirs (L"linuxbin",000000bf) 0024:trace:shell:PathFileExistsDefExtW (L"C:\windows\system32\linuxbin",191 ..... The first call to PathFileExistsDefExtW, is the exact location but for some reason it wants to continue looking though every search path.
Like I said, you need to call `ShellExecute( NULL, NULL, "linuxbinary.", "1", "C:\Temp\Application\linux", SW_SHOW);`, which is how `start.exe` would be doing.
Huw Davies (@huw) commented about dlls/shell32/shlexec.c:
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);
This seems to be overly indented.
Huw Davies (@huw) commented about dlls/shell32/shlexec.c:
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 programs can have any extensions. However, things get more complicated because
EOL space.
Huw Davies (@huw) commented about dlls/shell32/shlexec.c:
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
program