This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.


MIND


This article assumes you're familiar with Visual C++ or Visual Basic.
Download the code (57KB)

Take Total Control of Internet Explorer with Advanced Hosting Interfaces
Scott Roberts

With the Advanced Hosting Interfaces supported by Internet Explorer, programmers can actually drive the user interface and internals of the WebBrowser control.
As part of the Internet Client Development group of Microsoft® Developer Support, I'm on the front line of answering questions about applications that use the WebBrowser control. Often, customers call to ask how they can customize parts of the WebBrowser user interface and control file downloading and application execution.
      For example, a customer called me a couple of months ago regarding a problem with an app she had written that hosts the WebBrowser control. Her users could right-click in the WebBrowser window and choose View Source from the context menu, but she wanted to be able to hide her source code. Her users could also press Ctrl+O, causing the Open dialog to appear. Then, when they entered a URL in the dialog and pressed Enter, a new instance of the Microsoft Internet Explorer window would be started. She wanted to disable this functionality, so that her application would be used for all Internet and intranet browsing on a particular machine.
      Customizing the user interface of the WebBrowser control as well as extending the DHTML object model and controlling what is downloaded are all abilities provided by the Advanced Hosting Interfaces of Internet Explorer. These interfaces include IDocHostUIHandler, ICustomDoc, and IDocHostShowUI. A special ambient property is used to restrict what is downloaded and executed when you are hosting the WebBrowser control. Let's discuss the most important aspects of the Advanced Hosting Interfaces, as well as the ambient property used for download control. I will demonstrate these concepts with two samples.

Architecture
      Before I talk about the Advanced Hosting Interfaces, let's look at the architecture of a typical app that hosts the WebBrowser control (see Figure 1). A WebBrowser hosting application is any program that can host ActiveX® controls, such as one built using Visual C++®, Visual Basic®, or Visual J++™. This application hosts the WebBrowser control, which is an ActiveX control that has been around since Internet Explorer 3.0. The WebBrowser control can host Active Documents such as Microsoft Excel and Word documents, as well as display HTML.
Figure 1: WebBrowser Host Architecture
Figure 1: WebBrowser Host Architecture
      In order to parse and display HTML, the WebBrowser control hosts the MS-HTML component, which is an Active Document server as well as an ActiveX control host. That means that MSHTML can host ActiveX controls, Active Scripting engines such as VBScript and JScript, Java applets, browser plug-ins, and HTML. The MSHTML component provides your application with the ability to control certain aspects of the user interface through the Advanced Hosting Interfaces.

IDocHostUIHandler
      IDocHostUIHandler gives you control over certain user interface features such as menus, toolbars, scrollbars, context menus, and 3D borders. A WebBrowser hosting application that wants to control these user interface features will implement IDocHostUIHandler. Each time a new Web page is loaded by the WebBrowser control, the MSHTML component will call the QueryInterface method of its host and ask for the IDocHostUIHandler interface.
      During specified points in the execution of your application, MSHTML will call methods of your IDocHostUI--Handler implementation. You can control certain user interface features of the WebBrowser control through these meth-ods. I will discuss the most important of these methods: Get-Host-Info, ShowContextMenu, TranslateAccelerator, and GetExternal. For information about the other methods of IDocHostUIHandler, head to MSDN Workshop at http://msdn.microsoft.com/workshop/ and search for IDocHost-UIHandler under Site Search from the Site Information menu. (This information is also available on the SBN Web Snapshot CD that was included with the September issue of MIND.)
      The GetHostInfo method is called whenever a new Web page is loaded. This is the primary method for controlling the user interface of WebBrowser. This method receives a pointer to a DOCHOSTUIINFO structure. You must first set the cbSize member of this structure to the size of the structure itself. Then you can fill in the dwFlags member with flags that specify the UI capabilities of your hosting application, including enabling or disabling the 3D border, scroll bars, script, and a lot more. All the flags for GetHostInfo are listed in the SBN Workshop. Here's a typical implementation of Get-HostInfo:


STDMETHOD(GetHostInfo)(DOCHOSTUIINFO FAR *pInfo)
{
    pInfo->cbSize   = sizeof(DOCHOSTUIINFO);

    // Turn off the 3D border and scroll bar.
    pInfo->dwFlags |= DOCHOSTUIFLAG_NO3DBORDER|
                      DOCHOSTUIFLAG_SCROLL_NO;

    return S_OK;
}
      Earlier I told you about the developer who didn't want to allow her users to view the source code of her Web pages. She hosted the WebBrowser control in her application and didn't offer a View Source menu item. Therefore, the only way that her users could view the source of her Web pages was by right-clicking on the Web page and choosing View Source from the context menu. To work around this problem, an application that is hosting the WebBrowser control and has implemented IDocHostUIHandler can use the ShowCon-textMenu method. This method is called by MSHTML any time a context menu has been requested (typically with a right mouse click). Your application can cancel the default context menu by simply returning S_OK from this function, which tells MSHTML not to show its own context menu. You can also display your own context menu at this point, if you choose. The following code turns off the default context menu by using the ShowContextMenu method:

STDMETHOD(ShowContextMenu)(DWORD dwID, POINT FAR* ppt,
                           IUnknown FAR* pcmdtReserved,
                           IDispatch FAR* pdispReserved)
{
    if (m_bEnableCtxMenus)
        return S_FALSE;      // Show context menus
    else
        return S_OK;         // Do not show context menus
}
      It turns out that there is another method of IDocHost-UIHandler that helped that developer work around another problem. Besides viewing her source code, users were pressing Ctrl+O to execute the Open dialog. Then they could type in a URL, causing a new instance of the Internet Explorer window to open. They could also accomplish this by pressing Ctrl+N. Here's where the TranslateAccelerator method comes to the rescue. This method is called from MSHTML's implementation of IOleInPlaceActiveObject::Trans-late-Accelerator or IOleControlSite::TranslateAccelerator. Using your implementation of IDocHostUIHandler::Trans-late-Accelerator, you can turn off all accelerator keys or just certain ones. To turn off all accelerators, simply return S_OK from this method.
      If you want to turn off a specific accelerator key, when your TranslateAccelerator is called, check the LPMSG structure you receive for the accelerator key in question. If Translate-Accelerator was called in response to that key, simply return S_OK. The following code shows an implementation of TranslateAccelerator that turns off all accelerators:

STDMETHOD(TranslateAccelerator)(LPMSG lpMsg, const GUID FAR* pguidCmdGroup,
                                DWORD nCmdID)
{
    if (m_vbEnableAllAccels == VARIANT_TRUE)
        return S_FALSE;
    else
        return S_OK;
}
The WBCustomizer sample I'll describe later contains code to turn off specific accelerator keys.
      In addition to giving you the ability to control the user interface of the WebBrowser control, IDocHostUIHandler lets you extend the Dynamic HTML object model of your Web page. This means that you can access methods and properties of your hosting application from within script on a Web page. For example, if you have a method in your hosting application called SayHello, you can call this method from a Web page that is loaded by your application:

<SCRIPT LANGUAGE="VBScript">
    Sub Window_onLoad
         window.external.SayHello
    End Sub
</SCRIPT>
To resolve the SayHello method, the WebBrowser control goes through a few steps. First, it calls your IDocHostUIHandler::
      GetExternal method to get a pointer to your implementation of IDispatch. Then, the WebBrowser calls your IDispatch::GetIDsOfNames function to retrieve the ID of the SayHello method. Finally, it calls your IDispatch::Invoke method and passes it SayHello's ID.
      When implementing Invoke, you need only have a switch that includes a case statement for the SayHello ID. When you receive this ID, you can do whatever you want with it. Figure 2 shows a sample implementation of GetExternal and Invoke. This was taken from the AtlBrowser sample that I'll cover later. Since AtlBrowser is implemented using the Active Template Library (ATL) and it inherits from IDispatchImpl, the Get-IDsOfNames function is taken care of by ATL.

ICustomDoc
      After giving all this great information about IDocHost-UIHandler to my customer, I thought for sure that I had solved all her WebBrowser control problems. But one problem remained. Because her application is written in Visual Basic, she couldn't implement IDocHostUIHandler. That's where the ICustomDoc interface comes into play. This MSHTML interface allows you to implement the IDocHost-UIHandler interface in a COM object that is not a WebBrowser host. You simply query MSHTML (as represented by the IHTMLDocument2 interface) for ICustomDoc and call its only method, SetUIHandler, to inform the WebBrowser control that you're implementing IDocHost-UIHandler.
      There are a few caveats with this approach. Certain methods of IDocHostUIHandler (such as GetHostInfo and Get-External) are only called by MSHTML if the object im-plementing IDocHostUIHandler also implements IOleClient-Site. In other words, the object must be a host application. ShowContextMenu and TranslateAccelerator are exceptions to this rule, and can be called even if the object doesn't support IOleClientSite.
      Also, remember that the IDocHostUIHandler methods are called by MSHTML and that ICustomDoc is implemented by MSHTML. Since a new version of MSHTML is loaded each time you navigate to a new Web site, you must query the document for ICustomDoc and call the SetUIHandler method each time a new page is loaded. The earliest time you should call this method is when the WebBrowser control fires its NavigateComplete2 event.
      To set your implementation of IDocHostUIHandler using SetUIHandler, do the following:


if (m_spWebBrowser)
{
    CComPtr<IDispatch> spDoc;
    m_spWebBrowser->get_Document(&spDoc);

    if (spDoc)
    {
        CComQIPtr<ICustomDoc, &IID_ICustomDoc> spCustomDoc(spDoc);
        if (spCustomDoc)
            spCustomDoc->SetUIHandler(this);
    }
}
Note that m_spWebBrowser is a smart pointer for the WebBrowser control.
      I have since found that this customer's request is very common. A lot of developers who are creating applications that host the WebBrowser control with Visual Basic want to disable context menus and specific accelerator keys. As you know, you can do this by using two methods of IDocHost-UI-Handler: ShowContextMenu and TranslateAccelerator. However, you can't implement IDocHostUIHandler in Visual Basic.
      That is why I created WBCustomizer, a COM object that provides an IDocHostUIHandler implementation for Visual Basic-based applications. This COM object allows you to enable or disable context menus, all accelerators, or specific accelerators. Source code is available for the WBCustomizer COM object, the COM object itself compiled in release mode, and Visual Basic-based sample code that demonstrates it.
      WBCustomizer exposes the EnableAccelerator method and three properties: WebBrowser, EnableContext-Menus, and EnableAllAccelerators. The WebBrowser property is used to set WBCustomizer's internal reference to the WebBrowser control you are hosting. This property is crucial because it's through this reference that WBCustomizer is able to connect its implementation of IDocHostUIHandler to the WebBrowser control you are hosting. The EnableCon-textMenus and EnableAllAccelerators properties do just what they say, enabling or disabling context menus and all accelerators. The EnableAccelerator method allows you to enable or disable specific accelerator keys. This method takes the key code of the accelerator key, the extended key code for Ctrl, Alt, or Shift, and the state of the key (True or False depending on whether you want to enable or disable the accelerator key).
      To use WBCustomizer in your Visual Basic-based application, follow these steps:
  • Register WBCustomizer.dll on your system by using regsvr32 as follows:
 regsvr32 WBCustomizer.dll
  • Set a reference to Microsoft WebBrowser Customizer Sample Object in your Visual Basic-based application.
  • Dim a variable of type WBCustomizer:
 Dim CustomWB As WBCustomizer
  • In your Form_Load event, create a new instance of the WBCustomizer object:
 Set CustomWB = New WBCustomizer
  • WBCustomizer first needs a reference to the WebBrowser control that is on your form. Set this reference using the WBCustomizer.WebBrowser property as follows:
 Set WBCustomizer.WebBrowser = WebBrowser1
  • Turn context menus on or off by setting the Enable-ContextMenus property. A value of True turns context menus on, and False turns them off.
  • Turn all accelerator keys on or off by setting the Enable-AllAccelerators property. A value of True turns on the context menus, and False turns them off. Only those accelerators that require Ctrl, Shift, or Alt key combinations will be turned off. Those that do not require one of these keys, such as Tab and F1, can be turned off directly as described in the next step.
  • Turn specific accelerator keys on or off by using the EnableAccelerator method. The parameters in Figure 3 apply to this method.
      The sample Visual Basic-based application that shows you how to use WBCustomizer is called VBCustomWB. As you can see in Figure 4, VBCustomWB has checkboxes that you can use to enable or disable the context menus and accelerators. You can customize this sample application to fit your own needs.
Figure 4: VBCustomWB
Figure 4: VBCustomWB

IDocHostShowUI
      In addition to the user interface features described earlier, the WebBrowser control lets you customize its message boxes and help. The IDocHostShowUI interface gives you control of these items. This is another Advanced Hosting Interface that your WebBrowser hosting application can implement. Whenever the WebBrowser control needs to display a message box, MSHTML will call the ShowMessage method of your IDocHostShowUI implementation. You can then turn off the message box by returning S_OK. This method receives information about the message that you can use to display your own message. For instance, there may be a message displayed by the WebBrowser control that is confusing to your users. You can trap this message in the ShowMessage method and then display your own alternate message that pertains to your users.
      IDocHostShowUI also gives you control over help that the WebBrowser control displays. For example, when the user presses F1, MSHTML will call the ShowHelp method of your IDocHostShowUI implementation. As before, you can turn off this functionality by returning S_OK and optionally displaying your own help message.
      A sample implementation of IDocHostShowUI is given in the AtlBrowser sample that I will discuss shortly.

Download Control
      In addition to giving you flexibility with its user interface, the WebBrowser control also lets you choose what is downloaded and executed. This means that you can decide whether to download images, video clips, scripts, ActiveX controls, and so on. You can also tell the WebBrowser whether or not to execute scripts, ActiveX controls, and Java applets.
      To accomplish this, your host application implements a special dispatch ID referred to as DISPID_AMBIENT_ DLCONTROL. In your implementation of IDispatch::Invoke, you simply handle this dispatch ID as a case statement within a switch, as I discussed for SayHello. When Invoke is called with dispidMember set to this ID, you should set pvarResult to a combination of flags that indicate what can or cannot be downloaded or executed. You can find the complete list of these flags in the SBN Workshop. From the Workshop Contents, choose Reusing Browser Technology, click on Browser Overview, and then click on Download Control.
       Figure 5 shows an implementation of Invoke that handles DISPID_AMBIENT_DLCONTROL. This sample allows you to download images, videos, and background sounds but turns off the execution of scripts.

AtlBrowser
      The AtlBrowser sample puts to work all of the concepts I've discussed. AtlBrowser is a WebBrowser host application implemented with ATL 2.0, which comes with Visual C++ 5.0 and above. AtlBrowser implements several of the menu items from Internet Explorer. In addition, it has two menu items for user interface and download control. Using the UI Control menu item, you can specify whether the WebBrowser component should display context menus, 3D borders, and scrollbars. You can also specify that text selection is not allowed and that all links should open in a new window. The context menu item is implemented using the IDocHostUI-Handler::ShowContextMenu method. The remaining items mentioned are implemented using IDocHostUIHandler::GetHostInfo. There is another menu item under UI Control that specifies that the WebBrowser control should use Atl-Browser's help. This is implemented using IDocHost-ShowUI::ShowHelp.
      The Download Control menu item can be used to tell the WebBrowser control whether it can download images, videos, and background sounds. This menu can also be used to specify whether scripts, Java applets, and ActiveX controls should be executed. All these items are implemented as explained in the previous Download Control section.

Figure 6: AtlBrowser
Figure 6: AtlBrowser

      In addition to these menu items, AtlBrowser uses the IDoc-HostUIHandler::GetExternal method to extend the Dynamic HTML object model. AtlBrowser exposes a method I talked about earlier: SayHello. When you run AtlBrowser, navigate to the AtlBrowser.htm file that comes with the sample (see Figure 6). When you press the Say Hello button, the WebBrowser control calls the SayHello method implemented in AtlBrowser.

Summary
      The WebBrowser control that has been available as part of Internet Explorer since version 3.0 provides you with a simple way to include rich content and Web browsing functionality in your applications. In Internet Explorer 4.0, it has been taken one step further by providing you with the means to control the user interface of the WebBrowser control and what is downloaded and executed when you are hosting the control. Implementing this control in your own applications is easy and gives you total control over the browsing experience provided to your users.

From the October 1998 issue of Microsoft Interactive Developer.