Keywords: Webbrowser, Internet Explorer, custom context menu, showcontextmenu, and idochostuihandler
1. Overview
Internet Explorer provides very developed interfaces that allow developers not only to embed the core of their browsers into applications, but also to implement deeper control through various interfaces. This article will introduce the custom context menu, one of the topics for advanced browser control.
2. The simplest case
The simplest way to customize the context menu of IE and webbrowser is to add custom key values under HKEY_CURRENT_USER/software/Microsoft/Internet Explorer/menuext in the registry. The steps are as follows:
1)Add a new key. Its name is the name of the menu item that will be displayed in the context menu, for example:
HKEY_CURRENT_USER/software/Microsoft/Internet Explorer/menuext/& Google Search
2)Set the default value of the new key to the URL of a Web page containing scripts (or the full name of the file path ), the script on this webpage will be executed by the browser after the user clicks "Google Search" in the context menu.
3) you can create a new binary value contexts under the new key to specify whether the newly added menu item appears for a specific webpage object, the value can be a combination of the following values (logical or)
Context Value
Default 0x1
Images 0x2
Controls 0x4
Tables 0x8
Text Selection 0x10
Anchor 0x20
4)You can also create a DWORD-type flags item and set its value to 0x01. This will make the preceding script executed in a modal window, as if through a window. showmodaldialog is called, but the difference is that the window object can still be accessed in the script.
5)The instance script is as follows:
The method of modifying the Registry custom menu applies to Internet Explorer and webbrowser, and also has good scalability. However, if we want to execute not only scripts, but also code in our own programs, this method is not applicable.
3. Use a fully customized menu
1)The idochostuihandler interface provides a showcontextmenu method. Before the context menu needs to be displayed, the mshtml engine calls the interface that implements the idochostuihandler interface.
Showcontextmenu method of the Host Program.
Hresultidochostuihandler: showcontextmenu (
DWORD dwid,
Point * PPT,
Iunknown * pcmdtreserved,
Idispatch * pdispreserved
);
The significance of the dwid parameter is similar to the combination of contexts. PPT is the screen coordinate of the menu pop-up point. The pcmdtreserved interface points to the iolecommandtarget interface, which can be used to detect the webpage object status and execute commands. In ie5 or a later version, pdispreserved points to the idispatch interface of the webpage object to distinguish different objects. For example, we can obtain the pointer of the webpage object as follows:
Ihtmlelement * pelem;
Hresult hr;
HR = pdispreserved-> QueryInterface (iid_ihtmlelement, (void **) pelem );
If (succeeded (HR )){
BSTR;
Pelem-> get_tagname (BSTR );
Uses_conversion;
Atltrace ("tagname: % s/n", ole2t (BSTR ));
Sysfreestring (BSTR );
Pelem-> release ();
}
If s_ OK is returned in this method, it indicates that mshtml uses its own menu (interface). If it is s_false, the default menu is displayed.
2)Implementation
After the principle is clear, the implementation is very simple. It is similar to the pop-up menu. For example, the "file menu" of the main framework is displayed ":
Hresult cmyhtmlview: onshowcontextmenu (DWORD dwid, lppoint PPT, iunknown * pcmdtreserved, idispatch *)
{
// Load the main menu
Hmenu hmenuparent =: loadmenu (: AfxGetInstanceHandle (), makeintresource (idr_mainframe ));
If (hmenuparent)
{
Hmenu =: getsubmenu (hmenuparent, 0); // obtain the "file" submenu
If (hmenu)
{
// Display menu
Trackpopupmenuex (hmenu,
Tpm_leftalign | tpm_topalign,
PPT-> X,
PPT-> y,
: Afxgetmainwnd ()-> m_hwnd,
Null );
}
: Destroymenu (hmenuparent );
}
Return s_ OK;
}
4. Customize the standard context menu
1)Principle
In more cases, we hope to make some modifications based on the original menu of the browser, such as deleting "View Source File" and adding your own menu items, rather than completely avoiding the original menu, what should we do? Let's take a look at the example provided by msdn:
Hresult cbrowserhost: showcontextmenu (DWORD dwid, point * PPT, iunknown * pcmdtarget, idispatch * pdispobject)
{
# Define idr_browse_context_menu 24641
# Define idr_form_context_menu 24640
# Define shdvid_getmimecsetmenu 27
# Define shdvid_addmenuextensions 53
Hresult hr;
Hinstance hinstshdoclc;
Hwnd;
Hmenu;
Ccomptr Spct;
Ccomptr Spwnd;
Menuiteminfo MII = {0 };
Ccomvariant var, var1, var2;
HR = pcmdtarget-> QueryInterface (iid_iolecommandtarget, (void **) & spct );
HR = pcmdtarget-> QueryInterface (iid_iolewindow, (void **) & spwnd );
HR = spwnd-> getwindow (& hwnd); // get the browser window handle
Hinstshdoclc = loadlibrary (text ("shdoclc. dll "));
If (hinstshdoclc = NULL)
{
// Error loading module -- fail as securely as possible
Return;
}
Hmenu = loadmenu (hinstshdoclc, makeintresource (idr_browse_context_menu ));
Hmenu = getsubmenu (hmenu, dwid );
// Get the language submenu
HR = spct-> exec (& cgid_shelldocview, shdvid_getmimecsetmenu, 0, null, & var );
MII. cbsize = sizeof (MII );
MII. fmask = miim_submenu;
MII. hsubmenu = (hmenu) var. byref;
// Add language submenu to encoding context item
Setmenuiteminfo (hmenu, idm_language, false, & MII );
// Insert into cut menu extensions from Registry
V_vt (& var1) = vt_int_ptr;
V_byref (& var1) = hmenu;
V_vt (& var2) = vt_i4;
V_i4 (& var2) = dwid;
HR = spct-> exec (& cgid_shelldocview, shdvid_addmenuextensions, 0, & var1, & var2 );
// Remove View Source
Deletemenu (hmenu, idm_viewsource, mf_bycommand); // Delete the menu item "View Source File ".
// Show shortcut cut menu
Int iselection =: trackpopupmenu (hmenu,
Tpm_leftalign | tpm_rightbutton |Tpm_returncmd, // Return the user-selected menu command ID
PPT-> X,
PPT-> y,
0,
Hwnd,
(Rect *) null );
// Send selected shortcut menu item command to Shell
Lresult LR =: sendmessage (hwnd, wm_command, iselection, null); // it is sent to the Internet assumer_server for internal processing.
Freelibrary (hinstshdoclc );
Return s_ OK;
}
From the example above, we can see that the basic method is based on "shdoclc. DLL file, and then use the iolccommandtarget interface from pcmdtarget to obtain the "encoding" menu and the definition extension menu under HKEY_CURRENT_USER/software/Microsoft/Internet Explorer/menuext, call the trackpopupmenu or trackpopupmenuex pop-up menu with the tpm_returncmd flag, and teach the returned menu command ID to the browser window for processing. This method can call many commands and dialogs that cannot be directly called through a browser (see Internet Explorer programming Overview (5) Call the hidden commands of Internet Explorer).
Therefore, you only need to perform some custom operations before the menu is displayed to modify the default menu. For example, the "View Source File" menu item is deleted in the code above.
2)Problem
What happens if we not only delete the default menu item or modify the default menu item, but also add our own menu item? Because we use a mechanism similar to updateui in MFC and encounter a commandid that we don't know, the browser will set its status to disabled, so the menu we add ourselves cannot be selected.
It can be thought that if you set the menu status to enabled and call trackpopupmenu or trackpopupmenuex using the tpm_returncmd flag, then you can teach the returned command ID to a suitable window (such as the main frame window) for processing. The key point is how to set the menu status to enabled.
3)Implementation
The solution is to interceptWm_initmenupopupMessage. After the menu is created, the status of the previously modified menu item is not displayed, so the browser cannot do it. To intercept wm_initmenupopup messages, you can use subclass technology. We obtained the browser window handle hwnd through the iolewindow interface, so we can do this:
Hmenu g_hpubmenu = NULL;
Wndproc g_lpprevwndproc = NULL;
Lresult callback custommenuwndproc (hwnd, uint umsg, wparam, lparam)
{
If (umsg = wm_initmenupopup)
{
If (wparam = (wparam) g_hpubmenu)
{
: Enablemenuitem (custom menu command ID, mf_enabled | mf_bycommand );
: Checkmenuitem (custom menu command ID, mf_bycommand );
Return 0;
}
}
Return callwindowproc (g_lpprevwndproc, hwnd, umsg, wparam, lparam );
}
Hresult cmyhtmlview: onshowcontextmenu (DWORD dwid, lppoint PPT,
Lpunknown pcmdtreserved, lpdispatch pdispreserved)
{
// Save the browser menu handle in g_hpubmenu
......
// Subclass browser window
G_lpprevwndproc = (wndproc): setwindowlong (hwnd, gwl_wndproc, (long) custommenuwndproc );
// M_subclasswnd.subclasswindow (hwnd); // This method is easier to use in MFC
// Show shortcut cut menu
Int iselection =: trackpopupmenu (hsubmenu,
Tpm_leftalign | tpm_rightbutton | tpm_returncmd,
PPT-> X,
PPT-> y,
0,
Hwnd,
(Rect *) null );
// Unsubclass browser window
: Setwindowlong (hwnd, gwl_wndproc, (long) g_lpprevwndproc );
G_lpprevwndproc = NULL;
// M_subclasswnd.unsubclasswindow ();
If (iselection = custom menu command ID)
{
: Sendmessage (: afxgetmainwnd ()-> m_hwnd, wm_command, makewparam (loword (lresult), 0x0), 0 );
}
Else
{
Lresult LR =: sendmessage (hwnd, wm_command, iselection, null );
}
......
}
In MFC, it is more convenient to inherit a window class from cwnd. Assume It is cwebbrowsersubclasswnd and add a member variable of the cwebbrowsersubclasswnd type to cmyhtmlview. m_subclasswnd, call m_subclasswnd.subclasswindow (hwnd) and m_subclasswnd.unsubclasswindow () to subclass and remove them. The corresponding wm_initmenupopup message processing function is as follows:
Void cwebbrowsersubclasswnd: oninitmenupopup (cmenu * ppopupmenu, uint nindex, bool bsysmenu)
{
Cwnd: oninitmenupopup (ppopupmenu, nindex, bsysmenu );
Ppopupmenu-> enablemenuitem (custom menu command ID, mf_enabled | mf_bycommand );
Ppopupmenu-> checkmenuitem (custom menu command ID, mf_bycommand );
}
The following figure shows the effect of adding the "text size" menu item to the "encoding" menu item.
5. New Problems
After reading the above Code, we naturally think of another problem in browser programming, that is, the "encoding" menu. We specify that it is troublesome to manually create an "encoding" menu, and it is difficult to achieve the same effect as the "encoding" menu on the context menu of the browser. Why not use the above method to allow the browser to create the "encoding" menu and process the corresponding commands?
For specific implementation, see the next article "Internet Explorer programming Overview (7) Perfect" encoding "menu".
References:
Msdn: Adding entries to the standard context menu
Msdn: How to adding to the standard context menus of the webbrowser Control
Msdn: idochostuihandler: showcontextmenu Method
Beginthread.com: Custom webbrowser context menus
Reference address: Internet Explorer programming Overview (6) custom browser context menu