[SHELL32] Invoke the ItemIDList of shortcuts (#7152)

Invoking the IDList as if the target was double-clicked in Explorer fixes shortcuts to control panel items (both .cpl and ShellFolder types).

CORE-19690
This commit is contained in:
Whindmar Saksit 2024-07-22 19:31:48 +02:00 committed by GitHub
parent a45d375f60
commit f6a25d48d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 52 additions and 24 deletions

View file

@ -110,6 +110,21 @@ static int FindVerbInDefaultVerbList(LPCWSTR List, LPCWSTR Verb)
return -1;
}
EXTERN_C HRESULT SHELL32_EnumDefaultVerbList(LPCWSTR List, UINT Index, LPWSTR Verb, SIZE_T cchMax)
{
for (UINT i = 0; *List; ++i)
{
while (IsVerbListSeparator(*List))
List++;
LPCWSTR Start = List;
while (*List && !IsVerbListSeparator(*List))
List++;
if (List > Start && i == Index)
return StringCchCopyNW(Verb, cchMax, Start, List - Start);
}
return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
}
class CDefaultContextMenu :
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IContextMenu3,

View file

@ -2569,7 +2569,7 @@ HRESULT STDMETHODCALLTYPE CShellLink::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
// as the parent window handle... ?
/* FIXME: get using interface set from IObjectWithSite?? */
// NOTE: We might need an extended version of Resolve that provides us with paths...
HRESULT hr = Resolve(lpici->hwnd, 0);
HRESULT hr = Resolve(lpici->hwnd, (lpici->fMask & CMIC_MASK_FLAG_NO_UI) ? SLR_NO_UI : 0);
if (FAILED(hr))
{
TRACE("failed to resolve component error 0x%08x\n", hr);
@ -2624,7 +2624,7 @@ HRESULT CShellLink::DoOpen(LPCMINVOKECOMMANDINFO lpici)
if (m_pPidl)
{
sei.lpIDList = m_pPidl;
sei.fMask |= SEE_MASK_IDLIST;
sei.fMask |= SEE_MASK_INVOKEIDLIST;
}
else
{
@ -2633,12 +2633,9 @@ HRESULT CShellLink::DoOpen(LPCMINVOKECOMMANDINFO lpici)
sei.lpParameters = args;
sei.lpClass = m_sLinkPath;
sei.nShow = m_Header.nShowCommand;
if (lpici->nShow != SW_SHOWNORMAL && lpici->nShow != SW_SHOW)
sei.nShow = lpici->nShow; // Allow invoker to override .lnk show mode
sei.lpDirectory = m_sWorkDir;
sei.lpVerb = L"open";
// HACK for ShellExecuteExW: Change the default verb if this is a Control Panel applet
if (m_sPath && lstrcmpiW(PathFindExtensionW(m_sPath), L".cpl") == 0)
sei.lpVerb = L"cplopen";
return (ShellExecuteExW(&sei) ? S_OK : E_FAIL);
}

View file

@ -1557,16 +1557,25 @@ static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)
__SHCloneStrWtoA(&verb, sei->lpVerb);
__SHCloneStrWtoA(&parameters, sei->lpParameters);
CMINVOKECOMMANDINFOEX ici = {};
ici.cbSize = sizeof ici;
ici.fMask = (sei->fMask & (SEE_MASK_NO_CONSOLE | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI));
BOOL fDefault = !sei->lpVerb || !sei->lpVerb[0];
CMINVOKECOMMANDINFOEX ici = { sizeof(ici) };
ici.fMask = (sei->fMask & (SEE_MASK_NO_CONSOLE | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI)) | CMIC_MASK_UNICODE;
ici.nShow = sei->nShow;
ici.lpVerb = verb;
if (!fDefault)
{
ici.lpVerb = verb;
ici.lpVerbW = sei->lpVerb;
}
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.lpTitleW = sei->lpClass;
}
HMENU hMenu = CreatePopupMenu();
BOOL fDefault = !ici.lpVerb || !ici.lpVerb[0];
hr = cm->QueryContextMenu(hMenu, 0, 1, 0x7fff, fDefault ? CMF_DEFAULTONLY : 0);
if (!FAILED_UNEXPECTEDLY(hr))
{
@ -1575,6 +1584,7 @@ static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)
INT uDefault = GetMenuDefaultItem(hMenu, FALSE, 0);
uDefault = (uDefault != -1) ? uDefault - 1 : 0;
ici.lpVerb = MAKEINTRESOURCEA(uDefault);
ici.lpVerbW = MAKEINTRESOURCEW(uDefault);
}
hr = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);

View file

@ -130,9 +130,11 @@ BOOL HCR_MapTypeToValueA(LPCSTR szExtension, LPSTR szFileType, LONG len, BOOL bP
return TRUE;
}
EXTERN_C HRESULT SHELL32_EnumDefaultVerbList(LPCWSTR List, UINT Index, LPWSTR Verb, SIZE_T cchMax);
BOOL HCR_GetDefaultVerbW( HKEY hkeyClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len )
{
WCHAR sTemp[MAX_PATH];
WCHAR sTemp[MAX_PATH], verbs[MAX_PATH];
LONG size;
HKEY hkey;
@ -144,21 +146,25 @@ BOOL HCR_GetDefaultVerbW( HKEY hkeyClass, LPCWSTR szVerb, LPWSTR szDest, DWORD l
return TRUE;
}
size=len;
*szDest='\0';
if (!RegQueryValueW(hkeyClass, L"shell\\", szDest, &size) && *szDest)
/* MSDN says to first try the default verb */
size = _countof(verbs);
if (!RegQueryValueW(hkeyClass, L"shell", verbs, &size) && *verbs)
{
/* The MSDN says to first try the default verb */
lstrcpyW(sTemp, L"shell\\");
lstrcatW(sTemp, szDest);
lstrcatW(sTemp, L"\\command");
if (!RegOpenKeyExW(hkeyClass, sTemp, 0, KEY_READ, &hkey))
for (UINT i = 0;; ++i)
{
RegCloseKey(hkey);
TRACE("default verb=%s\n", debugstr_w(szDest));
return TRUE;
if (FAILED(SHELL32_EnumDefaultVerbList(verbs, i, szDest, len)))
break;
if (FAILED(StringCchPrintfW(sTemp, _countof(sTemp), L"shell\\%s\\command", szDest)))
break;
if (!RegOpenKeyExW(hkeyClass, sTemp, 0, KEY_READ, &hkey))
{
RegCloseKey(hkey);
TRACE("default verb=%s\n", debugstr_w(szDest));
return TRUE;
}
}
}
*szDest = UNICODE_NULL;
/* then fallback to 'open' */
lstrcpyW(sTemp, L"shell\\open\\command");