Starting with HTML Help

.

Environment: This demo is made with MS Visual C++ Version 6.0 with the latest Service Pack. It does NOT work under earlier versions of MSVC++.

One day I woke up and found myself wanting HTML Help in my project. So I started searching for docs on using it with MFC and found out that it wasn't as simple as I thought. All I wanted was one entry in the Help menu (Help Topics...) and a Help button in each dialog which would bring up the corresponding topic. And a nice contents pane in the Help of course so users could get a quick overview and easily navigate through Help.

For those of you who want to get started with HTML Help my explorations might be useful. For those of you who know of better or more ways to use it: let the world (and me!) know. For those of you who think "What in the world is HTML Help?" look at the Help in Internet Explorer 4.01 and you'll know.

Using HTML Help splits up in a few sections. On each of which I'll tell you the way I'm doing it.

Installing the HTML Help Authoring Kit

You can download the latest version for free here. I'll assume you install it in C:\Program Files\HTML Help Workshop. After installing you should prepare DevStudio: go to Tools, Options, Directories, then:

  • Under Show directories for choose Include files, click on New and type
    C:\Program Files\HTML Help Workshop\include
  • Under Show directories for choose Library files, click on New and type
    C:\Program Files\HTML Help Workshop\lib
  • Under Show directories for choose Executable files, click on New and type
    C:\Program Files\HTML Help Workshop
  • Close DevStudio and restart to save the changes.

Creating the topic files in HTML language

First, of course, you'll have to create the .htm topic files themselves. I like WYSIWIG on this so I am using Frontpage Explorer to create a web which will contain all of the files. Besides the .htm files you can add images, avi's, sounds, just about anything you want to use. The help file later on will behave like a website. You can also use one of Frontpage's themes if you want.

I do use a theme but I do not use the navigation features of Frontpage. The resulting buttons on each page take up to much space in the Help window. Besides that, I make use of the contents pane of the HTML Help. Navigating through a Help file by means of a Table of Contents pane is, in my humble opinion, much more clear to the user than criss-cross navigation with buttons on each page (when you use a theme you should add each .htm page to the navigation pane (all on the same level) and rename it. The themes use these names then for the page titles).

Under your project main directory create a directory called HTML. In HTML create a directory called Web. Publish the Frontpage web you've created to Web. Frontpage puts all sorts of files in here but the HTML Help Compiler will only include the files you and the pages you made refer to so don't bother about that.

Making the help file (.chm) itself

Start HTML Help Workshop, click on New, Project, Next. Browse to the HTML directory, type yourname, click Open, Next, Next, Finish. Click on Add/Remove Topic Files, Add, and browse to the Web directory. Select all the .htm files you've created and click Open, OK. Click on HTML Api Information, Header File and type yourname.hm. This will become the file with context ID's from the project. Ignore the warning from HTML Help Workshop and include the file anyway. Click on OK. By now you should have added a [FILES] section with the topic files and a [MAP] section with the header file in it.

There are many other things you can do. I've included a complete published web in the demo project so feel free to look into the HTML Help project file.

Creating a MFC project

When you create a MFC project with AppWizard you can choose for Context Sensitive Help. When you do this there will be a hlp directory in your project's main directory and a MakeHelp.bat. You won't need any of these files for HTML Help so leave the Context Sensitive Help unchecked.

The HTML Help Project has to be added to your project, just like the old WinHelp project. Quite a bit of manual changes to the project settings I'm afraid. Start with adding the HTML Help Project File: from DevStudio's menu choose Project, Add To Project, Files. Browse to the HTML directory, select the .hhp file and click OK. Now you can change the settings for your project. From the menu choose Project, Settings, All Configurations. Then make the following changes:

Setting for: Field/Button: Type:
Link tab Object/library modules htmlhelp.lib
yourname.hhp
(Custom Build tab)
Description Making HTML Help File...
  Commands hhc.exe html\$(InputName).hhp
echo.
copy html\$(InputName).chm $(OutDir)\$(InputName).chm
  Outputs html\$(InputName).chm
  Dependencies... html\$(TargetName).hm
Resource.h
(Custom Build tab)
Description Making HTML Help Include File...
  Commands makehm ID_,IDH_,0x10000 IDM_,IDH_,0x10000 resource.h >>"html\$(TargetName).hm"
makehm IDP_,IDH_,0x30000 resource.h >>"html\$(TargetName).hm"
makehm IDR_,IDH_,0x20000 resource.h >>"html\$(TargetName).hm"
makehm IDD_,IDH_,0x20000 resource.h >>"html\$(TargetName).hm"
makehm IDW_,IDH_,0x50000 resource.h >>"html\$(TargetName).hm"
echo. >>"html\$(TargetName).hm"
MakeIDH "html\$(TargetName).hm"
  Outputs html\$(TargetName).hm

and click on OK. Finally add the statement #include <htmlhelp.h> to your stdafx.h.

Comments on the custom build command for resource.h

I make use of the utility MAKEHM that comes with MSVC. It creates a file with renumbered ID's corresponding to the resource IDs in your RESOURCE.H. When you create a project with AppWizard and switch the Context Sensitive Help on you'll get a MAKEHELP.BAT file which calls MAKEHM and creates a .hm file with all your resource ID's mapped to another value in lines like HIDR_MAINFRAME 0x20080.

For some reason the gurus at Microsoft decided to do it differently in HTML Help. Somewhere in the MSDN docs I found the note "If you used the IDH_ prefix for your context-sensitive help topic IDs, HTML Help Workshop automatically compares the topic IDs in your compiled help file against those mapped to numeric values in your project file. Compiler messages will tell you where your context-sensitive help is broken so you can fix it." That's the reason I use IDH_ as a prefix only. The custom build command creates lines like IDH_MAINFRAME 0x20080.

Another decision the MS gurus made is that this wasn't good enough for HTML Help. There must be a #define in front of the ID. That's why I wrote a small utility named MAKEIDH. You'll find it in the main directory of the demo project. It parses a file and places #define in front of every line that starts with IDH_. Final result for the .hm file: #define IDH_MAINFRAME 0x20080. Copy the utility MAKEIDH.EXE to a subdirectory anywhere in your path to have it always available.

Implementing help calls

By now your project should compile without errors. There are a few changes to do in the source files. First, in InitInstance(), change the default file extension for the help file from .hlp to .chm:

    // Change extension for help file
    CString strHelpFile = m_pszHelpFilePath;
    strHelpFile.Replace(".HLP", ".chm");
    free((void*)m_pszHelpFilePath);
    m_pszHelpFilePath = _tcsdup(strHelpFile);

Then add a help handler in CMainFrame. Put the following in CMainFrame just before END_MESSAGE_MAP and outside the AFX_MSG_MAP tags:

    ON_COMMAND(ID_HELP, CMDIFrameWnd::OnHelp)

or, if you chose for single document view:

    ON_COMMAND(ID_HELP, CFrameWnd::OnHelp)

Use ClassWizard to add an override for WinHelp. Replace the contents of WinHelp() by:

    HtmlHelp(m_hWnd, AfxGetApp()->m_pszHelpFilePath, HH_HELP_CONTEXT, nCmd == HELP_CONTEXT ? dwData : 0);

Almost ready! When you compile your project now and press F1 or choose Help Topics you'll get the warning HH_HELP_CONTEXT called without a [MAP] section. The last thing you have to do is to map, in HTML Help Workshop, topic ID's from the generated .hm file to topic files. To have the help system react on F1 in the main window you would map IDH_MAINFRAME (single document view) or IDH_HTMLDETYPE (in my demo project with multiple document view) to INDEX.HTM. To show specific help for a dialog just add a button with an ID of ID_HELP to the dialog and map the corresponding translated dialog ID to the specific topic file. In the demo project I added a button to the About box so I mapped IDH_ABOUTBOX to ABOUT.HTM.

In HTML Help these mappings are called aliases. Open the HTML Help Project with HTML Help Workshop and doubleclick on the [MAP] section. Click on Alias, Add and type the ID in the first field. Select a topic file in the second and click OK, OK.

Using bookmarks

You can force HTML Help to scroll directly to a specific spot on a help page by adding a bookmark to the HTML file. Just add a bookmark to the HTML Help file and add a # and the name of the bookmark to the alias in HTML Help Workshop. In the demo project I've added a bookmark in ABOUT.HTM. Click in the demo on Help, How to use bookmarks to view the effect.
The compiler now generates a warning that can be ignored (in this case HHC3015: Warning: An alias has been created to "Web\about.htm#Bookmark" but the file does not exist).

Distributing HTML Help

HTML Help works through a control called HHCTRL.OCX. When you want to distribute your program with HTML Help, the user should have installed the latest version. Personally I state that users of my programs should have Internet Explorer 4.01 installed before they are able to use them. Then I'm sure they have HTML Help installed (and a recent COMCTL32.DLL, also handy). On the Microsoft web you can find information about updates for HTML Help called HHUPD.EXE. It can be implemented in a silent way (hhupd /q) in your setup program so you're sure they always use the latest HTML Help control.

Known problems and updates

  • Some readers couldn't get the demo working: the message HH_HELP_CONTEXT called without a [MAP] section keeps popping up. This seems to be caused by the sequence in which the files are compiled (if the .chm file is build before the .hm file, the help file doesn't contain updated ID's). When the project is rebuild twice, the error message disappears. To ensure the .hm is build before the .chm file go to Project Settings, Settings, choose All Configurations, select the .hhp file, click on Custom build, Dependencies and add html\$(TargetName).hm.
    This article (see Creating a MFC project) as well as the demo project is updated with these changes.
  • Jayant Umrani wanted the following: (quote) HOW TO GIVE KETWORD SEARCHES DIRECTLY FRON VC++. SUPPOSE THE USER PRESSES F1 KEY WHEN HE IS SOME FEILD OF THE DAILOG BOX AND IDH IS ASSOSIATED TO SOME HTML FILE BUT THE ACTUAL TEXT IS DEEP BELOW IN THAT HTML, THEM THE HELP SHOULD ME SHOWN WITH THAT PART ON TOP (unquote). A few hours later he supplied the solution himself so I implemented it in the demo project and updated this article (see Using bookmarks). Thanks for participating!

Well, that's it! Hope you find it useful.

Downloads

Download demo project - 126 KB