Search code examples
firemonkeychm

Adding a Help file in Firemonkey applications


I'm creating the help file for an application written in Delphi Firemonkey. Unfortunately I have discovered that Firemonkey APPLICATION class doesn't have the HelFile property that the VCL equivalent has, so it seems to not be possible to include a help file with the application. I would like to know if someone has dealt with this problem and which is the better strategy to solve this. I thought to write a launcher in VCL console mode. The launcher is started from the main application with some parameters including the help topic code. This launcher links the HELP file, so the only thing it does is to start the help and then terminate itself. but this solution seems tricky to me. I was wondering if a better solution exists.


Solution

  • I've dived deeply into the source code, and although I don't fully understand it, I found some interesting things. I don't have a custom help file to test with, but hopefully you can make this work.

    The first interesting thing that I found is that there is a unit called System.HelpIntfs. That is, this is a System unit, not a vcl unit, so you'd expect it to be usable with FMX.

    In order to call the Windows HTMLHelp system from FMX, you need to first call GetHelpSystem(), passing as an out parameter an iHelpSystem, iHelpSystem2, or iHelpSystem3 variable. You can then use the returned result to call for help.

    However, when I tried this, it mostly failed, because the returned result is supposed to contain a list of help viewers, but that list was empty. I then found that the list can be populated with one entry for the Windows HTMLHelp by using the unit vcl.HtmlHelpViewer. What is interesting here is that, despite the name, this unit has no vcl dependencies! The only units it uses are System.Classes, System.HelpIntfs, System.SysUtils, and Winapi.Windows.

    vcl.HtmlHelpViewer creates the viewer object and registers it in its Initialization section, so all you have to do with this is include it.

    I have assumed that you have populated your controls' .HelpContext or HelpKeyword properties.

    Your code will need to be something like this:

    unit Form1;
    
    interface
    
    uses System.HelpIntfs, Vcl.HtmlHelpViewer,   //Necessary
         winapi.Windows,FMX.Platform.Win,        //Only needed for the line with 'hook' in it.
         System.UITypes,                         //Just for F1 name.
         FMX.Types, FMX.Controls;                //You probably already have these two.
    .
    .
    .
    //Form's OnKeyUp event handler.
    procedure Form1.FormKeyUP(Sender:TObject; var Key:Word; var KeyChar:Char; Shift:TShiftState);
    var  o:    TFMXObject;
         Ctrl: TStyledControl absolute o;
         hs:   iHelpSystem; //Or iHelpSystem2 or iHelpSystem3.  See Delphi help for the differences.
    const      HelpFileName = 'MyHelpFile.chm';
    begin
      if (key=vkF1) and (Shift=[]) then begin
        o:=Focused.GetObject;        //Get the focussed control, that the user would be expecting help on.
        if o is TStyledControl then begin
          GetHelpSystem(hs);
          case WhatIWant of //pseudo-values now to show options
            IWantTOC:             hs.ShowTableOfContents;  //NB: This doesn't work, as we haven't provided a file name and this method doesn't take parameters.
            IWantTOC_thatWorks:   hs.hook(FormToHWND(self),HelpFileName,HH_DISPLAY_TOC,0)
            IWantContextHelp:     hs.ShowContextHelp(Ctrl.HelpContext,HelpFileName); 
            IWantKeywordHelp:     hs.ShowKeywordHelp(Ctrl.HelpKeyword,HelpFileName); //Untested, but doesn't crash.
            IWantSomethingElse:   ;//See Delphi help for other options.
          end; //case
        end;
      end;
    end
    
    

    Presumably you'll want to move some of that (such as the HelpFileName constant) somewhere else and add some more error checking, but this should give you the idea, and I hope you can get it working.