最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - Correct way to implement IContextMenu - Stack Overflow

programmeradmin7浏览0评论

I'm trying to implement IContextMenu, but I'm having some difficulties. In the QueryContextMenu method I add the menu like this:

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);
}

Now when the user selects a menu item, I need to perform the appropriate actions in the InvokeCommand method. For now, I determine the selected menu item like this:

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

    return S_OK;
}

Regarding the above code I have the following questions:

  1. In the InvokeCommand method, the menu ID is defined as auto selectedMenuID = LOWORD(pici->lpVerb). How reliable is this approach? I haven't found a clear definition for this in the documentation. Should I also check LOWORD for lpVerbW or lpVerb is sufficient?

  2. Some IContextMenu implementations implement adding a submenu not in the QueryContextMenu method, but in the IContextMenu3::HandleMenuMsg2 method (by handling WM_INITMENUPOPUP message). It turns out that we have two ways to add a submenu. How to choose the right way to add a submenu? What should you pay attention to in this case?

I'm trying to implement IContextMenu, but I'm having some difficulties. In the QueryContextMenu method I add the menu like this:

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);
}

Now when the user selects a menu item, I need to perform the appropriate actions in the InvokeCommand method. For now, I determine the selected menu item like this:

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

    return S_OK;
}

Regarding the above code I have the following questions:

  1. In the InvokeCommand method, the menu ID is defined as auto selectedMenuID = LOWORD(pici->lpVerb). How reliable is this approach? I haven't found a clear definition for this in the documentation. Should I also check LOWORD for lpVerbW or lpVerb is sufficient?

  2. Some IContextMenu implementations implement adding a submenu not in the QueryContextMenu method, but in the IContextMenu3::HandleMenuMsg2 method (by handling WM_INITMENUPOPUP message). It turns out that we have two ways to add a submenu. How to choose the right way to add a submenu? What should you pay attention to in this case?

Share Improve this question edited Mar 21 at 14:10 Joe J asked Mar 21 at 13:34 Joe JJoe J 4839 bronze badges 4
  • 1 Everything is documented here learn.microsoft/en-us/windows/win32/api/shobjidl_core/… and should answer your questions if your read it in details (cast CMINVOKECOMMANDINFO to CMINVOKECOMMANDINFOEX). Ids are used instead of verbs if no verb is associated with menu item, use unicode if CMIC_MASK_UNICODE is set, etc.). Also IContextMenu is sort of legacy, you should consider IExplorerCommand if you want to support Windows 11 (blogs.windows/windowsdeveloper/2021/07/19/…) – Simon Mourier Commented Mar 21 at 15:30
  • @SimonMourier Thanks, but I didn't find how to properly implement IExplorerCommand::EnumSubCommands to show the submenu. Maybe you have an example of how to implement a submenu in IExplorerCommand? All examples on the Internet that I found return E_NOTIMPL in EnumSubCommands – Joe J Commented Mar 21 at 16:37
  • 1 There's nothing particularly difficult to implement sub commands, here's the official sample github/microsoft/AppModelSamples/tree/master/Samples/… – Simon Mourier Commented Mar 21 at 17:44
  • @JoeJ any further questions about implementing IExplorerCommand should be posted separately, as they don't apply to this post regarding IContextMenu. – Remy Lebeau Commented Mar 21 at 17:48
Add a comment  | 

1 Answer 1

Reset to default 3
  1. There is no lpVerbW field in CMINVOKECOMMANDINFO. To access lpVerbW, you have to cast pici to CMINVOKECOMMANDINFOEX* first (if the cbSize is large enough). But even then, lpVerbW is only meaningful if the fMask field contains the CMIC_MASK_UNICODE flag. And only if your GetCommandString() implementation reports Unicode verbs. If you are using only menu offsets, or non-Unicode verbs, then lpVerb will suffice. However, you should use IS_INTRESOURCE() to decide whether to apply LOWORD() to lpVerb. The use of lpVerb vs lpVerbW is covered in the documentation:

    How to Implement the IContextMenu Interface: IContextMenu::InvokeCommand Method

  2. Menu items should be added by QueryContextMenu() only. This allows the Shell as well as applications to query and invoke commands without actually displaying the menu visually. IContextMenu3 was introduced to support owner-drawing of menu items when they are displayed visually.

发布评论

评论列表(0)

  1. 暂无评论