CHM-Datei in Projekt einbinden

Rund um die LCL und andere Komponenten
Kay
Beiträge: 134
Registriert: So 14. Nov 2010, 15:17

CHM-Datei in Projekt einbinden

Beitrag von Kay »

Hallo zusammen,

ich bin vor Kurzem von Borland Delphi auf Lazarus umgestiegen und muss sagen, dass ich echt begeistert bin: Gute IDE, jede Menge nützliche Features.
Hier im Forum habe ich auch bereits einige nützliche Tipps gefunden und ich hoffe, ihr könnt mir auch bei folgendem Problem helfen.

Ich habe meine vorhandenen Projekte (sofern nötig) nach Lazarus portiert. Nun verwende ich allerdings auch Hilfedateien im CHM-Format und da habe ich einige Probleme bei der Einbindung.
Wie ich gelesen habe, können die Komponenten THTMLHelpDatabase und THTMLBrowserHelpViewer verwendet werden. Ich habe auch bereits die der IDE beiliegende Beispielanwendung getestet - funktioniert einwandfrei. Das Problem ist nur, dass die Hilfetexte als einzelne Webseiten in einem Ordner vorliegen müssen. Ich habe keine Möglichkeit gefunden, eine fertig zusammengepackte CHM-Datei anzusprechen.
Da die Anwendung nur unter Windows laufen soll, habe ich mir überlegt, die Hilfe per Aufruf der hh.exe einzubinden. Unter Verwendung der ShellExecute-Funktion oder TProcess-Komponente klappt das auch problemlos. Wenn ich allerdings der Formulareigenschaft HelpContext einen Wert zuweise, damit ein bestimmtes Thema auch durch Drücken der Taste F1 angezeigt werden kann, dann funktioniert das natürlich nicht.
Zu diesem Zweck wollte ich einen HelpHook definieren und im Applikationsobjekt registrieren.

Das Problem ist nun Folgendes:
Wenn ich ein Hilfethema durch Klicken einer Schaltfläche aufrufen möchte, passiert überhaupt nichts.
Wenn ich F1 drücke, wird zwar der Hook aktiv, die EventHandler-Methode bekommt jedoch nur unsinnige Werte übergeben - der Parameter Command ist 0 und der Parameter Data irgendwas um 32 Mio.

Code: Alles auswählen

unit unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  StdCtrls;
 
type
  THelpHandler = class
  private
    FChmFile: String;
    FOldHelpEvent: THelpEvent;
    function HandleEvent(Command: Word; Data: PtrInt; var CallHelp: Boolean): Boolean;
  public
    constructor Create(AChmFile: String);
    destructor Destroy; override;
  end;
 
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end; 
 
var
  Form1: TForm1; 
  HelpHook: THelpHandler;
 
implementation
 
constructor THelpHandler.Create(AChmFile: String);
begin
  FChmFile := AChmFile;
  FOldHelpEvent := Application.OnHelp;
  Application.OnHelp := @HandleEvent;
end;
 
destructor THelpHandler.Destroy;
begin
  Application.OnHelp := FOldHelpEvent;
  inherited Destroy;
end;
 
function THelpHandler.HandleEvent(Command: Word; Data: PtrInt; var CallHelp: Boolean): Boolean;
begin
  Result := True;
  ShowMessage(IntToStr(Command));
  ShowMessage(IntToStr(Data));
  // Aufruf von hh.exe mit Parametern
  CallHelp := True;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  HelpContext := 1001;
  HelpHook := THelpHandler.Create('Hilfe.chm');
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
  HelpHook.Free;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  Application.HelpContext(1001);
end;
 
initialization
  {$I unit1.lrs}
 
end.
Was mache ich falsch? Wie binde ich CHM-Dateien am besten in mein Projekt ein?
Ich hoffe mir kann jemand einen Tiupp geben.

Vielen Dank schonmal und viele Grüße
Kay

PS: Ich verwende Lazarus 0.9.28.2 mit FPC 2.2.4 auf Windows XP (SP3).

marcov
Beiträge: 1102
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: CHM-Datei in Projekt einbinden

Beitrag von marcov »

Kay hat geschrieben:Hallo zusammen,
Wenn ich ein Hilfethema durch Klicken einer Schaltfläche aufrufen möchte, passiert überhaupt nichts.
Wenn ich F1 drücke, wird zwar der Hook aktiv, die EventHandler-Methode bekommt jedoch nur unsinnige Werte übergeben - der Parameter Command ist 0 und der Parameter Data irgendwas um 32 Mio.
Damit kann ich nicht helfen, aber via hh.exe ist schmerzhafter dann nötig.

Siehe mal packages/winunits-base/tests/hhex.pp and hhex2.pp in die Quellen.

MAC
Beiträge: 770
Registriert: Sa 21. Feb 2009, 13:46
OS, Lazarus, FPC: Windows 7 (L 1.3 Built 43666 FPC 2.6.2)
CPU-Target: 32Bit

Re: CHM-Datei in Projekt einbinden

Beitrag von MAC »

Ich hab mal gegooglet.
Das könnte interessant sein:
http://wiki.lazarus.freepascal.org/chm" onclick="window.open(this.href);return false;
http://www.lazarus.freepascal.org/index ... pic=7614.0" onclick="window.open(this.href);return false;

Code: Alles auswählen

Signatur := nil;

Kay
Beiträge: 134
Registriert: So 14. Nov 2010, 15:17

Re: CHM-Datei in Projekt einbinden

Beitrag von Kay »

@marcov:
Die beiden Dateien gibt's im gesamten Lazarus-Ordner nicht.

@MAC:
Die beiden Seiten hatte ich auch schon gefunden. Da wird aber lediglich erklärt, wie das CHM-Package strukturiert ist bzw. wie man CHM-Dateien selbst erstellen kann. Das möchte ich aber gar nicht - die Datei ist ja bereits vorhanden. Mit der Klasse TCHMReder kann ich zwar die Struktur der Datei auslesen, aber wie bringe ich das Ganze zur Anzeige und wie binde ich das so in meine Anwendung ein, dass sich ein Hilfethema durch Drücken von F1 öffnen lässt?

Eine kurze Erläuterung der Vorgehensweise wäre sicherlich hilfreich!

Vielen Dank
Kay

knight
Beiträge: 802
Registriert: Mi 13. Sep 2006, 22:30

Re: CHM-Datei in Projekt einbinden

Beitrag von knight »

Kay hat geschrieben:@marcov:
Die beiden Dateien gibt's im gesamten Lazarus-Ordner nicht.

Vielen Dank
Kay
Marco meint sicher die FPC Quelltexte. Hast du da mal nachgeschaut?

knight

marcov
Beiträge: 1102
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: CHM-Datei in Projekt einbinden

Beitrag von marcov »

Kay hat geschrieben:@marcov:
Die beiden Dateien gibt's im gesamten Lazarus-Ordner nicht.
Wie schon gesagt in die FPC Quellen, nicht die Lazarus quellen.
@MAC:
Die beiden Seiten hatte ich auch schon gefunden. Da wird aber lediglich erklärt, wie das CHM-Package strukturiert ist bzw. wie man CHM-Dateien selbst erstellen kann. Das möchte ich aber gar nicht - die Datei ist ja bereits vorhanden. Mit der Klasse TCHMReder kann ich zwar die Struktur der Datei auslesen, aber wie bringe ich das Ganze zur Anzeige und wie binde ich das so in meine Anwendung ein, dass sich ein Hilfethema durch Drücken von F1 öffnen lässt?

Eine kurze Erläuterung der Vorgehensweise wäre sicherlich hilfreich!
Es gibt zwei unterschiedliche Methoden:

1) via package CHM das read/write Zugang zu CHM bietet.
2) via winunits-base/htmlhelp, ein Header zur Microsoft htmlhelp api. (mit hhex1/2 als Beispiel Quellen)

Kay
Beiträge: 134
Registriert: So 14. Nov 2010, 15:17

Re: CHM-Datei in Projekt einbinden

Beitrag von Kay »

Also, ich hab die Dateien ja im fpc gesucht, wie angegeben im Ordner source\packages\winunits-base\tests.
Die Funktion HtmlHelp() gibt es ebenfalls nicht.

Die Klassen TCHMReader und TCHMWriter habe ich zwar gefunden, aber wie gesagt, ich hab keine Ahnung wie ich die Datei dann zur Anzeige bringen soll. Ich kann doch lediglich die Namen der enthaltenen Hilfethemen, Index-File usw. lesen, aber was nützt mir das? Und selbst wenn ich dafür eine Anzeigeprozedur schreibe, wie soll diese dann per F1 aufrufbar sein?

Viele Grüße
Kay

marcov
Beiträge: 1102
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: CHM-Datei in Projekt einbinden

Beitrag von marcov »

Kay hat geschrieben:Also, ich hab die Dateien ja im fpc gesucht, wie angegeben im Ordner source\packages\winunits-base\tests.
Und die du hast dich die angesehen? hhex* ?
Die Funktion HtmlHelp() gibt es ebenfalls nicht.
Sollte eine ebene tiefer, src/
Die Klassen TCHMReader und TCHMWriter habe ich zwar gefunden, aber wie gesagt, ich hab keine Ahnung wie ich die Datei dann zur Anzeige bringen soll. Ich kann doch lediglich die Namen der enthaltenen Hilfethemen, Index-File usw. lesen, aber was nützt mir das? Und selbst wenn ich dafür eine Anzeigeprozedur schreibe, wie soll diese dann per F1 aufrufbar sein?
Die würde ich nicht nutzen. Recherche die Tests in winunits-base ein bisschen mehr.

Kay
Beiträge: 134
Registriert: So 14. Nov 2010, 15:17

Re: CHM-Datei in Projekt einbinden

Beitrag von Kay »

Hallo marcov,

leider kann ich nichts weiter recherchieren, denn wie gesagt, es ist nichts da.

Hier das Verzeichnis-Listing:

Code: Alles auswählen

31.10.2010  22:38    <DIR>          .
31.10.2010  22:38    <DIR>          ..
05.01.2008  20:31            12.158 OOHelper.pp
05.01.2008  20:31             3.781 OOTest.pp
05.01.2008  20:31               428 testcom1.pp
05.01.2008  20:31             2.519 testcom2.pp
05.01.2008  20:31               292 testver.pp
               5 Datei(en)         19.178 Bytes
Viele Grüße
Kay

knight
Beiträge: 802
Registriert: Mi 13. Sep 2006, 22:30

Re: CHM-Datei in Projekt einbinden

Beitrag von knight »

Ich gehe mal davon aus, daß du Lazarus mittels des Windows-Installers installiert hast. In dem Fall werden nur die FPC Teile mit installiert, die für den Betrieb von Lazarus unbedingt notwendig sind (unter anderen Betriebssystemen muß FPC in der Regel separat installiert werden). Der "Nachteil" ist, daß man nicht alle FPC Dateien vorliegen hat. Ich würde vorschlagen, daß du FPC herunterlädst (http://www.freepascal.org/down/source/sources.var" onclick="window.open(this.href);return false;) und dort nach den Dateien suchst.

knight

marcov
Beiträge: 1102
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: CHM-Datei in Projekt einbinden

Beitrag von marcov »

Kay hat geschrieben:
leider kann ich nichts weiter recherchieren, denn wie gesagt, es ist nichts da.
Das ist denn eine alte Version. Versuche mal 2.4.0 oder 2.4.2.

Kay
Beiträge: 134
Registriert: So 14. Nov 2010, 15:17

Re: CHM-Datei in Projekt einbinden

Beitrag von Kay »

Hallo zusammen,

ja, ich hatte tatsächlich noch eine ältere FPC-Version. Beim Versuch, den Compiler zu aktualisieren, entstanden jedoch einige Probleme in der Lazarus-IDE. Auch eine Neukompilierung von Lazarus schlug fehl - die LCL (genauergesagt die Unit LResources) ließ sich mit dem aktuellen Compiler nicht mehr übersetzen.
Aber eh ich noch lange nach Fehlern suche, habe ich auch Lazarus kurzerhand aktualisiert - ich verwende jetzt Version 0.9.29 + FPC 2.4.3; ist das momentan der aktuellste Stand?
Die beiden Dateien hhex.pp und hhex2.pp habe ich wie angegeben gefunden und auch htmlhelp funktioniert jetzt einwandfrei. Dazu habe ich auch keine Frage weiter - die Syntax ist ja simpel.
Eine Sache hätte ich allerdings noch:
Mit htmlhelp() lässt sich die Hilfe von jeder beliebigen Stelle im Quelltext aus anzeigen, allerdings muss dazu ein expliziter Funktionsaufruf erfolgen.
Wenn ich also auf mein eingangs genanntes Problem zurückkomme und die Hilfe auch durch Drücken der Taste F1 (mit zugewiesenem Wert für HelpKeyword oder HelpContext versteht sich), gehe ich dann recht in der Annahme, dass sich das nur durch Hooken (wie oben dargestellt) erreichen lässt? Wäre zumindest die einfachste Sache, die mir jetzt auf Anhieb einfallen würde.

Viele Grüße
Kay

MmVisual
Beiträge: 1581
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 4 FPC 3.2.2)
CPU-Target: 32/64Bit

Re: CHM-Datei in Projekt einbinden

Beitrag von MmVisual »

Also falls bei Dir Lazarus wieder gehen solle, so geht bei mir der HH Aufruf:

Code: Alles auswählen

Uses ..., process, ...
 
Var
  sHilfeDatei: String; 
 
// Launch an external application
//Adapted from Source: http://wiki.lazarus.freepascal.org/Executing_External_Programs" onclick="window.open(this.href);return false;
procedure LaunchCHMHelp(ChmFileName: string; iID: Integer = -1);
var
  AProcess: TProcess;
begin
  If Not FileExists(ChmFileName) Then
  Begin
    ShowMessage('Cannot Open Helpfile ' + ChmFileName+ ' Context ' + IntToStr(iID));
    Exit;
  end;
{$ifdef WINDOWS}
  If iID < 0 Then iID:= 1; // Hier Default ID Eintragen für Hilfe-Aufruf
  AProcess := TProcess.Create(nil);
  // 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.CommandLine := 'hh.exe -mapid ' + IntToStr(iID) + ' ms-its:' + ChmFileName;
  AProcess.Execute;
  AProcess.Free;
{$else}
  If FileExists('/usr/bin/kchmviewer') Then
  Begin
    AProcess := TProcess.Create(nil);
    AProcess.CommandLine := 'kchmviewer ' + ChmFileName;
    AProcess.Execute;
    AProcess.Free;
  end Else ShowMessage('Cannot Open Helpfile ' + ChmFileName+ ' KChmViewer not found!');
{$endif}
end;
 
procedure TfrmMain.btnHelpClick(Sender: TObject);
Var
	iHelpContext: LongInt;
	Obj: TControl;
	Procedure LookControl;
	Begin
		While (Obj <> Nil) Do
		Begin
			If Obj.HelpContext > 0 Then
			Begin
				iHelpContext := Obj.HelpContext;
				Break;
			End Else Obj := Obj.Parent;
		End;
	End;
begin
	iHelpContext := 0;
 	If Screen.ActiveControl <> Nil Then
	Begin // Überprüfung, ob die Hilfe vom Aktuellen Formular gestartet werden kann
		If (Screen.ActiveControl Is TControl) Then
		Begin
			Obj := TControl(Screen.ActiveControl);
			If Obj Is TPageControl Then
				Obj := TControl(TPageControl(Obj).ActivePage);
			LookControl;
		End;
	End;
	If iHelpContext > 0 Then
	Begin
//		ShowMessage('ShowHelp: ' + IntToStr(iHelpContext));
		LaunchCHMHelp(sHilfeDatei, iHelpContext); // aufrufen.
	end;
end;
 
Function TFrmMain.FOnHelp(Command: Word; Data: Longint; var CallHelp: Boolean): Boolean;
Begin // Online-Hilfe aufrufen
  btnHelpClick(Nil);
  Result := True;
End;  
 
Procedure TfrmMain.FormCreate(Sender: TObject);
Begin
  sHilfeDatei := ChangeFileExt(Application.ExeName, '.chm');
  btnHelp.Enabled := FileExists(sHilfeDatei);
  Application.OnHelp := @FOnHelp;
End;
Die Programmierung im Formular:
- Das Formular muss mit dem HelpContext belegt werden, z.B. 100, so wie in der Hilfe-Datei hinterlegt.
- Wenn man mehrere Tabs mit einem TPageControl hinterlegt hat, so kann man in jedem Tab eine andere HelpContext ID hinterlegen.
- Die einzelnen Edit-Felder brauchen kein HelpContext, die Routine findet automatisch anhand dem ActiveControl das oberliegende Control welches ein HelpContext hat (<> 0) und öffnet damit die Hilfe.
- Wenn ein TPageControl verwendet wird sollte diese Zeilen drin sein:

Code: Alles auswählen

Procedure TfrmMain.pgMainChange(Sender: TObject);
Begin
  pgMain.HelpContext := pgMain.ActivePage.HelpContext;
  pgMain.HelpKeyword := pgMain.ActivePage.HelpKeyword; // Diese Zeile ist eigentlich nicht nötig
End;
Denn es kann sein dass zwar ein neuer Tab ausgewählt wurde, aber da der Focus auf TPageControl liegt nicht die Hilfe des Tabs gezeigt sondern die des Formulars was ja falsch ist. Daher diese Zeilen.

leider kennt der "kchmviewer" (Linux) keine Context-ID (HelpContext) :(
Kennt oder geht das vielleicht doch? (Linux-Exterten sind gefragt...)
Zuletzt geändert von MmVisual am Do 18. Nov 2010, 06:52, insgesamt 1-mal geändert.
EleLa - Elektronik Lagerverwaltung - www.elela.de

Kay
Beiträge: 134
Registriert: So 14. Nov 2010, 15:17

Re: CHM-Datei in Projekt einbinden

Beitrag von Kay »

Hallo MmVisual,

vielen Dank für das Codebeispiel und die Erläuterungen. Hab's gerade ausprobiert und das Ganze läuft einwandfrei - super!
Genauso hab ich mir das mit dem Starten von HH in einem Prozess und dem Behandeln des globalen Help-Events vorgestellt.
Eine Frage hätte ich allerdings noch: Wieso ist der Code im ButtonClick-Event so umfangreich? Würde nicht auch Folgendes ausreichen:

Code: Alles auswählen

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  sHilfeDatei := ChangeFileExt(Application.ExeName, '.chm');
  btnHelp.Enabled := FileExists(sHilfeDatei);
  Application.OnHelp := @FOnHelp;
end;
 
function TfrmMain.FOnHelp(Command: Word; Data: Longint; var CallHelp: Boolean): Boolean;
begin // Online-Hilfe aufrufen
  LaunchCHMHelp(sHilfeDatei, Data);
  Result := True;
end;
 
procedure TfrmMain.btnHelpClick(Sender: TObject);
begin
  Application.HelpContext(Self.HelpContext);
end;
Die Handler-Funktion wird ja im Application-Objekt registriert. So würde ich mir den ganzen Lookup sparen oder?

Viele Grüße
Kay

MmVisual
Beiträge: 1581
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 4 FPC 3.2.2)
CPU-Target: 32/64Bit

Re: CHM-Datei in Projekt einbinden

Beitrag von MmVisual »

Zum einen habe ich in meiner EXE ein TButton btnHelpFile, der ruft dann garantiert die Hilfe auf, auch wenn das mit Application.OnHelp mal nicht gehen sollte (warum auch immer) zum anderen sucht der Code die richtige HelpContext ID in den Steuerelementen bis hin zum obersten Parent anhand dem ActiveControl.
Den Button hatte ich auch drin um zu testen bis es ging. (Der wäre jetzt nicht mehr nötig, aber ist gut für die User)

Wenn man in der Applikation nur eine einzige Hilfe-Seite aufrufen möchte, kann man es machen. In meiner habe ich ein TPageControl drin, da wird anhand dem ausgewählten Tab/Funktion im Tab eine andere Hilfe-Seite aufgerufen.

Das "Application.OnHelp" findet bei der Verwendung von TPageControl nicht die richtige Hilfeseite (HelpContext).

Am besten mein Code so belassen, der Compiller meckert auch nicht wenn man kein TPageControl drin hat.
EleLa - Elektronik Lagerverwaltung - www.elela.de

Antworten