https://git.reactos.org/?p=reactos.git;a=commitdiff;h=724b20d41453a9d55b921…
commit 724b20d41453a9d55b9213149893f4d9bd41a29e
Author: Whindmar Saksit <whindsaks(a)proton.me>
AuthorDate: Thu Aug 8 19:30:14 2024 +0200
Commit: GitHub <noreply(a)github.com>
CommitDate: Thu Aug 8 19:30:14 2024 +0200
[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.
---
dll/win32/shell32/CDefaultContextMenu.cpp | 32 ++++++++++++++++++-------------
dll/win32/shell32/CShellLink.cpp | 3 +--
dll/win32/shell32/precomp.h | 9 +++++++++
dll/win32/shell32/shlexec.cpp | 22 +++++++++++----------
sdk/include/reactos/shellutils.h | 21 +++++++++++++++++++-
5 files changed, 61 insertions(+), 26 deletions(-)
diff --git a/dll/win32/shell32/CDefaultContextMenu.cpp
b/dll/win32/shell32/CDefaultContextMenu.cpp
index b7dd4eedf40..f55ed72dc3c 100644
--- a/dll/win32/shell32/CDefaultContextMenu.cpp
+++ b/dll/win32/shell32/CDefaultContextMenu.cpp
@@ -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;
diff --git a/dll/win32/shell32/CShellLink.cpp b/dll/win32/shell32/CShellLink.cpp
index 218fa2a8825..5a73cb3fe49 100644
--- a/dll/win32/shell32/CShellLink.cpp
+++ b/dll/win32/shell32/CShellLink.cpp
@@ -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)
diff --git a/dll/win32/shell32/precomp.h b/dll/win32/shell32/precomp.h
index 5b319322af6..8389048af63 100644
--- a/dll/win32/shell32/precomp.h
+++ b/dll/win32/shell32/precomp.h
@@ -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>
diff --git a/dll/win32/shell32/shlexec.cpp b/dll/win32/shell32/shlexec.cpp
index a74e1ff0f44..00b29dc27b7 100644
--- a/dll/win32/shell32/shlexec.cpp
+++ b/dll/win32/shell32/shlexec.cpp
@@ -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(¶meters, 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");
diff --git a/sdk/include/reactos/shellutils.h b/sdk/include/reactos/shellutils.h
index 7487288cee1..17d7e0e74e7 100644
--- a/sdk/include/reactos/shellutils.h
+++ b/sdk/include/reactos/shellutils.h
@@ -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