From f9325370f53560b96cc7d92d7ab34f578b12dc8e Mon Sep 17 00:00:00 2001 From: Whindmar Saksit Date: Sun, 28 Apr 2024 16:00:03 +0200 Subject: [PATCH] [SHELL32] DefView must set CMF_EXTENDEDVERBS, CMF_CANRENAME and CMF_EXPLORE (#6776) The caller of IContextMenu::QueryContextMenu must set these flags when needed, not CDefaultContextMenu. Notes: - CMF_CANRENAME is always set by DefView because it always supports rename in its current form. CDefaultContextMenu verifies that SFGAO_CANRENAME is also set on the items. All other callers are expected to not know how to rename unless they also set CMF_CANRENAME. This fixes the bug that the Rename item is present in the TreeView context menu even though the TreeView in ROS Explorer does not handle renaming. - While DefView now tries to set CMF_EXPLORE correctly, the flag is never actually set because BROWSEUI does not handle FCW_TREE yet. - This also fixes the bug where the File menu is missing the menu items when there is no selection. --- dll/win32/shell32/CDefView.cpp | 30 ++++++++++++++++++----- dll/win32/shell32/CDefaultContextMenu.cpp | 6 ++--- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/dll/win32/shell32/CDefView.cpp b/dll/win32/shell32/CDefView.cpp index 76cdf915d82..089e026a293 100644 --- a/dll/win32/shell32/CDefView.cpp +++ b/dll/win32/shell32/CDefView.cpp @@ -54,6 +54,20 @@ typedef struct // to call TrackPopupMenu and let it use the 0 value as an indication that the menu was canceled #define CONTEXT_MENU_BASE_ID 1 +static UINT +GetContextMenuFlags(IShellBrowser *pSB, SFGAOF sfgao) +{ + UINT cmf = CMF_NORMAL; + if (GetKeyState(VK_SHIFT) < 0) + cmf |= CMF_EXTENDEDVERBS; + if (sfgao & SFGAO_CANRENAME) + cmf |= CMF_CANRENAME; + HWND hwnd = NULL; + if (pSB && SUCCEEDED(pSB->GetControlWindow(FCW_TREE, &hwnd)) && hwnd) + cmf |= CMF_EXPLORE; + return cmf; +} + // Convert client coordinates to listview coordinates static void ClientToListView(HWND hwndLV, POINT *ppt) @@ -1362,14 +1376,16 @@ HRESULT CDefView::FillFileMenu() IUnknown_SetSite(m_pFileMenu, NULL); m_pFileMenu.Release(); } + UINT selcount = m_ListView.GetSelectedCount(); // Store context menu in m_pFileMenu and keep it to invoke the selected command later on - HRESULT hr = GetItemObject(SVGIO_SELECTION, IID_PPV_ARG(IContextMenu, &m_pFileMenu)); + HRESULT hr = GetItemObject(selcount ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pFileMenu)); if (FAILED_UNEXPECTEDLY(hr)) return hr; HMENU hmenu = CreatePopupMenu(); - hr = m_pFileMenu->QueryContextMenu(hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, 0); + UINT cmf = GetContextMenuFlags(m_pShellBrowser, SFGAO_CANRENAME); + hr = m_pFileMenu->QueryContextMenu(hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, cmf); if (FAILED_UNEXPECTEDLY(hr)) return hr; @@ -1511,10 +1527,10 @@ HRESULT CDefView::InvokeContextMenuCommand(CComPtr& pCM, LPCSTR lp cmi.hwnd = m_hWnd; cmi.lpVerb = lpVerb; - if (GetKeyState(VK_SHIFT) & 0x8000) + if (GetKeyState(VK_SHIFT) < 0) cmi.fMask |= CMIC_MASK_SHIFT_DOWN; - if (GetKeyState(VK_CONTROL) & 0x8000) + if (GetKeyState(VK_CONTROL) < 0) cmi.fMask |= CMIC_MASK_CONTROL_DOWN; if (pt) @@ -1558,7 +1574,8 @@ HRESULT CDefView::OpenSelectedItems() if (FAILED_UNEXPECTEDLY(hResult)) return hResult; - hResult = pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_DEFAULTONLY); + UINT cmf = CMF_DEFAULTONLY | GetContextMenuFlags(m_pShellBrowser, 0); + hResult = pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, cmf); if (FAILED_UNEXPECTEDLY(hResult)) return hResult; @@ -1617,8 +1634,9 @@ LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &b if (FAILED_UNEXPECTEDLY(hResult)) return 0; + UINT cmf = GetContextMenuFlags(m_pShellBrowser, SFGAO_CANRENAME); // Use 1 as the first id we want. 0 means that user canceled the menu - hResult = m_pCM->QueryContextMenu(m_hContextMenu, 0, CONTEXT_MENU_BASE_ID, FCIDM_SHVIEWLAST, CMF_NORMAL); + hResult = m_pCM->QueryContextMenu(m_hContextMenu, 0, CONTEXT_MENU_BASE_ID, FCIDM_SHVIEWLAST, cmf); if (FAILED_UNEXPECTEDLY(hResult)) return 0; diff --git a/dll/win32/shell32/CDefaultContextMenu.cpp b/dll/win32/shell32/CDefaultContextMenu.cpp index 0e1bdb99083..e1556710d5a 100644 --- a/dll/win32/shell32/CDefaultContextMenu.cpp +++ b/dll/win32/shell32/CDefaultContextMenu.cpp @@ -603,9 +603,7 @@ CDefaultContextMenu::AddStaticContextMenusToMenu( if (hkVerb) { - // FIXME: GetAsyncKeyState should not be called here, clients - // need to be updated to set the CMF_EXTENDEDVERBS flag. - if (!(uFlags & CMF_EXTENDEDVERBS) && GetAsyncKeyState(VK_SHIFT) >= 0) + if (!(uFlags & CMF_EXTENDEDVERBS)) hide = RegValueExists(hkVerb, L"Extended"); if (!hide) @@ -807,7 +805,7 @@ CDefaultContextMenu::QueryContextMenu( DeleteMenu(hmenuDefault, IDM_CREATELINK, MF_BYCOMMAND); if (!(rfg & SFGAO_CANDELETE)) DeleteMenu(hmenuDefault, IDM_DELETE, MF_BYCOMMAND); - if (!(rfg & SFGAO_CANRENAME)) + if (!(rfg & SFGAO_CANRENAME) || !(uFlags & CMF_CANRENAME)) DeleteMenu(hmenuDefault, IDM_RENAME, MF_BYCOMMAND); if (!(rfg & SFGAO_HASPROPSHEET)) DeleteMenu(hmenuDefault, IDM_PROPERTIES, MF_BYCOMMAND);