Custom WebBrowser Registry Settings
The WebBrowser control stores many kinds of different information about user preferences inside the registry. These settings are stores in the HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\ registry key (as well as the keys below it). Investigate that registry key using REGEDIT.EXE. You’ll find many different settings there. Changing those settings will change how the WebBrowser looks and acts. See my Changing IE Show Picture Setting article for an example of how to change a key value that toggles the "Show Picture" setting of the WebBrowser control. What is important is touching any keys or values at that location will affect all the instances of the WebBrowser control in the system, including Internet Explorer. This is not a polite thing for an application to change the settings which are system-wide in this way.
MSHTML provides two ways to allow an application customize these settings through changing the registry, and yet not affecting the whole system with those changes. What makes this possible is the use of IDocHostUIHandler and IDocHostUIHandler2 interfaces. An application can implement either one of both those interfaces, and let MSHTML know of its custom registry path for reading the settings from.
IDocHostUIHandler has a function named GetOptionKeyPath( ). This function’s first parameter can be set by an application to a string which specifies a subkey of HKEY_CURRENT_USER which contains the settings for the application. Some small points are worth mentioning here. First, there is no way for an application to specify a registry key under a different key rather than HKEY_CURRENT_USER. So, for example you can’t make the WebBrowser control to read the settings from HKEY_LOCAL_MACHINE\MyCompany\MyApp registry key. Second, the memory for the first parameter of GetOptionKeyPath( ) that must be set to the string specifying the registry settings key should be allocated only and only using the ::CoTaskMemAlloc( ) function. The WebBrowser control will be responsible for freeing this memory.
IDocHostUIHandler2 provides a fucntion named GetOverrideKeyPath( ). This function is very similar to IDocHostUIHandler::GetOptionKeyPath( ). Its first parameter should be set to a string specifying a subkey of HKEY_CURRENT_USER from which the WebBrowser control will read its user settings from. The same two notes I mentioned above about IDocHostUIHandler::GetOptionKeyPath( ) apply to GetOverrideKeyPath( ) as well.
But what is the difference between these two functions? The difference is very slight, yet very important. GetOptionKeyPath( ) specifies the registry key from which the WebBrowser control will read all its settings from. If you use GetOptionKeyPath( ), the WebBrowser control will no longer look at the HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\ registry key. Any keys or values that do not exist under your own registry key will be set to their defaults by the WebBrowser control. On the other hand, GetOverrideKeyPath( ) specifies a registry key which only overrides the settings stored at HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\. Any settings that do not exist at the key specified by you will be read from the default HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\ key.
To give you an example, suppose that two custom context menus are installed below the HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\ key (see the Scenario 1 in Custom WebBrowser Context Menus), and you have specified the registry key HKEY_CURRENT_USER\Foo\Bar registry key using the GetOptionKeyPath( ) function. Also suppose that there is no MenuExt subkey under your registry key. When the WebBrowser control tries to retrieve its custom menu extensions from the registry. It looks at the Foo\Bar subkey, and notices there is no MenuExt subkey there. Then, it gives up searching, and assumes there are no custom context menus stored in the registry. Now suppose you had specified the HKEY_CURRENT_USER\Foo\Bar registry key using the GetOverrideKeyPath( ) function. In that case, when the WebBrowser control finds out that there is no MenuExt key under Foo\Bar, it will look at the default HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\, and loaded the MenuExt subkey items from there.
So, as it turns out, GetOverrideKeyPath( ) will give you more flexibility for specifying registry settings. The only disadvantage with that is that it’s only supported when IE 5.5 or higher is installed (and as the Knowledge Base article ID Q272968 specifies, it’s not actually supported inside IE 5.5 as well, so you should look at IE 6 and above for this feature), whereas GetOptionKeyPath( ) only requires IE 4 or higher.
Using any of these two functions require IDocHostUIHandler or IDocHostUIHandler2 interfaces to be implemented. If you are using CHtmlView, I have written a set of classes that does all the implementation necessary for you. It’s available at my Advanced CHtmlView Hosting article. To use those classes for using GetOptionKeyPath( ) or GetOverrideKeyPath( ), you only need to derive your HTML view class from CDocHostHtmlView, and override the OnGetOptionKeyPath( ) or OnGetOverrideKeyPath( ) functions. These functions have the same return type and parameters as their IDocHostUIHandler and IDocHostUIHandler2 equivalents. Note that to use the implementation of IDocHostUIHandler2 in my classes, you need to configure your project for targeting Internet Explorer 5.5 and above by defining the appropriate preprocessor macros. To see how you should do this, see my Windows Target Version Macros article.
Implementing these functions is just half of the work you need to do. For any of these functions to have a real effect, you should add the desired registry keys and values to the registry. This can be done in a number of ways. You can create a .reg file and spawn the REGEDIT application to merge the data located in that file into the registry, or you can add them programmatically at the start of your program. A nice place for doing this is inside your application class’s InitInstance( ) function. If you want to do it programmatically, you can use ATL’s CRegKey class defined inside atlbase.h. This class is very helpful, and using it is far easier than using Win32 APIs for manipulating the registry.
The sample application which can be downloaded at the bottom of this article uses the implementation of GetOptionKeyPath( ) described in my Advanced CHtmlView Hosting article. This application also writes a set of registry keys and values in its InitInstance( ) function. Look at the CCustomRegistryApp::SetupRegistry( ) function to see how I’ve implemented writing the values to the registry using the CRegKey class.
The sample applications changes how the links look like by default. It turns off underlining the links, so that the links will not be underlined by default. It also defines a hover color for links, so that every time the mouse cursor moves on a link, the link’s color changes. All this is achieved without changing the original HTML content.