Repository navigation
fix(context-menu): re-snapshot lazily populated system submenus (items missing in "Send to" / "New") - #846
fix(context-menu): re-snapshot lazily populated system submenus (items missing in "Send to" / "New")#846v4806 wants to merge 1 commit into
Conversation
现象
Win10 上 Shell 菜单里的「发送到」子菜单只显示 3~5 项,且每次内容都不一样;
原生菜单稳定有 9 项。丢的是「压缩(zipped)文件夹」「桌面快捷方式」「邮件收件人」
「文档」以及驱动器项 —— 即所有非 .lnk 的 shell 扩展项。
根因
Shell 在 Initialize()(IContextMenu::QueryContextMenu 阶段)就把原始菜单抓成快照
(build_system_menuitems),但 shell32 是惰性填充的:那一刻「发送到」子菜单里
只有几个 .lnk 项,其余 shell 扩展项和驱动器项还没加进去,快照因此残缺。
而该子菜单真正弹出(WM_INITMENUPOPUP 指向它)时,原始句柄已经补齐,
但 OnInitMenuPopup 只重放旧快照,于是永远丢项。
修法
- menuitem_t 记录抓快照时对应的原始子菜单句柄 source_handle;
menu_t 记录它所对应的 menuitem_t(std_owner)。
- OnInitMenuPopup 中,若 GetMenuItemCount(source_handle) > 快照项数,
就清空并用 build_system_menuitems() 对原始句柄重抓 —— 仍然走 Shell 自己的
menuitem_t 路径。不直接拷贝原始 HMENU 里的项:那些是 explorer 的 owner-draw 项
(dwItemData 指向 explorer 的数据),直接插入会画不出来。
- 主菜单弹出时对整树刷新一次,作为兜底。
验证
Win10 22H2 + Shell 1.9.19,桌面 .lnk 右键 → 更多选项 → 发送到:
修复前 3 项,修复后稳定 9 项(连续 4 轮,含 explorer 重启)。
运行时日志: [FIX] refetch '发送到(&N)' snapshot=3 now=9
未触发重抓时行为与改动前完全一致(纯新增代码 + 一处条件调用)。
|
Also reported as #749, #464, #614, #815 — all four look like the same root cause: shell32 fills the "Send To" submenu lazily, but Shell takes its snapshot of the original menu much earlier (during 同一根因的其它报告:#749、#464、#614、#815 —— shell32 是惰性填充「发送到」子菜单的,而 Shell 抓快照的时机远早于此( |
|
Thanks for this. I ported it into Nilesoft Shell Pro, a community fork of Nilesoft Shell that I maintain, with credit in the commit. It is in the current release: https://github.com/Abdullah-Masood-05/Shell/releases/latest |
Symptom
System submenus that Shell takes from the original menu can lose items and vary between openings,
while the native menu is always complete. Most visible in Send to: only 3-5 of the 9 items appear,
and a different subset each time. The same symptom has been reported for the New submenu and for
certain file types.
Affects both Windows 10 and Windows 11 - see #749 (also reported there on Win 11 25H2) and #815
(also reported there on Win 11 23H2), plus #464 and #614.
Root cause
build_system_menuitems()snapshots the original menu duringInitialize(), i.e. in theIContextMenu::QueryContextMenuphase. But shell32 fills these submenus lazily: at that momentonly a few items exist, so the snapshot is incomplete. When the submenu actually pops up, explorer's
original handle already contains the full set, yet
OnInitMenuPopup()only replays the stalesnapshot.
Fix
menuitem_tgainsHMENU source_handle- the original submenu handle, recorded while snapshotting.menu_tgainsmenuitem_t *std_owner- points back to its snapshot item.OnInitMenuPopup(), ifGetMenuItemCount(source_handle)exceeds the snapshot count, the snapshotis cleared and rebuilt from the original handle; the main menu refreshes the whole tree once as a
safety net.
Rebuilding through Shell's own
build_system_menuitems()is required: copying the items out ofexplorer's HMENU with
InsertMenuItemWcannot work, because they are owner-draw items whosedwItemDatapoints at explorer-internal data.The change is purely additive plus one conditional call - when
source_count <= snapshot_countthebehaviour is exactly as before.
Verification
Windows 10 22H2 + Shell 1.9.19, desktop shortcut -> More options -> Send to:
I could not test Windows 11 myself, but the mechanism is version-independent (the snapshot is taken
before shell32 populates the submenu) and the same symptom is reported there in #749/#815.