将帮助文件链接到Delphi XE2应用程序——除了主窗体,一切正常。

6
我正在为我们的软件设置帮助文件。我为许多特定的表单/框架/控件添加了HelpContext编号,它们都很好用。问题是主窗体根本没有弹出任何帮助。在所有这些情况下,我只使用F1来尝试触发帮助。
我对Delphi或帮助文件一窍不通,但我会发布我所做和我所看到的内容。
编辑:感谢一些帮助,我现在看到问题是由于主窗体是MDI父窗体而导致的。这仍然不能解决问题...对我来说几乎像是一个错误,但我想这可能是有意为之的某种原因。结束编辑
我包含此单元:HtmlHelpViewer 用于查看器。在主窗体创建构造函数中,我已添加了 Application.Helpfile := 'asdf.chm'。对于所有其他表单,我只是添加了上下文号码,并且它立即起作用。我尝试在主窗体上这样做,但什么也没发生。所以我尝试添加一个Application.OnHelp事件,但这不会在主窗体上调用(并且在所有其他可以工作的表单上确实会被调用)。
我能想到的最后一招是深入代码追踪并查看发生了什么。我到达了Vcl.Forms中的TCustomForm.WMHelp作为发生分裂的地方。该函数具有此循环:
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

当主表单调用帮助控件时,帮助控件将为零然后退出。其他任何事情都会很好地进行。

显然我不知道这是为什么。答案可能是非常基本的。欢迎任何想法!


你是否为主窗体自身设置了'HelpContext'呢? - David Heffernan
@DavidHeffernan:是的,我做到了。我应该提到这一点,但它只是主窗体,而不是它的子窗体。我在窗体上放了一个按钮(没有上下文帮助),当它获得焦点并且我按下F1键时,主窗体的帮助上下文加载。如果没有可见的焦点,则不会加载任何帮助。 - Sentient
@DavidHeffernan 我看了一下,但似乎并没有什么帮助。FindControl 对于表单返回 nil,对于工作的控件返回结果,但是当我去查看原因时,我到达了这一行'Result := Pointer(GetProp(Handle, MakeIntAtom(ControlAtom)))'(在 Vcl.Controls,FindControl 中)。对于链接的控件,它会返回一些内容。但是对于主表单,它返回 nil。我无法进行更深入的调试,因为它只是转到属性(或类似属性的东西)。 - Sentient
1
好的,这是问题的核心。FindControl返回nil是没有帮助显示的原因。问题是为什么会这样。下一步是查看hItemHandle是什么并尝试识别它。我将使用Spy ++来调试它的这部分。 - David Heffernan
@DavidHeffernan 那可能行得通.. 我不太知道该怎么做,但我认为这似乎远非理想。我真的不明白为什么 Delphi 会有这种行为。我能够在一个新项目中重现这个问题,在那里如果窗体是 MDI 父窗体,则主窗体不会触发任何帮助,但切换回 fsNormal 就可以正常触发了。 - Sentient
显示剩余4条评论
1个回答

6
根据您的评论,WM_HELP消息是针对您的MDI客户端窗口的。由于那不是VCL控件,因此它不会响应WM_HELP消息。您可以拦截消息并请求主窗体处理该问题:
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 (Message.HelpInfo.iContextType=HELPINFO_WINDOW) 
  and (FindControl(Message.HelpInfo.hItemHandle)=nil) then 
    Message.HelpInfo.hItemHandle := Handle;

我刚刚看了一下我的MDI应用程序,发现我有相似的代码来处理这个问题。如果这段代码不是10年前编写的,我可能会更早地记起来!


非常感谢您的帮助!我对您的代码进行了小修改,我添加了以下内容: with Message.HelpInfo{$IFNDEF CLR}^{$ENDIF} do,因为编译器不喜欢iContextType,我从VCL.Forms中的WMHelp中获取了它。(然后从and的第二部分中删除了Message.HelpInfo。) - Sentient

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接