Last update: 24-Aug-2005 (Added Solution 3)
Author: MVP Rob Chandler
Continues from how_tomerge.htm#ContextHelpIDs.
Defining context mappings (see how_to_context.htm) works fine in a standalone CHM, but in a merged help system we can run into problems when trying to open a Slave topic though the master CHM.
We could make all the slave CHMs use the Master TOC and merge (shown in Step 3 of the Demo Project). That way all CHMs look the same, and we can open Slave1.CHM directly to access Slave1 topics or context Ids. The problem here is that each CHM has its own favourites and window position info. Also we really just want the application to have to deal with the master CHM.
Note: Since the latest Windows critical update (hhctrl.ocx 5.2.3735.x) some older techniques for making context calls to slave topics have broken. See how_tomerge.htm#ContextHelpIDs to see the older solutions. Some of these techniques still work fine if an index is not require.
Here are some new idea for 2004. Hopefully there is a solution that will help you.
By using a redirection file in your Master CHM your application can make context calls to any topic (in master or slave) while accessing only the Master CHM. The application requires no modification.
#define IDH_MASTER_TEST1 1
#define IDH_MASTER_TEST2 2
#define IDH_SLAVE1_INDEX 110
#define IDH_SLAVE1_ANOTHER 111
#define IDH_SLAVE2_INDEX 120
#define IDH_SLAVE2_ANOTHER 121
As you can see this Master .HHP file still contains the normal HTML Help mapping info. However notice that the URLs for the slave topics (in the ALIAS section) point to a redirection file stored in the master CHM. Each URL passes a unique string ID to the redirection file via a bookmark.
IDH_MASTER_TEST1 & IDH_MASTER_TEST2 items simply demonstrate that no special attention is needed for those topics (eg. index.htm & linkdemo.htm) residing within the master CHM file.
<html> <head><title>Redirect Page</title> <script> var Code = window.location.hash.substring(1); var URL= ""; if (Code == "IDH_SLAVE1_INDEX") URL="its:slave1.chm::/s1_index.htm"; else if (Code == "IDH_SLAVE1_ANOTHER") URL="its:slave1.chm::/s1_another.htm"; else if (Code == "IDH_SLAVE2_INDEX") URL="its:slave2.chm::/s2_index.htm"; else if (Code == "IDH_SLAVE2_ANOTHER") URL="its:slave2.chm::/s2_another.htm"; if (URL != "") window.location.replace(URL) else if (Code != "") alert("Redirection code not defined: "+ Code); </script> </head> <body> </body> </html>
Notice the above redirection file contains the real mapping info.
window.location.hash.substring(1); returns the bookmark (anchor) of the URL and stores it in variable CODE. We then set the URL variable according the value in CODE.
window.location.replace(); simply takes you to the URL while replacing the current page. The Replace part removes the redirection file from the browsers history list.
alert("Redirection code not defined: "+ Code); This just pops up a debug message if an incoming bookmark is unknown.
Tip: Make sure all window types use the
$Global_ prefix to force all CHM help into the same window.
I find it best to avoid the HH_HELP_CONTEXT Context call completely. Instead of defining ContextID/URL mappings on the help side, store them on the application side and use the more reliable HH_DISPLAY_TOPIC call.
We keep all our mapping info in a separate INI file, that way bug fixes do not require a rebuild of either help or executable. Also the INI file can be maintained by either the tech-writers or programmers.
When a help event occurs your application code simply takes the context ID of the current dialog or page, and looks up the corresponding help URL in the INI file. It then opens that URL using the HH_DISPLAY_TOPIC command.
Note that we open slave topics via a redirection file in the Master CHM. The target slave URL is passed as a bookmark (anchor). Thus our application only has to open the Master CHM, never a Slave.
Very simple. When Redirect.xhtm is opens it grabs the URL from the bookmark and immediately goes to that location. Thus our application can make the following call and the master will open but the slave 1 topic will be displayed.
The redirect file is never seen. The .replace statement stops the Redirect.xhtm URL from going into the browser history. The .x in the Redirect.xhtm file name stops the file from being parsed for full-text search info by the HH compiler (hh compiler traditionally only parses files with a trailing .h* ).
Unlike the redirection file in Solution #1 above we never have to edit this file. Also slave topics containing bookmarks are no problem. The following URL works fine:
Tip: Make sure all window types use the $Global_ prefix to force all CHM help into the same window.
Additional - You may not need to use the "its:" protocol prefix. Not needed in the modern IE browser (in fact I've been told the IE7 Beta2 does not like it at all).
This is a similar to Solution to #2 however instead of using a redirection file we effectively make every slave CHM into a Master CHM. Then it doesn't matter which CHM you open first since they all open and perform the same.
Let's say we have a master.chm (with a master.hhc TOC) and 2 slave chms
called SiteA.chm and SiteB.chm.
(Sorry, for this solution I've changed my naming convention from slave1 to SiteA because the downloadable example uses SiteA).
Notice this time our application mapping file does not need a redirection file. Things are simpler in that respect. The application just grabs the URL from the mapping file and open the help using the HH_DISPLAY_TOPIC API call.
eg. HtmlHelp(0, "c:\SiteB.chm::/Intro.htm>TP", HH_DISPLAY_TOPIC, 0); will show the full merged help.
The only downside to this approach is that HH Favorites information is stored with the CHM name. So if you open Master.chm, setup several favourites links, they will be missing if you then close master and open a slave chm.
How do I make all CHMs look the same (effectively all masters)?
Its pretty easy.
For more detail and a downloadable demo please see
Here's a slight twist you can use (this is used by the code download).
The SiteB.hhp project file contains the following window definition settings
Notice that TP is the default window definition. If you open SiteB.chm
normally it will show only its own TOC.
However if you open SiteB.chm using the TP2 window definition then you will see the merged help TOC.
Following this logic you could then make your mapping file as follows.
Notice here that whenever a slave CHM is opened, the >TP2 means it is opened using the TP2 window definition and thus you will always see the master (merged) TOC. Note: The URL>WinDefName syntax is standard HTML Help syntax (see HH Workshop online help for more info).
As always it is good practice to prefix your window def names with
$Global_ (so everywhere TP or TP2 is defined or used rename to $Global_TP
and $Global_TP2). See section
on $Global_ for more info. This old example code does not do this but
probably should. If you open master, then slave 1, then slave 2 and end up with
3 separate windows instead of 1, then you know you should have used the $Global_