View Issue Details

IDProjectCategoryView StatusLast Update
0028321FPCPackagespublic2021-04-09 23:29
Reporterwp Assigned ToMarco van de Voort  
Status closedResolutionfixed 
Product Version3.1.1 
Summary0028321: chmfilewriter does not write TOC
DescriptionUnit chmfilewriter (in directory chm/src) can be used to create chm help files. These files, however, different from other chm files: there is no table-of-contents (TOC).

chmfilewriter does contain code to handle the TOC. But due to incorrect handling of relative file names the TOC actually is not written to the file.

The attached patch fixes this issue.
Steps To Reproduce- Compile and run the project "chmmaker" in "lazarus/tools/chmmmaker"
- Load the sample file "example.hfp" (in folder "example"). This chm project contains a TOC file which should be included with the chm file.
- Click "Compile and view"
- This creates the "example.chm" help file and loads it into Lazarus' CHM viewer LHelp, or in Windows, double-click on example.chm to open it in the system's help viewer.
- The page "Contents" is missing.

- Apply the patch and repeat
- Page "Contents" now is present.
Fixed in Revision49071,49125
Attached Files


related to 0028332 closedwp Lazarus Lhelp shows some chars incorrectly 



2015-06-17 22:33


chmfilewriter.pas.patch (2,439 bytes)   
Index: chmfilewriter.pas
--- chmfilewriter.pas	(revision 31070)
+++ chmfilewriter.pas	(working copy)
@@ -1088,7 +1088,6 @@
   // give it the list of other files
   // now some settings in the chm
@@ -1142,23 +1141,24 @@
    if FTableOfContentsFileName<>'' then
-     if fileexists(FTableOfContentsFileName) then
+     if fileexists(FBasePath+FTableOfContentsFileName) then
-           FTocStream.loadfromfile(FTableOfContentsFilename);
+           FTocStream.loadfromfile(FBasePath+FTableOfContentsFilename);
            //writeln(ftableofcontentsfilename, ' ' ,ftocstream.size);
-           ftoc.savetofile('bla.something');
+           //ftoc.savetofile('bla.something');
           on e:exception do
                error(chmerror,'Error loading TOC file '+FTableOfContentsFileName);
-               freeandnil(ftoc); freeandnil(FTocStream);
+               freeandnil(ftoc);
+               freeandnil(FTocStream);
@@ -1167,21 +1167,23 @@
    if FIndexFileName<>'' then
-     if fileexists(FIndexFileName) then
+     if fileexists(FBasePath+FIndexFileName) then
-          FIndexStream.LoadFromFile(FIndexFileName);
+          FIndexStream.LoadFromFile(FBasePath+FIndexFileName);
-          FIndex.loadfromfile(FIndexFileName);
+          FIndex.LoadFromStream(FIndexStream);
+          //FIndex.SaveToFile('bla-index.something');
           on e: Exception do
               error(chmerror,'Error loading index file '+FIndexFileName);
-              freeandnil(findex); freeandnil(findexstream);
+              freeandnil(findex);
+              freeandnil(findexstream);
chmfilewriter.pas.patch (2,439 bytes)   

Marco van de Voort

2015-06-22 15:03

manager   ~0084654

Afaik toc and index file don't need to be in the project directory. If you inspect the code that you patched then you'll see only the stream is loaded.

So probably now it is possible to pass a toc file outside the tree, have it converted to binary TOC and not store the file in the archive textually.

IIRC toc and index file need to be actively included in the project to be in the archive, and local files already are added automatically.

Sure, something could be wrong with the way it is now (the division in labour between chmwrite and filewrite to be exact), but I don't think that patch is the solution, since it forces a condition that is common but not always true.


2015-06-22 23:16

reporter   ~0084671

Last edited: 2015-06-25 12:35

View 3 revisions

I modified the patch to be more general.

At first, the new version makes sure that the TOC and index filenames are relative to the chm project by changing to its folder.

Secondly, the path is no longer stripped from the TOC and index filenames; otherwise they would be required to be in the subdirectory of the project folder only.


The other patch added (chmmaker-uni1.pas.patch) makes sure that the created chm file is found by the lhelp viewer. Sorry - this one does not exactly fit to the topic of the bug report, but I saw this issue during testing. Feel free to apply it or not.


2015-06-22 23:17


chmfilewriter.pas.v2.patch (774 bytes)   
Index: chmfilewriter.pas
--- chmfilewriter.pas	(revision 30990)
+++ chmfilewriter.pas	(working copy)
@@ -1098,8 +1098,10 @@
   Writer.FullTextSearch := MakeSearchable;
   Writer.HasBinaryTOC := MakeBinaryTOC;
   Writer.HasBinaryIndex := MakeBinaryIndex;
-  Writer.IndexName := ExtractFileName(IndexFileName);
-  Writer.TocName   := ExtractFileName(TableOfContentsFileName);
+  Writer.IndexName := IndexFileName;
+  Writer.TocName   := TableOfContentsFileName;
+//  Writer.IndexName := ExtractFileName(IndexFileName);
+//  Writer.TocName   := ExtractFileName(TableOfContentsFileName);
   Writer.ReadmeMessage := ReadmeMessage;
   Writer.DefaultWindow := FDefaultWindow;
   for i:=0 to files.count-1 do
chmfilewriter.pas.v2.patch (774 bytes)   


2015-06-22 23:18


chmmaker-unit1.pas.patch (833 bytes)   
Index: unit1.pas
--- unit1.pas	(revision 49412)
+++ unit1.pas	(working copy)
@@ -231,6 +231,7 @@
   OutFile := TFileStream.Create(Project.OutputFileName, fmCreate or fmOpenWrite);
@@ -247,6 +248,7 @@
   LHelpConn: TLHelpConnection;
   Proc: TProcess;
   ext: String;
+  chmName: String;
   if ChmFileNameEdit.FileName = '' then
@@ -286,7 +288,8 @@
   LHelpConn := TLHelpConnection.Create;
     LHelpConn.StartHelpServer('chmmaker', LHelpName);
-    LHelpConn.OpenFile(ChmFileNameEdit.FileName);
+    chmName := Project.ProjectDir + CreateRelativeProjectFile(ChmFileNameEdit.FileName);
+    LHelpConn.OpenFile(chmName);
chmmaker-unit1.pas.patch (833 bytes)   

Marco van de Voort

2017-07-14 11:17

manager   ~0101708

I only see the secondly part, not the part that you call "at first".


2017-07-14 19:14


chmwriter.pas-v3.patch (3,923 bytes)   
Index: packages/chm/src/chmcmd.lpi
--- packages/chm/src/chmcmd.lpi	(revision 36729)
+++ packages/chm/src/chmcmd.lpi	(working copy)
@@ -1,7 +1,7 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
-    <Version Value="9"/>
+    <Version Value="10"/>
         <LRSInOutputDirectory Value="False"/>
@@ -12,7 +12,6 @@
       <Language Value=""/>
       <CharSet Value=""/>
-      <StringTable ProductVersion=""/>
     <BuildModes Count="1">
       <Item1 Name="default" Default="True"/>
@@ -33,15 +32,11 @@
         <Filename Value="chmcmd.lpr"/>
         <IsPartOfProject Value="True"/>
-        <UnitName Value="chmcmd"/>
     <Version Value="11"/>
-    <SearchPaths>
-      <OtherUnitFiles Value="/home/andrew/programming/projects/chmmaker/;/home/andrew/programming/lazarus/components/chmhelp/packages/chm/;/home/andrew/programming/projects/lzxcompress/"/>
-    </SearchPaths>
         <UseAnsiStrings Value="False"/>
@@ -55,14 +50,9 @@
-        <UseHeaptrc Value="True"/>
-        <UseValgrind Value="True"/>
-        <GenGProfCode Value="True"/>
+        <UseExternalDbgSyms Value="True"/>
-    <Other>
-      <CompilerPath Value="$(CompPath)"/>
-    </Other>
     <Exceptions Count="2">
Index: packages/chm/src/chmcmd.lpr
--- packages/chm/src/chmcmd.lpr	(revision 36729)
+++ packages/chm/src/chmcmd.lpr	(working copy)
@@ -122,8 +122,10 @@
   Project: TChmProject;
   xmlname: string;
   ishhp  : boolean;
+  currdir: String;
+  currdir := GetCurrentDir;
   Project := TChmProject.Create;
   Project.ReadMeMessage:='Compiled by CHMCmd '+CHMCMDVersion;
@@ -155,6 +157,8 @@
+  ChDir(Project.ProjectDir);
   OutStream := TFileStream.Create(Project.OutputFileName, fmCreate);
   if Project.ScanHtmlContents then
@@ -167,6 +171,7 @@
+  ChDir(currDir);
Index: packages/chm/src/chmfilewriter.pas
--- packages/chm/src/chmfilewriter.pas	(revision 36729)
+++ packages/chm/src/chmfilewriter.pas	(working copy)
@@ -562,7 +562,8 @@
  { Defaults other than global }
-   MakeBinaryIndex:=True;
+  MakeBinaryIndex:=True;
+  FFileName := AFileName;
   secs := TStringList.create;
@@ -1072,7 +1073,10 @@
   IndexStream: TFileStream;
   nd         : TChmContextNode;
   I          : Integer;
+  currDir    : String;
+  currDir := GetCurrentDir;
+  ChDir(FBasePath);
@@ -1103,8 +1107,8 @@
   Writer.FullTextSearch := MakeSearchable;
   Writer.HasBinaryTOC := MakeBinaryTOC;
   Writer.HasBinaryIndex := MakeBinaryIndex;
-  Writer.IndexName := ExtractFileName(IndexFileName);
-  Writer.TocName   := ExtractFileName(TableOfContentsFileName);
+  Writer.IndexName := IndexFileName; //ExtractFileName(IndexFileName);
+  Writer.TocName   := TableOfContentsFileName; //ExtractFileName(TableOfContentsFileName);
   Writer.ReadmeMessage := ReadmeMessage;
   Writer.DefaultWindow := FDefaultWindow;
   for i:=0 to files.count-1 do
@@ -1131,6 +1135,8 @@
   if Assigned(TOCStream) then TOCStream.Free;
   if Assigned(IndexStream) then IndexStream.Free;
+  ChDir(currDir);
 procedure TChmProject.ShowUndefinedAnchors;
chmwriter.pas-v3.patch (3,923 bytes)   


2017-07-14 19:22

reporter   ~0101714

Last edited: 2017-07-19 13:10

View 3 revisions

No idea what has happened here...

I looked into this issue again, and I think the "At first" part means that WriteCHM should change directory to FBasePath in order to make all relative paths relative to the location of the project file. This way the TOC and index are written correctly to the chm file, and the chm file shows everything.

I am attaching a new patch (-v3) which combines the "at first" and "secondly" parts.

This new patch also fixes chmcmd which worked only when it was called from the project directory (,37523.msg252589.html#msg252589). Now it can be called from any location if the path to the hhp project file is specified. This corresponds to the behavior of HTML Help Workshop. It is a bit annoying, though, that the output file is considered to be relative to the current directory, not to the location of the project file. Therefore I added another "chdir" to chmcmd before the output file stream is created.

And finally I removed the compiler options -gv and -pg (which prevent compilation under Windows) and some historic path assignment of Andrew.


Please do not apply the chmmaker patch, I think it is not necessary any more.

Marco van de Voort

2017-12-31 00:11

manager   ~0105171

I meant that changing working directories is not a good thing, and certainly not in a library.

I meant it is better to introduce some basedir variable, and then make everything relative.

Marco van de Voort

2019-05-31 14:55

manager   ~0116477

The serbod repository has something like this, but as usual, it is combined with reformatting, so hard to find out what all needs changing.

Marco van de Voort

2021-03-28 15:01

manager   ~0129943

I commited the serbod fix to trunk. It is not ideal (no difference between project location, and chm root yet), but it is better than nothing.


2021-03-28 16:01

reporter   ~0129949


I am testing with the help files for fpspreadsheet which I created by pasdoc yesterday - I am attaching the entire help project. Using MS HTML Workshop a chm file can be created easily without any issues, and this tells me that the required files were correctly created by pasdoc.

Using chmcmd to create the chm file, I noticed that it is still required to call chmcmd from the directory with the hhp project file - but you already noted that there is no change yet.

Starting with the old fpc-trunk before your commit, the chm file compiles, however a great number of warnings (ok...) and errors is displayed. The error message always has this structure:
  "fpSpreadsheet.TsWorksheet.html#@Properties undefined; first use Site Map for Properties"
 where the word before "undefined" refers to all kinds of help topics.

The warnings have this structure:
  "Warning: Duplicate anchor definitions with ID IfThen found while scanning fpsUtils.html";
here the word after "ID" and the last word vary from messge to message.

Opening the chm file in the MS help viewer works correctly, no errors.

Then I updated my fpc and recompiled chmcmd and repeated the same with the new version:

- The long list of error messages is gone.
- Still the warnings, same structure
- BUT: when I open the chm file it displays "Cannot find "mk:@MSITStore:D:\<my path>\fpspreadsheet:chm::/fpspreadsheet.hhc"", and looking carefully at the output of chmcmd I find that there is still an error message at second sight: "Error: Can't find TOC filefpspreadsheet.hhc".

As I noted, I am displaying the chm file with the MS viewer. I also tried LHelp, but was not very successfully with it: the generated file loads without issues but the tree at the left is empty showing only to the top level node (even for the file created by Help workshop) which makes the generated chm useless for LHelp.

Marco van de Voort

2021-03-28 17:12

manager   ~0129955

Ok, it indeed didn't work. I also tried executing outside the directory (with path + hhp as argument), and that gives more errors.

But now I have a test setup. Will work some more, but that won't be today.

Marco van de Voort

2021-04-05 21:30

manager   ~0130116

I did some fixes, commited as r49125, please test.

I get some warnings about hhk having some anchors like file.html#@classes, while a @classes anchor doesn't exist in file.html. Pasdoc error?

Marco van de Voort

2021-04-06 15:28

manager   ~0130137

Last edited: 2021-04-06 15:28

View 2 revisions

Hmm, after a bit more testing, this works quite fine. Resolve, please reopen on problems


2021-04-09 23:29

reporter   ~0130212

Excellent, thank you, Marco.

Issue History

Date Modified Username Field Change
2015-06-17 22:33 wp New Issue
2015-06-17 22:33 wp File Added: chmfilewriter.pas.patch
2015-06-21 09:51 Juha Manninen Relationship added related to 0028332
2015-06-22 15:03 Marco van de Voort Note Added: 0084654
2015-06-22 23:16 wp Note Added: 0084671
2015-06-22 23:17 wp File Added: chmfilewriter.pas.v2.patch
2015-06-22 23:18 wp File Added: chmmaker-unit1.pas.patch
2015-06-22 23:27 wp Note Edited: 0084671 View Revisions
2015-06-25 12:35 wp Note Edited: 0084671 View Revisions
2017-07-14 11:17 Marco van de Voort Note Added: 0101708
2017-07-14 19:14 wp File Added: chmwriter.pas-v3.patch
2017-07-14 19:22 wp Note Added: 0101714
2017-07-14 19:27 wp Note Edited: 0101714 View Revisions
2017-07-19 13:10 wp Note Edited: 0101714 View Revisions
2017-12-31 00:11 Marco van de Voort Note Added: 0105171
2018-09-30 18:06 Marco van de Voort Assigned To => Marco van de Voort
2018-09-30 18:06 Marco van de Voort Status new => assigned
2018-12-22 18:06 Marco van de Voort Tag Attached: chm
2019-04-25 18:31 Marco van de Voort Relationship added related to 0035445
2019-04-27 14:56 Marco van de Voort Relationship deleted related to 0035445
2019-05-31 14:55 Marco van de Voort Note Added: 0116477
2021-03-28 15:01 Marco van de Voort Status assigned => feedback
2021-03-28 15:01 Marco van de Voort FPCTarget => -
2021-03-28 15:01 Marco van de Voort Note Added: 0129943
2021-03-28 15:28 Marco van de Voort Fixed in Revision => 49071
2021-03-28 16:01 wp Note Added: 0129949
2021-03-28 16:01 wp File Added:
2021-03-28 16:01 wp Status feedback => assigned
2021-03-28 17:12 Marco van de Voort Note Added: 0129955
2021-04-05 21:30 Marco van de Voort Note Added: 0130116
2021-04-06 15:28 Marco van de Voort Status assigned => resolved
2021-04-06 15:28 Marco van de Voort Resolution open => fixed
2021-04-06 15:28 Marco van de Voort Fixed in Revision 49071 => 49071,49125
2021-04-06 15:28 Marco van de Voort Note Added: 0130137
2021-04-06 15:28 Marco van de Voort Note Edited: 0130137 View Revisions
2021-04-09 23:29 wp Status resolved => closed
2021-04-09 23:29 wp Note Added: 0130212