Flier's Sky

天空,蓝色的天空,眼睛看不到的东西,眼睛看得到的东西
posts - 115, comments - 305, trackbacks - 42, articles - 0

编译 CHM 项目的 API 接口

Posted on 2004-07-08 10:07 Flier Lu 阅读(1874) 评论(7)  编辑 收藏 网摘
编译 CHM 项目的 API 接口

http://www.blogcn.com/user8/flier_lu/index.html?id=1196784&run=.04005F8

    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.
 



Feedback

#1楼   回复  引用    

2005-02-27 22:10 by qjh
可以用VB 或VFP写一下吗?qjhjeff@tom.com

#2楼   回复  引用    

2005-02-28 09:50 by Flier Lu[未注册用户]
抱歉,因为里面进行包装时用到了一些汇编等底层实现技术,用vb或vfp估计不好实现。如果实在要用,你可以弄个dll进行二次包装。

#3楼   回复  引用    

2005-03-29 21:35 by janrey[未注册用户]
谢谢Flyer Lu,
虽然没有拿到什么头文件,从上面的代码也已经给出了所有的信息,只是说得不够清楚,让我连续折腾了快一天了。
用C/C++实现没有问题,JNI也没问题了。其实我只是为了做了个JAVA的东西玩,平时用CHM做资料整理,但没有一个特别好的,所以就自己写一个,本来想直接用HHC.exe就完事了,这篇文章到引起了我的好奇。

不管怎么说,都是有收获的。

补充二点,一是注意那段汇编代码,调用方式比较特别,似乎是先将一个0入栈了。没时间做深的探究。二是,注意引入ActiveX的CoInitialize/CoUnInitialize,这是对COM调用环境的一个初始化。一般调用不成功都是这个原因。


不知能不能把头文件发来看看?算了,既然RDA就诚信一点吧。交个朋友。

#4楼[楼主]   回复  引用  查看    

2005-04-06 23:51 by Flier Lu      
:S 这个就是全部实际的代码了,呵呵,Delphi下面不需要头文件什么的 :P

那个汇编基本上就只是能跑而已,因为不太喜欢这种hard hack模式的编码,就懒得深究了 :S

至于 CoInitialize/CoUnInitialize 这些调用,在Delphi里面是由VCL内部自己处理了,呵呵,如果移植到其他语言则需要指定。或者有什么其他需求,可以显示调用 OleInitialize 那套 API。

#5楼   回复  引用    

2005-04-29 08:38 by sanjin@kingesoft.com[未注册用户]
楼主的HHA_CompileHHP分析有误,原型应该是:
BOOL WINAPI HHA_CompileHHP(PCSTR pszHhpFile, FARPROC pLogString, FARPROC pProgress, INT nRes);

这个nRes是保留参数,实际未用到

这也就是为什么在写那段代码时需要先将一个0入栈原因,_stdcall方式函数压栈方式参数从右向左。

任何问题欢迎到http://www.kingesoft.com

#6楼   回复  引用    

2005-06-20 10:27 by 喜欢
我关心怎样把HTML文件生成 HPP文件.

#7楼   回复  引用    

2008-02-23 16:39 by LeeB[未注册用户]
(sorry for english post!)

the optional 4th parameter sanjin mentioned actually looks like a results structure - my best guess is:

struct HHAData
{
unsigned long sizeIn; // Size of structure.
unsigned long unk1_1; // ??
unsigned long unk1_2; // ??
unsigned long unk1_3; // ??
unsigned long nTopics;
unsigned long nLocalLinks;
unsigned long nGraphics;
unsigned long nInternetLinks;
unsigned long unk3_1; // ??
unsigned long unk3_2; // ??
unsigned long unk3_3; // ??
unsigned long unk3_4; // ??
char tgtname[MAX_PATH];
};

http://www.benf.org/other/hhclite/hhc_lite.cpp

(haha now I have to add update that you beat me to it ;)



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 22288




相关文章:

相关链接: