[SHELL32] Improve FindExecutableW (#6635)
authorKatayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
Wed, 27 Mar 2024 08:04:49 +0000 (17:04 +0900)
committerGitHub <noreply@github.com>
Wed, 27 Mar 2024 08:04:49 +0000 (17:04 +0900)
Follow-up to #6656. An approach to
implement ShellExecuteEx correctly.
JIRA issue: CORE-19493
- Rewrite code by using AssocQueryStringW
  and PathResolveW functions.

dll/win32/shell32/shlexec.cpp

index 3d74c66..10d2756 100644 (file)
@@ -1256,29 +1256,52 @@ HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResu
  */
 HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult)
 {
-    UINT_PTR retval = SE_ERR_NOASSOC;
-    WCHAR old_dir[1024];
-    WCHAR res[MAX_PATH];
+    UINT_PTR retval;
+    WCHAR old_dir[MAX_PATH], res[MAX_PATH];
+    DWORD cch = _countof(res);
+    LPCWSTR dirs[2];
 
     TRACE("File %s, Dir %s\n", debugstr_w(lpFile), debugstr_w(lpDirectory));
 
-    lpResult[0] = '\0'; /* Start off with an empty return string */
-    if (lpFile == NULL)
-        return (HINSTANCE)SE_ERR_FNF;
+    *lpResult = UNICODE_NULL;
 
-    if (lpDirectory)
+    GetCurrentDirectoryW(_countof(old_dir), old_dir);
+
+    if (lpDirectory && *lpDirectory)
     {
-        GetCurrentDirectoryW(ARRAY_SIZE(old_dir), old_dir);
         SetCurrentDirectoryW(lpDirectory);
+        dirs[0] = lpDirectory;
     }
+    else
+    {
+        dirs[0] = old_dir;
+    }
+    dirs[1] = NULL;
 
-    retval = SHELL_FindExecutable(lpDirectory, lpFile, L"open", res, MAX_PATH, NULL, NULL, NULL, NULL);
-    if (retval > 32)
-        strcpyW(lpResult, res);
+    if (!GetShortPathNameW(lpFile, res, _countof(res)))
+        StringCchCopyW(res, _countof(res), lpFile);
+
+    if (PathResolveW(res, dirs, PRF_TRYPROGRAMEXTENSIONS))
+    {
+        // NOTE: The last parameter of this AssocQueryStringW call is "strange" in Windows.
+        if (PathIsExeW(res) ||
+            SUCCEEDED(AssocQueryStringW(ASSOCF_NONE, ASSOCSTR_EXECUTABLE, res, NULL, res, &cch)))
+        {
+            StringCchCopyW(lpResult, MAX_PATH, res);
+            retval = 42;
+        }
+        else
+        {
+            retval = SE_ERR_NOASSOC;
+        }
+    }
+    else
+    {
+        retval = SE_ERR_FNF;
+    }
 
     TRACE("returning %s\n", debugstr_w(lpResult));
-    if (lpDirectory)
-        SetCurrentDirectoryW(old_dir);
+    SetCurrentDirectoryW(old_dir);
     return (HINSTANCE)retval;
 }
 
@@ -2550,7 +2573,7 @@ HRESULT WINAPI ShellExecCmdLine(
     if (dwSeclFlags & SECL_RUNAS)
     {
         dwSize = 0;
-        hr = AssocQueryStringW(0, ASSOCSTR_COMMAND, lpCommand, L"RunAs", NULL, &dwSize);
+        hr = AssocQueryStringW(ASSOCF_NONE, ASSOCSTR_COMMAND, lpCommand, L"RunAs", NULL, &dwSize);
         if (SUCCEEDED(hr) && dwSize != 0)
         {
             pszVerb = L"runas";