From 6f277e97662e5b558b6ee545d49ce6ad2935dcf8 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Mon, 15 Jul 2024 21:16:04 +0900 Subject: [PATCH] [SHELL32] shlexec.cpp: Parse 'shell:' and '::{CLSID}' (#7126) JIRA issue: CORE-14177 JIRA issue: CORE-17482 - Add SHELL_InvokePidl helper function. - Call SHParseDisplayName and SHELL_InvokePidl in a specific condition. --- dll/win32/shell32/CDefaultContextMenu.cpp | 2 - dll/win32/shell32/precomp.h | 2 + dll/win32/shell32/shlexec.cpp | 66 +++++++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/dll/win32/shell32/CDefaultContextMenu.cpp b/dll/win32/shell32/CDefaultContextMenu.cpp index 817f6ab2cc9..c82834dfac1 100644 --- a/dll/win32/shell32/CDefaultContextMenu.cpp +++ b/dll/win32/shell32/CDefaultContextMenu.cpp @@ -11,10 +11,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmenu); - // FIXME: 260 is correct, but should this be part of the SDK or just MAX_PATH? #define MAX_VERB 260 -#define VERBKEY_CCHMAX 64 // Note: 63+\0 seems to be the limit on XP static HRESULT SHELL_GetRegCLSID(HKEY hKey, LPCWSTR SubKey, LPCWSTR Value, CLSID &clsid) diff --git a/dll/win32/shell32/precomp.h b/dll/win32/shell32/precomp.h index dd9fe8b6924..5b319322af6 100644 --- a/dll/win32/shell32/precomp.h +++ b/dll/win32/shell32/precomp.h @@ -127,6 +127,8 @@ extern const GUID SHELL32_AdvtShortcutComponent; #define MAX_PROPERTY_SHEET_PAGE 32 +#define VERBKEY_CCHMAX 64 // Note: 63+\0 seems to be the limit on XP + extern inline BOOL CALLBACK diff --git a/dll/win32/shell32/shlexec.cpp b/dll/win32/shell32/shlexec.cpp index 2aa999a19db..80d4dd012c7 100644 --- a/dll/win32/shell32/shlexec.cpp +++ b/dll/win32/shell32/shlexec.cpp @@ -1738,6 +1738,59 @@ static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters return appKnownSingular; } +static BOOL +SHELL_InvokePidl( + _In_ LPSHELLEXECUTEINFOW sei, + _In_ LPCITEMIDLIST pidl) +{ + // Bind pidl + CComPtr psfFolder; + LPCITEMIDLIST pidlLast; + HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psfFolder), &pidlLast); + if (FAILED_UNEXPECTEDLY(hr)) + return FALSE; + + // Get the context menu to invoke a command + CComPtr pCM; + hr = psfFolder->GetUIObjectOf(NULL, 1, &pidlLast, IID_NULL_PPV_ARG(IContextMenu, &pCM)); + if (FAILED_UNEXPECTEDLY(hr)) + return FALSE; + + // Invoke a command + CMINVOKECOMMANDINFO ici = { sizeof(ici) }; + ici.fMask = (sei->fMask & (SEE_MASK_NO_CONSOLE | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI)); + ici.nShow = sei->nShow; + ici.hwnd = sei->hwnd; + char szVerb[VERBKEY_CCHMAX]; + if (sei->lpVerb && sei->lpVerb[0]) + { + WideCharToMultiByte(CP_ACP, 0, sei->lpVerb, -1, szVerb, _countof(szVerb), NULL, NULL); + szVerb[_countof(szVerb) - 1] = ANSI_NULL; // Avoid buffer overrun + ici.lpVerb = szVerb; + } + else // The default verb? + { + HMENU hMenu = CreatePopupMenu(); + const INT idCmdFirst = 1, idCmdLast = 0x7FFF; + hr = pCM->QueryContextMenu(hMenu, 0, idCmdFirst, idCmdLast, CMF_DEFAULTONLY); + if (FAILED_UNEXPECTEDLY(hr)) + { + DestroyMenu(hMenu); + return FALSE; + } + + INT nDefaultID = GetMenuDefaultItem(hMenu, FALSE, 0); + DestroyMenu(hMenu); + if (nDefaultID == -1) + nDefaultID = idCmdFirst; + + ici.lpVerb = MAKEINTRESOURCEA(nDefaultID - idCmdFirst); + } + hr = pCM->InvokeCommand(&ici); + + return !FAILED_UNEXPECTEDLY(hr); +} + static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR wszKeyname, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc) { UINT_PTR retval; @@ -2031,6 +2084,19 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) return retval > 32; } + if (!(sei_tmp.fMask & SEE_MASK_IDLIST) && // Not an ID List + (StrCmpNIW(sei_tmp.lpFile, L"shell:", 6) == 0 || + StrCmpNW(sei_tmp.lpFile, L"::{", 3) == 0)) + { + CComHeapPtr pidlParsed; + HRESULT hr = SHParseDisplayName(sei_tmp.lpFile, NULL, &pidlParsed, 0, NULL); + if (SUCCEEDED(hr) && SHELL_InvokePidl(&sei_tmp, pidlParsed)) + { + sei_tmp.hInstApp = (HINSTANCE)UlongToHandle(42); + return TRUE; + } + } + /* Has the IDList not yet been translated? */ if (sei_tmp.fMask & SEE_MASK_IDLIST) {