How to extract .HHC filename from .chm file.
Copyright (C) Kingon, 2007
如果要合并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;
注意处理没有HHC的情况
没有HHC,需要结合其他的数据来处理的。
CHM有一些格式,可以参考网络上面的相关文档。
推荐hhcode.zip,可以去yahoo下载相关代码,其中Example 10,就可以提取CHM中的数据,非常有用,上面的代码也是参考了它的。