Skip to content

fix(context-menu): re-snapshot lazily populated system submenus (items missing in "Send to" / "New") - #846

Open
v4806 wants to merge 1 commit into
moudey:mainfrom
v4806:fix/sendto-lazy-submenu-snapshot
Open

v4806 wants to merge 1 commit into
moudey:mainfrom
v4806:fix/sendto-lazy-submenu-snapshot

Conversation

@v4806

@v4806 v4806 commented Oct 11, 2026 •

Copy link
Copy Markdown

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 during Initialize(), i.e. in the
IContextMenu::QueryContextMenu phase. But shell32 fills these submenus lazily: at that moment
only 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 stale
snapshot.

Fix

  • menuitem_t gains HMENU source_handle - the original submenu handle, recorded while snapshotting.
  • menu_t gains menuitem_t *std_owner - points back to its snapshot item.
  • In OnInitMenuPopup(), if GetMenuItemCount(source_handle) exceeds the snapshot count, the snapshot
    is 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 of
explorer's HMENU with InsertMenuItemW cannot work, because they are owner-draw items whose
dwItemData points at explorer-internal data.

The change is purely additive plus one conditional call - when source_count <= snapshot_count the
behaviour is exactly as before.

Verification

Windows 10 22H2 + Shell 1.9.19, desktop shortcut -> More options -> Send to:

Items
Before 3
After 9 (stable over 4 consecutive rounds, including an explorer restart)

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.

[FIX] refetch '发送到(&N)' snapshot=3 now=9

现象
  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
  未触发重抓时行为与改动前完全一致(纯新增代码 + 一处条件调用)。
@v4806

v4806 commented Oct 11, 2026

Copy link
Copy Markdown
Author

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 QueryContextMenu). By the time the submenu is actually popped up the original handle is complete, yet OnInitMenuPopup() replays the stale snapshot forever. This PR re-snapshots at popup time, so it should fix all of them.

同一根因的其它报告:#749、#464、#614、#815 —— shell32 是惰性填充「发送到」子菜单的,而 Shell 抓快照的时机远早于此(QueryContextMenu 阶段)。子菜单真正弹出时原始句柄已经完整,但 OnInitMenuPopup() 只会重放旧快照。本 PR 在弹出时重抓快照,应当一并修复这几个问题。

@v4806 v4806 changed the title fix(context-menu): re-snapshot lazily populated system submenus (SendTo shows only 3 of 9 items) fix(context-menu): re-snapshot lazily populated system submenus (items missing in "Send to" / "New") Oct 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant