This article shows you how to use the MSHTML Advanced Hosting Interfaces,
IDocHostUIHandler, from .NET. These interfaces allow you very fine
control over the user interface presented by the Microsoft Web Browser Control,
for example, you can show your own context menu. I'll show you an easy way to
use this interface without having to re-write the interface definitions yourself.
As a bonus, I'll show you how to receive events from elements in the document.
It is easy enough to put a web browser control on a form and
get a fully-functional browser right away. But in your application,
you might want finer control over how the control interacts with
the user. For example, the standard IE context menu does not look
particularly nice when you application shows an ultra-cool DHTML-based
user interface. An interface called
IDocHostUIHandler affords you
this level of control.
IDocHostUIHandler has to be implemented by your application.
You can then use
ICustomDoc::SetUIHandler to tell MSHTML that
you have this interface.
IDocHostUIHandler is defined in MsHtmHst.idl in the Internet
Development SDK, part of the Platform SDK. One approach I've seen
is to do the import by hand - write the interface definition
yourself in your source code.
The other approach, the one I'm going to use, is to create
a type library with the interfaces we need declared in it, and
then use the tlbimp tool to create an Interop assembly. No
fiddling with marshalling yourself.
The first step would be to create an IDL file with the
interfaces we need declared in it. You shall also need
a UUID for the generated type library. There are only a few
interfaces we need, and the entire IDL becomes:
I've included all the Advanced Hosting interfaces and enumerations
The next step is to generate the type library. Just compile the
IDL file to get a TLB, using the Platform SDK tool MIDL.
midl MsHtmHstInterop.idl /tlb bin\MsHtmHstInterop.tlb
Now we need an interop assembly. We just have to use tlbimp
on the newly created TLB file:
tlbimp bin\MsHtmHstInterop.tlb /out:bin\MsHtmHstInterop.dll
Now we can use the interfaces we need with just a
statement in our C# code:
For the sample application, I have put just a single
web browser control on a form. The form class implements
To hook up the interface to MSHTML, we first need to
ICustomDoc interface, and then call the
method with our interface as an argument.
HtmlUI.cs (partial - HtmlUIForm constructor)
object flags = 0;
object targetFrame = String.Empty;
object postData = String.Empty;
object headers = String.Empty;
this.WebBrowser.Navigate("about:blank", ref flags, ref targetFrame,
ref postData, ref headers);
ICustomDoc cDoc = (ICustomDoc)this.WebBrowser.Document;
this.WebBrowser.Navigate(@"res://HtmlUI.exe/Sample1.htm", ref flags, ref targetFrame,
ref postData, ref headers);
That's all there is to it. Of course, the form class
IDocHostUIHandler member functions.
HTML files in resources
You'll notice that I've used the res: protocol in my code.
This is a neat way to package your HTML files and other support files
- they're in the EXE itself. There are several advantages to this
approach: your users cannot easily change the application's user interface,
and you don't have to bother with packing more files into your
You just have to make an RC file defining the resource:
Sample1.htm HTML "Sample1.htm"
This can then be compiled to get a RES file. You can
add the RES file to your assembly with the /win32res C# compiler
Handling Document Events
If your application has a DHTML-based user interface, you
would definitely need to catch events from elements on the page
in order to make it functional. If you run the sample app, you
can see that clicking the button on the page shows you a message
box. This message box has been invoked from the C# app, not from
any scripts on the page. Here's the code:
private void WebBrowser_DocumentComplete(object sender,
IHTMLDocument2 doc = (IHTMLDocument2)this.WebBrowser.Document;
HTMLButtonElement button = (HTMLButtonElement)doc.all.item("theButton", null);
private bool Button_onclick(IHTMLEventObj e)
MessageBox.Show("Alert from the app: Received theButton.onclick!");
Building the app
I have included a makefile which you can use to build from the
command prompt. Just use nmake all to build the app.
Note that the tlbimp mshtml.tlb step takes a while.