HTML-Hilfe

Inhalt:

Schritt 1: Anwendungsgerüst
Schritt 2: Programmlogik
Schritt 3: Neue Hilfeeinträge
Schritt 4: Von der View zur Hilfe
Bilder
Hilfe für Dialoge

Ziel dieses Beispiels:
Ein HTML-basierendes Hilfesystem soll verwendet werden.
Hier gibt es das Beispiel zum Download: HTMLHelp.zip
Referenz-Links:
Knowledge Base Artikel 191118 How To Create Context-Sensitive HTML Help in an MFC Application
Technical Note TN028 Context-Sensitive Help Support

Schritt 1: Anwendungsgerüst

Erstellen des Anwendungsgerüsts (SDI-Anwendung) wie in den bisherige Beispielen.
In den "Advanced Features" wird die Checkbox "Context-sensitive Help" mit der Option "HTML Help Format" gesetzt.
HTML-Hilfe aktivieren
Beim Compilieren des Projekts wird der Help Compiler aufgerufen. Wird das Projekt gestartet gelangt man durch Drücken von "F1" oder über das Menü "Hilfe" in ein Hilfe-Template, das schon Einträge für die generierten Menüpunkte enthält.
Neu ist ein Unterverzeichnis "hlp" im Projekt, dass die HTML-Dateien der Hilfe enthält.
Verzeichnisstruktor
Aus diesen erzeugt der HTML Help Compiler (hhc.exe, im Verzeichnis "C:\Programme\HTML Help Workshop"), der beim compilieren kurz als Dos-Fenster auftaucht, eine chm-Datei, die ins Debug/Release-Verzeichnis kopiert wird.

Will man sich die Ausgabe dieses Kommandozeilenfensters anschauen (z.B. weil ein Fehler zu vermuten ist), dann kann man das so erreichen: Rechtsklick auf die Datei "HTMLHelp.hhp" im Projektmappen-Explorer, in die Eigenschaften gehen, und unter "Konfigurationseigenschaften" -> "Benutzerdef. Buildschritt" -> "Allgemein" die "Befehlszeile" öffnen. Hier ersetzt man die erste Zeile start /wait hhc "hlp\HTMLHelp.hhp" (der Name der hpp-Datei kann variieren) durch hhc "hhc hlp\HTMLHelp.hhp" . Dadurch landet die Ausgabe von "hhc.exe" direkt auf der Konsole. Im anhängenden Beispielprojekt ist dies geschehen.
HHC-Aufruf

Im Code findet sich nur eine einzige Änderung:
In MainFrm.cpp gibt es vier neue Einträge in der Message Map, die die Hilfe-Befehle auf Standard-Methoden von CFrameWnd (bzw. CWnd, dort sind sie deklariert) umleiten.

	// Globale Hilfebefehle
	ON_COMMAND(ID_HELP_FINDER, CFrameWnd::OnHelpFinder)
	ON_COMMAND(ID_HELP, CFrameWnd::OnHelp)
	ON_COMMAND(ID_CONTEXT_HELP, CFrameWnd::OnContextHelp)
	ON_COMMAND(ID_DEFAULT_HELP, CFrameWnd::OnHelpFinder)
Das Drücken von "F1" wird durch die Methode "OnHelp" abgehandelt.

Schritt 2: Programmlogik

Das Fenster der CView soll zwei Rechtecke enthalten. Wenn der User in eines davon klickt (sozusagen ein Auswählen) und dann F1 drückt soll er eine Contextabhängige Hilfe bekommen. Dazu im OnDraw zwei Rechteckt der Größe 200x200 zeichnen, das aktuell gewählte bekommt ein Fokus-Rechteck.
So soll es aussehen
Das Event "OnLButtonDown" speichert die Mausklick-Position in einer Instanzvariablen (im Konstruktor mit "-1/-1" initialisiert) und löst ein Repaint aus.


Schritt 3: Neue Hilfeeinträge

Jeder Hilfseintrag steht in einer eigenen HTML-Datei. Normalerweise enthalten diese den Namen des Controls/Menüpunkts, für den sie gelten. Da wir hier aber eigene Hilfe-Themen gebaut haben, verwenden wir einen leicht anderen Ansatz.
Zuerst einmal bauen wir drei HTML-Dateien "htmlhelp_links.htm", "htmlhelp_rechts.htm" und "htmlhelp_none.htm" im Verzeichnis "hlp". Ich habe hierzu die Datei "scrollbars.htm" kopiert und umbenannt. Der Inhalt ist reines HTML, zu beachten ist nur dass der Anchor mit dem Namen der Hilfe-Datei vorhanden ist (im Beispiel: htmlhelp_links.htm):
	<A NAME="htmlhelp_links"></A> 
Wichtig: Diese Dateien dem Projekt zufügen: im "Projektmappen-Explorer" die "HTML-Hilfethemen" auswählen, Rechtsklick und "Hinzufügen" -> "Vorhandenes Element..." wählen. Die drei Dateien auswählen.

In der Datei "./help/HTMLHelp.hhp" erfolgt die Definition der Hilfe.
In der Sektion "[FILES]" fügen wir drei neue Einträge ein:
	htmlhelp_links.htm
	htmlhelp_rechts.htm
	htmlhelp_none.htm  
In der Sektion "[ALIAS]" (Mapping von internen Alias-Namen auf Dateien) erfolgen ebenfalls drei Einträge:
	HTMLHELP_RECHTECK_LINKS				= HTMLHELP_LINKS.HTM
	HTMLHELP_RECHTECK_RECHTS			= HTMLHELP_RECHTS.HTM 
	HTMLHELP_RECHTECK_NONE				= HTMLHELP_NONE.HTM

Schließlich werden in der Sektion "[MAP]" die drei Alias-Namen aus der vorherigen Sektion definiert:
	#define HTMLHELP_RECHTECK_LINKS			0x1
	#define HTMLHELP_RECHTECK_RECHTS		0x2
	#define HTMLHELP_RECHTECK_NONE			0x3 
Gemäß Technical Note 28 ist der Bereich von 0x00000000 bis 0x0000FFFF "user defined", darf also für sonstige Hilfe-IDs verwendet werden.
Achtung: NICHT mit "0x0" beginnen, da die Help-ID bei der Message "WM_HELPHITTEST" als Rückgabe dient und "0x0" dann "nicht gefunden" bedeuten würde !
Hinweis: In der "[MAP]"-Sektion wird zuerst "HTMLDefines.h" includiert. Dort können wir unsere Defines jedoch nicht unterbringen da die Datei bei jedem compilieren neu (aus der Resourcen-Datei ?) erzeugt wird.

Im Beispielprogramm ist dies ein wenig cleverer gelöst, indem die Defines in eine eigene Headerdatei "HTMLHelpDefines.d" verschoben sind.
In der "[MAP]"-Sektion von "HTMLHelp.hhp" wird nur diese Datei eingebunden (die in diesem Fall nicht im gleichen Verzeichnis wie die hhp-Datei liegt !):
	#include ..\HTMLHelpDefines.h 

Letzter Schritt: die Dateien in den Hilfe-Inhalt-Baum eintragen. Dazu die Datei "HTMLHelp.hcc" öffnen und folgendes einfügen:
	<LI> <OBJECT type="text/sitemap">
		<param name="Name" value="Rechteck: links">
		<param name="Local" value="htmlhelp_links.htm">
		</OBJECT>
	<LI> <OBJECT type="text/sitemap">
		<param name="Name" value="Rechteck: rechts">
		<param name="Local" value="htmlhelp_rechts.htm">
		</OBJECT>
	<LI> <OBJECT type="text/sitemap">
		<param name="Name" value="Rechteck: none">
		<param name="Local" value="htmlhelp_none.htm">
		</OBJECT> 
Das Ergebnis sieht so aus:
Hilfe-Inhalt
ACHTUNG, WICHTIG !
Die .hhc-Datei dürfen wir NIE, NIE, NIE mit Visual Studio editieren ! Tun wir dass (was sowieso schwierig ist weil das HTML beschissen formatiert ist), dann funktioniert das Generieren des Hilfe-Inhaltsverzeichnisses NICHT mehr (es gibt keine Fehlermeldungen, es passiert einfach nichts mehr) ! Auf jeden Fall nur mit dem absoluten Profi-Editor "Notepad" bearbeiten !

Jetzt können wir das Programm starten und sehen unsere Hilfedateien in der Hilfe selbst, kommen aber mit F1 noch nicht dorthin.


Einträge in Karteikarte "Index" einfügen:
Hierzu einfach folgenden Eintrag in den Body einer HTML-Datei einfügen:
	<OBJECT TYPE="application/x-oleobject" CLASSID="clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e">
		<PARAM NAME="Keyword" VALUE="Rechteckfenster">
	</OBJECT> 
Wichtig ist das "Value"-Attribut des Elements "param".
Im Beispiel habe ich für alle drei Rechteckfenster-Hilfedateien diesen Eintrag eingefügt. Das führt zu diesem Ergebnis:
Hilfeindex

Schritt 4: Von der View zur Hilfe

Hier können wir keine Standard-MFC-Verknüpfung der Hilfeeinträge verwenden, da diese nur pro Menüpunkt oder Control angebbar ist, aber nicht dynamisch. Also tricksen wir in der View ein wenig:


Bilder

Den Hilfe-Dateien können wir Bilder zufügen. Diese werden im Unterverzeichnis ".\hlp\Images" abgelegt und beim Erstellen der Hilfe in die chm-Datei eingebunden, sofern aus einer HTML-Datei darauf verwiesen wird. Im Beispiel: die Hilfethemen für "Linkes/rechtes Rechteck gewählt" haben jeweils einen Screenshot eingebunden. Das HTML dazu sieht so aus (aus htmlhelp_links.htm):

<img src="./Images/htmlhelplinks.png" title="Linkes Rechteck gewählt" alt="Linkes Rechteck gewählt" width="542" height="320" />

Ins Projekt (Projektmappen-Explorer) hängen wir diese Dateien unter "Ressourcendateien" (indem wir sie per Rechtsklick -> "Hinzufügen" -> "Vorhandenes Element..." einhängen).
Projektmappen-Explorer

Hilfe für Menüpunkte und Dialoge

Der Standard-Weg: Hilfe für einen Menüpunkt ohne Tricks und Co: Das Beispiel hat bisher einen Riesen-Aufwand gezeigt um Mausposition-bezogene Hilfe einzubauen. Für Menüpunkte, Controls und Fenster gibt es aber auch ganz normale Standard-Hilfe, die man ohne Aufwand erreicht. Das Beispiel enthält im Menü "Bearbeiten" einen Menüpunkt "ID_EDIT_MENUEPUNKT" (der einen Dialog aufruft). Beim Compilieren wird in ".\hlp\HTMLDefines.h" ein neuer Hilfe-Alias angelegt:
	// Commands (ID_* and IDM_*) 
	#define HID_EDIT_MENUEPUNKT                     0x18004 
Die ID des Menüpunkts ergibt durch Voranstellen von "H" den Hilfe-Alias. Jetzt legen wir die HTML-Datei dazu an und benennen sie genauso wie den Alias (hid_edit_menuepunkt.htm). Ich habe im Beispiel die Datei aus "hid_edit_cut.htm" dupliziert.
In "HTMLHelp.hhp" müssen wir die Datei wie gehabt unter "[FILES]" eintragen, außerdem einen Eintrag in die Alias-Verknüpfungen vornehmen.
	[FILES]
	...
	hid_edit_menuepunkt.htm 
	...
	[ALIAS]
	...
	HID_EDIT_MENUEPUNKT			= HID_EDIT_MENUEPUNKT.HTM 
Wir könnten den Eintrag als neuen Unterknoten im Inhalt beim Menü "Bearbeiten" einfügen. Dazu in "HTMLHelp.hhc" folgendes nach dem Knoten "Befehle im Menü 'Bearbeiten'" einfügen:
	<UL>
	<LI> <OBJECT type="text/sitemap">
		<param name="Name" value="Menüpunkt 'Menüpunkt'">
		<param name="Local" value="hid_edit_menuepunkt.htm">
		</OBJECT>
	</UL>

Und nochmal der Standard-Weg: Hilfe für einen Dialog.
Dem Beispiel einen Dialog "DialogHirnlos" zufügen und diesen anzeigen wenn der Menüpunkt aus dem letzten Schritt gewählt wird. In ".\hlp\HTMLDefines.h" wird ein neuer Eintrag mit einer Hilfe-ID angelegt:
	// Dialogs (IDD_*) 
	#define HIDD_ABOUTBOX                           0x20064
	#define HIDD_DIALOGHIRNLOS                      0x20067 
Auch hier eine HTML-Datei für die Dialog-Hilfe anlegen ("hidd_dialoghirnlos.htm") und in "HTMLHelp.hhp" unter "[FILES]" und "[ALIAS]" Einträge vornehmen.
	[FILES]
	...
	hidd_dialoghirnlos.htm
	...
	[ALIAS]
	...
	HIDD_DIALOGHIRNLOS			= HIDD_DIALOGHIRNLOS.HTM  



Stand 21.08.2006
Historie:
26.06.2006 Beispiel zugefügt (erstellt aus der VS2003-Doku des letzten Semesters)
21.08.2006 Nachricht WM_HELPINFO wird jetzt verarbeitet (wie im 2003er-Beispiel)