[SHELL32] OpenWith should use dll path instead when the command starts with rundll32 (#7712)

CORE-16980
This commit is contained in:
Whindmar Saksit 2025-02-15 14:27:51 +01:00 committed by GitHub
parent 396249d9e0
commit a1157f86f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 71 additions and 17 deletions

View file

@ -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)
{

View file

@ -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;

View file

@ -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);