6
votes

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!

1
Did you set HelpContext for the main form itself?David Heffernan
@DavidHeffernan: Yes I did. I should have mentioned this, but it's just the main form, not its children. I put a button on the form (with no context help) and when it has focus and I push F1 the helpcontext for the main form loads. If there's no visible focus then no help loads.Sentient
I'd have a look at the WMHelp handler under the debugger and see what is returned from FindControl.David Heffernan
@DavidHeffernan I looked down through that but it doesn't seem very helpful. FindControl is returning nil for the form and a result for controls that work, but when I go to see why I get to this line 'Result := Pointer(GetProp(Handle, MakeIntAtom(ControlAtom)))' (in Vcl.Controls, FindControl) And for a control that links, that returns something. But when for the main form it return nil. I can't debug any deeper because it just goes to a property (or something that kind of looks like one).Sentient
Well, this is getting to the nub of the problem. FindControl returning nil is why no help appears. The question is why that is so. Next step is to look at what hItemHandle is and try to identify it. I'd be using Spy++ to debug that part of it.David Heffernan

1 Answers

6
votes

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!