Monthly Archives: June 2008

An old article of mine

I just found a very old article of mine, which got published in Dr. Dobb’s Journal, the Tech Tips section, on October 1, 2003!  The title of the article was Preventing Class Derivation in Visual C++ .NET.  Either see that link, or read on if you’re interested.

Preventing Class Derivation in Visual C++ .NET

Here is a tip for preventing derivation from a class in C++. Suppose you have a class B, and you don’t want any class to derive from this class. C++, unlike other languages such as Java, doesn’t have any built-in support for this task, but this can be done using virtual inheritance. You should create and use a Lock class as this example shows:


class Lock {
Lock() {}
friend class B;
};

class B : private virtual Lock
{
public:
B() {}
};

class D : public B
{
public:
D() {}
};

int main()
{
B b;
D d;

return 0;
}

B is a friend of Lock, so B::B() has access to Lock::Lock() and can initialize the virtual base class. On the other hand, D is not a friend of B, so D::D() can’t initialize the virtual base class due to its inability to call Lock::Lock(). Thus, attempting to compile the aforementioned program will lead to an error. Microsoft Visual C++ .NET 2003 produces the following error messages when compiling this application:

h:\Projects\VC++.NET\test\test\test\test.cpp(17): error C2248: 'Lock::Lock' : cannot access private member declared in class 'Lock'
h:\Projects\VC++.NET\test\test\test\test.cpp(3): see declaration of 'Lock::Lock'
h:\Projects\VC++.NET\test\test\test\test.cpp(2): see declaration of 'Lock'
h:\Projects\VC++.NET\test\test\test\test.cpp(22): error C2248: 'Lock::Lock' : cannot access private member declared in class 'Lock'
h:\Projects\VC++.NET\test\test\test\test.cpp(3): see declaration of 'Lock::Lock'
h:\Projects\VC++.NET\test\test\test\test.cpp(2): see declaration of 'Lock'

Posted in Blog Tagged with:

Version Manager

Version Manager is a COM Add-in for Visual C++ .NET written in C++.  Its job is to increment the version number of the application being developed by one on each build (best known as the application’s build number).  This add-in searches the project for an .rc file, and it if it finds one, it parses the .rc file to find the version information token(s), and increments the build count by one, and saves the file, and allows the compiler to proceed in compiling the application.

To use it, you should first build the project file which can be downloaded at the bottom of this article to generate the add-in’s DLL and register it, so that it’s accessible by Visual C++ .NET.  The next time you start your IDE, Version Manager automatically loads, and increments the build count before each build in a quite transparent manner to you.  To disable it, use the Add-in Manager dialog in Visual C++ .NET, accessible from Tools | Add-in Manager menu item.  Needless to say, if the project is not a Visual C++ project, or if it doesn’t have an .rc file, Version Manager will not do anything.

Version Manager is unlikely to corrupt the resource file (I haven’t met any such situation even during the development of this add-in, and I use it all the time, but can’t guarantee that it won’t happen for you).  Just in case the resource file is corrupted for whatever reason, this tool automatically generates backup files with the same name and extension as the resource file by appending extensions of .backup1, .backup2, .backup3, where .backup1 file is the most recent backup, and .backup3 is the oldest backup file.

Bug Fixes

2004, Oct 10
Howard Swinehart [support AT binaryboy DOT com] found a serious bug in Version Manager, which resulted in an empty resource file if it does not include a version resource block. Luckily, of course, Version Manager makes a backup of the resource script before modifying it, but at any rate, this was a serious bug. Howard himself was willing to supply a patch that fixed the bug. I have verified his patch, and it’s working correctly. The latest version of Version Manager, which includes this patch, can be downloaded at the bottom of this article, thanks to Howard! The latest version is 1.0.0.154. If you are using version 1.0.0.153 or an older version, upgrade immediately.

What’s New

The current version of Version Manager support Microsoft Visual Studio .NET 2003, as well as Microsoft Visual Studio .NET 2002.  For the Microsoft Visual Studio .NET 2003 project, open the VersionManager2003.sln file inside the ZIP package at the bottom of this article.

Known issues

Version manager will fail to update the version information in the .rc file if the .rc file is checked in the source control manager (if you use one).  This is not an issue, in my opinion, because if you have a file checked in, it means that you don’t wish it to be changed under your nose, however, you must know this.

Other than this, I don’t know of any issue in Version Manager, but the general "use it at your own risk" terms apply to it, and after all you have the source code available for studying/changing anything.

Limitations

Currently, Version Manager only supports C++ projects in Visual Studio .NET, and I plan on extending it to handle Visual C#, Visual J#, and Visual Basic .NET projects as well.  You can see this clearly in the source code.  However, when I find enough time to do this is unknown to me, and I would be happy to know if someone adds support for those environments as well.  If you do, please contact me, and I will include the updated version in this article mentioning your name.

Enjoy auto version incrementing!

 Download source code for the article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

WebBrowser Goodies

I have worked with Microsoft WebBrowser control, MSHTML (the HTML parsing and rendering engine behind the WebBrowser control) and Internet Explorer quite a bit, and I have gained a lot of experience and information about them.  I have several articles on this subject, each of which cover a certain point about the topics mentioned above.  Here is a list of articles on this subject; I will update this list as I add newer articles.  Some of the articles on this list you may already have seen, the others are new.  I have also provided a short description on what each article is about.  Hope they will be useful to you.

Usually when you want to load some HTML content into a WebBrowser control, you have to create an HTML page (either as a resource, or as a separate file) and then navigate to that page.  But there is another more flexible way to add HTML content to the WebBrowser control on the fly.  This article introduces a C++ class which can be used to simplify the details of adding HTML content dynamically.

If an application implements some standard interfaces, such as IDocHostUIHandler, IDocHostUIHandler2, and IDocHostShowUI, it can gain a lot of flexibility on how the WebBrowser control acts and looks.  Implementing those interfaces is a bit trick, especially when it comes to use them with CHtmlView as well.  I have written a set of classes which simplify the details of implementing those interfaces, and enable you to override WebBrowser’s behavior by implementing a set of virtual functions.  All information about this subject is covered in this article.

This article demonstrates how to change the registry settings to change the behavior of the WebBrowser control.  The sample application is this article toggles the Show Picture setting of the WebBrowser control from on to off and vice versa.  The sample also demonstrates how to write a simple and small Unicode program as well.  See the Why to Use Unicode and Unicode articles for more information.

Many of the applications which host the WebBrowser control need to implement some common commands which apply to almost any application.  This can be implementing the View Source feature, showing the Properties dialog, invoking the Find command, etc.  This article gathers many parts of one of my applications which hosts the WebBrowser control, and using the sample code of this article, you will be able to implement almost every feature on Internet Explorer in your own applications.

Most of the time, you don’t want the standard context menu of the WebBrowser control inside your applications.  You may want to show a completely customized menu, or add or remove items to the standard context menu.  This article divides all the possible cases into three scenarios, and fully describes the steps you need to take to customize the context menu in any way you’d like.

The WebBrowser control needs to show message boxes on different occasions.  You may want to disable those message boxes altogether, log them to log files, change the way the message boxes look, change their title, or display a completely customized user interface.  This article shows how to intercept the default behavior of the WebBrowser control in this regard.

Many of the WebBrowser control’s settings can be altered via the registry, and all you need to do is to change registry keys and values.  An application can ask the WebBrowser control to change the location it reads the settings from to a completely custom registry key, and this way, customize the settings for the WebBrowser control in their own applications while leaving other application which use the WebBrowser control (including Internet Explorer) intact.  This article shows how you should do this.

An HTML user interface would be of little use if you can’t communicate from the HTML page to your application’s code and vice versa.  While this may seem impossible, all you need to do to make this work is to write a COM object, and provide the communication from the scripts inside the page to the C++ code via that object.  This article demonstrates how this can be done, and the sample application how a simple object can communicate between the script code and the C++ code easily.

This article shows how to use MSHTML to display HTML dialogs.  HTML dialogs are great UI elements which can be created with little effort on your part.  The C++ class presented in this article turns displaying a modal HTML dialog into a set of simple function calls.

This utility application is a spy tool for monitoring the WebBrowser control instances created in the system (even in other processes), and shows how to execute commands on those WebBrowser controls.  For example, using this utility, you can instantly view the HTML source for any WebBrowser control’s contents you want!  This tool comes with the source code.

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

IE Spy

IE Spy is a tool I wrote some time ago.  This tool enumerates all the windows of the WebBrowser control (including instances of Internet Explorer), and executes a set of standard commands on them, like View Source, Save, Refresh, Print, etc.  This tool may be useful to you for your special needs.  For example, suppose a program shows an HTML dialog and you want to see the HTML source of the page the dialog is displaying.  One way would be digging into the EXE resources and/or finding the page being displayed, using a Win32 Resource Editor utility (if necessary), and see its source code.  But this is tedious.  You can just use IE Spy plus Spy++ to obtain the source code instantly.  You should just use Spy++ to obtain the window handle of the WebBrowser control embedded inside the dialog, and use IE Spy to grab its HTML source.

When playing with IE Spy, you can find other useful things it can do as well.  But maybe the biggest advantage of IE Spy is using it as a sample application.

IE Spy mostly demonstrates two things.  The first thing it demonstrates is enumerating all windows (including both parent and child windows) that exist inside the current Windows session.  This is done using two API functions: ::EnumWindows( ) and ::EnumChildWindows( ).  Study the source code inside the file IESpyView.h to see how it’s implemented (Did I mention that the sample application can be downloaded from the link at the bottom of this article?).

The next thing that IE Spy demonstrates is clearly sending commands to the WebBrowser control.  Contrary to what you might think, this is very easy to do.  You just need to know how to do it.  All you need to do is to post a WM_COMMAND message to the window of the WebBrowser (of which you get the HWND by calls to ::EnumWindows( ) and ::EnumChildWindows( )), set the WPARAM’s lower WORD to an appropriate command ID, the higher word of it to 0, and the LPARAM value to 0.  And if you think those command IDs are some undocumented numbers you must find out about the hard way (I mean, running Internet Explorer under a debugger, and watching the asm code for weeks and weeks), well, you’ll be glad to know that you are wrong!  All possible command ID’s are defined inside mshtmcid.h.  Of course, those command IDs are not documented inside the MSDN, but it’s not a hard task to guess what they do if you have ever worked with Internet Explorer.  After all, what could IDM_VIEWSOURCE mean except the command ID to invoke the View Source command?!

Of course, the catch here is that almost all of those command IDs are applicable only when you use the WebBrowser control in Editor mode (like what Outlook Express does, when composing HTML email messages).  And for some of them I could not find any actions at all (before you ask, their names did not indicate their action clearly).  But the most common commands are shown in the IE Spy application.

So, using a set of basic tasks, I have written an application that may surprise many programmers at the first glance.  Just to give you some quick hints on how to use it, please read on.  You should first open an instance of the application (uh!), from the Spy menu, click Begin.  This begins enumerating all the WebBrowser windows in the system.  According to the number of windows (which varies all the time) and the speed of your machine, this might take a moment to complete.  Then, inside the big list view, you’ll see a list of HWND values.  These are useless by themselves (what can you understand from 0x0012E049?!).  At this time, you must invoke Spy++ (which comes with VC++ as a Tool), and use its Find Window tool to get the HWND of the WebBrowser control instance you’re curious about.  Then, you must find the entry inside the list view (the list view is sorted, so it shouldn’t be a hard task) and either right click on it, or click the Spy menu again, and begin your espionage!  The items inside that (well, lengthy) menu are self explanatory, and if you didn’t figure out what a certain item does, look at the status bar which shows a brief help message about it.  If you didn’t figure out the action again, try to test it on the WebBrowser control instance you have selected, since this will be your last resort!

If you are one of those people who are always curious about different things (and hence need nice espionage utilities!) I think you’ll like IE Spy.  Anyway, hope you find it useful.

 Download IE Spy and its source code

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

Common WebBrowser Commands

Almost everyone has used the MFC AppWizard to create a CHtmlView-based application at least once.  Many of us also have written programs which are totally based upon CHtmlView and hence on the WebBrowser control.  When you use the MFC AppWizard to create the project, you’ll get a relatively nice and functional web browser right away.  You can simply implement standard commands of a web browser like Back, Forward, Home, Refresh, etc. by means of methods provided by CHtmlView.  Nothing could be easier than this!  But, what if you want to implement the View Source command for example?  Or, let’s say, you need to have Add to Favorites command, or show the Properties dialog for the page.  Any of these requires writing the code yourself, which involves doing a research to find out how what you want to do should be done, trying to implement it, debug the code, etc.  This article’s goal is to demonstrate the implementation of common commands applicable to the WebBrowser control, with use of CHtmlView.

I introduce a C++ class, derived from CHtmlView, named CHtmlView2 in this article.  It has numerous member functions for performing different things that is available in the Internet Explorer itself.  Some of those member functions are simply a one-line call to a CHtmlView function to do a specific job, and some of them consist of lots of COM code to deal with the details of the WebBrowser control.  This class was evolved from one of my own projects which was centered around the WebBrowser control.  I was wondering how can I perform different things, like for example invoking the Find dialog box (which is an HTML dialog by the way); and this class is the result of my work.

Here I provide an alphabetically sorted list of the member functions important to the user of the class.  To see how these functions can be used, see the sample application.  Under the Command menu of the sample application, all the features that my class is providing is shown.  You can simply play with it, and also view the source code for each message handler function inside the sample’s CCommonCommandsView class.  Of course nearly all of these functions are as easy-to-use as possible, most of them don’t receive any parameters, and they simply return bool, or void, so using them must be easy to everyone!

bool AddToFavorites( );
This function shows the standard Add to Favorites dialog which allows the user to add the current HTML document being displayed to the Favorites folder.  It acts like IE’s Add to Favorites menu command.

void Copy( );
This function copies the selected parts of the document, if any, to the Clip Board.  It acts like the standard IE’s Copy command.

bool CreateShortcut( );
This function creates a shortcut file (with .url extension) to the current document inside a user-selected folder.  This function shows a dialog which allows the user to select (or create) a directory, and then it saves the shortcut file inside that directory.  If the title of the current page is TITLE, the file name would be "Shortcut to TITLE.url".

void Cut( );
This function cuts the selected parts of the document, if any, to the Clip Board.  When using this function, note that it actually cuts the selection, not simply copy it.  It means that if you select a picture, and invoke the Cut( ) function, the picture itself will disappear from the page being displayed!  Exactly as it would happen when using an HTML editor.  To prevent this odd and non-user-friendly behavior, you should use another function, UpdateCutHelper( ), as I’ll describe later in this article.

BOOL FontSizeLargestUpdateHelper( );
This function, like the other update helper functions you’ll see later, is useful inside ON_UPDATE_COMMAND_UI handlers.  You usually call a CCmdUI function passing the return value from one of the update handler functions to it, and everything is taken care of automatically.  The CHtmlView2 provides the facility of changing the text size, as IE does using its View | Text Size menu items.  Five possible font sizes can be selected: Smallest, Small, Medium, Large, Largest.  This function returns TRUE if the font size is set to Largest, and FALSE otherwise.  Usually (as in the sample application) its return value is passed to CCmdUI::SetRadio( ).

BOOL FontSizeLargeUpdateHelper( );
This update handler function returns TRUE if the font size is set to Large, and FALSE otherwise.

BOOL FontSizeMediumUpdateHelper( );
This update handler function returns TRUE id the font size is set to Medium, and FALSE otherwise.

BOOL FontSizeSmallestUpdateHelper( );
This update handler function returns TRUE id the font size is set to Smallest, and FALSE otherwise.

BOOL FontSizeSmallUpdateHelper( );
This update handler function returns TRUE id the font size is set to Small, and FALSE otherwise.

CString GetActiveElement( );
This function returns a CString object which contains the HTML tag name of the currently selected element on the page.  For example, it might be "IMG" if the user has selected a picture, or "P" if she has selected a text paragraph.  If a text input element is active, the return value will be "INPUT-TEXT".  If a file selection input element is selected, the return value will be "INPUT-FILE".  If a password input field is active, the return value will be "INPUT-PASSWORD".  If an error occurs, the return value is "".  The return value is always an upper case string.

bool GetActiveElement( IHTMLElement ** ppActiveElement );
This function returns a pointer to the document’s active element, in form of an IHTMLElement interface.  If this function succeeds, *ppActiveElement is set to point to the active element’s IHTMLElement, and the function returns true.  If the function fails, the return value is false, and *ppActiveElement is not changed.

enum CHtmlView2::FontSize GetCurrentFontSize( );
This function returns the current font size in form of the CHtmlView2::FontSize enum.

CString GetDocumentSelection( );
This function returns the HTML code of the selected document parts in form of a CString object.  If this function fails, or no part is selected, the return value is an empty string.

bool InvokeFind( );
This function shows the IE’s default Find dialog which can be used for finding pieces of text inside the page.

bool InvokeInternetOptions( );
This function shows the Internet Options dialog which is accessible from Control Panel, as well as IE’s Tools menu.

bool InvokeViewSource( );
This function shows the HTML source of the current page inside the default program for showing text files.  This function is similar to the View Source function in IE.

bool IsGlobalOffline( );
This function returns true if the global connected setting is offline, and false if the global connected setting is online, or an error occurs.  You can check the value of GetLastError( ) if you receive false from this function to figure out whether the status is online, or an error has occurred.

bool OrganizeFavorites( );
This function shows IE’s default Organize Favorites dialog, which allows the user to manipulate the Favorites folder, and items inside it.

void Paste( );
This function pastes the contents of the clipboard into the current page.  Take care when using this function, because it actually pastes the clipboard contents into the page, possibly changing how it looks like.  For a more smart version of this function, use PasteSmart( ) instead.

void PasteSmart( );
This function pastes the contents of the clipboard only if a text edit field is active, so that it behaves like the normal IE’s Paste command.  To handle the Paste command for normal applications, use this function instead of Paste( ).

void Properties( );
This function shows IE’s Properties dialog (which is an HTML dialog by the way) for the active item.  If the active element is a picture, the Properties dialog for the picture is shown; if it’s a link, the Properties dialog for the link is shown.  Otherwise, the Properties dialog for the page itself will be shown.  This function behaves exactly like IE’s File | Properties menu item.

bool SaveInternetShortcut( LPCTSTR pszFileName, LPCTSTR pszURL, LPCTSTR pszDescription, LPCTSTR pszIconFile, int nIndex );
This function saves an internet shortcut file (with .url extension).  The file name is specified by the pszFileName parameter; the URL of the item you want the shortcut to point to is specified by pszURL; the description for the shortcut is specified by pszDescription; the location of the icon file (with .ico extension) is specified by pszIconFile; and nIndex specifies the index for the icon if the icon file consists of more than one icon.  The last three parameters are optional, if you pass NULL for pszDescription and pszIconFile, it means that the shortcut file will not have any description or icon file, if you pass -1 for nIndex, it means that the icon file’s index is not required.

bool SavePage( );
This function shows the default file save dialog box, allows the user to choose a location/file name, and saves the current page (plus any of its dependency files, if any) in that location.  Its behavior is exactly like the File | Save As menu item in IE.

void SelectAll( );
This function selects all the HTML document being displayed.  Its behavior is just like IE’s Edit | Select All menu item.

bool SetAsDesktopItem( IHTMLElement * pElement );
This function sets the item specified by pElement as an Active Desktop item, just like you right click the item in IE and choose Set As Desktop Item context menu command.

bool SetAsDesktopItem( );
This function sets the active element as an Active Desktop item.

void SetFontSizeLarge( );
This function sets the current font size to Large.

void SetFontSizeLargest( );
This function sets the current font size to Largest.

void SetFontSizeMedium( );
This function sets the current font size to Medium.

void SetFontSizeSmall( );
This function sets the current font size to Small.

void SetFontSizeSmallest( );
This function sets the current font size to Smallest.

static bool StartWebBrowser( );
This function starts the default web browser with an empty window.

void ToggleWorkOffline( );
This function toggles the connected state for the WebBrowser control from Online to Offline and vice versa.  Its behavior is exactly like the File | Work Offline menu command in IE.

void Undo( );
This function undoes the last action, which is likely editing the text inside an input field.

BOOL UpdateCopyHelper( );
This update handler function returns TRUE when there is something to copy to the clipboard (in other words, something is being selected) and FALSE otherwise.

BOOL UpdateCutHelper( );
This update handler function returns TRUE when there is something to cut to the clipboard (in other words, some part of the text inside an input field is selected) and FALSE otherwise.  Note that unlike UpdateCopyHelper( ), it does not return TRUE when anything is selected.  This provides an easy way for preventing the user from cutting off pieces of the page unexpectedly by Cut( ).  This function should be used inside the ON_UPDATE_COMMAND_UI handler for the Cut menu command, so that it disables the menu item when something other than the text inside an input field is selected.  See the sample application to see how it’s used with the Cut menu item.

BOOL UpdatePasteHelper( );
This update handler function returns TRUE when something appropriate for pasting into the document is available on the clipboard, and FALSE otherwise.  It returns FALSE even when something appropriate to paste is available, but some part of the document other than an input field is selected.  This prevents the odd behavior of replacing page contents with the clipboard contents as an HTML editor would do.

BOOL WorkOfflineUpdateHelper( );
This update handler function returns TRUE is the WebBrowser is in offline mode, and FALSE otherwise.


A note about using this class.  Using this class is simply a matter of copying HtmlView2.h and HtmlView2.cpp files from the sample application to your application’s directory, and deriving your view class from CHtmlView2 instead of CHtmlView.  This involves replacing all the occurrences of CHtmlView with CHtmlView2 everywhere inside your view’s .h and .cpp files.

Hope this class helps you during the development of your applications!


Bug Fixes:

10/24/2003 – Neville Franks (the author of ED for Windows, see http://www.getsoft.com) kindly reported a bug in the code which caused a crash on the occasions that the user selected a large portion of the document’s text and right clicked on it.  Actually he tracked the bug, and showed me how to fix it.  So the whole credit of reporting and fixing the bug shall go to him.

 Download source code for the article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

HTML Dialogs

One of the most useful UI elements that can be simply merged into applications is HTML dialogs.  An HTML dialog is a normal dialog, except that it shows HTML content instead of normal dialog elements.  You can use any HTML code for an HTML dialog; even you can use DHTML, and scripting, embed Flash animations, use Java applets, and absolutely anything you can do with normal applications.  If you are good in designing pages, HTML dialogs provide a rapid way for developing rich user interfaces.  Many big applications are using HTML dialogs.  The most famous sample is Microsoft Internet Explorer.  Open up IE, choose Help | About menu item, and yuppers!  What you see is an HTML dialog!  Microsoft’s Visual Studio .NET IDE also makes heavy use of HTML dialogs for its wizards.  So, why shouldn’t you use them in your own applications?

Although not difficult, the implementation of an HTML dialog is a big task.  The MSHTML.DLL which is the core HTML parser engine of IE exports a function named ShowHTMLDialog which – as you’d guess – is used for showing an HTML dialog.  A lot of details must be considered in calling that function, which was the reason I wrote the CHTMLDlg class.

This class enables you to show any HTML dialog easily by using only a few C++ code lines.  You create an object of this class, call CHTMLDlg::Init( ), pass the URL (could be a web URL, a ile path, or a res protocol URL) of the HTML document, as well as the handle to the parent window of the dialog (could be NULL, if you don’t want the dialog to have any parents) to it, and then call CHTMLDlg::Show( ).  CHTMLDlg::Show( ) takes an optional parameter which is a pointer to a VARIANT structure containing some arguments.  These arguments can be retrieved from the HTML document’s scripts using the window.dialogArguments object.  The dialog can also pass data to your application upon returning.  The script code inside the dialog sets the window.returnValue object to some meaningful data, and your application retrieves that data in the form of a VARIANT structure by calling CHTMLDlg::GetResult( ).  That’s it for showing a modal HTML dialog!

There are also several other public member functions inside the CHTMLDlg class under the section of Attributes inside the header file.   These are very simple methods which either get or change the properties of the dialog.  You can change any of these properties before showing the dialog.  The sample application shows how you can use each and every of these properties.  Play around with the properties to know how you want the dialog to look, and then study the source code to figure out which methods you have to call to simulate those properties.  The sample application also enables you to send arguments to the dialog, and retrieve the returned data from it.

So, you can have dialogs with rich UI and capable of communicating with the host application available, just start inserting HTML dialogs in your own applications.  There is a big chance that the users would like the UI better.  A nice thing about this is that you can write JavaScript code to manage the user interface items (like disabling a button on some condition, for example) which is far easier than writing C++ code to do the same thing on normal dialogs.  The only dependency that using HTML dialogs introduces is that the user should have IE 4 or higher installed on their machine (and who doesn’t have that nowadays?!).

To use CHTMLDlg, download the sample application at the bottom of the article, copy and paste the HTMLDlg.h and HTMLDlg.cpp files to your application’s directory, add them to your project, and here you go!  Start using the CHTMLDlg class!  BTW, this class is not dependent upon MFC, so you can even use it inside your SDK projects if you’re one of those SDK gurus.  Have fun with it!

 Download source code for the article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

Advanced CHtmlView Hosting

The WebBrowser control (and CHtmlView, as its wrapper) is a great tool.  It saves you quite a bit of work to enable web-browsing features inside your applications.  But since it’s not written by you, you have a limited amount of control over how it looks and acts.  The developers of WebBrowser control and MSHTML have provided use some advanced hosting features, so that once an application implements them, it can customize the behavior of the WebBrowser control in more aspects.  These customizations are accomplished by a set of interfaces.  The host application has to implement these interfaces, and MSHTML will query its host for these interfaces, and uses them if available.  These interfaces are IDocHostUIHandler, IDocHostShowUI, and ICustomDoc, which are introduced with Internet Explorer 4.0 for the first time.  Internet Explorer 5.5 introduced another interface, called IDocHostUIHandler2, too.  Note that because of a bug in IE 5.5 that is described in the Knowledge Base article ID Q272968, IDocHostUIHandler2 will not work with IE 5.5, but it works well with IE 6.

One of the less known interfaces which can be used to achieve cool features of the Web Browser control is the IDocHostUIHandler interface.  This interface allows the programmer to customize the behavior of the Web Browser control easily.  The MSHTML code will call this interface’s methods to query options you would like to use, and the interface implementation inside your own code will pass the desired parameters back to MSHTML, and MSHTML will handle the details for you.  So, using IDocHostUIHandler is as easy as implementing that interface!

Well, I admit that I lied on the above line.  It is a bit tricky to implement IDocHostUIHandler, and get it to work, especially when you want to incorporate this into an MFC application which is using CHtmlView.  The Microsoft Knowledge Base article ID Q236312 describes how this should be done, but I think that it’s not exactly the best way to do it.  Using that method requires manual changes to the application class InitInstance( ) functions, including header files here and there, and all this is not good in my opinion.  I wrote some classes which do a better encapsulation, in a way that the only change you need to make to an existing application to add support for the IDocHostUIHandler interface (as well as IDocHostShowUI and IDocHostUIHandler2 interfaces) is deriving your HTML view class from my class instead of CHtmlView.  I have gathered all the necessary code inside the sample application downloadable at the bottom of the article, and I will let you know how to use the classes.  The good news is that MFC 7 (which comes with Visual Studio .NET) has native support for IDocHostUIHandler inside its CHtmlView implementation, and they are as easy as a piece of cake to use.  Because of this, I tried to provide a similar interface to MFC 7 version of CHtmlView, which allows an MFC 6 application using my custom class to be ported to MFC 7 in less than one minute (yes, I’m not joking!).

The other advanced hosting interface is IDocHostShowUI.  This interface allows the application provide its own custom message boxes and help files, and the WebBrowser control will use them, instead of its default message boxes and help files.  This interface is not supported in MFC 7, but my classes provide support for this as well.  This interface has only two methods, ShowHelp( ) and ShowMessage( ).  To use these functions, all the thing you need to do is to derive your HTML view class from my class, and override the OnShowHelp( ) and OnShowMessage( ) functions, which take the same parameters, and have HRESULT return values, like the original IDocHostShowUI methods.

My classes also support IDocHostUIHandler2.  This interface has only a single method which is called GetOverrideKeyPath( ), and it maps to the virtual OnGetOverrideKeyPath( ) function.  Since this interface is provided with IE 5.5 and above, I have used preprocessor conditions so that if you build your application for any version of IE less than 5.5, the IDocHostUIHandler2-related code will not compile, and you don’t have the support (even if you override OnGetOverrideKeyPath( ) in your HTML view class).  In order to compile your application for IE 5.5 and above, see my Windows Target Version Macros article.

The classes you’ll need when implementing IDocHostUIHandler are CDocHostSite, CDocHostOccManager, and CDocHostHtmlView.  To use these classes, just copy the DocHostSite.h, DocHostSite.cpp, DocHostHtmlView.h, and DocHostHtmlView.cpp files into your application’s folder, add them to your project, and derive your HTML view class from CDocHostHtmlView instead of CHtmlView.  To make sure it happens correctly, don’t forget to use the Find and Replace feature to replace CHtmlView with CDocHostHtmlView in both your header and implementation file for the HTML view class.  By the way, whenever you want to port the code to MFC 7, just remove those four files, and change CDocHostHtmlView back to CHtmlView, and that would be all the actions necessary for performing the port.  Clean, isn’t it?!  Of course, remember that if you are using the IDocHostShowUI and/or IDocHostUIHandler2 support, you should watch out, because MFC 7 doesn’t have native support for them.  In that case, just leave your code as it is with MFC 6, and compile it using Visual C++ .NET, you’ll see that my classes support MFC 7 as well, only in that case, they use their own implementation, and don’t rely on MFC’s implementation (however, all this is transparent to the programmer).

One other thing to note is that the only class you’ll have to work with directly is CDocHostHtmlView (of which you should derive your HTML view class).  The rest of the classes do their job in the background, and you don’t have to mess with them at all, although they also need to be included in the project.

To customize the behavior of the Web Browser control, you have to override the virtual functions provided inside CDocHostHtmlView, and do what you need according to the documentation of the IDocHostUIHandler interface.  For example, the sample application which can be downloaded at the bottom of this article disables the context menu by overriding the OnShowContextMenu( ) function which corresponds to the IDocHostUIHandler::ShowContextMenu( ) function.

All the virtual functions declared inside the CDocHostHtmlView have return types and parameters exactly identical to their corresponding IDocHostUIHandler, IDocHostShowUI, or IDocHostUIHandler2 functions.  All of them except OnDocWindowActivate( ) and OnFrameWindowActivate( ) only have an "On" prefix in their names, and that’s the only difference with the signature of the corresponding IDocHostUIHandler functions.  So, for example, to change the implementation of IDocHostUIHandler::GetExternal( ), you have to override the virtual function CDocHostHtmlView::OnGetExternal( ).  Note that the sample application does not demonstrate the use of IDocHostUIHandler2 or IDocHostShowUI interfaces.  For samples of customizing the behavior of these two interfaces, see the articles listed at the bottom of this article.

Here I will list some of the possible customizations applicable to this interface, and I will show you which function you need to override.  It’s relatively straightforward to implement the functions if you read the IDocHostUIHandler documentations.  Remember that even more customizations are possible, I’ll only list the commonly used ones.

To gain this feature…

… override this function of CDocHostHtmlView.

Add/remove supported clip board formats for the WebBrowser control OnFilterDataObject( )  [IDocHostUIHandler]
Accessing the host application’s methods from the script inside the web pages OnGetExternal( )  [IDocHostUIHandler]
Disable the selection of texts in the forms OnGetHostInfo( )  [IDocHostUIHandler]
Disable the 3D border OnGetHostInfo( )  [IDocHostUIHandler]
Disable scroll bars OnGetHostInfo( )  [IDocHostUIHandler]
Disable the execution of scripts inside the page OnGetHostInfo( )  [IDocHostUIHandler]
Open links in new windows OnGetHostInfo( )  [IDocHostUIHandler]
Flat scroll bars OnGetHostInfo( )  [IDocHostUIHandler]
Enabling the auto complete feature inside forms OnGetHostInfo( )  [IDocHostUIHandler]
Enable/disable the usage of Themes for the UI elements of the Web Browser control OnGetHostInfo( )  [IDocHostUIHandler]
Changing the registry key under which the WebBrowser control reads the user settings from OnGetOptionKeyPath( )  [IDocHostUIHandler]
Overriding the registry key under which the WebBrowser control reads the user settings from OnGetOverrideKeyPath( )  [IDocHostUIHandler2]
Show custom context menus/disable context menus OnShowContextMenu( )  [IDocHostUIHandler]
Override the accelerator keys for the Web Browser control OnTranslateAccelerator( )  [IDocHostUIHandler]
Modify the URLs before loading them OnTranslateUrl( )  [IDocHostUIHandler]
Show custom help files OnShowHelp( )  [IDocHostShowUI]
Show custom message boxes OnShowMessage( )  [IDocHostShowUI]

I have provided a set of articles which demonstrate some of the customizations possible, and each of them comes with sample applications that actually do the customizing.  Here is a list of them, in alphabetic order:

This article demonstrates three possible scenarios for customizing the WebBrowser’s context menu, sorted by the difficulty of implementation from easy to hard.  For each scenario, it provides a sample application which demonstrates the necessary code for performing the customizations.  It’s a must-read for those who are going to customize the WebBrowser control’s context menus.

This article demonstrates how to show custom message boxes instead of the message boxes being displayed by the WebBrowser control by default.  The sample application for this article extracts the message box caption from a DLL string resource, and ensures that no message box with the caption "Microsoft Internet Explorer" are shown.

This article demonstrates how to make the WebBrowser control read its registry settings from the location you specify to it.  This allows you to simply change some of the features of the WebBrowser control for your own application without touching the settings that the WebBrowser control uses for other applications.  The sample application demonstrates how to change the default link colors for your application, and also define a hover color for the links.

This article shows how to extend the WebBrowser control’s DOM in your own applications.  Using this method, you can provide a communication means between your application and HTML pages you display; such a communication is quite necessary for creating an application which uses the WebBrowser control to display its user interface.  This communication is provided using a COM object.  Major applications like Microsoft Outlook Express® (which comes with Internet Explorer®) and Microsoft Outlook® (which is a part of the Office® family) use the same technique for creating rich HTML user interfaces.

Updates

The CDocHostHtmlView class is now (2003/03/27) updated with a new fix submitted by Todd Perlmutter.  This fixes a sizing issue with the WebBrowser control which is the result of some MFC code and results in the WebBrowser control’s scrollbars being clipped.  The article’s download ZIP file contains the new class with the WM_SIZE handler Todd has added.  Thanks, Todd!

 Download source code for the article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

Extending the WebBrowser DOM

Any application that uses the WebBrowser control for its User Interface will have to implement some functionality which allows the application to talk with the HTML page and vice versa.  Without this, using WebBrowser control will not make much sense, unless you only want to show the users some nice HTML stuff without allowing them to do anything with it.

The HTML itself does not provide any facilities to communicate with a host application.  After all HTML itself is nothing but a markup language which specifies what content should appear inside a page, and provides some information about its formatting, positioning, etc.  But fortunately the WebBrowser control supports scripting, and you can insert script code inside your pages easily using a SCRIPT HTML tag.  The script you insert can be written in various languages; two of them which are most popular, and supported by default are JScript and VBScript.  In this article, I use JScript (because it’s my favorite scripting language, and has a syntax similar to C), but you must be able to use VBScript to do what the sample does easily.

So, everything is solved, no?  Well, not exactly!  The scripting language itself does not do anything useful.  What we’ll use is the native COM support in the scripting languages and runtime.  Any code written in JScript or VBScript can communicate with COM objects (written in VC++, VB, etc.).  The WebBrowser also control exposes its Document Object Model (DOM) using COM objects.  For example, the popular window object inside the browser’s DOM is actually implemented as a COM object supporting the IHTMLWindow2 interface (declared inside mshtml.h).  So, in order to provide a communication route from the application to the scripting environment, you need a COM object.  You can write the COM object using MFC, or ATL (of course, if you feel like writing a lot of boilerplate code, you can do this in raw C++ as well).  This object can even live inside a different module, either in a separate DLL, or even a separate EXE.  Of course, putting it inside a different EXE module makes little sense, because after all this COM object is only a means of talking to the scripting environment, and any logic governing it is tightly bound to the application itself.

This COM object, like any COM object, must fulfill a set of contracts.  In this case, the object has to be derived from IDispatch.  This is the case for any COM object to be accessible from scripting environment, because IDispatch provides general methods for calling a method on an object having its name as a string, and knowing nothing about its binary layout inside the memory.

So, how is the scripting environment going to know about the existence of such an object?  As one would guess, the scripting environment calls a method on a predefined interface, and that method will return an IDispatch pointer to the application’s COM object (which should already be created).  The method which is responsible for this is IDocHostUIHandler::GetExternal( ).  This method returns an IDispatch pointer to the application’s COM object responsible for communication between the scripting environment and the application.  If this method succeeds, the scripting environment can access any methods and/or properties of the COM object using their string names.  How does the writer of the script code access the COM object?  The external property of the window object will contain the COM object returned by IDocHostUIHandler::GetExternal( ).

These are the details you need to know before stepping into writing the code.  But wait!  I talked about the IDocHostUIHandler.  What is it?  How should one implement it?  How should it be passed to the WebBrowser control?  You don’t need to worry about these things at all, because I have already provided another article which discusses this interface, and offers a useful class for implementing this interface.  You should read this article before proceeding, and also investigate its source code, if you have not done so already.

The sample application which can be downloaded at the bottom of the article uses the classes presented in my Advanced CHtmlView Hosting article to implement the IDocHostUIHandler interface.  The sample only overrides one virtual function of the class CDocHostHtmlView.  The CExtendingDOMView::OnGetExternal( ) function is overridden to return the IDispatch pointer to the COM object.

The COM object implementation is simple if you have used ATL to write COM objects before.  I simply used the ATL Object Wizard to create a Simple Object.  To do this, you should select the Insert | New ATL Object menu item.  ATL Object Wizard will ask you if you would like to add ATL support to your MFC project.  Click Yes to add the necessary support for ATL to your MFC project.  Right after you click Yes, you’ll get a message box complaining about an error.  Don’t worry, this is the normal behavior!  Now you have ATL support added to your project (if you doubt, open stdafx.h and see the lines added to it).  Now you have to run the Wizard again, this time you’ll see a list of possible objects you can create.  What you need is an ordinary Simple Object (which is the first choice inside the Wizard.  Click Next.  In the next dialog box, type "ProxyObj" inside the Short Name edit box; you’ll see the rest of the edit boxes update accordingly.  Then switch to the Attributes tab, select Single for the Threading Model, and also check the Support ISupportErrorInfo check box.  Clicking OK will create the boilerplate code for the object.

Now you have to add methods and properties to your object.  The methods and properties you’ll add depend on the application’s needs.  I have added some sample methods and properties just for testing purposes.  you can check out the sample application to see them.  Pay special attention on the RaiseError( ) method.  This method intentionally raises an error, to demonstrate how it is handled inside the scripting environment.

Note:  Because of a bug, you may get the compiler error "error C2668: ‘InlineIsEqualGUID’ : ambiguous call to overloaded function".  The Microsoft Knowledge Base article ID Q243298 describes this problem.

The last thing you should consider is how to pass the COM object you’ve just created to the OnGetExternal( ) function.  This should be rather simple.  Because the COM object lives inside our own module, you don’t need to bother with the standard way of creating COM objects, which is calling ::CoCreateInstance( ).  So, how should you do it?  You might think you can simply create an object of the CProxyObj class.  But you can’t, because standard IUnknown methods of each interface are not implemented inside CProxyObj.  In other words, CProxyObj is an abstract class.  What you need to do is to wrap the class inside a CComObject object.  To create the actual object, you call the static CComObject::CreateInstance( ) function.  Because these are all standard ATL subjects (and I suppose you’re familiar with them) I won’t describe it further.  If you’re not familiar with this method of creating COM objects, read up the documentations on the MSDN.

The last decision to make is where should the COM object belong to.  You might want to put it inside the document’s class, or the view class.  Even you might want to put it inside the main frame class.  This really depends on the application.  The most generic place for creating such an object (if you don’t want to create a global object) is inside the application’s class; but then again this is the worst solution in my opinion.  Anyway, I decided to have the COM object as a member of my view class.  Also I added a public method to the application’s class which is responsible for getting an IDispatch pointer to the COM object from the view class.  This method is accessed from the OnGetExternal( ) function.

You can build the sample application, and run it.  The main page shows the necessary controls for manipulating the COM objects.  The JScript source code used inside the page is also shown.  See how window.external is used to access the COM object.  Note that if you open the HTML file in IE (the file is mainpage.htm in the src folder) you get errors saying object does not support this property or method.  This is because that the window.external property of IE does not have access to our COM object, and hence cannot resolve method calls using the IDispatch interface.

One last note.  The application hosts a COM object, so it should be registered first.  You can register it using this command line:

ExtendingDOM /RegServer

This is the standard way to register COM EXE servers by the way.  Also note that if you are going to ship the application, you need to ship the .tlb file generated by the MIDL Compiler, too.

Using these pieces of information, you can build applications which use the WebBrowser control to show their main user interface.  By the way, you have probably seen applications which are implemented this way before.  Both Outlook Express, and Microsoft Outlook use the same technique I have described to generate their HTML UI, and make it useful.  If you like their UI, you can start to create your own HTML UI today.  Good luck!

Update List

10/31/2003 – Added support for Visual C++ .NET 2003 to the sample project (thanks to Jason DeGeorge).

 Download source code for the article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

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.

 Download source code for the article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++

Custom WebBrowser Message Boxes

Imagine you have written an application which uses rich HTML user interface, with a lot of scripting and DHTML effects.  Maybe somewhere in your script codes, you have used the window.alert( ) function, and as soon as the alert message pops up, what do the users see?  A message box titled "Microsoft Internet Explorer"!  Hey, of course you are using the IE technology, but you don’t like the normal user notice it, do you?!

OK, to defeat this problem, you promise yourself not to use the alert( ) function.  But sometimes you will see that there is no way better than showing an alert box!  Well, you can’t have much control on it, really.  Of course, you may be able to do something by setting up different kinds of hooks and spying utilities, but there is a better and simpler way.

Microsoft has provided the interface IDocHostShowUI which (as its name implies) provides a means for your application to show its own user interface elements instead of those which are the default for the WebBrowser control.  This interface has two methods, ShowHelp( ) and ShowMessage( ).  The ShowHelp( ) function is used for showing your own help files or help context instead of those default to the WebBrowser control.  I won’t discuss this function in this article.

The ShowMessage( ) function is prototyped like this:

HRESULT ShowMessage(HWND     hwnd,
LPOLESTR lpstrText,
LPOLESTR lpstrCaption,
DWORD dwType,
LPOLESTR lpstrHelpFile,
DWORD dwHelpContext,
LRESULT* plResult
);

The hwnd parameter is the handle to the parent window.  If you show your UI using ::MessageBox( ) for example, this should be passed as the first parameter.  The lpstrText is the message text to be shown.  This is the default text that MSHTML provides.  You can modify it if necessary.  The lpstrCaption parameter is the caption for the message box.  You can change it to suit your own needs inside the application.  You will most likely want to change it to your application’s name; I will describe how you should do it later.  The dwType parameter is exactly like the fourth parameter of the ::MessageBox( ) function.  The lpstrHelpFile parameter indicates the help file path name.  If you want to show the help file, you must store this string somewhere, add a MB_HELP style to the message box, handle the WM_HELP messages inside the owner window (the window that is specified by the hwnd parameter), and inside the WM_HELP message handler, call ::WinHelp( ) and pass this string as the help file name.  The dwHelpContext specifies the context identifier of the help file which is also useful when you want to display a help file.  The plResult parameter points to an LRESULT variable.  This LRESULT variable should be set to the return value of the ::MessageBox( ) function, which specifies which button the user has clicked.

To use this function, you should provide an implementation of IDocHostShowUI.  This is a relatively tricky task, especially when you want to do it in a CHtmlView based application.  I have provided a set of classes inside my Advanced CHtmlView Hosting article which simplify things a lot.  See that article if you haven’t already.  To use ShowMessage( ) with my classes, you must derive your HTML view class from CDocHostHtmlView instead of CHtmlView, and override the virtual OnShowMessage( ) function.  Inside this function, you can show your own message box with custom text or caption.

The sample application which can be downloaded at the bottom of this article demonstrates a simple OnShowMessage( ) that replaces the caption of the message box with its own caption if it is the default "Microsoft Internet Explorer" caption.  Note that the WebBrowser control may show other message boxes which have a different caption, so you shouldn’t change the caption blindly.  My application uses the standard way to see if the caption of the message box is set to the standard caption or not.  It loads SHDOCLC.DLL, and loads the string resource number 2213.  This is the string resource which the WebBrowser control obtains its default message box title from.  If the lpstrCaption parameter equals this string, OnShowMessage( ) will change the caption.  If not, it does not touch it.  It also checks to see if the message box style contains the style for showing an exclamation mark.  If so, it changes it so that the message box would show the information icon.

One small note here.  You can’t customize the message boxes that come from within the scripting engine this way.  For example, for a JavaScript runtime error, the WebBrowser control does not show any message box, what you see is the message box being displayed by JSCRIPT.DLL, so even the WebBrowser control can’t control it!  The best way to avoid these kinds of message boxes is of course writing your script code in a way that it does not generate a runtime error.

 Download source code for the article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++