首页  编辑  

编译CHM文件

Tags: /超级猛料/API.Windows应用程序接口/未公开的API/   Date Created:

编译CHM文件

HHA_CompileHHP正确声明:

type

 PCallBack = ^TCallBack;

 TCallBack = procedure(AMessage:PChar);

 function HHA_CompileHHP(AFileName:PChar;AMessage,AStatus:PCallBack;Reserve:Integer=0):boolean;stdcall;

// 以下两个都可以编译CHM文件!

function CompileHHP(pszHhpFile: PCHAR; pLogString: Pointer; pProgress: Pointer):bool;stdcall;external 'hhc.dll';

function HHA_CompileHHP(pszHhpFile: PCHAR; pLogString: Pointer; pProgress: Pointer; Reserve: Integer=0):bool;stdcall;external 'hha.dll';

如果要合并CHM文件,一种方式是针对多个CHM文件生成一个总的索引,这个索引中管理了所有的CHM文件,可以支持全文检索,目录结构;另外一种方式是反编译CHM,然后把所有的反编译的CHM文件的结果文件重新编译一次,生成新CHM文件。第一种方式速度快,但缺点是必须分发新的CHM文件和老的CHM文件,第二种方式优点是只要分发一个文件,可以独立原来的chm文件,缺点是速度慢。

采用第一个方式合并CHM的时候,需要从每个CHM中抽取其hhc文件名并用Merge方式合并到新的hhc当中,请参考附件的hhc和hhp文件。

下面的代码可以抽取CHM中的HHC文件名:

function ExtractHHCFileNameFromCHM(const CHMFileName: string): string;

var

 ItsStorage: IItsStorage;

 storage: IStorage;

 Stream: IStream;

 Positon, Size: Largeint;

 R : LongInt;

 Buff: PChar;

 p : PChar;

begin

 // [2007-2-13]Kingron: 创建流对象

 OleCheck(CoCreateInstance(CLSID_ITStorage, nil, CLSCTX_INPROC_SERVER, IID_ITStorage, ItsStorage));

 OleCheck(ItsStorage.StgOpenStorage(PWideChar(WideString(CHMFileName)), nil, STGM_READ or STGM_SHARE_DENY_WRITE, nil, 0, storage));

 OleCheck(Storage.OpenStream('#STRINGS', nil, STGM_READ or STGM_SHARE_EXCLUSIVE, 0, Stream));

 // [2007-2-13]Kingron: 提取#STRINGS整个数据的大小

 Stream.Seek(0, soFromEnd, Positon);

 Size := Positon;

 // [2007-2-13]Kingron: 重新定位到开头

 Stream.Seek(0, soFromBeginning, Positon);

 // [2007-2-13]Kingron: 申请内存并读取到缓冲区

 GetMem(Buff, Size);

 try

   Stream.Read(PChar(Buff), Size, @R);

   // [2007-2-13]Kingron: 提取HHC信息,HHC是第3个字符串

   R := 0;

   p := Buff;

   while R < 3 do

   begin

     if p^ = #0 then Inc(R);

     Inc(P);

   end;

   Result := StrPas(p);

 finally

   FreeMem(Buff);

 end;

end;

这个单元用于编译HHP文件。

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, 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.

一个典型的 单文件 hhp 文件如下:

[OPTIONS]

Compatibility=1.1

Display compile progress=No

Language=Language=0x804 中文(中国)

Default Window=win

Compiled file=projectname.chm

Binary Index=No

Default topic=test.htm

Error log file=Errlog.txt

[WINDOWS]

win="projectname",,,"test.htm","test.htm",,,,,0x040120,,0x304E,[0,0,800,580],0x0,0x0,,,,,

[FILES]

test.htm

##out1.hhc (0.9KB)
Microsoft's HTML Help (_chm) format.htm (13.9KB)
chm-spec.zip (710.0KB)
chmtools.zip (27.3KB)
delphikit.zip (31.3KB)
hhcode.zip (1.1MB)
out1.hhp (0.9KB)