From 53685ada35fe4ee2b372084bd63e8f505b37cd08 Mon Sep 17 00:00:00 2001 From: Whindmar Saksit Date: Thu, 15 May 2025 12:21:22 +0200 Subject: [PATCH] [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 --- dll/win32/shdocvw/CNSCBand.cpp | 20 ++++++- dll/win32/shell32/CDefView.cpp | 43 ++++++-------- dll/win32/shell32/CDefaultContextMenu.cpp | 70 ++++++++--------------- dll/win32/shell32/CNewMenu.cpp | 10 ++-- dll/win32/shell32/brfolder.cpp | 2 +- dll/win32/shlwapi/rosordinal.c | 7 ++- sdk/include/reactos/shellutils.h | 6 ++ 7 files changed, 77 insertions(+), 81 deletions(-) diff --git a/dll/win32/shdocvw/CNSCBand.cpp b/dll/win32/shdocvw/CNSCBand.cpp index 8868931bb1e..266f3e62034 100644 --- a/dll/win32/shdocvw/CNSCBand.cpp +++ b/dll/win32/shdocvw/CNSCBand.cpp @@ -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 *** 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; SHELL_RemoveVerb(contextMenu, idCmdFirst, menuTemp, L"link"); + HWND hWndWorker = SHCreateWorkerWindowW(MenuMessageForwarderWndProc, m_hWnd, 0, + WS_CHILD | WS_VISIBLE, NULL, + (LONG_PTR)static_cast(contextMenu)); + HWND hWndMenuOwner = hWndWorker ? hWndWorker : m_hWnd; + 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) { uCommand -= idCmdFirst; @@ -1050,6 +1066,8 @@ LRESULT CNSCBand::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &b hr = _ExecuteCommand(contextMenu, uCommand); } + if (hWndWorker) + ::DestroyWindow(hWndWorker); return TRUE; } diff --git a/dll/win32/shell32/CDefView.cpp b/dll/win32/shell32/CDefView.cpp index 247d3a03358..c67cc83c028 100644 --- a/dll/win32/shell32/CDefView.cpp +++ b/dll/win32/shell32/CDefView.cpp @@ -141,16 +141,16 @@ struct MenuCleanup } ~MenuCleanup() { - if (m_hMenu) - { - DestroyMenu(m_hMenu); - m_hMenu = NULL; - } if (m_pCM) { IUnknown_SetSite(m_pCM, NULL); 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 OnChangeNotify(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 OnInitMenuPopup(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_UPDATESTATUSBAR, OnUpdateStatusbar) MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu) - MESSAGE_HANDLER(WM_DRAWITEM, OnCustomItem) - MESSAGE_HANDLER(WM_MEASUREITEM, OnCustomItem) + MESSAGE_HANDLER(WM_DRAWITEM, OnMenuMessage) + MESSAGE_HANDLER(WM_MEASUREITEM, OnMenuMessage) MESSAGE_HANDLER(WM_SHOWWINDOW, OnShowWindow) MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) @@ -3009,10 +3009,7 @@ LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & return TRUE; } -HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId); -HRESULT SHSetMenuIdInMenuMsg(UINT uMsg, LPARAM lParam, UINT CmdId); - -LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) +LRESULT CDefView::OnMenuMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (!m_pCM) { @@ -3020,19 +3017,9 @@ LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bH ERR("no context menu\n"); return FALSE; } - - // lParam of WM_DRAWITEM WM_MEASUREITEM contains a menu id and - // this also needs to be changed to a menu identifier offset - 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 result = 0; + HRESULT hres = SHForwardContextMenuMsg(m_pCM, uMsg, wParam, lParam, &result, TRUE); + return SUCCEEDED(hres); } 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; int nPos = LOWORD(lParam); - UINT menuItemId; + UINT menuItemId; + if (m_isEditing) + ListView_CancelEditLabel(m_ListView); if (m_pCM) - OnCustomItem(uMsg, wParam, lParam, bHandled); + OnMenuMessage(uMsg, wParam, lParam, bHandled); HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW); diff --git a/dll/win32/shell32/CDefaultContextMenu.cpp b/dll/win32/shell32/CDefaultContextMenu.cpp index 8cb12bfae9a..f631f180e78 100644 --- a/dll/win32/shell32/CDefaultContextMenu.cpp +++ b/dll/win32/shell32/CDefaultContextMenu.cpp @@ -157,6 +157,7 @@ class CDefaultContextMenu : UINT m_cKeys; PIDLIST_ABSOLUTE m_pidlFolder; DWORD m_bGroupPolicyActive; + UINT m_iIdQCMFirst; /* The first id passed to us in QueryContextMenu */ CAtlList m_DynamicEntries; UINT m_iIdSHEFirst; /* first used id */ UINT m_iIdSHELast; /* last used id */ @@ -244,6 +245,7 @@ CDefaultContextMenu::CDefaultContextMenu() : m_cKeys(NULL), m_pidlFolder(NULL), m_bGroupPolicyActive(0), + m_iIdQCMFirst(0), m_iIdSHEFirst(0), m_iIdSHELast(0), m_iIdSCMFirst(0), @@ -841,7 +843,7 @@ CDefaultContextMenu::QueryContextMenu( UINT uFlags) { HRESULT hr; - UINT idCmdNext = idCmdFirst; + UINT idCmdNext = m_iIdQCMFirst = idCmdFirst; UINT cIds = 0; TRACE("BuildShellItemContextMenu entered\n"); @@ -1536,7 +1538,6 @@ CDefaultContextMenu::InvokeCommand( else return E_INVALIDARG; } - CmdId = LOWORD(LocalInvokeInfo.lpVerb); if (!m_DynamicEntries.IsEmpty() && CmdId >= m_iIdSHEFirst && CmdId < m_iIdSHELast) @@ -1726,8 +1727,7 @@ CDefaultContextMenu::HandleMenuMsg( WPARAM wParam, LPARAM lParam) { - /* FIXME: Should we implement this as well? */ - return S_OK; + return HandleMenuMsg2(uMsg, wParam, lParam, NULL); } HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId) @@ -1744,25 +1744,6 @@ HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId) *CmdId = pMeasureStruct->itemID; return S_OK; } - - return E_FAIL; -} - -HRESULT SHSetMenuIdInMenuMsg(UINT uMsg, LPARAM lParam, UINT CmdId) -{ - if (uMsg == WM_DRAWITEM) - { - DRAWITEMSTRUCT* pDrawStruct = reinterpret_cast(lParam); - pDrawStruct->itemID = CmdId; - return S_OK; - } - else if (uMsg == WM_MEASUREITEM) - { - MEASUREITEMSTRUCT* pMeasureStruct = reinterpret_cast(lParam); - pMeasureStruct->itemID = CmdId; - return S_OK; - } - return E_FAIL; } @@ -1774,34 +1755,31 @@ CDefaultContextMenu::HandleMenuMsg2( LPARAM lParam, LRESULT *plResult) { - if (uMsg == WM_INITMENUPOPUP) - { - 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; - } + if (!SHELL_IsContextMenuMsg(uMsg)) + return E_FAIL; UINT CmdId; - HRESULT hr = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdId); - 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) + if (uMsg == WM_INITMENUPOPUP) { - SHSetMenuIdInMenuMsg(uMsg, lParam, CmdId - pEntry->iIdCmdFirst); - SHForwardContextMenuMsg(pEntry->pCM, uMsg, wParam, lParam, plResult, TRUE); + CmdId = GetMenuItemID((HMENU)wParam, 0); + 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 diff --git a/dll/win32/shell32/CNewMenu.cpp b/dll/win32/shell32/CNewMenu.cpp index f525bf4ada4..656ae2d9592 100644 --- a/dll/win32/shell32/CNewMenu.cpp +++ b/dll/win32/shell32/CNewMenu.cpp @@ -704,7 +704,7 @@ HRESULT WINAPI CNewMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) { - return S_OK; + return HandleMenuMsg2(uMsg, wParam, lParam, NULL); } HRESULT @@ -734,19 +734,19 @@ CNewMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plRes if (!lpdis || lpdis->CtlType != ODT_MENU) break; - DWORD id = LOWORD(lpdis->itemID); + DWORD id = lpdis->itemID; HICON hIcon = NULL; - if (m_idCmdFirst + id == m_idCmdFolder) + if (id == m_idCmdFolder) { hIcon = m_hIconFolder; } - else if (m_idCmdFirst + id == m_idCmdLink) + else if (id == m_idCmdLink) { hIcon = m_hIconLink; } else { - SHELLNEW_ITEM *pItem = FindItemFromIdOffset(id); + SHELLNEW_ITEM *pItem = FindItemFromIdOffset(id - m_idCmdFirst); if (pItem) hIcon = pItem->hIcon; } diff --git a/dll/win32/shell32/brfolder.cpp b/dll/win32/shell32/brfolder.cpp index 0e8e5e791f7..da44e41a9c4 100644 --- a/dll/win32/shell32/brfolder.cpp +++ b/dll/win32/shell32/brfolder.cpp @@ -1337,7 +1337,7 @@ BrFolderDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if (!info) return 0; - if (info->pContextMenu) + if (info->pContextMenu && SHELL_IsContextMenuMsg(uMsg)) { LRESULT result; if (SHForwardContextMenuMsg(info->pContextMenu, uMsg, wParam, diff --git a/dll/win32/shlwapi/rosordinal.c b/dll/win32/shlwapi/rosordinal.c index d392b641202..0839d5fa6ff 100644 --- a/dll/win32/shlwapi/rosordinal.c +++ b/dll/win32/shlwapi/rosordinal.c @@ -15,6 +15,9 @@ HRESULT WINAPI SHForwardContextMenuMsg(IUnknown* pUnk, UINT uMsg, WPARAM wParam, IContextMenu3* pcmenu3; IContextMenu2* pcmenu2; + if (!pUnk) + return E_FAIL; + /* First try to use the IContextMenu3 interface */ hr = IUnknown_QueryInterface(pUnk, &IID_IContextMenu3, (void**)&pcmenu3); if (SUCCEEDED(hr)) @@ -35,7 +38,9 @@ HRESULT WINAPI SHForwardContextMenuMsg(IUnknown* pUnk, UINT uMsg, WPARAM wParam, hr = IContextMenu2_HandleMenuMsg(pcmenu2, uMsg, wParam, lParam); 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 */ diff --git a/sdk/include/reactos/shellutils.h b/sdk/include/reactos/shellutils.h index 531d022ba54..f4da9914bf8 100644 --- a/sdk/include/reactos/shellutils.h +++ b/sdk/include/reactos/shellutils.h @@ -635,6 +635,12 @@ typedef CCoInitBase COleInit; #define SEE_CMIC_COMMON_FLAGS (SEE_CMIC_COMMON_BASICFLAGS | SEE_MASK_HOTKEY | SEE_MASK_ICON | \ 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) { return pidl == ILFindLastID(pidl);