CHM-Hilfe

Hierbei geht es um Tipps und Tricks bei der Erstellung von CHM-Dateien, so 'ne Art geziptes HTML, funktioniert ab Windows 98 bis heute. Unter Linux sind einige geeignete Betrachter verfügbar. Leider (oder zum Glück?) ist die Browser-Fähigkeit begrenzt, in etwa auf Internet Explorer 7.

Die bekannten Einschränkungen:

CHM wird ab Windows 98 durchgängig unterstützt, ist also quasi gemeinsam mit USB verfügbar. Die alte RTF-basierte Hilfe ist ab Vista nicht mehr da und muss extra installiert werden.

Auf der Wunschliste steht ja zumeist:

Diese an-sich-Standard-Wunschliste lässt sich ziemlich schwer realisieren!!

Siehe auch http://chmspec.nongnu.org/

CHM-Authoring-Systeme kosten Geld und generieren Bloatware. Finger weg! Es geht auch ohne. Nützlich ist ein Editor mit Syntaxhervorhebung und mit Suchen/Ersetzen über mehrere Dateien. Etwa Notepad++. Kostet nur den Download. Seit der Einführung von CSS lässt sich die Gestaltung der Hilfeseiten bequem zentral steuern, und der HTML-Quelltext ist übersichtlich per Texteditor pflegbar.
Die Aufteilung der Hilfethemen sollte je nach angedachtem Verwendungszweck geschehen:

Ein Beispiel

*.hhp (Projektdatei):
[OPTIONS]
Binary TOC=Yes
Compiled file=gwbasic.chm
Default Window=main
Contents file=gwbasic.hhc
Index file=gwbasic.hhk
Default topic=default.html
Full-text search=Yes
Language=0x409 Englisch (USA)
Title=GW-BASIC User's Guide

[WINDOWS]
main=,"gwbasic.hhc","gwbasic.hhk","default.html","default.html",,,,,0x62520,,0x70384E,,,,,,,,0
popup=,,,,,,,,,0,,0x80,,,,,,,,

[FILES]
gwbasic.hhp
chapter1.html
Die Angaben bei main generieren alle erdenklichen (sinnvollen!) Extra-Knöpfe, nämlich Browse-Buttons, History zurück und vorwärts, Rückwärtssuche sowie Einstellen der Schriftgröße.

Das 0x80 bei popup generiert ein ToolWindow mit schmaler Titelzeile.

Wichtig zu wissen:

Ungelöst:
*.hhc (Inhaltsverzeichnis):
<HTML><HEAD><!-- Sitemap 1.0 --></HEAD><BODY><UL>
 <LI><OBJECT type="text/sitemap"><param name="Name" value="Chapters"><param name="Local" value="default.html"></OBJECT>
 <UL>
  <li><object type="text/sitemap"><param name="Name" value="1. Welcome"><param name="Local" value="Chapter1.html"></object>
  …
 </UL>
 <LI><OBJECT type="text/sitemap"><param name="Name" value="Appendicies"></OBJECT>
 <UL>
  <li><object type="text/sitemap"><param name="Name" value="A. Error Codes and Messages"><param name="Local" value="AppendixA.html"></object>
 </UL>
 <li><object type="text/sitemap"><param name="Name" value="Glossary"><param name="Local" value="Glossary.html#1"><param name="New" value="1"></object>
</UL></BODY></HTML>
Nicht jeder Knoten muss eine dahinter stehende URL haben. Leider gibt's da keinen Automatismus, mit dem Windows bspw. ein anderes Icon benutzt.

Alles in allem ziemlich geschwätzig; ein Texteditor mit regulären Ausdrücken und Wortersetzung ist hier zweckmäßig. Es kommt der Eindruck auf, das Microsoft die Programmierer quälen möchte. Eine simple ASCII-Datei mit verschiedenen Einrücktiefen und gewöhnlichen HTML-Links hätte es ja auch getan.

Hochkommas kann man weglassen, wo kein Leerzeichen eingeschlossen ist.

Wichtig zu wissen:


*.hhk (Index = Schlüsselwörter):
<HTML><HEAD><!-- Sitemap 1.0 --></HEAD><BODY><UL>
 <li><object type="text/sitemap"><param name="Name" value="ABS"><param name="Local" value="ABS.html"></object>
 <li><object type="text/sitemap"><param name="Name" value="ASC"><param name="Local" value="ASC.html"></object>
 … 
</UL></BODY></HTML>
Auch hier wieder viel Blabla. Reguläre Ausdrücke helfen, eine Wortliste entsprechend umzuformen.

Wichtig zu wissen:

Ungelöst:

Tipps (HTML)

Da die HTML-Dateien ziemlich lausig gepackt werden sollten unnötige Bestandteile möglichst vermieden werden, um das resultierende .CHM klein zu halten:

HTML zersägen

Macht sich gut, wenn man fürs Web die gleiche HTML-Datei in einem Stück haben möchte!
<object type="application/x-oleobject" classid="clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e">
 <param name="New HTML file" value="USB-Funktionen.htm">
 <param name="New HTML title" value="USB-Funktionen">
</object>
Die Angabe „HTML-Titel“ kann man sich sparen, wenn die HTML-Seite im Inhaltsverzeichnis erscheint; jener Titel wird immer dann verwendet, etwa bei der Auf­lösung von Mehr­fach­referenzen im Index.
Unbedingt einen <body>-Tag ganz am Anfang einbauen! Sonst stürzt der Hilfe-Compiler ab. Weiteres HTML-Gesülz wird nicht benötigt.
Zersägte Dateien klein halten: Möchte man das seitenweise HTML-Ausdrucken unterstützen, passt da auch ein
<br clear=all style='page-break-before:always'>
davor.

Die Links im Inhaltsverzeichnis und Index müssen sich auf die zersägten Dateinamen beziehen!

Womöglich kann man sogar Inhaltsverzeichnis und Index mit hineinstecken.

HTML5-Anzeige

Egal wie neu der installierte Internet Explorer ist, bei .CHM-Dateien kennt der Browser einfach keine HTML5-Features, etwa das <canvas>-Tag.

Hierzu muss man in der Registrierung einen Eintrag vornehmen. Für den Aufruf aus einer selbst geschriebenen Echse heraus muss dessen Name anstatt hh.exe stehen.

Windows Registry Editor Version 5.00

[HKEY_USERS\S-1-5-21-1559349094-3728892266-3505865260-1007\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION]
"hh.exe"=dword:00002710

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION]
"hh.exe"=dword:00002710
Dieses Manko hat MS Help 2 (*.HxS) zwar nicht, aber hier sind die übrigen Probleme noch größer.

Tricks

HHP-Datei selbst erstellen

Von einem vorhergehenden Projekt kann man einfach die HHP-Datei kopieren und die Strings entsprechend anpassen.

Die [Files]-Sektion kann leer bleiben, da alle abhängigen Dateien automatisch hineingepackt werden. Nur die HHP-Datei wird als einzige nicht hineingesteckt (siehe nächster Tipp), da diese in compilierter Form in der „#SYSTEM“-Datei vorliegt.

Quelle sparen

Da die Total-Commander-Packer-Erweiterung ChmDir den bequemen Zugriff auf den Inhalt einer .CHM-Datei erlaubt, ist es zweckmäßig, bei [Files] auch die *.hhp-Datei hineinzustecken. So hat man jederzeit die komplette Quelle verfügbar, ohne dafür ein extra Verzeichnis herumschleppen zu müssen.

Das beißt sich allerdings mit der Möglichkeit, HTML-Dateien zu zersägen.

Die gleiche Funktionalität bietet 7zip im Windows-Explorer. Leider sind die Datumsangaben der Dateien futsch. Die üblichen Auspack-Programme setzen diese auf das Datum der CHM-Datei.

Unverständlich erscheint es, dass der Hilfe-Compiler die Inhalts- und Indexdateien (HHC und HHK) mit hineinsteckt, obwohl diese, bei aktiviertem Binary TOC, bereits in versteckten Binärdateien hineincompiliert sind. Man muss diese ggf. nachträglich mit dem Total-Commander-Tool herauslöschen.

Clientseitige Syntaxhervorhebung

Ist nunmehr als Teil meiner universellen h.js realisiert. Zeilen 308 … 466, also gar nicht übermäßig viel.

Funktionierendes Beispiel.

CHM-Darstellung auf Webseiten

Manch einem trifft gewisses Unbehagen, CHM-Dateien zu erstellen, weil man für's Web alles noch einmal machen müsste. Kann man nicht CHM-Dateien im beliebigen Web-Browser darstellen?

Dies ist mittels viewchm.php und dem auf chmlib aufsetzenden unchm.c bei mir gelöst. Noch unfertig, keine Volltextsuche, und die Browse-Buttons funktionieren nicht. Hier ein (anderes) Beispiel. Die PHP-Datei benötigt derzeit Shell-Aufrufe und ist für hochsichere Server und kostenlose Webspaceanbieter nicht geeignet.

Da die typische CHM-Darstellung einer Frame-Aufteilung am besten nahekommt, ist es hier auch so implementiert. Das ist zweifelsohne Smartphone-inkompatibel. Eine gesonderte Smartphone-Unterstützung — erfordert eine völlig andere Präsentations-Struktur womöglich mit einem iframe für Inhalts- und Stichwortverzeichnis.

HTML-Seite im CHM?

Manchmal will oder muss man HTML-Seiten erstellen, die sich in CHM-Umgebung anders verhalten sollen als bspw. mit dem vorangegangenen viewchm.php. Ganz einfach: Die URL einer CHM-Datei enthält stets zwei Doppelpunkte hintereinander, was auf einem Webserver sicherlich nie vorkommt.

 var inside_chm = location.href.indexOf("::") >= 0;

Persistente Einstellungen

Für das Erstellen einer Dokumentation ist es sehr nützlich, irrelevante Informationen automatisch ausblenden zu lassen. Beispiele:

Die Vorgehensweise ist, in die betreffenden Seiten ein <iframe> mit einer immer gleichen Webseite einzubauen. Da Cookies nicht funktionieren, speichert dieses iframe seinen Zustand in parent.name! Dadurch ist der Zustand leider nicht persistent zwischen dem Schließen und erneutem Öffnen der CHM-Datei. Nur damit viewchm.php nicht mit dem wechselnden Namen des rechten Frame-Fensters durcheinanderkommt, besser mit Fallunterscheitung:

// Lesen:
 val = inside_chm ? parent.name : document.cookie;
// Schreiben:
 if (inside_chm) parent.name = val; else document.cookie = val;

Und hier ein praktisches Beispiel.

Echte Peristenz in CHM-Dateien

Das geht nicht ohne Verrenkungen. Entweder eine (nur eine) externe HTML-Datei, damit Cookies funktionieren. Die passende URL beschaffen. Oder irgendwas mit ActiveX und Dateizugriff (muss ich noch mal finden).

Persistente Einstellungen für jede Seite

Es ist natürlich mühselig, für jede einzelne Webseite das iframe einzubinden. Da jede Seite ohnehin einen Bezug zur global.css und global.js braucht, kann das Javascript dieses iframe dynamisch generieren.

Weiterhin ist es nützlich, für verschiedene Browser und verschiedene Größen von Eingabeelementen das iframe genau passend zu machen. Da dies window.getComputedStyle erfordert, geht das nur mit neueren Browsern, also bspw. mit viewchm.php und aktuellem Browser.

 if (window.getComputedStyle) {
   var cs = window.getComputedStyle(sel);		// sel = Eine Combobox; Firefox liefert Höhe = "21px"
   var fr = parent.document.getElementsByTagName("iframe")[0];
   fr.style.width = cs.width;
   fr.style.height = cs.height;	// Größe anpassen
   fr.style.right = 0;
   fr.style.top = 0;		// in die obere rechte Ecke platzieren (das <iframe> hat CSS position:fixed)
 }