Ich schreibe schon seit über 10 Jahren Programme für Windows und Linux und liefer dazu eine Kontextbezogene Hilfe im CHM Format mit.
Ich schreibe die Hilfe als HTML Dateien, und kann diese (als sozusagen zusätzliches Feature) 1:1 online stellen ins Internet.
Mit dem Microsoft CHM File Compiler (recht alt, von 2002) linke ich alle Dateien zusammen in eine CHM Datei.
Dazu gibt es die Dateien:
xxxx.hhp - Html Help Project
xxxx.hhc - Html Help Content, diese ist der linke Baum in der Hilfe-Datei und wird mit dem Microsoft Help File compiller erzeugt
Alis.h - Hier wird einem Alias Name die Reale HTML Datei zugewiesen
Index.h - Hier stehen #defines drin die einem Alisnamen einen Wert zuweisen (die Kontext-Nummer)
Mehr zusätzliche Dateien braucht es nicht.
Unter Windows wird in der regel die Hilfe mit der "hh.exe" gestartet und als Parameter der Dateiname sowie die Kontext Nummer übergeben.
Unter Linux braucht es die Zusätzliche Installation von "KChmViewer", der unterstützt ebenfalls die Kontext Nummer und man kann somit die entsprechende Hilfe Seite öffnen. (Den KChmViewer gibt es auch für Windows und mag ich leiber als das HH Tool von MS)
Nun kann man in der eigenen EXE bei den Steuerelementen die Eigenschaft "Context" mit der gleichen Zahl füllen wie die "Kontext Nummer" in der Hilfe. Drückt man die F1 Taste, so sucht man am dem ActiveControl so lange nach dem Parent Control bis man eine Zahl > 0 in "Context" gefunden hat, somit braucht nicht jedes Steuerelement diese "Context", sondern nur der Reiter oder das Formular. Anschließend startet man die jeweilige EXE mit den Parametern (CHM Datei Order/Name, Kontext Nummer).
Ich finde die Variante der CHM Datei sehr einfach, da man nur diese 4 Dateien hat, (+ die HTML Dateien). Diese Dateien sind zudem alles Textdateien, die man somit perfekt mit z.B. SVN verwalten kann und sehr einfach aufgebaut sind.
Beispiel Datei HHP:
Code: Alles auswählen
[OPTIONS]
;Default Font=Arial,10,0
Compatibility=1.1
Compiled file=XXXX.chm
Contents file=XXXX.hhc
Default topic=Index.htm
Display compile progress=No
Full-text search=Yes
Language=0x407 Deutsch (Deutschland)
Title=EleLa - XXXX - Hilfe
[FILES]
Index.htm
[ALIAS]
#include Alias.h
[MAP]
#include Index.h
Beispiel Datei HHC (XML Format):
Code: Alles auswählen
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML>
<HEAD>
<meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1">
<!-- Sitemap 1.0 -->
</HEAD><BODY>
<OBJECT type="text/site properties">
<param name="Window Styles" value="0x800025">
</OBJECT>
<UL>
<LI> <OBJECT type="text/sitemap">
<param name="Name" value="Inhalt">
<param name="Local" value="Index.htm">
</OBJECT>
<LI> <OBJECT type="text/sitemap">
<param name="Name" value="Installation">
<param name="Local" value="Install.htm">
</OBJECT>
</UL>
</BODY></HTML>
Beispiel Datei Alis.h:
Beispiel Datei Index.h:
Initialisierung:
Code: Alles auswählen
Application.OnHelp := @FOnHelp;
function TfrmMain.FOnHelp(Command: word; Data: PtrInt; var CallHelp: boolean): boolean;
begin // Online-Hilfe aufrufen
btnHelpClick(nil);
Result := True;
end;
procedure TfrmMain.btnHelpClick(Sender: TObject);
var
iHelpContext: longint;
Obj: TControl;
sActivControl: String;
procedure LookControl;
begin
while (Obj <> nil) do
begin
if Obj.HelpContext > 0 then
begin
iHelpContext := Obj.HelpContext;
Break;
end
else Begin
Obj := Obj.Parent;
sActivControl := sActivControl + ' > ' + Obj.Name;
end;
end;
end;
begin
iHelpContext := 0;
sActivControl := '';
if Screen.ActiveControl <> nil then
begin // Überprüfung, ob die Hilfe vom Aktuellen Formular gestartet werden kann
if (Screen.ActiveControl is TControl) then
begin
sActivControl := TControl(Screen.ActiveControl).Name;
Obj := TControl(Screen.ActiveControl);
if Obj is TPageControl then
Obj := TControl(TPageControl(Obj).ActivePage);
LookControl;
end;
end;
if iHelpContext > 0 then
begin
If ErrMessagesDebugMode >= 1 Then
DoLog('ShowHelp: ' + IntToStr(iHelpContext) + ' / ' +sActivControl);
LaunchCHMHelp(sHilfeDatei, iHelpContext); // aufrufen.
End Else Begin
DoLog('E: Cannot open help, ContextID=0! ' + sActivControl);
end;
end;
// Launch an external application
//Adapted from Source: http://wiki.lazarus.freepascal.org/Exec ... l_Programs
procedure LaunchCHMHelp(ChmFileName: string; iID: integer = -1);
var
AProcess: TProcessUTF8;
{$ifdef WINDOWS}
s: String;
Reg: TRegistry;
bKC: Boolean;
{$endif}
begin
If Assigned(frmMain) Then
frmMain.SetSlHilfe(); // HTML Hilfe Dateinamen in slHilfe übertragen. .Object ist der Hilfe-Index
if not FileExistsUTF8Mm(ChmFileName) then
begin
If Assigned(frmMain) Then
frmMain.DoLog('Cannot Open Helpfile ' + ChmFileName + ' Context ' + IntToStr(iID));
Exit;
end;
if iID < 0 then
iID := 1; // Hier Default ID Eintragen für Hilfe-Aufruf
{$ifdef WINDOWS}
s := ExtractFilePath(Application.ExeName) + 'kchmviewer.exe';
bKC := FileExistsUTF8Mm(s);
If not bKC Then
Begin
Reg := TRegistry.Create;
Reg.RootKey := HKEY_LOCAL_MACHINE;
AProcess := TProcessUTF8.Create(nil);
If Reg.OpenKeyReadOnly('\SOFTWARE\Wow6432Node\Ulduzsoft\KchmViewer') Then
Begin // KChmViewer gefunden
s := IncludeTrailingPathDelimiter(Reg.ReadString('')) + 'kchmviewer.exe'; // Nutze KChmViewer unter Windows
bKC := FileExistsUTF8Mm(s); // EXE auch vorhanden
end;
Reg.Free;
End;
If bKC Then
Begin // Nutze KChmViewer unter Windows
AProcess.Executable := s;
AProcess.Parameters.Clear;
AProcess.Parameters.Add('-token');
AProcess.Parameters.Add('de.mmvisual.elela');
iID := slHilfe.IndexOfObject(TObject(PtrInt(iID))); // Dateiname aus Hilfe-Index lesen
If iID >= 0 Then
Begin
AProcess.Parameters.Add('-showPage');
AProcess.Parameters.Add(slHilfe[iID]);
End;
AProcess.Parameters.Add(ChmFileName);
If Assigned(frmMain) Then
frmMain.DoLog(AProcess.Executable + ' ' + StringReplace(AProcess.Parameters.Text, CRLF, ' ', [rfReplaceAll]));
End Else Begin // Nutze hh.exe unter Windows
// Use AProcess to execute the Microsoft HTML Help file in the windows directory
// The "10" in "-mapid 10 ms-its:" signifies the table of contents
AProcess.Executable := 'hh.exe';
AProcess.Parameters.Clear;
AProcess.Parameters.Add('-mapid');
AProcess.Parameters.Add(IntToStr(iID));
AProcess.Parameters.Add('ms-its:' + UTF8ToSys(ChmFileName)); // *DEBUG UTF8
// AProcess.CommandLine := 'hh.exe -mapid ' + IntToStr(iID) + ' ms-its:' + UTF8ToSys(ChmFileName); // *DEBUG UTF8
end;
AProcess.Execute;
AProcess.Free;
{$else}
If FileExistsUTF8Mm('/usr/bin/kchmviewer') Then
Begin
iID := slHilfe.IndexOfObject(TObject(PtrInt(iID))); // Dateiname aus Hilfe-Index lesen
AProcess := TProcessUTF8.Create(nil);
AProcess.Executable := '/usr/bin/kchmviewer';
AProcess.Parameters.Clear;
AProcess.Parameters.Add('-token');
AProcess.Parameters.Add('de.mmvisual.elela');
If iID >= 0 Then
Begin
AProcess.Parameters.Add('-showPage');
AProcess.Parameters.Add(slHilfe[iID]);
End;
AProcess.Parameters.Add(ChmFileName);
If Assigned(frmMain) Then
frmMain.DoLog(AProcess.Executable + ' ' + StringReplace(AProcess.Parameters.Text, LF, ' ', [rfReplaceAll]));
AProcess.Execute;
AProcess.Free;
End Else OpenDocumentMm(ChmFileName);
{$endif}
end;
{$ifdef UNIX}
Function OpenURLMm(AURL: String): Boolean;
Begin
Result := OpenURL(AURL);
end;
{$ELSE}
function OpenURLMm(AURL: String): Boolean;
var
{$IFDEF WinCE}
Info: SHELLEXECUTEINFO;
{$ELSE}
PURL: String;
ws, wsp: WideString;
ans, ansp: AnsiString;
IsFileUriWithSpaces: Boolean;
const
FileURIScheme = 'file://';
{$ENDIF}
begin
Result := False;
if AURL = '' then Exit;
PURL := ExtractFileDir(AURL);
If PURL = AURL Then PURL := '';
If Not DirectoryExistsUTF8Mm(PURL) Then PURL := '';
{$IFDEF WinCE}
FillChar(Info, SizeOf(Info), 0);
Info.cbSize := SizeOf(Info);
Info.fMask := SEE_MASK_FLAG_NO_UI;
Info.lpVerb := 'open';
Info.lpFile := PWideChar(UTF8Decode(AURL));
ToDo:
Info.lpDir := ....
Result := ShellExecuteEx(@Info);
{$ELSE}
if Win32Platform = VER_PLATFORM_WIN32_NT then
begin
//Urls that start with file:// are allowed to contain spaces and should be quoted on NT platform,
//but on Win9x quoting it fails
//Since on Windows filenames cannot contain the " character, we need not care about it and simply enclose the AURL
IsFileUriWithSpaces := (Pos(#32,AURL) > 0) and (CompareText(Copy(AURL,1,Length(FileURIScheme)), FileURIScheme) = 0);
if IsFileUriWithSpaces then AURL := '"' + AURL + '"';
ws := UTF8Decode(AURL);
if PURL <> '' Then
Begin
IsFileUriWithSpaces := (Pos(#32,PURL) > 0) and (CompareText(Copy(PURL,1,Length(FileURIScheme)), FileURIScheme) = 0);
if IsFileUriWithSpaces then PURL := '"' + PURL + '"';
wsp := UTF8Decode(PURL);
end Else wsp := '';
Result := ShellExecuteW(0, nil, PWideChar(ws), nil, PWideChar(wsp), SW_SHOWNORMAL) > 32;
end
else
begin
ans := Utf8ToAnsi(AURL); // utf8 must be converted to Windows Ansi-codepage
ansp := Utf8ToAnsi(PURL);
Result := ShellExecute(0, nil, PAnsiChar(ans), nil, PAnsiChar(ansp), SW_SHOWNORMAL) > 32;
end;
{$ENDIF}
end;
{$ENDIF}
// Open a document with the default application associated with it in the system
{$ifdef UNIX}
Function OpenDocumentMm(APath: String): Boolean;
Begin
Result := OpenDocument(APath);
end;
{$ELSE}
function OpenDocumentMm(APath: String): Boolean;
begin
Result := OpenURLMm(APath);
end;
{$ENDIF}
Das "DoLog()" kannst Du löschen.
Nun wird ein Steuerelement mit "Context:=100" angelegt, der Focus ist da drauf, drücken auf die F1 Taste öffnet die Hilfe mit der Datei "Install.htm".
Sollte ich noch irgend ein Stück Code "vergessen" zu kopieren haben, dann einfach das xxxxxMM zu xxxxx (ohne MM im Funktionsname) ersetzen, dann sollte es gehen. (z.B. "OpenDocumentMm()" >> "OpenDocument()")