The Application Framework and WinHelp
You've seen WinHelp running as a standalone program. The application framework and WinHelp cooperate to give you context-sensitive help. Here are some of the main elements:
You select the Context-Sensitive Help option when you run the MFC Application Wizard. Select WinHelp (rather than HTML Text) as the help system.
The MFC Application Wizard generates a Help Topics command on your application's Help menu, and it creates one or more generic RTF files together with an HPJ file and a batch file that runs the Help Compiler.
The MFC Application Wizard inserts a keyboard accelerator for the F1 key, and it maps the F1 key and the Help Topics command to member functions in the main frame window object.
When your program runs, it calls WinHelp when the user presses F1 or chooses the Help Topics command, passing a context ID that determines which help topic is displayed.
You now need to understand how WinHelp is called from another application and how your application generates context IDs for WinHelp.
Calling WinHelp
The CWinApp member function WinHelp activates WinHelp from within your application. If you look up WinHelp in the online documentation, you'll see a long list of actions that the optional second parameter controls. We'll ignore the second parameter and pretend that WinHelp has only one unsigned long integer parameter, dwData. This parameter corresponds to a help topic.Suppose the SIMPLE help file is available and that your program contains the following statement:
AfxGetApp()->WinHelp(HID_TOPIC1);
When the statement is executed in response to the F1 key or some other event, the Help Topic 1 screen appears, as it would if the user had clicked on Topic 1 in the Help Table Of Contents screen."Wait a minute," you might say. "How does WinHelp know which help file to use?" The name of the help file matches the application name. If the executable program name is Simple.exe, the help file is named Simple.hlp .
Note | You can force WinHelp to use a different help file by setting the CWinApp data member m_pszHelpFilePath. |
And how does WinHelp match the program constant HID_TOPIC1 to the help file's context ID? The help project file must contain a MAP section that maps context IDs to numbers. If your application's resource.h file defines HID_TOPIC1 as 101, the Simple.hpj MAP section will look like this:
[MAP]
HID_TOPIC1 101
The program's #define constant name doesn't have to match the help context ID; only the numbers must match. Making the names correspond is good practice, however.
Using Search Strings
For a text-based application, you might need help based on a keyword rather than a numeric context ID. In this case, you can use the WinHelp HELP_KEY or HELP_PARTIALKEY option, as follows:
CString string("find this string");
AfxGetApp()->WinHelp((DWORD) (LPCSTR) string, HELP_KEY);
The double cast for string is necessary because the first WinHelp parameter is multi-purpose; its meaning depends on the value of the second parameter.
Calling WinHelp from the Application's Menu
The MFC Application Wizard generates a Help Topics command on the Help menu, and it maps that command to CWnd::OnHelpFinder in the main frame window, which calls WinHelp in this way:
AfxGetApp()->WinHelp(0L, HELP_FINDER);
With this call, WinHelp displays the Help Table Of Contents screen, and the user can navigate through the help file using jumps and searches.If you want the old-style table of contents, you can call WinHelp in this way instead:
AfxGetApp()->WinHelp(0L, HELP_INDEX);
And if you want a "help on help" item, you can make this call:
AfxGetApp()->WinHelp(0L, HELP_HELPONHELP);
HELP_HELPONHELP is a standard identifier that asks the help system to display help on how to use Windows Help. This works only if the Winhlp32.hlp file is available.
Help Context Aliases
The ALIAS section of the HPJ file allows you to equate one context ID with another. Suppose your HPJ file contains the following statements:
[ALIAS]
HID_TOPIC1 = HID_GETTING_STARTED
[MAP]
HID_TOPIC1 101
Your RTF files can use HID_TOPIC1 and HID_GETTING_STARTED interchangeably. Both will be mapped to the help context 101 as generated by your application.
Determining the Help Context
You now have enough information to add a simple context-sensitive help system to an MFC program. You define F1 (the standard MFC library Help key) as a keyboard accelerator, and then you write a command handler that maps the program's help context to a WinHelp parameter. You could invent your own method for mapping the program state to a context ID, but why not take advantage of the system that's already built into the application framework?The application framework determines the help context based on the ID of the active program element. These identified program elements include menu commands, frame windows, dialog boxes, message boxes, and control bars. For example, a menu command might be identified as ID_EDIT_CLEARALL. The main frame window usually has the IDR_MAINFRAME identifier. You might expect these identifiers to map directly to help context IDs. IDR_MAINFRAME, for example, will map to a help context ID of the same name. But what if a frame ID and a command ID have the same numeric value? Obviously, you need a way to prevent such overlaps.The application framework solves the overlap problem by defining a new set of help #define constants that are derived from program element IDs. These help constants are the sum of the element ID and a base value, as shown in the following table.
Program Element | Element ID Prefix | Help Context ID Prefix | Base (Hexadecimal) |
---|---|---|---|
Menu command or toolbar button | ID_, IDM_ | HID_, HIDM_ | 10000 |
Frame or dialog box | IDR_, IDD_ | HIDR_, HIDD | 20000 |
Error message box | IDP_ | HIDP_ | 30000 |
Nonclient area | H… | 40000 | |
Control bar | IDW_ | HIDW_ | 50000 |
Dispatch error messages | 60000 |
HID_EDIT_CLEARALL (0x1E121) corresponds to ID_EDIT_CLEARALL (0xE121), and HIDR_MAINFRAME (0x20080) corresponds to IDR_MAINFRAME (0x80).
F1 Help
Two separate context-sensitive help access methods are built into an MFC application and are available if you've selected the MFC Application Wizard's Context-Sensitive Help option. The first is standard F1 help. The user presses F1, the program makes its best guess about the help context, and then it calls WinHelp. In this mode, it is possible to determine the currently selected menu command or the currently selected window (frame, view, dialog box, or message box).
Shift+F1 Help
With Shift+F1 help, which is more powerful than the F1 mode, the program can identify the following help contexts:
A menu command selected with the mouse cursor
A toolbar button
A frame window
A view window
A specific graphics element within a view window
The status bar
Various nonclient elements such as the system menu control
Note | Shift+F1 help doesn't work with modal dialog boxes or message boxes. |
The user activates Shift+F1 help by pressing Shift+F1 or by clicking the Context Help toolbar button. In either case, the mouse cursor changes to include a question mark next to it. On the next mouse click, the help topic appears, with the position of the mouse cursor determining the context.
Message Box Help: The AfxMessageBox Function
The global function AfxMessageBox displays application framework error messages. This function is similar to the CWnd::MessageBox member function except that it has a help context ID as a parameter. The application framework maps this ID to a WinHelp context ID and then calls WinHelp when the user presses F1. If you can use the AfxMessageBox help context parameter, be sure to use prompt IDs that begin with IDP_. In your RTF file, use help context IDs that begin with HIDP_.There are two versions of AfxMessageBox. In the first version, the prompt string is specified by a character-array pointer parameter. In the second version, the prompt ID parameter specifies a string resource. If you use the second version, your executable program will be more efficient. Both AfxMessageBox versions take a style parameter that makes the message box display an exclamation point, a question mark, or another graphics symbol.
Generic Help
When context-sensitive help is enabled, the MFC Application Wizard assembles a series of default help topics that are associated with standard MFC library program elements. Here are some of the standard topics:
Menu and toolbar commands (File, Edit, and so forth)
Nonclient window elements (maximize box, title bar, and so forth)
Status bar
Error message boxes
These topics are contained in the files AfxCore.rtf and AfxPrint.rtf , which are copied, along with the associated bitmap files, to the application's \hlp subdirectory. Your job is to customize the generic help files.
Note | The MFC Application Wizard generates AfxPrint.rtf only if you specify the Printing And Print Preview option. |