There are three Windows help systems: WinHelp, HTMLHelp Version 1 and
HTMLHelp Version 2.
WinHelp is the original help system from 16-bit Windows. WinHelp help
files have a HLP extension. Writing the source for a WinHelp help file is
especially cumbersome; the source files must be in a RTF file format and must
use specific word processing tags in specific ways and in ways that are not
obvious or consistent with expectations. Some people might say that it is not
intuitive, but intuition means something that is understood without being
obvious whereas WinHelp's use of RTF is not easily understood regardless of
whether it is obvious or not.
HTMLHelp Version 1 is the help system used most commonly now.
Certainly most Microsoft software uses it now. HTMLHelp help files have a CHM
extension. HTMLHelp help files are called compiled help files since they are
actually many files gathered ("compiled") and compressed together. Usually most
of the files are HTML files but not all are. All versions of MFC provided
with Visual C++ versions prior to 7 had support of WinHelp built in. This means
that use of HTMLHelp with a MFC application built using VC 6 or prior requires
overriding MFC's use of WinHelp.
HTMLHelp Version 2 is new for .Net. It is being used for .Net software
but it's future is not yet certain. Microsoft does not (currently) recommend
using it with software not designed to use it.
The remainder of this article is a brief introduction to using
HTMLHelp and describes how to add very minimal support of HTMLHelp to a MFC
application. I have a few simple tips that will help too. This article will not
get into context-sensitive help. For the purposes of this article I am using a
MFC SDI application generated by the AppWizard without support of
Context-sensitive help. Use of HTMLHelp by a MDI application would be the same
except the class for the frame window would be different. I am not sure what
would be needed for a dialog-based application; I will investigate and describe
that further later.
Whenever possible, and when using VC 6 and previous versions of VC to create
a new project, if HTMLHelp will be used, then the project should be generated by
the AppWizard without the Context-sensitive help option. If a project is
generated with the Context-sensitive help option then the HTML Help
Workshop can probably help convert the generated help to files for use by
HTMLHelp but I don't describe that here. The HTML Help Workshop documentation
and other articles can help with that.
Installation of the Microsoft HTML Help SDK
The HTMLHelp SDK is not provided with Visual Studio, at least not version 6.
So if you have not installed it separately then you need to, as described in
Installing HTML Help. Then look at my Introduction
to HTMLHelp article if you need help getting started writing HTML Help
files. Then set up the VC environment as described in
Including HTML Help Support Files in an Application.
Program Modifications
The following is my version of how to modify a MFC
application to use HTMLHelp.
Modifying the Resources
First create string resources to be used as prompts for the menus. Add the
following ids with these strings or whatever other strings you choose. The
resource editor will probably use the correct "Value" so you should not need to
be concerned about that. I don't know if it matters whether the exact values I
show here must be used. Also it is probably not necessary to use all 6, probably
only ID_HELP_CONTENTS, ID_HELP_INDEX and ID_HELP_SEARCH are necessary.
ID |
Value |
Caption |
ID_HELP_INDEX |
57666 |
Display the Index of the Help file\nDisplay Index |
ID_HELP_FINDER |
57667 |
List Help topics\nHelp Topics |
ID_HELP_USING |
57668 |
Display instructions about how to use help\nHelp |
ID_HELP |
57670 |
Shows the help file |
ID_HELP_SEARCH |
57671 |
Display the Search tab of the Help file\nDisplay Search |
ID_HELP_CONTENTS |
57672 |
Display the Table of Contents of the Help file\nDisplay Contents |
Next add the following to a menu: ID_HELP_CONTENTS, ID_HELP_INDEX and ID_HELP_SEARCH.
It is necessary to add them to a menu first since otherwise they will not be
available in the ClassWizard to add handlers for them.
Modifying the Application
In your application's InitInstance add the following so that the help file
path and filename are set automatically. This assumes that your chm file is the
same filename as your exe file except with a chm extension instead of the exe
extension. It should also be in the same directory. That is the convention MFC
uses and the following will just change the extension from hlp to chm. Next this
code verifies that the chm file exists.
CString strHelpFile = m_pszHelpFilePath;
strHelpFile.MakeLower();
if (strHelpFile.Right(4) == ".hlp") {
strHelpFile = strHelpFile.Left(strHelpFile.GetLength()-4) + ".chm";
free((void*)m_pszHelpFilePath);
m_pszHelpFilePath = _tcsdup(strHelpFile);
}
CFileStatus FileStatus;
if (!CFile::GetStatus(m_pszHelpFilePath, FileStatus)) {
CString Message("Help file not found:\r\n");
AfxMessageBox(Message+m_pszHelpFilePath);
return FALSE; // Optional; this can be removed
}
Modifying CMainFrame
Use ClassWizard to add handlers for ID_HELP_CONTENTS, ID_HELP_INDEX and ID_HELP_SEARCH
then modify them as follows. I don't know where I got the following code for
OnHelpSearch from and I am not sure what it does. I should get answers to both
those questions.
void CMainFrame::OnHelpContents() {
HWND hWnd = HtmlHelp(0, AfxGetApp()->m_pszHelpFilePath, HH_DISPLAY_TOC, NULL);
}
void CMainFrame::OnHelpIndex() {
HWND hWnd = HtmlHelp(0, AfxGetApp()->m_pszHelpFilePath, HH_DISPLAY_INDEX, NULL);
}
void CMainFrame::OnHelpSearch() {
HH_FTS_QUERY q;
memset(&q, 0, sizeof(HH_FTS_QUERY));
q.cbStruct = sizeof(HH_FTS_QUERY);
q.fUniCodeStrings = FALSE;
q.pszSearchQuery = "";
q.iProximity = HH_FTS_DEFAULT_PROXIMITY;
q.fStemmedSearch = FALSE;
q.fTitleOnly = FALSE;
q.fExecute = TRUE;
q.pszWindow = NULL;
HWND hWnd = HtmlHelp(0, AfxGetApp()->m_pszHelpFilePath, HH_DISPLAY_SEARCH, (DWORD)&q);
}
Then use ClassWizard again to override WinHelp, which is a virtual function,
and then modify it as follows.
void CMainFrame::WinHelp(DWORD dwData, UINT nCmd) {
HWND hWnd = HtmlHelp(m_hWnd, AfxGetApp()->m_pszHelpFilePath, nCmd, dwData);
}
Custom Build Step
It is very convenient to have a custom build step for your chm file so that
if you change it then it gets copied from wherever it is put by the HTMLHelp
compiler to your project's output directory (Debug or Release or whatever)
automatically. By using a custom build step, this copy is done whenever you do a
build of your VC project but only if the chm file has been changed. To create a custom build step for the help file, first add the file to the
project. Then create the custom build step by using the "Custom Build Step" of
the project settings. Select the chm file in the tree on the left then enter the following:
- Description:
- Copying $(InputPath)
- Commands:
- copy $(InputPath) $(OutDir)\$(InputName).chm
- Outputs:
- $(OutDir)\$(InputName).chm
References
Microsoft Knowledge Base Articles
140676 - PRB: ClassWizard Uses WM_HELPINFO
Instead of WM_HELP simply says that the ClassWizard uses WM_HELPINFO for the
WM_HELP message.