So I keep coming back to this article on CodeProject:
https://www.codeproject.com/Articles/4758/How-to-customize-the-context-menus-of-a-WebBrowser
I then realise
I have got to the bottom of this. There were a few key things that I learned along the way.
I was not away of the CHtmlView::OnShowContextMenu function which I needed to implement:
HRESULT CChristianLifeMinistryHtmlView::OnShowContextMenu(DWORD dwID, LPPOINT ppt,
LPUNKNOWN pcmdtReserved, LPDISPATCH pdispReserved)
{
return CustomContextMenu(ppt, pcmdtReserved);
}
In my defence, the IDE in Visual Studio did not offer it in the list as a possibly override. But it existed non-the-less.
The menu IDs for all custom menu items fall between IDM_MENUEXT_FIRST__
and IDM_MENUEXT_LAST__
for a maximum of 33 custom commands. In my case I manually create some #define
values in my resource.h
file:
#define CUSTOM_MENU_PRINT_PREVIEW 3700
#define CUSTOM_MENU_EXPORT 3701
Note that I am not happy using literal values. I wish I could use IDM_MENU_EXT_FIRST + 1
etc. for my definitions but I do not know how to do that. Possible?
When you design your custom menu you can infill existing commands with the IDM_XXX values too:
IDR_MENU_HTML_POPUP MENU
BEGIN
POPUP "CustomPopup"
BEGIN
MENUITEM "Select All", 31
MENUITEM SEPARATOR
MENUITEM "Export", CUSTOM_MENU_EXPORT
MENUITEM SEPARATOR
MENUITEM "Page Setup", 2004
MENUITEM "Print Preview", CUSTOM_MENU_PRINT_PREVIEW
MENUITEM SEPARATOR
MENUITEM "Refresh", 2300
MENUITEM SEPARATOR
MENUITEM "View Source", 2139
END
END
The same note still applies though. I can't work out how to assign the IDM_* constants to my own #defines rather than using literal values.
Your custom menu items will be greyed out if you don't use the right ID values.
Then you have to create the context menu (see original question for that code).
This is closely related to item 4. TrackMenuPopup
needed to be adjusted in my situation as follows:
// Show shortcut menu
iSelection = ::TrackPopupMenu(hPopupMenu,
TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
ppt->x,
ppt->y,
0,
hwnd,
(RECT*)NULL);
// Send selected shortcut menu item command to shell
if (iSelection != 0)
{
if (iSelection == CUSTOM_MENU_PRINT_PREVIEW)
{
::SendMessage(GetParent()->GetSafeHwnd(), WM_COMMAND, ID_FILE_PRINTPREVIEW, NULL);
}
else if (iSelection == CUSTOM_MENU_EXPORT)
{
::SendMessage(GetParent()->GetSafeHwnd(), WM_COMMAND, ID_FILE_EXPORT, NULL);
}
else
{
(void) ::SendMessage(hwnd, WM_COMMAND, iSelection, NULL);
}
}
The key was testing the return value of TrackMenuPopup
and doing custom handling. In-fact, whilst writing this answer I now realise that my "Print Preview" menu item can be defined as the value of IDM_PRINTPREVIEW
and I test again that, like this:
if (iSelection != 0)
{
if (iSelection == IDM_PRINTPREVIEW)
{
::SendMessage(GetParent()->GetSafeHwnd(), WM_COMMAND, ID_FILE_PRINTPREVIEW, NULL);
}
else if (iSelection == CUSTOM_MENU_EXPORT)
{
::SendMessage(GetParent()->GetSafeHwnd(), WM_COMMAND, ID_FILE_EXPORT, NULL);
}
else
{
(void) ::SendMessage(hwnd, WM_COMMAND, iSelection, NULL);
}
}
So my only gripe is that my own #define are values are using literal numbers and I would prefer them to be based on the IDM constants if possible. But either way, it all works fine!