[SHELL32] Don't add the file to the parameters if the registry command did not ask for a file (#7139)

Bugs fixed:
 - fDefault detection of default verb is flawed because it checks the ici struct after conversion instead of the source sei struct.
 - The command to execute should not have the filename appended just because %1 nor %L did not appear in the registry command template.
This commit is contained in:
Whindmar Saksit 2024-08-08 19:30:14 +02:00 committed by GitHub
parent 8f483a76a6
commit 724b20d414
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 61 additions and 26 deletions

View file

@ -1302,8 +1302,7 @@ CDefaultContextMenu::TryToBrowse(
HRESULT
CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFOEX lpcmi, LPCITEMIDLIST pidl, PStaticShellEntry pEntry)
{
BOOL unicode = lpcmi->cbSize >= FIELD_OFFSET(CMINVOKECOMMANDINFOEX, ptInvoke) &&
(lpcmi->fMask & CMIC_MASK_UNICODE);
const BOOL unicode = IsUnicode(*lpcmi);
LPITEMIDLIST pidlFull = ILCombine(m_pidlFolder, pidl);
if (pidlFull == NULL)
@ -1315,7 +1314,23 @@ CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFOEX lpcmi, LPCITEMIDLIST pid
BOOL bHasPath = SHGetPathFromIDListW(pidlFull, wszPath);
WCHAR wszDir[MAX_PATH];
if (bHasPath)
SHELLEXECUTEINFOW sei = { sizeof(sei) };
sei.fMask = SEE_MASK_CLASSKEY | SEE_MASK_IDLIST | (CmicFlagsToSeeFlags(lpcmi->fMask) & ~SEE_MASK_INVOKEIDLIST);
sei.hwnd = lpcmi->hwnd;
sei.nShow = lpcmi->nShow;
sei.lpVerb = pEntry->Verb;
sei.lpIDList = pidlFull;
sei.hkeyClass = pEntry->hkClass;
sei.dwHotKey = lpcmi->dwHotKey;
sei.hIcon = lpcmi->hIcon;
sei.lpDirectory = wszDir;
if (unicode && !StrIsNullOrEmpty(lpcmi->lpDirectoryW))
{
sei.lpDirectory = lpcmi->lpDirectoryW;
}
else if (bHasPath)
{
wcscpy(wszDir, wszPath);
PathRemoveFileSpec(wszDir);
@ -1326,25 +1341,16 @@ CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFOEX lpcmi, LPCITEMIDLIST pid
*wszDir = UNICODE_NULL;
}
CComHeapPtr<WCHAR> pszParamsW;
SHELLEXECUTEINFOW sei = { sizeof(sei) };
sei.hwnd = lpcmi->hwnd;
sei.nShow = SW_SHOWNORMAL;
sei.lpVerb = pEntry->Verb;
sei.lpDirectory = wszDir;
sei.lpIDList = pidlFull;
sei.hkeyClass = pEntry->hkClass;
sei.fMask = SEE_MASK_CLASSKEY | SEE_MASK_IDLIST;
if (bHasPath)
sei.lpFile = wszPath;
CComHeapPtr<WCHAR> pszParamsW;
if (unicode && !StrIsNullOrEmpty(lpcmi->lpParametersW))
sei.lpParameters = lpcmi->lpParametersW;
else if (!StrIsNullOrEmpty(lpcmi->lpParameters) && __SHCloneStrAtoW(&pszParamsW, lpcmi->lpParameters))
sei.lpParameters = pszParamsW;
ShellExecuteExW(&sei);
ILFree(pidlFull);
return S_OK;

View file

@ -2592,8 +2592,7 @@ HRESULT STDMETHODCALLTYPE CShellLink::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
HRESULT CShellLink::DoOpen(LPCMINVOKECOMMANDINFO lpici)
{
BOOL unicode = lpici->cbSize >= FIELD_OFFSET(CMINVOKECOMMANDINFOEX, ptInvoke) &&
(lpici->fMask & CMIC_MASK_UNICODE);
const BOOL unicode = IsUnicode(*lpici);
CStringW args;
if (m_sArgs)

View file

@ -155,6 +155,15 @@ UINT
GetDfmCmd(_In_ IContextMenu *pCM, _In_ LPCSTR verba);
#define SHELL_ExecuteControlPanelCPL(hwnd, cpl) SHRunControlPanel((cpl), (hwnd))
#define CmicFlagsToSeeFlags(flags) ((flags) & SEE_CMIC_COMMON_FLAGS)
static inline UINT SeeFlagsToCmicFlags(UINT flags)
{
if (flags & SEE_MASK_CLASSNAME)
flags &= ~(SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE);
return flags & SEE_CMIC_COMMON_FLAGS;
}
// CStubWindow32 --- The owner window of file property sheets.
// This window hides taskbar button of property sheet.
class CStubWindow32 : public CWindowImpl<CStubWindow32>

View file

@ -491,7 +491,7 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
/* make sure we don't fail the CreateProcess if the calling app passes in
* a bad working directory */
if (psei->lpDirectory && psei->lpDirectory[0])
if (!StrIsNullOrEmpty(psei->lpDirectory))
{
DWORD attr = GetFileAttributesW(psei->lpDirectory);
if (attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_DIRECTORY)
@ -1559,9 +1559,9 @@ static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)
__SHCloneStrWtoA(&verb, sei->lpVerb);
__SHCloneStrWtoA(&parameters, sei->lpParameters);
BOOL fDefault = !sei->lpVerb || !sei->lpVerb[0];
BOOL fDefault = StrIsNullOrEmpty(sei->lpVerb);
CMINVOKECOMMANDINFOEX ici = { sizeof(ici) };
ici.fMask = (sei->fMask & (SEE_MASK_NO_CONSOLE | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI)) | CMIC_MASK_UNICODE;
ici.fMask = SeeFlagsToCmicFlags(sei->fMask) | CMIC_MASK_UNICODE;
ici.nShow = sei->nShow;
if (!fDefault)
{
@ -1571,20 +1571,20 @@ static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)
ici.hwnd = sei->hwnd;
ici.lpParameters = parameters;
ici.lpParametersW = sei->lpParameters;
if ((sei->fMask & (SEE_MASK_HASLINKNAME | SEE_MASK_CLASSNAME)) == SEE_MASK_HASLINKNAME)
{
ici.fMask |= CMIC_MASK_HASLINKNAME;
ici.dwHotKey = sei->dwHotKey;
ici.hIcon = sei->hIcon;
if (ici.fMask & (CMIC_MASK_HASLINKNAME | CMIC_MASK_HASTITLE))
ici.lpTitleW = sei->lpClass;
}
enum { idFirst = 1, idLast = 0x7fff };
HMENU hMenu = CreatePopupMenu();
hr = cm->QueryContextMenu(hMenu, 0, 1, 0x7fff, fDefault ? CMF_DEFAULTONLY : 0);
hr = cm->QueryContextMenu(hMenu, 0, idFirst, idLast, fDefault ? CMF_DEFAULTONLY : 0);
if (!FAILED_UNEXPECTEDLY(hr))
{
if (fDefault)
{
INT uDefault = GetMenuDefaultItem(hMenu, FALSE, 0);
uDefault = (uDefault != -1) ? uDefault - 1 : 0;
uDefault = (uDefault != -1) ? uDefault - idFirst : 0;
ici.lpVerb = MAKEINTRESOURCEA(uDefault);
ici.lpVerbW = MAKEINTRESOURCEW(uDefault);
}
@ -1600,7 +1600,6 @@ static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)
}
/*************************************************************************
* ShellExecute_FromContextMenu [Internal]
*/
@ -1676,6 +1675,8 @@ static UINT_PTR SHELL_execute_class(LPCWSTR wszApplicationName, LPSHELLEXECUTEIN
&resultLen, (psei->lpDirectory && *psei->lpDirectory) ? psei->lpDirectory : NULL);
if (!done && wszApplicationName[0])
{
#if 0 // Given HKCR\.test=SZ:"test" and HKCR\test\shell\open\command=SZ:"cmd.exe /K echo.Hello", no filename is
// appended on Windows when there is no %1 nor %L when executed with: shlextdbg.exe /shellexec=c:\file.test /INVOKE
strcatW(wcmd, L" ");
if (*wszApplicationName != '"')
{
@ -1685,6 +1686,7 @@ static UINT_PTR SHELL_execute_class(LPCWSTR wszApplicationName, LPSHELLEXECUTEIN
}
else
strcatW(wcmd, wszApplicationName);
#endif
}
if (resultLen > ARRAY_SIZE(wcmd))
ERR("Argify buffer not large enough... truncating\n");

View file

@ -609,6 +609,12 @@ struct CCoInit
#define S_GREATERTHAN S_FALSE
#define MAKE_COMPARE_HRESULT(x) ((x)>0 ? S_GREATERTHAN : ((x)<0 ? S_LESSTHAN : S_EQUAL))
#define SEE_CMIC_COMMON_BASICFLAGS (SEE_MASK_NOASYNC | SEE_MASK_ASYNCOK | SEE_MASK_UNICODE | \
SEE_MASK_NO_CONSOLE | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_SEPVDM | \
SEE_MASK_FLAG_LOG_USAGE | SEE_MASK_NOZONECHECKS)
#define SEE_CMIC_COMMON_FLAGS (SEE_CMIC_COMMON_BASICFLAGS | SEE_MASK_HOTKEY | SEE_MASK_ICON | \
SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE)
static inline BOOL ILIsSingle(LPCITEMIDLIST pidl)
{
return pidl == ILFindLastID(pidl);
@ -627,6 +633,19 @@ static inline PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const* pida, SIZE_T i)
#ifdef __cplusplus
#if defined(CMIC_MASK_UNICODE) && defined(SEE_MASK_UNICODE)
static inline bool IsUnicode(const CMINVOKECOMMANDINFOEX &ici)
{
const UINT minsize = FIELD_OFFSET(CMINVOKECOMMANDINFOEX, ptInvoke);
return (ici.fMask & CMIC_MASK_UNICODE) && ici.cbSize >= minsize;
}
static inline bool IsUnicode(const CMINVOKECOMMANDINFO &ici)
{
return IsUnicode(*(CMINVOKECOMMANDINFOEX*)&ici);
}
#endif // CMIC_MASK_UNICODE
DECLSPEC_SELECTANY CLIPFORMAT g_cfHIDA = NULL;
DECLSPEC_SELECTANY CLIPFORMAT g_cfShellIdListOffsets = NULL;
@ -784,7 +803,7 @@ DataObject_SetOffset(IDataObject* pDataObject, POINT* point)
return DataObject_SetData(pDataObject, g_cfShellIdListOffsets, point, sizeof(point[0]));
}
#endif
#endif // __cplusplus
#ifdef __cplusplus
struct SHELL_GetSettingImpl