Question

I am able to open a CHM file by passing a ShortInteger and casting it as a Word for the dwData parameter. I.E.

Unit Help;   //this is where the Id's are set with their description
 Interface
 Const

Address_File = 35;  //delphi identifies Address_File as a shortint
etc..


Call get help pass my ID

GetHelp(Address_File); //call get help pass my ID to open to the Address_File topic


GetHelp procedure

procedure GetHelp(HelpID : Word);
begin
  Application.HelpFile := ProgramPath + 'help.chm';
  HtmlHelpW(0, PWideChar(Application.HelpFile),HH_HELP_CONTEXT , HelpID);
end;


HtmlHelpW function

function HtmlHelpW(hwndCaller : HWND; pszFile: PWideChar; uCommand : Integer;
         dwData : DWORD) : HWND; stdcall; external 'hhctrl.ocx' name 'HtmlHelpW';

As I pass different ShortIntegers I am able to initialize the help file at different sections. However I can't figure out how the values are mapped. There are some sections in the chm file that I want to be able to map to but the short Integer or context ID associated with them is not documented in the program or is not mapped.

Was it helpful?

Solution

Free Pascal comes with a chmls.exe util that has a command that tries to recover the alias (context) data:

chmls, a CHM utility. (c) 2010 Free Pascal core.

Usage: chmls [switches] [command] [command specific parameters]

Switches :
 -h, --help     : this screen
 -p, --no-page  : do not page list output
 -n,--name-only : only show "name" column in list output

Where command is one of the following or if omitted, equal to LIST.
 list       <filename> [section number]
            Shows contents of the archive's directory
 extract    <chm filename> <filename to extract> [saveasname]
            Extracts file "filename to get" from archive "filename",
            and, if specified, saves it to [saveasname]
 extractall <chm filename> [directory]
            Extracts all files from archive "filename" to directory
            "directory"
 unblockchm <filespec1> [filespec2] ..
            Mass unblocks (XPsp2+) the relevant CHMs. Multiple files
            and wildcards allowed
 extractalias <chmfilename> [basefilename] [symbolprefix]
            Extracts context info from file "chmfilename"
            to a "basefilename".h and "basefilename".ali,
            using symbols "symbolprefix"contextnr
 extracttoc <chmfilename> [filename]
            Extracts the toc (mainly to check binary TOC)
 extractindex <chmfilename> [filename]
            Extracts the index (mainly to check binary index)

This might be a start, since at least you'll know which pages are exported using an ID, and maybe the URL names will give some information.

The util is in recent releases (make sure you get 2.6.0) and also available in Free Pascal source, which should be convertable to Delphi with relatively minor effort.

Basically the chmls tool was created out of various test codebases. The testprograms decompiled and printed contents of different CHM sections and were used while creating the helpfile compiler, chmcmd, which is also part of FPC.

OTHER TIPS

In Delphi, calling a help file is rather easy. In any VCL Forms application, you can set the HelpContext property of almost any control to a unique Context ID, which corresponds to a particular topic in the Help File. The Help File was compiled with these mappings, but when you decompile it, these mappings are no longer there. You must have access to the original help file project in order to know these ID's.

  1. Set HelpContext of controls to the corresponding Context ID in the Help File
  2. Set HelpType of controls to htContext to use the HelpContext ID
  3. Assign Application.HelpFile to the appropriate location of the CHM file
  4. When pressing F1 anywhere in your application, the help file will open based on the Help Context ID on the control, or its parent control

If you don't have the original project, and you don't want to re-create it, then you would have a long task of iterating through the Context ID's of your help file. Try to call the help file starting from 0 through 1,000 or possibly 50,000, depending on the size of it.

A practice I implement is a set of constants in a designated unit called HelpConstants.pas which is shared across our common application base. Each constant name uniquely and briefly describes the topic which it represents. Upon starting the application, I dynamically assign these Context ID's to their corresponding controls (usually forms) and VCL takes care of the rest.

I got the utility Marco suggested from https://github.com/alrieckert/freepascal_arm/blob/master/packages/chm/bin/i386-win32/chmls.exe (download by selecting View Raw). I was able to extract all the context tags from the .chm help file and add the one I was interested in to my C++ Builder program by calling Application->HelpJump(). HTH

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top