https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a1157f86f2766e2916147…
commit a1157f86f2766e2916147965293bc532e70f66af
Author: Whindmar Saksit <whindsaks(a)proton.me>
AuthorDate: Sat Feb 15 14:27:51 2025 +0100
Commit: GitHub <noreply(a)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);