编译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