Undocumented WinHelp Macros
This article first appeared in Windows/DOS Developer's Journal, January 1994
Download the code samples for this article (undoc1.zip, 2KB)
Considering that most large systems these days have one or more undocumented features, I wasn't too terribly surprised when my exploration of Windows Help turned up a number of undocumented macros. As you might expect, without adequate information it's difficult to say for sure what some of these undocumented macros do, but the operation of others was fairly easy to determine. In all, I discovered nine undocumented macros-all but two of which I was able to find a use for-and a few undocumented identifiers. Let's take a look at what they all do.
Enabling and Disabling Menu Items
Three undocumenteed macros-ExtAbleItem, ExtInsertItem, and ExtInsertMenu-give you more control over the appearance of the menus and menu items that you create. ExtAbleItem combines the functions of the DisableItem and EnableItem macros to provide a more convenient means for applications programs to enable and disable menu items. ExtInsertItem and ExtInsertMenu provide enhanced item and menu creation options.
Like DisableItem and EnableItem, the first parameter that you pass to ExtAbleItem is the item-id of the menu item that you want to modify. ExtAbleItem requires a second parameter, which specifies whether you want the menu item enabled or disabled. For example, if you create a menu item that has an item-id of `itm_clock', either of the following will disable it:
To enable the item, you could write:
The second parameter to ExtAbleItem can be any unsigned integer. If it's even, the menu item is enabled, and if it's odd, the menu item is disabled.
This macro isn't especially useful to help authors, but programmers will probably find it easier to use ExtAbleItem in WinHelp() API calls than to use DisableItem and EnableItem.
Creating Disabled Menu Items
Although both AppendItem and InsertItem allow you to add items to the WinHelp menus, they don't allow you to create an item that is initially disabled. For example, if you wanted to create an initially-disabled (i.e. grayed) Clock item on the Help menu, you would have to write two macros, like this:
InsertItem(`mnu_help', `itm_clock', `&Clock', `ExecProgram(`clock.exe', 0)', 4)
The undocumented ExtInsertItem macro allows you to do this with a single macro. The first four parameters to ExtInsertItem are identical to the first four parameters to InsertItem. The last parameter, though, is an unsigned integer that specifies whether you want the item to initially enabled or disabled-0 for enabled, 1 for disabled. Unlike ExtAbleItem, which will accept any number to determine the enabled state, passing values larger than 4 to ExtInsertItem causes some unusual (and sometimes unpleasant) effects.
Using ExtInsertItem, the example above can be written with a single macro, like this:
One option that I found suspiciously absent from WinHelp is the ability to create sub-menus-menus that are activated by selecting an item from a top-level menu. As a result, I was very pleasantly surprised when I discoverd the ExtInsertMenu macro, which allows you to create sub-menus and menus that are initially disabled.
ExtInsertMenu takes six parameters. The second through fourth are identical to the parameters accepted by InsertMenu, and the last parameter is the initial enabled state-0 for enabled and 1 for disabled. The first parameter, though, is the most interesting. It specifies the parent menu to which the newly-created menu should be added. So, if you wanted to create a Tools menu that consists of two sub-menus: Accessories and Games. This can't be done with the documented WinHelp macros, but ExtInsertMenu makes it easy, as you can see from the [CONFIG] section of UNDOC.HPJ (Listing 1).
Do note that, whereas it's possible to create an initially-disabled menu using this macro, there doesn't seem to be a method of enabling the menu later. There is no DisableMenu or EnableMenu macro.
Undocumented Menu and Item Ids
According to the SDK documentation, you can't delete or disable any of the standard WinHelp menu items, and WinHelp enforces this by simply not publishing the item ids for these items. However, in searching through WINHELP.EXE, I found two item ids-mnu_helpon and mnu_helpontop-that aren't documented in the SDK. mnu_helpon, it turns out, is documented in the Microsoft Developer's Network CD-ROM.
These two names are the item ids for the Help menu's How to Use Help and Always on Top items, respectively. With these ids, it's possible to disable, enable, or delete these two items from the Help menu.
Another interesting find was the mnu_main identifier, which is the menu id for the menu bar. Using this identifier, it's possible to add items (not menus) to the menu bar. For example, to append the Clock item to the menu bar, you would write:
You can also use mnu_main as the first parameter to ExtInsertMenu to add a top-level menu to the menu bar.
By far the most interesting discovery was the mnu_floating identifier, which defines a floating menu that is accessed with the FloatingMenu macro.
Using the Floating Menu
In addition to the four standard menus, WinHelp defines a "floating" that can pop up over help text within the help window. This menu is useful if you want local options to appear in response to the user's selecting a hot spot or button.
Like the standard menus, the floating menu is already defined. But it doesn't have any items in it. To use this menu, you need to add items to it using one of the item-creation macros, and then you have to activate it by executing the FloatingMenu macro. The [CONFIG] section of Listing 1 contains macros that add items to this menu, and UNDOC.RTF (Listing 2) makes use of the macro.
The undocumented ResetMenu macro, which takes no parameters, restores the WinHelp menu bar to its default state by removing all inserted menus and menu items, including any items that you may have added to the floating menu. In addition the How to Use Help and Always on Top menu items are restored to the Help menu if they were removed, and all item bindings are restored to their default states.. You might use this macro to clear the menu after exiting a topic that modifies the standard menus.
JumpHash and PopupHash
The undocumented JumpHash and PopupHash macros operate similar to the JumpContext, JumpId, PopupContext, and PopupId macros. All six of these macros provide links to topics in other help files. JumpId and PopupId each accept a help file name and a context string, and then display the topic that matches that context string in the specified help file. JumpContext and PopupContext also display topics in other help files, but they accept a context number rather than a context string.
JumpHash and PopupHash, rather than accepting a context string or a context number, accept a hash code, which is formed from a topic's context string. Since topic context strings are not stored in the help file-only the hash codes formed from the context strings are stored-these two macros are likely used internally by WinHelp when processing the JumpId and PopupId macros. JumpHash and PopupHash are useful when exploring help files for which you don't have the source. Listing 3, HASH.C, courtesy of Ron Burk, contains a function that creates a hash code from a passed context string.
Other Undocumented Macros
Two other undocumented macros, Generate and Command, look interesting, but as of this writing I have been unable to come up with any idea of what they do. I do know that passing certain values to Generate can crash WinHelp, but I haven't been able to get the macro to do anything useful.
I'm fairly certain that I've discovered all of the undocumented macros and menu ids that exist in the current (3.1) version of WINHELP.EXE. I'm sure that there's some undocumented functionality to some of the standard macros, and the Command and Generate macros remain a mystery. If you or somebody you know has any information about undocumented macros or functionality, please leave a message in my Compuserve mailbox, or contact me through the magazine.