【问题标题】:Helpfile (*.chm) file not opening within embarcadero application帮助文件 (*.chm) 文件未在 embarcadero 应用程序中打开
【发布时间】:2019-01-24 21:26:09
【问题描述】:

问题

我正在使用 Embarcadero C++ Builder XE。 当用户按下键盘上的 F1 按钮时,我试图触发打开帮助文件 (*.chm)。 我以为我所做的一切都是正确的,但是按下 F1 时我没有得到任何响应/操作。

我做了什么:

我创建了一个 .chm 帮助文件(使用 Microsoft HTML Help Workshop)。 我已将编译后的 .chm 文件复制到应用程序目录。 我已经设置:

Application->HelpFile = "My_Help.chm";

在主窗体中,我已将 HelpFile 属性设置为相同的 .chm 文件。

在主窗体中,我包含了以下两行代码:

#include "HtmlHelpViewer.hpp"
#pragma link "HTMLHelpViewer"

令人困惑的是:几周前我有这个工作,随后“丢失”了代码:(

从那以后,当我去重新创建解决方案时,我没有成功。

还有

如果我定义了一个帮助按钮,详见此处 (embarcadero),仍然没有任何反应。

但是,如果我将以下代码附加到按钮上,则会打开帮助文件:

Application->HelpContext(0);

问题

有没有人知道为什么这以前会起作用,但现在却不起作用? 也许我过去做过一个简单的步骤但忘记了,但我已经搜索了我能找到的所有帮助(包括helpscribble),并涵盖了我看到的所有步骤。 任何帮助将不胜感激。

(我尝试在 Embarcadero 论坛上发帖,但目前这完全是浪费时间)

【问题讨论】:

  • 特别是,您在本地目录中有 CHM 文件吗?我听说 chm 和 Windows 10 更新存在一些问题。
  • 我想您会发现 CHM 存在某种安全限制。一旦您批准它,HTML 帮助文件就会成功打开。我记得有一个工作同事有这样的问题。给他们发邮件也有问题..
  • 可能取决于您在表单的帮助上下文/关键字字段中输入的内容?
  • help-info: 我已经在本地目录和其他目录中尝试过 CHM。另外,我使用的是 Windows 7,而不是 10。 JGFMK:我不知道如何检查 CHM 文件的安全限制,但如果这是可能的,那么安装我的应用程序的任何用户都将不得不跳过相同的障碍可笑。 Marco:我尝试了大约 10 种不同的 CHM 文件——我的,以及与其他应用程序一起使用的标准文件。全部:我不断回到这个事实:我让它在我的 PC 上和我的应用程序上运行 - 然后丢失了代码并试图再次这样做。
  • @garrettB 我一定忽略了“丢失的代码”部分。我的印象是您的代码有效,并且只有在升级 win 之后它才停止(在这种情况下,我的回答将是相关的)。但显然情况并非如此,所以请忽略我的回答(我删除了它)。在没有看到您的应用程序的代码/层次结构/组织的情况下,我唯一能想到的是,您要么在某处覆盖 VCL 事件,要么更有可能出现内存访问错误/泄漏覆盖 VCL 代码(过去确实发生在我身上几次导致奇怪的行为而没有抛出任何错误/异常)

标签: c++builder chm c++builder-xe helpfile


【解决方案1】:

我有帮助创作的经验,但我不是 C++ 程序员。尽管如此,我的 Windows10 PC 上还是安装了 C++ Builder 社区版。

我的 SDIForm 有以下代码 sn-p:

#include "Vcl.HTMLHelpViewer.hpp"
#pragma package(smart_init)
#pragma link "Vcl.HTMLHelpViewer"

我将 CHM 文件 (CHM-example.chm) 复制到构建目录以进行简化(Base、Debug 和 Release)。它对我有用。

我生成的 HTMLHelp 查看器窗口:

void __fastcall TSDIAppForm::Button1Click(TObject *Sender)
{
  Application->HelpContext(10000);
}
//---------------------------------------------------------------------------

void __fastcall TSDIAppForm::FormCreate(TObject *Sender)
{
  ShowMessage("The form has been created");
  Application->HelpFile = "CHM-example.chm";
}

删除上述三个目录中的 CHM 文件 (CHM-example.chm) 后,我尝试按照文档中的步骤进行操作 - 这也有效。但请注意我必须删除以下代码(见截图):

Application->HelpFile = "CHM-example.chm";

为应用程序指定主帮助文件的常用方法是使用全局应用程序对象的 HelpFile 属性。

打开项目选项对话框(项目>选项)并选择外观页面(在应用程序下)。在帮助文件选项中,指定帮助文件。单击浏览。默认情况下,应用程序帮助文件对话框仅显示扩展名为 .hlp 的文件。要指定其他类型的帮助文件,请在 Files of type 控件中选择 Any file (.) 类型。然后,您将能够选择 .CHM、.HTML 等类型的帮助文件。

此选项设置 Application.HelpFile 属性。此属性定义应用程序的主要帮助文件。当应用程序收到任何帮助处理命令时,默认情况下,它使用此帮助文件来执行帮助命令。

要为特定表单指定单独的帮助文件,您可以使用该表单的 HelpFile 属性。

【讨论】:

  • help-info.de:我认为您只是在重复我采取的步骤?我在这里没有看到任何新内容。
  • @garrettB:我的 CHM 文件 see HTMLHelp Download section 已检查上下文 ID。这可能是您的 CHM 文件中的一个问题,具体取决于您在与 context-ID 相关的 CHM 生成方面的经验(只是一个提示)。以下代码 sn-p #include "Vcl.HTMLHelpViewer.hpp" 是不同的,“它正在为我工​​作......”带有一些步骤是消息。真的丢失了很多控件的上下文相关帮助代码?
  • 我正在使用您的帮助文件,但没有成功。我总是能够通过单击按钮打开帮助文件,但现在我无法使用 F1 键打开帮助文件。您使用“Vcl.HTMLHelpViewer.hpp”指令而我使用“HTMLHelpViewer.hpp”的原因是因为我的 Embarcadero 版本(C++ XE Builder)不使用 VCL 范围名称,但在后续版本中(从 XE2 开始)HtmlHelpViewer 属于“Vcl”单元范围
【解决方案2】:

发现和解决方法

我已经有了一些发现,并且暂时想出了一个解决方法,直到我了解更多关于这个主题的信息

发现一号

如果 HelpContext 值非零且有效(即 ID 在 CHM 文件中定义),则它似乎有效。

  • 如果我输入一个非零且有效的值,则帮助文件将打开 当我按 F1 时向上(在正确的页面上)我(几乎)确定 以前用于工作的零值 - 它会打开帮助文件 第一个/默认页面

发现二

我的主要应用程序(我应该考虑过这个并在之前提到过),由一个包含大量帧的表单组成。主窗体包含一个导航菜单和一个框架支架空间,框架就像用户可以导航到的“页面”。

所以,一旦我到达 Discovery one(非零 ContextHelp 值),我注意到帮助文件在同一页面上打开,无论显示哪个框架 - 即使我为每个框架定义了不同的 HelpContext 值.

所以每一帧的 HelpContext 值似乎没有什么区别。 我想知道这是否是由于在同一位置重叠了多个帧,并且用户导航有效地涉及使一个帧可见而前一帧不可见。然而,发现三号让我不这么认为。

发现三

在其中一个框架(“页面”)上,我定义了以下组件:TGroupBox、TPanel、TStaticText、TCheckbox、TMemo 和 TButton

  • TGroupBox、TPanel 和 TStaticText 的 ContextHelp 值 组件无效。
  • TCheckbox 的 ContextHelp 值, TMemo 和 TButton 组件确实可以工作

所以看起来 ContextHelp 只适用于交互式组件——对点击做出明显响应的组件

这就是为什么我认为 ContextHelp 值永远不会适用于 TFrame 组件的原因。

发现四

我有许多在整个应用程序使用过程中动态创建和删除的弹出表单。为这些表单定义的 ContextHelp 值确实有效。

解决方法

我只为每个表单定义了非零且有效的 ContextHelp 值,包括主表单

我定义了一个工具栏菜单项(我使它不可见),并为其分配了 F1 快捷方式。现在,当按下 F1 时,首先运行此菜单的 OnClick 事件,然后调用常规的 OnHelp 处理。

在菜单的 OnClick 事件中,我确定哪个框架当前处于“活动”(可见)状态,并将所需的 ContextHelp 值分配给主窗体。然后调用常规 OnHelp 处理,并使用这个新分配的 ContextHelp 值打开所需页面上的帮助文件。

终于

我对这个解决方法相当满意,因为它要求我在一个函数中列出所有 ContextHelp 值——我本来打算为框架做的——为了清晰和易于维护。

【讨论】: