将帮助文件链接到 Delphi XE2 应用程序 - 除主窗体外一切正常

Posted

技术标签:

【中文标题】将帮助文件链接到 Delphi XE2 应用程序 - 除主窗体外一切正常【英文标题】:Linking helpfile to an Delphi XE2 Application - everything works except main form 【发布时间】:2012-04-16 14:49:05 【问题描述】:

我正在使用我们的软件设置帮助文件。我为许多特定的表单/框架/控件添加了 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

当主窗体调用帮助控件时,它将为 nil,然后它会退出。其他任何事情都会顺利进行。

我显然不知道为什么会这样。答案可能是非常基本的。任何想法将不胜感激!

【问题讨论】:

您是否为主表单本身设置了HelpContext @DavidHeffernan:是的,我做到了。我应该提到这一点,但它只是主要形式,而不是它的孩子。我在表单上放了一个按钮(没有上下文帮助),当它有焦点时,我按 F1 键加载主表单的帮助上下文。如果没有可见的焦点,则不会加载任何帮助。 我会看看调试器下的 WMHelp 处理程序,看看 FindControl 返回了什么。 @DavidHeffernan 我往下看了看,但它似乎没有多大帮助。 FindControl 为表单返回 nil 并为有效的控件返回结果,但是当我去看看为什么我到达这一行 'Result := Pointer(GetProp(Handle, MakeIntAtom(ControlAtom)))' (在 Vcl.Controls 中, FindControl) 对于链接的控件,它返回一些东西。但是当它返回主要形式时,它返回 nil。我无法进行更深入的调试,因为它只是转到一个属性(或类似的东西)。 好吧,这就是问题的关键所在。 FindControl 返回nil 是没有帮助出现的原因。问题是为什么会这样。下一步是查看hItemHandle 是什么并尝试识别它。我会使用 Spy++ 来调试它的那一部分。 【参考方案1】:

根据您的 cmets,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。)

以上是关于将帮助文件链接到 Delphi XE2 应用程序 - 除主窗体外一切正常的主要内容,如果未能解决你的问题,请参考以下文章

新的 Delphi XE2 自动生成的内部版本号是不是链接到 1.1.2000 00:00:00?

Delphi XE2:跳到 CHM 中的锚点?

如何使用Delphi XE2覆盖WSDL中的服务名称?

让Delphi XE2程序支持UAC

Delphi TADOStoredProc / D6 和 RAD Studio XE2 最近的故障

尝试从 VS2013 C# 程序调用 DELPHI XE2 DLL 时出错