https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a1157f86f2766e2916147965293bc532e70f66af

commit a1157f86f2766e2916147965293bc532e70f66af
Author:     Whindmar Saksit <whinds...@proton.me>
AuthorDate: Sat Feb 15 14:27:51 2025 +0100
Commit:     GitHub <nore...@github.com>
CommitDate: Sat Feb 15 14:27:51 2025 +0100

    [SHELL32] OpenWith should use dll path instead when the command starts with 
rundll32 (#7712)
    
    CORE-16980
---
 dll/win32/shell32/COpenWithMenu.cpp      | 77 +++++++++++++++++++++++++-------
 dll/win32/shell32/dialogs/filedefext.cpp | 10 ++++-
 dll/win32/shell32/precomp.h              |  1 +
 3 files changed, 71 insertions(+), 17 deletions(-)

diff --git a/dll/win32/shell32/COpenWithMenu.cpp 
b/dll/win32/shell32/COpenWithMenu.cpp
index 96a73dd822d..3e081de625b 100644
--- a/dll/win32/shell32/COpenWithMenu.cpp
+++ b/dll/win32/shell32/COpenWithMenu.cpp
@@ -31,6 +31,56 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell);
 
 EXTERN_C BOOL PathIsExeW(LPCWSTR lpszPath);
 
+static SIZE_T PathGetAppFromCommandLine(LPCWSTR pszIn, LPWSTR pszOut, SIZE_T 
cchMax)
+{
+    SIZE_T count = 0;
+    WCHAR stop = ' ';
+    if (pszIn[0] == '"')
+        stop = *(pszIn++);
+
+    for (LPCWSTR pwszSrc = pszIn; *pwszSrc && *pwszSrc != stop; ++pwszSrc)
+    {
+        if (++count >= cchMax)
+            return 0;
+        *(pszOut++) = *pwszSrc;
+    }
+    *pszOut = UNICODE_NULL;
+    return count;
+}
+
+HRESULT SHELL32_GetDllFromRundll32CommandLine(LPCWSTR pszCmd, LPWSTR pszOut, 
SIZE_T cchMax)
+{
+    WCHAR szDll[MAX_PATH + 100];
+    if (!PathGetAppFromCommandLine(pszCmd, szDll, _countof(szDll)))
+        return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
+
+    PWSTR pszName = PathFindFileNameW(szDll);
+    if (_wcsicmp(pszName, L"rundll32") && _wcsicmp(pszName, L"rundll32.exe"))
+        return E_UNEXPECTED;
+
+    PCWSTR pszDllStart = pszCmd + (pszName - szDll) + lstrlenW(pszName);
+
+    if (*pszDllStart == '\"')
+        ++pszDllStart; // Skip possible end quote of ..\rundll32.exe" 
foo.dll,func
+    while (*pszDllStart <= ' ' && *pszDllStart)
+        ++pszDllStart;
+    if (PathGetAppFromCommandLine(pszDllStart, szDll, _countof(szDll)))
+    {
+        BOOL quoted = *pszDllStart == '\"';
+        PWSTR pszComma = szDll + lstrlenW(szDll);
+        while (!quoted && pszComma > szDll && *pszComma != ',' && *pszComma != 
'\\' && *pszComma != '/')
+            --pszComma;
+        SIZE_T cch = pszComma - szDll;
+        if (cch <= cchMax && (quoted || *pszComma == ','))
+        {
+            *pszComma = UNICODE_NULL;
+            lstrcpynW(pszOut, szDll, cchMax);
+            return S_OK;
+        }
+    }
+    return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
+}
+
 class COpenWithList
 {
     public:
@@ -396,26 +446,23 @@ BOOL COpenWithList::LoadInfo(COpenWithList::SApp *pApp)
 
 BOOL COpenWithList::GetPathFromCmd(LPWSTR pwszAppPath, LPCWSTR pwszCmd)
 {
-    WCHAR wszBuf[MAX_PATH], *pwszDest = wszBuf;
+    WCHAR wszBuf[MAX_PATH];
 
     /* Remove arguments */
-    if (pwszCmd[0] == '"')
-    {
-        for(LPCWSTR pwszSrc = pwszCmd + 1; *pwszSrc && *pwszSrc != '"'; 
++pwszSrc)
-            *(pwszDest++) = *pwszSrc;
-    }
-    else
-    {
-        for(LPCWSTR pwszSrc = pwszCmd; *pwszSrc && *pwszSrc != ' '; ++pwszSrc)
-            *(pwszDest++) = *pwszSrc;
-    }
+    if (!PathGetAppFromCommandLine(pwszCmd, wszBuf, _countof(wszBuf)))
+        return FALSE;
 
-    *pwszDest = 0;
+    /* Replace rundll32.exe with the dll path */
+    SHELL32_GetDllFromRundll32CommandLine(pwszCmd, wszBuf, _countof(wszBuf));
 
-    /* Expand evn vers and optionally search for path */
+    /* Expand env. vars and optionally search for path */
     ExpandEnvironmentStrings(wszBuf, pwszAppPath, MAX_PATH);
     if (!PathFileExists(pwszAppPath))
-        return SearchPath(NULL, pwszAppPath, NULL, MAX_PATH, pwszAppPath, 
NULL);
+    {
+        UINT cch = SearchPathW(NULL, pwszAppPath, NULL, MAX_PATH, pwszAppPath, 
NULL);
+        if (!cch || cch >= MAX_PATH)
+            return FALSE;
+    }
     return TRUE;
 }
 
@@ -644,7 +691,7 @@ VOID COpenWithList::LoadRecommendedFromHKCU(LPCWSTR pwszExt)
         LoadMRUList(hKey);
         LoadProgIdList(hKey, pwszExt);
 
-        /* Handle "Aplication" value */
+        /* Handle "Application" value */
         DWORD cbBuf = sizeof(wszBuf);
         if (RegGetValueW(hKey, NULL, L"Application", RRF_RT_REG_SZ, NULL, 
wszBuf, &cbBuf) == ERROR_SUCCESS)
         {
diff --git a/dll/win32/shell32/dialogs/filedefext.cpp 
b/dll/win32/shell32/dialogs/filedefext.cpp
index e8beb7f936a..ce7f1dbe3f2 100644
--- a/dll/win32/shell32/dialogs/filedefext.cpp
+++ b/dll/win32/shell32/dialogs/filedefext.cpp
@@ -299,17 +299,23 @@ CFileDefExt::InitOpensWithField(HWND hwndDlg)
     BOOL bUnknownApp = TRUE;
     LPCWSTR pwszExt = PathFindExtensionW(m_wszPath);
 
+    // TODO: Use ASSOCSTR_EXECUTABLE with ASSOCF_REMAPRUNDLL | 
ASSOCF_IGNOREBASECLASS
     if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, L"", RRF_RT_REG_SZ, NULL, 
wszBuf, &dwSize) == ERROR_SUCCESS)
     {
         bUnknownApp = FALSE;
         StringCbCatW(wszBuf, sizeof(wszBuf), L"\\shell\\open\\command");
         dwSize = sizeof(wszPath);
+        // FIXME: Missing FileExt check, see COpenWithList::SetDefaultHandler 
for details
+        // FIXME: Use HCR_GetDefaultVerbW to find the default verb
         if (RegGetValueW(HKEY_CLASSES_ROOT, wszBuf, L"", RRF_RT_REG_SZ, NULL, 
wszPath, &dwSize) == ERROR_SUCCESS)
         {
             /* Get path from command line */
             ExpandEnvironmentStringsW(wszPath, wszBuf, _countof(wszBuf));
-            PathRemoveArgs(wszBuf);
-            PathUnquoteSpacesW(wszBuf);
+            if (SHELL32_GetDllFromRundll32CommandLine(wszBuf, wszBuf, 
_countof(wszBuf)) != S_OK)
+            {
+                PathRemoveArgs(wszBuf);
+                PathUnquoteSpacesW(wszBuf);
+            }
             PathSearchAndQualify(wszBuf, wszPath, _countof(wszPath));
 
             HICON hIcon;
diff --git a/dll/win32/shell32/precomp.h b/dll/win32/shell32/precomp.h
index 267ed1d44c9..3a70cb606c8 100644
--- a/dll/win32/shell32/precomp.h
+++ b/dll/win32/shell32/precomp.h
@@ -293,6 +293,7 @@ BindCtx_RegisterObjectParam(
 BOOL PathIsDotOrDotDotW(_In_ LPCWSTR pszPath);
 BOOL PathIsValidElement(_In_ LPCWSTR pszPath);
 BOOL PathIsDosDevice(_In_ LPCWSTR pszName);
+HRESULT SHELL32_GetDllFromRundll32CommandLine(LPCWSTR pszCmd, LPWSTR pszOut, 
SIZE_T cchMax);
 HRESULT SHILAppend(_Inout_ LPITEMIDLIST pidl, _Inout_ LPITEMIDLIST *ppidl);
 
 PIDLIST_ABSOLUTE SHELL_CIDA_ILCloneFull(_In_ const CIDA *pCIDA, _In_ UINT 
Index);

Reply via email to