Introduction
Generally, when hosting the WebBrowser Control in our MFC application, we call ExecWB
method of m_pBrowserApp
(IWebBrowser2
interface) to invoke common web browser commands (zoom the browser, select all text in the browser, etc.).
We also invoke queryInterface
to get an IDispatch
pointer for the IOleCommandTarget
interface and call its Exec
method to invoke the "Find in This Page" dialog or "View Source" command. But there still exists some dialogs we can't invoke, i.e. the "Add To Favorite" dialog, the "Import/Export Wizard" dialog. Though we can invoke "AddFavorite" command and "ImportExportFavorites" command through IShellUIHelper
interface, the former command results in a modeless "Add To Favorite" dialog independent from the application mainframe while the latter command results in a quite simple consequence.
This article will introduce an innovative but simple way to invoke the MODAL "Add To Favorite" dialog and MODAL "Import/Export Wizard" dialog in your own web browser.
Background
The idea comes from the IDocHostUIHandler::ShowContextMenu
demo of "WebBrowser Customization" in the MSDN. The IDocHostUIHandler::ShowContextMenu
demo presents us the way to manually build IE's context menu from the correlative resource file "SHDOCLC.DLL" and remove "View Source" from it. The key point of the code is after popping up the context menu, it calls SendMessage()
API to send the MenuItem ID returned by TrackPopupMenu()
to the "Internet Explorer_Server" window through WM_COMMAND
message. So, if we get the MenuItem ID of the "Add To Favorite" command or the "Import/Export Wizard" command, we may probably solve the problems stated above.
......
int iSelection = ::TrackPopupMenu(hMenu,
TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
ppt->x,
ppt->y,
0,
hwnd,
(RECT*)NULL);
LRESULT lr = ::SendMessage(hwnd, WM_COMMAND, iSelection, NULL);
......
Using the code
Some command messages are handled by the "Internet Explorer_Server" window while some others are handled by its parent "Shell DocObject View" window. Therefore, the first thing is to get the Window Handle of the two windows from your CHtmlView
. To simplify the resolution, I borrow the cute class CFindWnd
below from Paul DiLascia.
class CFindWnd {
private:
static BOOL CALLBACK FindChildClassHwnd(HWND hwndParent, LPARAM lParam) {
CFindWnd *pfw = (CFindWnd*)lParam;
HWND hwnd = FindWindowEx(hwndParent, NULL, pfw->m_classname, NULL);
if (hwnd) {
pfw->m_hWnd = hwnd;
return FALSE;
}
EnumChildWindows(hwndParent, FindChildClassHwnd, lParam);
return TRUE;
}
public:
LPCSTR m_classname;
HWND m_hWnd;
CFindWnd(HWND hwndParent, LPCSTR classname)
: m_hWnd(NULL), m_classname(classname)
{
FindChildClassHwnd(hwndParent, (LPARAM)this);
}
};
void CDemoView::InvokeShellDocObjCommand(int nID)
{
CFindWnd FindIEWnd( m_wndBrowser.m_hWnd, "Shell DocObject View");
::SendMessage( FindIEWnd.m_hWnd, WM_COMMAND,
MAKEWPARAM(LOWORD(nID), 0x0), 0 );
}
void CDemoView::InvokeIEServerCommand(int nID)
{
CFindWnd FindIEWnd( m_wndBrowser.m_hWnd, "Internet Explorer_Server");
::SendMessage( FindIEWnd.m_hWnd, WM_COMMAND,
MAKEWPARAM(LOWORD(nID), 0x0), 0 );
}
Command IDs handled by the "Internet Explorer_Server" window:
#define ID_IE_CONTEXTMENU_ADDFAV 2261
#define ID_IE_CONTEXTMENU_VIEWSOURCE 2139
#define ID_IE_CONTEXTMENU_REFRESH 6042
Command IDs handled by the "Shell DocObject View" window:
#define ID_IE_FILE_SAVEAS 258
#define ID_IE_FILE_PAGESETUP 259
#define ID_IE_FILE_PRINT 260
#define ID_IE_FILE_NEWWINDOW 275
#define ID_IE_FILE_PRINTPREVIEW 277
#define ID_IE_FILE_NEWMAIL 279
#define ID_IE_FILE_SENDDESKTOPSHORTCUT 284
#define ID_IE_HELP_ABOUTIE 336
#define ID_IE_HELP_HELPINDEX 337
#define ID_IE_HELP_WEBTUTORIAL 338
#define ID_IE_HELP_FREESTUFF 341
#define ID_IE_HELP_PRODUCTUPDATE 342
#define ID_IE_HELP_FAQ 343
#define ID_IE_HELP_ONLINESUPPORT 344
#define ID_IE_HELP_FEEDBACK 345
#define ID_IE_HELP_BESTPAGE 346
#define ID_IE_HELP_SEARCHWEB 347
#define ID_IE_HELP_MSHOME 348
#define ID_IE_HELP_VISITINTERNET 349
#define ID_IE_HELP_STARTPAGE 350
#define ID_IE_FILE_IMPORTEXPORT 374
#define ID_IE_FILE_ADDTRUST 376
#define ID_IE_FILE_ADDLOCAL 377
#define ID_IE_FILE_NEWPUBLISHINFO 387
#define ID_IE_FILE_NEWCORRESPONDENT 390
#define ID_IE_FILE_NEWCALL 395
#define ID_IE_HELP_NETSCAPEUSER 351
#define ID_IE_HELP_ENHANCEDSECURITY 375
The following code demonstrates how to invoke the MODAL "Add To Favorite" dialog.
void CDemoView::OnFavAddtofav()
{
InvokeIEServerCommand(ID_IE_CONTEXTMENU_ADDFAV);
}
Points of Interest
You know, to keep working all the night, and finally you find the answer. I call this happiness!