[SHELL32][SHDOCVW] Only forward menu messages to the correct shell extension (#7968)

Folder Marker 1.4 fails if it gets a WM_INITPOPUPMENU it does not expect.

CORE-17811
This commit is contained in:
Whindmar Saksit 2025-05-15 12:21:22 +02:00 committed by GitHub
parent 6bfb792439
commit 53685ada35
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 77 additions and 81 deletions

View file

@ -973,6 +973,17 @@ struct CMenuTemp
} }
}; };
static LRESULT CALLBACK MenuMessageForwarderWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT ret = 0;
IContextMenu *pCM = (IContextMenu*)GetWindowLongPtrW(hWnd, 0);
if (uMsg == WM_DESTROY)
SetWindowLongPtrW(hWnd, 0, 0);
else if (pCM && SHForwardContextMenuMsg(pCM, uMsg, wParam, lParam, &ret, TRUE) == S_OK)
return ret;
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
// *** ATL event handlers *** // *** ATL event handlers ***
LRESULT CNSCBand::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) LRESULT CNSCBand::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{ {
@ -1033,8 +1044,13 @@ LRESULT CNSCBand::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &b
return 0; return 0;
SHELL_RemoveVerb(contextMenu, idCmdFirst, menuTemp, L"link"); SHELL_RemoveVerb(contextMenu, idCmdFirst, menuTemp, L"link");
HWND hWndWorker = SHCreateWorkerWindowW(MenuMessageForwarderWndProc, m_hWnd, 0,
WS_CHILD | WS_VISIBLE, NULL,
(LONG_PTR)static_cast<IContextMenu*>(contextMenu));
HWND hWndMenuOwner = hWndWorker ? hWndWorker : m_hWnd;
enum { flags = TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON }; enum { flags = TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON };
UINT uCommand = ::TrackPopupMenu(menuTemp, flags, pt.x, pt.y, 0, m_hWnd, NULL); UINT uCommand = ::TrackPopupMenu(menuTemp, flags, pt.x, pt.y, 0, hWndMenuOwner, NULL);
if (uCommand) if (uCommand)
{ {
uCommand -= idCmdFirst; uCommand -= idCmdFirst;
@ -1050,6 +1066,8 @@ LRESULT CNSCBand::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &b
hr = _ExecuteCommand(contextMenu, uCommand); hr = _ExecuteCommand(contextMenu, uCommand);
} }
if (hWndWorker)
::DestroyWindow(hWndWorker);
return TRUE; return TRUE;
} }

View file

@ -141,16 +141,16 @@ struct MenuCleanup
} }
~MenuCleanup() ~MenuCleanup()
{ {
if (m_hMenu)
{
DestroyMenu(m_hMenu);
m_hMenu = NULL;
}
if (m_pCM) if (m_pCM)
{ {
IUnknown_SetSite(m_pCM, NULL); IUnknown_SetSite(m_pCM, NULL);
m_pCM.Release(); m_pCM.Release();
} }
if (m_hMenu)
{
DestroyMenu(m_hMenu);
m_hMenu = NULL;
}
} }
}; };
@ -497,7 +497,7 @@ public:
LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT OnUpdateStatusbar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnUpdateStatusbar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnMenuMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT OnChangeCBChain(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnChangeCBChain(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
@ -548,8 +548,8 @@ public:
MESSAGE_HANDLER(SHV_CHANGE_NOTIFY, OnChangeNotify) MESSAGE_HANDLER(SHV_CHANGE_NOTIFY, OnChangeNotify)
MESSAGE_HANDLER(SHV_UPDATESTATUSBAR, OnUpdateStatusbar) MESSAGE_HANDLER(SHV_UPDATESTATUSBAR, OnUpdateStatusbar)
MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu) MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
MESSAGE_HANDLER(WM_DRAWITEM, OnCustomItem) MESSAGE_HANDLER(WM_DRAWITEM, OnMenuMessage)
MESSAGE_HANDLER(WM_MEASUREITEM, OnCustomItem) MESSAGE_HANDLER(WM_MEASUREITEM, OnMenuMessage)
MESSAGE_HANDLER(WM_SHOWWINDOW, OnShowWindow) MESSAGE_HANDLER(WM_SHOWWINDOW, OnShowWindow)
MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode) MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy) MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
@ -3009,10 +3009,7 @@ LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &
return TRUE; return TRUE;
} }
HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId); LRESULT CDefView::OnMenuMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
HRESULT SHSetMenuIdInMenuMsg(UINT uMsg, LPARAM lParam, UINT CmdId);
LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{ {
if (!m_pCM) if (!m_pCM)
{ {
@ -3020,19 +3017,9 @@ LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bH
ERR("no context menu\n"); ERR("no context menu\n");
return FALSE; return FALSE;
} }
LRESULT result = 0;
// lParam of WM_DRAWITEM WM_MEASUREITEM contains a menu id and HRESULT hres = SHForwardContextMenuMsg(m_pCM, uMsg, wParam, lParam, &result, TRUE);
// this also needs to be changed to a menu identifier offset return SUCCEEDED(hres);
UINT CmdID;
HRESULT hres = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdID);
if (SUCCEEDED(hres))
SHSetMenuIdInMenuMsg(uMsg, lParam, CmdID - CONTEXT_MENU_BASE_ID);
/* Forward the message to the IContextMenu2 */
LRESULT result;
hres = SHForwardContextMenuMsg(m_pCM, uMsg, wParam, lParam, &result, TRUE);
return (SUCCEEDED(hres));
} }
LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
@ -3049,10 +3036,12 @@ LRESULT CDefView::OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
{ {
HMENU hmenu = (HMENU) wParam; HMENU hmenu = (HMENU) wParam;
int nPos = LOWORD(lParam); int nPos = LOWORD(lParam);
UINT menuItemId; UINT menuItemId;
if (m_isEditing)
ListView_CancelEditLabel(m_ListView);
if (m_pCM) if (m_pCM)
OnCustomItem(uMsg, wParam, lParam, bHandled); OnMenuMessage(uMsg, wParam, lParam, bHandled);
HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW); HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW);

View file

@ -157,6 +157,7 @@ class CDefaultContextMenu :
UINT m_cKeys; UINT m_cKeys;
PIDLIST_ABSOLUTE m_pidlFolder; PIDLIST_ABSOLUTE m_pidlFolder;
DWORD m_bGroupPolicyActive; DWORD m_bGroupPolicyActive;
UINT m_iIdQCMFirst; /* The first id passed to us in QueryContextMenu */
CAtlList<DynamicShellEntry> m_DynamicEntries; CAtlList<DynamicShellEntry> m_DynamicEntries;
UINT m_iIdSHEFirst; /* first used id */ UINT m_iIdSHEFirst; /* first used id */
UINT m_iIdSHELast; /* last used id */ UINT m_iIdSHELast; /* last used id */
@ -244,6 +245,7 @@ CDefaultContextMenu::CDefaultContextMenu() :
m_cKeys(NULL), m_cKeys(NULL),
m_pidlFolder(NULL), m_pidlFolder(NULL),
m_bGroupPolicyActive(0), m_bGroupPolicyActive(0),
m_iIdQCMFirst(0),
m_iIdSHEFirst(0), m_iIdSHEFirst(0),
m_iIdSHELast(0), m_iIdSHELast(0),
m_iIdSCMFirst(0), m_iIdSCMFirst(0),
@ -841,7 +843,7 @@ CDefaultContextMenu::QueryContextMenu(
UINT uFlags) UINT uFlags)
{ {
HRESULT hr; HRESULT hr;
UINT idCmdNext = idCmdFirst; UINT idCmdNext = m_iIdQCMFirst = idCmdFirst;
UINT cIds = 0; UINT cIds = 0;
TRACE("BuildShellItemContextMenu entered\n"); TRACE("BuildShellItemContextMenu entered\n");
@ -1536,7 +1538,6 @@ CDefaultContextMenu::InvokeCommand(
else else
return E_INVALIDARG; return E_INVALIDARG;
} }
CmdId = LOWORD(LocalInvokeInfo.lpVerb); CmdId = LOWORD(LocalInvokeInfo.lpVerb);
if (!m_DynamicEntries.IsEmpty() && CmdId >= m_iIdSHEFirst && CmdId < m_iIdSHELast) if (!m_DynamicEntries.IsEmpty() && CmdId >= m_iIdSHEFirst && CmdId < m_iIdSHELast)
@ -1726,8 +1727,7 @@ CDefaultContextMenu::HandleMenuMsg(
WPARAM wParam, WPARAM wParam,
LPARAM lParam) LPARAM lParam)
{ {
/* FIXME: Should we implement this as well? */ return HandleMenuMsg2(uMsg, wParam, lParam, NULL);
return S_OK;
} }
HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId) HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId)
@ -1744,25 +1744,6 @@ HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId)
*CmdId = pMeasureStruct->itemID; *CmdId = pMeasureStruct->itemID;
return S_OK; return S_OK;
} }
return E_FAIL;
}
HRESULT SHSetMenuIdInMenuMsg(UINT uMsg, LPARAM lParam, UINT CmdId)
{
if (uMsg == WM_DRAWITEM)
{
DRAWITEMSTRUCT* pDrawStruct = reinterpret_cast<DRAWITEMSTRUCT*>(lParam);
pDrawStruct->itemID = CmdId;
return S_OK;
}
else if (uMsg == WM_MEASUREITEM)
{
MEASUREITEMSTRUCT* pMeasureStruct = reinterpret_cast<MEASUREITEMSTRUCT*>(lParam);
pMeasureStruct->itemID = CmdId;
return S_OK;
}
return E_FAIL; return E_FAIL;
} }
@ -1774,34 +1755,31 @@ CDefaultContextMenu::HandleMenuMsg2(
LPARAM lParam, LPARAM lParam,
LRESULT *plResult) LRESULT *plResult)
{ {
if (uMsg == WM_INITMENUPOPUP) if (!SHELL_IsContextMenuMsg(uMsg))
{ return E_FAIL;
POSITION it = m_DynamicEntries.GetHeadPosition();
while (it != NULL)
{
DynamicShellEntry& info = m_DynamicEntries.GetNext(it);
SHForwardContextMenuMsg(info.pCM, uMsg, wParam, lParam, plResult, TRUE);
}
return S_OK;
}
UINT CmdId; UINT CmdId;
HRESULT hr = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdId); if (uMsg == WM_INITMENUPOPUP)
if (FAILED(hr))
return S_FALSE;
if (CmdId < m_iIdSHEFirst || CmdId >= m_iIdSHELast)
return S_FALSE;
CmdId -= m_iIdSHEFirst;
PDynamicShellEntry pEntry = GetDynamicEntry(CmdId);
if (pEntry)
{ {
SHSetMenuIdInMenuMsg(uMsg, lParam, CmdId - pEntry->iIdCmdFirst); CmdId = GetMenuItemID((HMENU)wParam, 0);
SHForwardContextMenuMsg(pEntry->pCM, uMsg, wParam, lParam, plResult, TRUE); if (CmdId == ~0ul)
return E_FAIL;
} }
else
{
HRESULT hr = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdId);
if (FAILED(hr))
return S_FALSE;
}
CmdId -= m_iIdQCMFirst; // Convert from Win32 id to our base
return S_OK; if (CmdId >= m_iIdSHEFirst && CmdId < m_iIdSHELast)
{
if (PDynamicShellEntry pEntry = GetDynamicEntry(CmdId - m_iIdSHEFirst))
return SHForwardContextMenuMsg(pEntry->pCM, uMsg, wParam, lParam, plResult, TRUE);
}
// TODO: _DoCallback(DFM_WM_*, ...)
return E_FAIL;
} }
HRESULT HRESULT

View file

@ -704,7 +704,7 @@ HRESULT
WINAPI WINAPI
CNewMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) CNewMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
return S_OK; return HandleMenuMsg2(uMsg, wParam, lParam, NULL);
} }
HRESULT HRESULT
@ -734,19 +734,19 @@ CNewMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plRes
if (!lpdis || lpdis->CtlType != ODT_MENU) if (!lpdis || lpdis->CtlType != ODT_MENU)
break; break;
DWORD id = LOWORD(lpdis->itemID); DWORD id = lpdis->itemID;
HICON hIcon = NULL; HICON hIcon = NULL;
if (m_idCmdFirst + id == m_idCmdFolder) if (id == m_idCmdFolder)
{ {
hIcon = m_hIconFolder; hIcon = m_hIconFolder;
} }
else if (m_idCmdFirst + id == m_idCmdLink) else if (id == m_idCmdLink)
{ {
hIcon = m_hIconLink; hIcon = m_hIconLink;
} }
else else
{ {
SHELLNEW_ITEM *pItem = FindItemFromIdOffset(id); SHELLNEW_ITEM *pItem = FindItemFromIdOffset(id - m_idCmdFirst);
if (pItem) if (pItem)
hIcon = pItem->hIcon; hIcon = pItem->hIcon;
} }

View file

@ -1337,7 +1337,7 @@ BrFolderDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
if (!info) if (!info)
return 0; return 0;
if (info->pContextMenu) if (info->pContextMenu && SHELL_IsContextMenuMsg(uMsg))
{ {
LRESULT result; LRESULT result;
if (SHForwardContextMenuMsg(info->pContextMenu, uMsg, wParam, if (SHForwardContextMenuMsg(info->pContextMenu, uMsg, wParam,

View file

@ -15,6 +15,9 @@ HRESULT WINAPI SHForwardContextMenuMsg(IUnknown* pUnk, UINT uMsg, WPARAM wParam,
IContextMenu3* pcmenu3; IContextMenu3* pcmenu3;
IContextMenu2* pcmenu2; IContextMenu2* pcmenu2;
if (!pUnk)
return E_FAIL;
/* First try to use the IContextMenu3 interface */ /* First try to use the IContextMenu3 interface */
hr = IUnknown_QueryInterface(pUnk, &IID_IContextMenu3, (void**)&pcmenu3); hr = IUnknown_QueryInterface(pUnk, &IID_IContextMenu3, (void**)&pcmenu3);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
@ -35,7 +38,9 @@ HRESULT WINAPI SHForwardContextMenuMsg(IUnknown* pUnk, UINT uMsg, WPARAM wParam,
hr = IContextMenu2_HandleMenuMsg(pcmenu2, uMsg, wParam, lParam); hr = IContextMenu2_HandleMenuMsg(pcmenu2, uMsg, wParam, lParam);
IContextMenu2_Release(pcmenu2); IContextMenu2_Release(pcmenu2);
return hr; if (pResult)
*pResult = 0;
return hr == S_OK ? S_FALSE : hr;
} }
/* http://undoc.airesoft.co.uk/shlwapi.dll/SHAreIconsEqual.php */ /* http://undoc.airesoft.co.uk/shlwapi.dll/SHAreIconsEqual.php */

View file

@ -635,6 +635,12 @@ typedef CCoInitBase<OleInitialize, OleUninitialize> COleInit;
#define SEE_CMIC_COMMON_FLAGS (SEE_CMIC_COMMON_BASICFLAGS | SEE_MASK_HOTKEY | SEE_MASK_ICON | \ #define SEE_CMIC_COMMON_FLAGS (SEE_CMIC_COMMON_BASICFLAGS | SEE_MASK_HOTKEY | SEE_MASK_ICON | \
SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE) SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE)
static inline BOOL SHELL_IsContextMenuMsg(UINT uMsg)
{
return uMsg == WM_MEASUREITEM || uMsg == WM_DRAWITEM ||
uMsg == WM_INITMENUPOPUP || uMsg == WM_MENUSELECT || uMsg == WM_MENUCHAR;
}
static inline BOOL ILIsSingle(LPCITEMIDLIST pidl) static inline BOOL ILIsSingle(LPCITEMIDLIST pidl)
{ {
return pidl == ILFindLastID(pidl); return pidl == ILFindLastID(pidl);