Thursday, December 09, 2004

 

Open source CHM projects

1.
在http://www.blogcn.com/user8/flier_lu/main.asp?id=1196784 中,Flier 提到编译CHM项目的API接口,原文如下

Microsoft 提供的HTML Help Workshop只支持在GUI界面或者使用其自带的HCC.exe程序编译CHM项目文件(.hpp),并不直接提供API供第三方软件使用。而实际上其CHM项目编译器的HHA.DLL中提供了名为HHA_CompileHPP的导出函数,实现了对.hpp的CHM项目文件直接进行编译,并通过两个回调函数通知用户当前编译进度。

以下为引用:

BOOL WINAPI HHA_CompileHHP(PCSTR pszHhpFile, FARPROC pLogString, FARPROC pProgress);

参数pszHhpFile传入要编译的CHM项目工程文件文件(.hhp);pLogString和pProgress分别执行两个回调函数,向用户报告当前编译进度。

以下为引用:

typedef void (CALLBACK *LOGSTRINGPROCA)(PCSTR pszMsg);
typedef BOOL (CALLBACK *PROGRESSPROCA)(PCSTR pszFile);

使用时只需要载入动态链接库HHA.DLL,并通过函数名字(HHA_CompileHHP)或序号(0x13F)获得函数入口即可。

btw: CHM的文件格式好些也被搞定了,Code Project上有一个支持Pocket PC 2003的开源CHM阅读器。

下面HHA_CompileHHP的一个Delphi移值版本:

以下为引用:

unit ChmCompiler;

interface

uses
Windows, SysUtils;

type
TChmCompileFunc = function(pszHhpFile: PChar; pLogString: Pointer; pProgress: Pointer): Bool; stdcall;

TLogMessageEvent = procedure(Msg: string) of object;
TProgressEvent = function(FileName: string): Boolean of object;

TChmCompiler = class
private
FDll: HMODULE;
FProc: TChmCompileFunc;

FOnLogMessage: TLogMessageEvent;
FOnProgress: TProgressEvent;
protected
constructor Create;
public
destructor Destroy; override;

class function Default: TChmCompiler;

function Compile(FileName: TFileName): Boolean;

property OnLogMessage: TLogMessageEvent read FOnLogMessage write FOnLogMessage;
property OnProgress: TProgressEvent read FOnProgress write FOnProgress;
end;

implementation

uses
ActiveX;

var
GChmCompiler: TChmCompiler;

procedure LogMessageFunc(pszMsg: PChar); stdcall;
begin
Assert(Assigned(GChmCompiler));

if Assigned(GChmCompiler.OnLogMessage) then
GChmCompiler.OnLogMessage(pszMsg);
end;

function ProgressFunc(pszFile: PChar): Bool; stdcall;
begin
Assert(Assigned(GChmCompiler));

if Assigned(GChmCompiler.OnProgress) then
Result := GChmCompiler.OnProgress(pszFile)
else
Result := True;
end;

{ TChmCompiler }

constructor TChmCompiler.Create;
begin
FDll := SafeLoadLibrary('HHA.DLL');

if FDll = 0 then RaiseLastOSError;

FProc := TChmCompileFunc(GetProcAddress(FDll, 'HHA_CompileHHP'));
//FProc := TChmCompileFunc(GetProcAddress(FDll, PChar($13F)));

if @FProc = nil then RaiseLastOSError;

CoInitialize(nil);
end;

destructor TChmCompiler.Destroy;
begin
CoUninitialize();

FProc := nil;

if FDll <> 0 then
Win32Check(FreeLibrary(FDll));

inherited;
end;

class function TChmCompiler.Default: TChmCompiler;
begin
if not Assigned(GChmCompiler) then
GChmCompiler := TChmCompiler.Create;

Result := GChmCompiler;
end;

function TChmCompiler.Compile(FileName: TFileName): Boolean;
var
szFileName: PChar;
LogMessageProc, ProgressProc, CompileProc: Pointer;
Ret: BOOL;
begin
szFileName := PChar(FileName);
LogMessageProc := @LogMessageFunc;
ProgressProc := @ProgressFunc;
CompileProc := @FProc;
asm
XOR EAX, EAX
PUSH EAX
MOV EAX, ProgressProc
MOV ECX, LogMessageProc
MOV EDX, szFileName;
PUSH EAX
PUSH ECX
PUSH EDX
CALL CompileProc
MOV Ret, EAX
end;
Result := Ret;
end;

initialization
GChmCompiler := nil;

finalization
if Assigned(GChmCompiler) then FreeAndNil(GChmCompiler);
end.

2.
关于CHM的制作和分解,可以参见
http://bonedaddy.net/pabs3/hhm/
http://www.speakeasy.org/~russotto/chm/
看了这个站点后,基本已经没有什么秘密啦。

3.
Jed Wing的那个也很简单
http://66.93.236.84/~jedwin/projects/chmlib/

4.
Codejock Software的A guide to MSDN Collection Integration
http://www.codejock.com/developer/article01.asp
很直白,不过使用不慎可能导致程序自动退出

5.
更进一步集成入Visual Studio .NET Help Integration Kit
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/htmlhelp/html/hwmscextendingnethelp.asp

6.
至于HPP等文件应该怎么写,看看NDoc或者别的同类产品的原代码即可

7.
Volker Bartheld写的Revisited: HtmlHelpTest and makehhp
http://www.codeguru.com/Cpp/W-P/help/html/article.php/c6505/
和Peter Boulton写的Create HTML Help Files with the HTMLHelp Helper Utility
http://www.codeguru.com/Cpp/W-P/help/html/article.php/c6509/

8.
Klaus Weisser
HtmlHelp library and example viewer
http://www.codeproject.com/csharp/HtmlHelp.asp
C#下面的,做的不错

9.
在2003-5-29的blog “CHM相关项目” 中,我们讨论了CHM文件编译和反编译的基本思想和相关开源项目。但是各位同好也发现开发中可能还是有这样那样的问题,解决这些问题的最方便途径是去下面几个地点。

10.
http://www.mshelpwiki.com/
http://www.mshelpwiki.com/index.php?page=MSHelpWiki

The MSHelpWiki is a knowledgebase of Microsoft Help-related information, initially created by the MicrosoftHelpMVPs and maintained by the Help authoring community (and you, if you want to get involved).

There are lots of great Help-related sites on the Web and we hope this will tie them all together by becoming a central location where you can search for answers. Please help contribute by sharing your knowledge, adding links to available resources, and publishing your tips and tricks.

这两个站点带有官方色彩,消息灵通,值得注意。

11.
http://helpware.net/

The Helpware Group

Welcome to the home of The Helpware Group. Here you will find support for MS HTML Help 1.x and MS Help 2.0, FrontPage and Delphi. We are based in Melbourne Australia. Enjoy the site. All comments welcome.


http://www.helpware.net/FAR/far_faq.htm
有多种常见错误的分析和解决,非常有参考价值

顺便说起gozhhu留言中提到出现Access Violation,我想最有可能是这个问题

HTML Help Workshop May Cause an Access Violation When Editing Contents File with .hhc Extension
http://support.microsoft.com/?kbid=294990

SYMPTOMS
When you are editing an HTML Help contents file with the Microsoft HTML Help Workshop, you may receive an access violation in Hhw.exe. This can occur when you are moving, adding, or deleting items through the graphical interface for editing individual items.

Also, when you are editing large content files, you can receive illegal operations error messages simular to the following:

HHW caused an invalid page fault in module HHA.DLL
-or-



HHW caused an invalid page fault in module MFC40.DLL
CAUSE
This is due to a bug in the HTML Help Workshop's memory management code.
RESOLUTION
For additional information about how to resolve this issue using the hotfix found in the Resolution section of Q304412, click the article number below to view the article in the Microsoft Knowledge Base:
304412 FIX: HTML Help Compiler May Not Compile Correctly on Japanese Windows

STATUS
Microsoft has confirmed that this is a problem in the Microsoft products that are listed at the beginning of this article.

另外,也有可能是

HH_CLOSE_ALL Bug and HH_INITIALIZE Problem:

Marcel van Brakel has uncovered a real problem with HH_CLOSE_ALL. When you call HH_CLOSE_ALL on shut down, the HH API creates another thread and sometimes does not return until after you have performed UnLoadLibrary(hhctrl.ocx). In this case the HH_CLOSE_ALL thread returns to nothing and causes an access violation.

Discussion:

Ralph Walden (x-Microsoft) describes the problem:

The switch to a background thread was done after I left (the MS help team) in order to solve a problem with Visual Studio. I knew they should have fixed Visual Studio instead of "fixing" HTML Help (which wasn't broken). I've never actually tried it, but along with that change was a hack that allowed you to call the API in a way that it would create an interface, and then you'd call the API again to release that interface. You start off with HH_INITIALIZE and end with HH_UNINITIALIZE. Another alternative would be to set the HH_GPROPID_SINGLETHREAD property to TRUE -- that might get HTML Help back onto the parent's thread.

Fix:

As described by Ralph above, you can try using the HH_INITIALIZE, HH_UNINITIALIZE commands. These are documented in the HH Workshop online help.
Call HH_CLOSE_ALL earlier. Get more space between the HH_CLOSE_ALL and your call to UnloadLibrary. In VB and Delphi you would perform the call on the Form QueryUnload _not_ on the Form Close or Destroy.
Marcel van Brakel seemed to fix it by calling Sleep(0); immediately after the call to HH_CLOSE_ALL. Again providing more time for the rogue thread to return.
More Tips:

Here is an alternative to using HH_CLOSE_ALL. What I do with my applications is keep the handle of the HH Windows when making a help call: _HHwinHwnd := htmlhelp(...) and on shutdown call:

if IsWindow(_HHwinHwnd) then
SendMessage( _HHwinHwnd, wm_close, 0, 0 );

This is 10 times faster code, and eliminates the need for HH_CLOSE_ALL completely.

Also, as programming wizard Roland Mechling points out, don't blindly call HH_CLOSE_ALL on shutdown. If a user does not have HTML Help installed then this call will crash your application. Here is safer code. Notice we are checking if HH is installed before calling HtmlHelp();

procedure HHCloseAll;
begin
If @HH.HtmlHelp <> Nil then //HH API is available
begin
HH.HtmlHelp(0, nil, HH_CLOSE_ALL, 0);
Sleep(0);
end;
end;

这后一种情况chinashandongliu 在flier大人的blog上也提了出来,我想可能是同样的原因。

12.
另外附一篇

Chm不能运行的原因及对策

作者:coolstar

,试试改文件名和所在目录为英文名称

2,在控制面板-区域和语言选项-高级 三个中文全选上

3,检查你下载的文件是否不完整或者已经受损,否则应该重新下载,试试把文件名和所在目录改成英文

4,控制面板-管理工具---服务----Help and Support
启用在此计算机上运行帮助和支持中心。如果停止服务,帮助和支持中心将不可用。如果禁用服务,任何直接依赖于此服务的服务将无法启动。
看看这个是否被关闭或禁用了,以及和它相关的服务

5,是HH.EXE的动态链接库文件受损所致。检查一下系统目录下是否有Hh.exe这个文件(如C:\Windows下),这个文件用来打开CHM文件。如果破坏,请从别的正常的XP系统下System32
文件夹下复制HHActiveX.dll、hhctrl.ocx、hhsetup.dll等三(或者两个)个文件,到你的机器上的相同下,即可解决

6,如果你确认你下载的文件没问题,系统目录下也有Hh.exe,但仍然打不开,那可能是程序所需链接库文件受损,请下载安装微软的Hhupd.exe就能解决问题。 http://www.kaoyan.com/uploads/bbs/hhupd.exe


解决关联的问题

把下面的内容保存为一个reg文件,双击导入

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\.chm]
@="chm.file"

[HKEY_CLASSES_ROOT\chm.file]
@="已编译的 HTML 帮助文件"

[HKEY_CLASSES_ROOT\chm.file\DefaultIcon]
@="C:\\WINNT\\hh.exe,0"

[HKEY_CLASSES_ROOT\chm.file\shell]

[HKEY_CLASSES_ROOT\chm.file\shell\open]

[HKEY_CLASSES_ROOT\chm.file\shell\open\command]
@="\"C:\\WINNT\\hh.exe\" %1"

Comments: Post a Comment

<< Home

This page is powered by Blogger. Isn't yours?