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:
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?
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?
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
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.