Question

I'm working on getting the helpfile setup with our software. I have added HelpContext numbers for lots of specific forms/frame/controls and they all work fine. The problem is that the main form is not bringing up any help at all. For all of this I'm only using F1 to try to trigger the help.

I'm not at all an expert on Delphi or helpfiles, but I'll post what I've done and where I've looked.

Edit: Thanks to some help I now see the issue is due to the main form being a MDI parent. This still doesn't solve the problem.. it almost seems like a bug to me but I suppose it could be intentional for some reason. EndEdit

I'm including this unit: HtmlHelpViewer for the viewer. In the main forms Create constructor I've added the Application.Helpfile := 'asdf.chm'. For all the other forms I have just added context numbers and it's worked right away. I tried that on the main form and nothing happens. So I tried adding an Application.OnHelp event but this doesn't get called on the main form (and it does for all the other forms where help is working).

Last resort that I could think of was to trace deep down into the code and see what was happening. I got to TCustomForm.WMHelp in Vcl.Forms as the place where the split was happening. Said function has this loop:

if iContextType = HELPINFO_WINDOW then
begin
  Control := FindControl(hItemHandle);
  while (Control <> nil) and ( not ControlHasHelp(Control)) do
    Control := Control.Parent;
  if Control = nil then Exit;
  GetHelpInfo(Control, HType, ContextID, Keyword);
  Pt := Control.ClientToScreen(Point(0, 0));
end

When the main form was calling the Help Control would be nil and then it would exit. Anything else would go on fine.

I obviously don't know why this is happening. The answer could be something very basic. Any ideas would be appreciated!

Was it helpful?

Solution

According to your comments, the WM_HELP message is being targetted at your MDI client window. And since that is not a VCL control it does not respond to the WM_HELP message. You can deal with the problem by intercepting the message and asking the main form to handle it:

type
  TMainForm = class(TForm)
  protected
    procedure WMHelp(var Message: TWMHelp); message WM_HELP;
  end;
....
procedure TMainForm.WMHelp(var Message: TWMHelp);
begin
  if (Message.HelpInfo.iContextType=HELPINFO_WINDOW) 
  and (Message.HelpInfo.hItemHandle=ClientHandle) then 
    Message.HelpInfo.hItemHandle := Handle;
  inherited;
end;

If you want to be even more defensive you could write it like this:

  if (Message.HelpInfo.iContextType=HELPINFO_WINDOW) 
  and (FindControl(Message.HelpInfo.hItemHandle)=nil) then 
    Message.HelpInfo.hItemHandle := Handle;

I've just had a look at my own MDI application and I can see that I have similar code to deal with this exact issue. If it hadn't been written over 10 years ago I might have remembered sooner!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top