在季老大的帮助下完美解决了BCB6/Delphi7下调用CHM帮助的问题,把实现过程写下来,同时散分!!!

yifei1900 2005-09-01 04:29:57
本文主要讲解如何在C++Builder6.0及之前的版本中使用Microsoft的新型帮助:"CHM格式帮助文件",对于如何制作CHM格式帮助,以及如何获取帮助文件制作工具,本文只会一笔带过,给出官方链接或推荐其它这方面好的教程,就不再赘述。

  CHM格式帮助文件制作工具
  需要Microsoft的html help workshop来制作CHM格式的帮助,可以到Microsoft站点下载:
  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/htmlhelp/html/hwMicrosoftHTMLHelpDownloads.asp
  好的CHM帮助制作教程
  学习如何制作CHM格式帮助文档,请参考:
  Html Help Sample in Delphi[卡夫].chm  作者:卡夫[cgcalf@263.net]
  跟我学HtmlHelp Workshop[冯惠军][石家庄铁道学院].chm  作者:冯惠军[石家庄铁道学院]
  如果想了解更多关于Microsoft Html Help的知识,可以查阅:
  Microsoft Html Help Docs.zip  Microsoft官方文档
  更好的是直接在线查阅Microsoft的官方文档,到MSDN搜索关键字:"html help",可以搜索到很多关于Microsoft html help的内容,有最新的html workshop下载、在线API手册、制作帮助文件示例等等。

  到这里,我假设读者已经安装了Microsoft html help workshop,且已掌握如何制作CHM格式帮助文件。
  本文中程序中调用的示例帮助文件包含四个主题,这四个主题的源代码如下:
  1001.htm
  <html>
  <head>
  <title>第一个主题</title>
  </head>
  <body>
  <p>第一个主题</p>
  </body>
  </html>
  
  1002.htm
  <html>
  <head>
  <title>第二个主题</title>
  </head>
  <body>
  <p>第二个主题</p>
  </body>
  </html>
  
  1003.htm
  <html>
  <head>
  <title>第三个主题</title>
  </head>
  <body>
  <p>第三个主题</p>
  </body>
  </html>
  
  1004.htm
  <html>
  <head>
  <title>第四个主题</title>
  </head>
  <body>
  <p>第四个主题</p>
  </body>
  </html>

  添加索引“第一个主题”、“第二个主题”、“第三个主题”、“第四个主题”,添加搜索关键定“第一个主题”、“第二个主题”、“第三个主题”、“第四个主题”,制作好CHM帮助文件。下一步的工作,是添加此帮助文件对程序UI界面的上下文敏感关系。方法如下:
  用文本编辑器写一个.h文件(头文件,CHM编译器需要用它),文件名任意,内容如下:
  #define 第一个主题 1001
  #define 第二个主题 1002
  #define 第三个主题 1003
  #define 第四个主题 1004
  即把主题“第一个主题”定义为一个数字1001...,向CHM工程文件中添加这个.h文件,方法如下:
  (1).打开HTML HELP WorkShop,打开刚才这个CHM工程,在Project页面上左侧,点击第四个按钮“HtmlHelp API information”,在弹出的界面上点击“Alias”,添加主主题的别名,添加“第一个主题”对应html文件1001.htm...;
  (2).在刚才的“HtmlHelp API Information”弹出界面上点击“Map”,点击右侧第一个按钮“Head Files”,选择“include”刚才制作的那个.h文件
  (3).重新编译CHM工程,生成的文件就是满足要求的有上下文敏感关系的CHM帮助文件了。
  测试一下您的CHM格式帮助文件是否正确,点击HTML HELP WorkShop的“Text”->“HTMLHelp API”,在弹出的界面上,浏览刚才生成的CHM文件,“Command”选择“HH_HELP_CONTEXT”,第二个参数“Window”默认,第三个参数“Map Numbers”,输入那个.h文件中定义的数字,点击确定,就会打开这个CHM文件并激活相关的主题了。

  到这为止,已经成功了一半,我们已经用HTML HELP WorkShop制作出了上下文敏感的CHM格式帮助,下一步的重点是在C++Builder和Delphi中来调用这个上下文敏感的CHM帮助文件。
  早期的Windows中,Microsoft 为其设计了一套API,用于Windows Help系统,一直到Windows XP SP2仍然保留这套API,它的问题是,只能表现文字等简单内容,不能象HTML而那样表现丰富的内容。因此,Microsoft在1998年推出了全新一代的帮助系统:Compiled Help Manual,将HTML文件编译和压缩,提供了WEB页一样的丰富的表现力,停止了对旧的Windows Help的开发。
  Borland C++ Builder 6.0/Delphi7.0及之间的版本的用户手册等资源都是旧的Windows Help的,而VCL也只提供了对旧的Windows Help的支持,在当今WEB流行的今天,如果你的软件还用旧的Windows Help,未免有些老土吧!
  我搜索了大量的网络资源并在季老大的帮助下,完美解决了在C++Builder6.0/Delphi7.0及以前版本中使用上下文敏感的CHM格式帮助的方法。
  VCL默认支持旧的上下文敏感的Windows Help,通过设置控件的HelpContext值来指定与控件相关的帮助主题,如果Application收到WM_HELP消息,就会解析WM_HELP消息中的HelpContext,调用Windows Help,显示相关的主题,因此,调用CHM格式帮助时,我们也需要设置相应控件的HelpContext(值就是上面定义的.h文件中的与主题相关的数值),我们需要截获发到程序中的WM_HELP消息,分析HelpContext,并调用我们自己制作的CHM帮助,一切就完成了。但是事实却没有这么简单。
  (1).HTML Help的API都封装在hhctrl.ocx库中(Windows 98及以后的Windows系统安装这一个库),因此,我们使用Borland开发工具中的导入工具implib.exe即可以导入这个库的静态版本:implib hhctrl.lib hhctrl.dll,把这个静态库添加到我们的工程中,在我们的程序中添加htmlhelp.h头文件(Borland开发工具已包含这个头文件),即可以调用HELP Help的API了;
  (2).VCL构架的应用程序在以下三种方式中收到WM_HELP消息:在主菜单及其菜单项上按F1、在窗体元素上按F1、在弹出的PopupMenu上按F1,第一种和第二种情况下的消息很容易截取,但是第三种情况却比较特殊,VCL对PopupMenu消息的处理比较特殊,它封装了一个不可见的窗体PopupList->Window来统一管理弹出菜单的消息,十分感激季老大,我才截取了第三种方式的WM_HELP消息。

  实现的细节如下:
  在上述的第一种和第二种方式的WM_HELP消息来源,只要自定义一个WM_HELP消息处理句柄即可,然后根据菜单消息还是其它控件消息来分开处理;
  对于上述第三种WM_HELP消息来源,需要在程序运行时重设PopupList->Window的窗体函数,并在程序退出还原,然后在自己定义的这个窗体函数中处理WM_HELP消息。
...全文
565 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
zhaoli_824 2005-09-11
  • 打赏
  • 举报
回复
哈我的CB没有问题~~ 我来拿分
yifei1900 2005-09-03
  • 打赏
  • 举报
回复
老宋,是我,呵呵
constantine 2005-09-02
  • 打赏
  • 举报
回复
把例子文章放到ccrun那里也不错
netsys2 2005-09-02
  • 打赏
  • 举报
回复
很好嘛,建议结题后放入FAQ。

Javpp 2005-09-02
  • 打赏
  • 举报
回复
加俊???!!!

是不是?
LngDotin 2005-09-02
  • 打赏
  • 举报
回复
jf
leonatcs 2005-09-02
  • 打赏
  • 举报
回复
解决问题之后总结一下,应该是CSDN大力提倡的。
ccrun.com 2005-09-02
  • 打赏
  • 举报
回复
已经转载到偶的站点上了。呵呵。
zjsyw 2005-09-02
  • 打赏
  • 举报
回复
楼主乐于助人,很好,顶
myredsun 2005-09-01
  • 打赏
  • 举报
回复
来接分的,支持共享只是经验
yifei1900 2005-09-01
  • 打赏
  • 举报
回复
谢谢各位捧场,
小弟以后倍加努力!
constantine 2005-09-01
  • 打赏
  • 举报
回复
恭喜+支持
我不懂电脑 2005-09-01
  • 打赏
  • 举报
回复
祝贺
cimgg 2005-09-01
  • 打赏
  • 举报
回复
不错,发表文章要是都能这样就好了,多谢了。顺便在老菜的指引下接点分:)
hdwong 2005-09-01
  • 打赏
  • 举报
回复
顶!JF
yifei1900 2005-09-01
  • 打赏
  • 举报
回复
这么多星星,
多谢捧场 :)
amvivian 2005-09-01
  • 打赏
  • 举报
回复
up
samchoy 2005-09-01
  • 打赏
  • 举报
回复
顶一下
ccrun.com 2005-09-01
  • 打赏
  • 举报
回复
支持一下。呵呵。
yifei1900 2005-09-01
  • 打赏
  • 举报
回复
//-------------------------------MainFormUnit.cpp----------------------------
  // 作者:yifei
  // 日期:2005-08-31
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "htmlhelp.h"
#include "MainFormUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

TMainForm *MainForm;
static FARPROC OldMenuProc=NULL; //保存旧的弹出菜单处理函数

// NewMenuProc 为新的消息处理函数--新的PopupList->Window的窗体函数
static long CALLBACK NewMenuProc(HWND hwnd,UINT uMsg, WPARAM wParam, LPARAM lParam);
//---------------------------------------------------------------------------
__fastcall TMainForm::TMainForm(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::MyHelp(Messages::TMessage &Message)
{
HELPINFO *HI = (HELPINFO*)Message.LParam;
TWinControl *WC;
TMenuItem *MI;
TMenu *Menu;
    //主菜单上传来的WM_HELP消息
if(HI->iContextType == HELPINFO_MENUITEM) {
for(int i=0;i<this->ComponentCount;i++) {
Menu = dynamic_cast<TMenu*>(this->Components[i]);
if(Menu != NULL) {
MI = Menu->FindItem(HI->iCtrlId,fkCommand);
if(MI != NULL) {
break;
}
}
}

if(MI != NULL && MI->HelpContext != 0) {
HtmlHelp(this->Handle,Application->HelpFile.c_str(),HH_HELP_CONTEXT,MI->HelpContext);
} else {
HtmlHelp(this->Handle,Application->HelpFile.c_str(),HH_DISPLAY_TOPIC,0);
}
    //活动控件上传来的WM_HELP消息
} else {
WC = FindControl(HI->hItemHandle);
if(WC != NULL && WC->HelpContext != 0) {
HtmlHelp(this->Handle,Application->HelpFile.c_str(),HH_HELP_CONTEXT,WC->HelpContext);
} else {
HtmlHelp(this->Handle,Application->HelpFile.c_str(),HH_DISPLAY_TOPIC,0);
}
}
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ActionCloseExecute(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
/**
if(dynamic_cast<TCustomEdit*>(Sender) != NULL) {
ShowMessage("这个按钮是TControl类的子类");
}
*/
void __fastcall TMainForm::ActionHelpExecute(TObject *Sender)
{
HtmlHelp(this->Handle,Application->HelpFile.c_str(),HH_DISPLAY_TOPIC,0);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FormClose(TObject *Sender, TCloseAction &Action)
{
// 还原 PopupList 的消息处理函数,必须要还原,否则会有问题
::SetWindowLong(PopupList->Window, GWL_WNDPROC, (long)OldMenuProc);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FormCreate(TObject *Sender)
{
// 更改 PopupList 的消息处理函数并保存旧的PopupList的消息处理函数
OldMenuProc = (FARPROC)::SetWindowLong(PopupList->Window, GWL_WNDPROC,(long)NewMenuProc);
}
//---------------------------------------------------------------------------
static long CALLBACK NewMenuProc(HWND hwnd,UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int n;
int ContextID;
TMenu* PopMenu;
TMenuItem* MenuItem;
    //如果消息不是WM_HELP,直接使用CallWindowProc 这个API把消息传递到旧的消息处理函数中处理
if (uMsg != WM_HELP)
return ::CallWindowProc(OldMenuProc,
hwnd, uMsg, wParam, lParam);

HELPINFO* phi = (HELPINFO*)lParam;
for(n=0; n<PopupList->Count; n++) {
PopMenu = (TMenu*)PopupList->Items[n];
if (phi->hItemHandle == PopMenu->Handle)
MenuItem = PopMenu->Items; //无SubMenu情况
else
MenuItem = ((TPopupMenu*)PopMenu)->
FindItem((int)phi->hItemHandle,
fkHandle); //有SubMenu的情况
if (MenuItem != NULL) {
ContextID = PopMenu->GetHelpContext(
phi->iCtrlId, true); //iCtrlId保存TMenuItem的Command
if (ContextID == 0)
ContextID = PopMenu->GetHelpContext(
(int)phi->hItemHandle, false);
if (Screen->ActiveForm==NULL) break;
if (ContextID == 0)
ContextID = Screen->ActiveForm->
HelpContext;
// 这儿弹出 ContextID 的帮助信息
if(ContextID != 0) {
HtmlHelp(hwnd,Application->HelpFile.c_str(),HH_HELP_CONTEXT,ContextID);
} else {
HtmlHelp(hwnd,Application->HelpFile.c_str(),HH_DISPLAY_TOPIC,0);
}
break;
}
}
return TRUE;
}
//---------------------------------------------------------------------------

解决问题的过程相关的贴子:
(1)http://community.csdn.net/Expert/TopicView.asp?id=4201850
(2)http://community.csdn.net/Expert/TopicView.asp?id=4206790

本文中提到的chm格式和zip格式的资源,可以向我来信索取:yifei1900@tom.com,源文件也可以来信索取。
如果转载本文,请保留原作者及来源,谢谢合作!
加载更多回复(1)

1,221

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧