diff --git a/src/dll/src/ContextMenu.cpp b/src/dll/src/ContextMenu.cpp index e7239da0..9e228ec8 100644 --- a/src/dll/src/ContextMenu.cpp +++ b/src/dll/src/ContextMenu.cpp @@ -995,6 +995,7 @@ namespace Nilesoft m_sub->owner = mii; m_sub->std_items = &item->items; + m_sub->std_owner = item; string path; if(!mii->path.empty()) @@ -1096,12 +1097,14 @@ namespace Nilesoft MenuItemInfo *owner = nullptr; if(menu->is_main) { + refresh_system_submenus(__system_menu_tree); menu->dynamics = _cache->dynamic.items; menu->std_items = &__system_menu_tree->items; } else { owner = menu->owner; + refresh_system_submenu_item(menu->std_owner); } prepare_system_items(_system_items, menu); @@ -4256,6 +4259,7 @@ namespace Nilesoft else { item->type = mii.hSubMenu != nullptr; + item->source_handle = mii.hSubMenu; item->disabled = mii.fState & MFS_DISABLED; item->checked = mii.fState & MFS_CHECKED; item->radio_check = mii.fType & MFT_RADIOCHECK; @@ -4336,6 +4340,48 @@ namespace Nilesoft } } + // shell32 fills some submenus (e.g. "SendTo") lazily, after QueryContextMenu. + // Our snapshot taken at Initialize() time can therefore be incomplete. + // Re-snapshot any submenu whose native source menu already has more items. + void ContextMenu::refresh_system_submenu_item(menuitem_t *item) + { + if(!item || !item->is_menu()) + return; + + if(!item->source_handle || !::IsMenu(item->source_handle)) + return; + + const auto source_count = ::GetMenuItemCount(item->source_handle); + const auto snapshot_count = static_cast(item->items.size()); + + if(source_count <= snapshot_count) + return; + + for(auto child : item->items) + delete child; + item->items.clear(); + + build_system_menuitems(item->source_handle, item, false); + + _log.info(L"[FIX] refetch '%s' snapshot=%d now=%d", + item->title.c_str(), snapshot_count, static_cast(item->items.size())); + } + + void ContextMenu::refresh_system_submenus(menuitem_t *menu) + { + if(!menu) + return; + + for(auto item : menu->items) + { + if(!item || !item->is_menu()) + continue; + + refresh_system_submenu_item(item); + refresh_system_submenus(item); + } + } + bool ContextMenu::Initialize() { try diff --git a/src/dll/src/Include/ContextMenu.h b/src/dll/src/Include/ContextMenu.h index 3a3743b0..32f19abf 100644 --- a/src/dll/src/Include/ContextMenu.h +++ b/src/dll/src/Include/ContextMenu.h @@ -92,6 +92,7 @@ namespace Nilesoft int checked = 0; ULONG_PTR dwItemData = 0; HBITMAP image = nullptr; + HMENU source_handle = nullptr; menuitem_t *parent = nullptr; string path; Position position = Position::Auto; @@ -359,6 +360,7 @@ plutovg_move_to(pluto, start.x, start.y); std::vector dynamics; std::vector *std_items = nullptr; + menuitem_t *std_owner = nullptr; NativeMenu *parent{}; //bool dynamic{}; @@ -734,6 +736,8 @@ plutovg_move_to(pluto, start.x, start.y); int Uninitialize(); int InvokeCommand(int id); void build_system_menuitems(HMENU hMenu, menuitem_t *menu, bool is_root = false); + void refresh_system_submenus(menuitem_t *menu); + void refresh_system_submenu_item(menuitem_t *item); void build_main_system_menuitems(menuitem_t *menu, bool is_root = false);