You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

IContextMenu实现疑问:InvokeCommand取值可靠性与子菜单添加方案选择

IContextMenu接口实现相关问题解答

我的IContextMenu实现代码

QueryContextMenu方法实现

HRESULT QueryContextMenu(
    HMENU hmenu,
    UINT  indexMenu,
    UINT  idCmdFirst,
    UINT  idCmdLast,
    UINT  uFlags
)
{
    if (uFlags & CMF_DEFAULTONLY)
    {
        return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
    }

    HMENU hSubMenu1 = CreatePopupMenu();
    AppendMenu(hSubMenu1, MF_STRING, idCmdFirst + 1, L"Submenu Item 1");
    AppendMenu(hSubMenu1, MF_STRING, idCmdFirst + 2, L"Submenu Item 2");
    AppendMenu(hmenu, MF_STRING | MF_POPUP, (UINT_PTR)hSubMenu1, L"Top-level menu");

    return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 3);
}

InvokeCommand方法实现

HRESULT InvokeCommand(
    CMINVOKECOMMANDINFO* pici
)
{
    auto selectedMenuID = LOWORD(pici->lpVerb); // 1 or 2

    return S_OK;
}

技术疑问

  1. 在InvokeCommand方法中,使用auto selectedMenuID = LOWORD(pici->lpVerb)获取选中菜单ID的方式是否可靠?文档中未找到明确定义,是否需要同时检查lpVerbW的LOWORD值?
  2. 部分IContextMenu实现不在QueryContextMenu方法中添加子菜单,而是通过IContextMenu3::HandleMenuMsg2处理WM_INITMENUPOPUP消息来添加。两种子菜单添加方式该如何选择?需要注意哪些事项?

问题解答

关于InvokeCommand中获取菜单ID的可靠性

这种方式不完全可靠,需区分调用环境的字符集:

  • ANSI环境下,lpVerb会被填充为命令ID的低16位,此时LOWORD(pici->lpVerb)能拿到正确值;但Unicode环境中,系统会使用CMINVOKECOMMANDINFOEX结构,lpVerbW才是命令ID的正确存储位置,lpVerb可能无效。
  • 正确流程:先检查pici->cbSize是否等于sizeof(CMINVOKECOMMANDINFOEX),若是则转为CMINVOKECOMMANDINFOEX*指针,取LOWORD(piciEx->lpVerbW);否则再取LOWORD(pici->lpVerb)
  • 额外注意:拿到的LOWORD值需要减去idCmdFirst,才能对应你定义的菜单项索引(比如结果为1对应Submenu Item 1)。

子菜单添加方式的选择与注意事项

1. QueryContextMenu中直接添加(静态子菜单)

  • 适用场景:子菜单内容固定,无需根据右键对象动态调整,或调整逻辑简单。
  • 优点:实现简单,无需额外处理消息,系统直接显示菜单。
  • 注意事项
    • 分配的命令ID必须在idCmdFirstidCmdLast范围内,超出会被系统忽略。
    • 创建的子菜单无需手动销毁,系统会在菜单关闭时自动清理。
    • 返回的HRESULT第三个参数要准确,即添加的菜单项总数(含顶级菜单和子项,你返回3是正确的)。

2. 通过IContextMenu3::HandleMenuMsg2处理WM_INITMENUPOPUP(动态子菜单)

  • 适用场景:子菜单内容需根据右键对象实时状态调整(如文件权限、编辑状态),或子项过多提前创建影响性能。
  • 优点:延迟加载子菜单,仅在用户展开时创建内容,节省资源;可动态更新菜单状态(如灰掉不可用项)。
  • 注意事项
    • 必须实现IContextMenu3接口,且确保系统能通过QueryInterface获取到该接口。
    • 处理WM_INITMENUPOPUP时,要判断目标子菜单,避免误处理其他菜单。
    • 动态添加的菜单项仍需遵循命令ID范围限制,且要避免重复添加(如用户多次展开子菜单时)。
    • 若需更新菜单项状态(如MF_GRAYED),可在WM_INITMENUPOPUP中修改,或处理WM_MENUSELECT消息。

内容的提问来源于stack exchange,提问作者Joe J

火山引擎 最新活动