C#生成CHM文件(中级篇)

在上篇《C#生成CHM文件(入门篇)》中,我们利用微软自带的hhc.exe以编程的方式创建一个CHM文件,而且调用的是一个静态的HMTL文件。
 
在中篇中,实现以下几个目标
 1.将在线的网页保存为CHM文件
 2.我们将对我们进行编译的CHM文件进行反编译,使用的还是微软自带的一个exe(hh.exe)。
 3.以编程的方式将CHM文件转换为Word

 

在中篇中,把界面稍微调整了下,如下图

 

 

一、将在线的网页保存为CHM文件


 曾尝试直接使用网址来编译html文件,结果一直报错,于是就放弃了。现在实现的方法的思想是这样的:先将输入的url地址的网页保存到本地,然后利用上一篇中的方法生成CHM文件。不过经测试,这样的效率还是比较低的,主要的花费在将htm文件下载到本地,如果带宽不够的话,将会很慢,不过总归是种方法,大家如果有更好的解决方案,希望能告诉我。

 HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse myResp = (HttpWebResponse)myReq.GetResponse();
 StreamReader respStream = new StreamReader(myResp.GetResponseStream(), Encoding.Default);
string respStr = respStream.ReadToEnd();
respStream.Close();
FileStream fs = new FileStream(startPath+@"\test.htm"FileMode.Create, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs, Encoding.Default);
sw.Write(respStr);
sw.Close();
思路是将网页保存在本地的,startPath为项目所在路径。 大家可以以http://www.baidu.com/index.htm为例(注意要以htm或html为结尾),测试下,看看能不能正常将百度的首页保存到CHM文件中。
效果图是这样的:
 

 

 

二、反编译CHM


反编译CHM的方法同初篇中的利用Process类来进行。

 

ExpandedBlockStart.gif 代码
///   <summary>
        
///  反编译CHM文件
        
///   </summary>
        
///   <param name="CHMFile"> CHM文件名 </param>
        
///   <returns> 返回hhc文件名 </returns>
        
///   <remarks> uses the  <see cref="DecompileChm"></see></remarks>
         public   string  DecompileChm( string  CHMFile)
        {
            
string  pathDir  =  Path.GetDirectoryName(CHMFile); // 得到chm文件的绝对路径
            pathDir  =  Path.Combine(pathDir, Path.GetFileNameWithoutExtension(CHMFile));
            
return  DecompileChm(CHMFile,  ref  pathDir);
        }
        
///   <summary>
        
///  反编译CHM文件
        
///   </summary>
        
///   <param name="CHMFile"> CHM文件名 </param>
        
///   <param name="FolderToPut"> 反编译后的文件存放路径 </param>
        
///   <returns> 返回反编译后的hhc文件名 </returns>
        
///   <remarks> 使用hh.exe反编译 </remarks>
         public   string  DecompileChm( string  CHMFile,  ref   string  FolderToPut)
        {
            
if  (( ! System.IO.File.Exists(CHMFile)))
            {
                
throw   new  ArgumentException(CHMFile + " 文件不存在 " );
            }
            
if  (( ! Directory.Exists(FolderToPut)))
            {
                FolderToPut 
=  FolderToPut.Replace( "   " " _ " );
                Directory.CreateDirectory(FolderToPut);
            }
            DirectoryInfo di 
=   new  DirectoryInfo(FolderToPut);
            
if  ((di.Name.Contains( "   " )))
            {
                
throw   new  ArgumentException( " 反编译的文件夹名不能包含空格 " );
            }
            
string  strD  =   null ;
            strD 
=   "  -decompile  "   +  di.FullName  +   "   "   +  CHMFile; // 反编译命令
            Console.WriteLine(strD);
            Process p 
=  Process.Start( " hh.exe " , strD); // 调用hh.exe进行反编译

            p.WaitForExit();
            
return  Directory.GetFiles(FolderToPut,  " *.HHC " )[ 0 ];
        }

 

 

三、CHM文件转换为Word


接下来,我们来延伸下,利用反编译的文件,将CHM转换成Word文件。思路是这样的:利用反编译,得到hhc文件(hhc文件中包含htm或html文件的文件名)和一大堆web页面(如果一开始编译进去的是一大堆的话,呵呵),创建一个word文件,将html文件插入到word中,下面以实例的方式来实现。
为了方便代码管理,我创建了一个类库项目,命名为CHM2Word,里面主要实现将CHM文件反编译并将反编译的文件整合为Word。在CreateCHM项目中调用代码即可,另需要你的机器安装Office2003(对应,添加引用 ->COM->Microsoft Word 11.0 Object Library)或2007(对应,添加引用->COM->Microsoft Word 12.0 Object Library)。

 

ExpandedBlockStart.gif 代码
  ///   <summary>
        
///  添加到word中
        
///   </summary>
        
///   <param name="pathFileHHC"></param>
        
///   <param name="saveAs"></param>
         public   void  AddToWord( string  pathFileHHC,  string  saveAs)
        {
            
if  (File.Exists(saveAs))
            {
                
throw   new  Exception( " word文件已经存在! " );
            }
            Object Nothing 
=  System.Reflection.Missing.Value;
            Microsoft.Office.Interop.Word.Application wApp 
=  (Microsoft.Office.Interop.Word.Application) this .Word();
            Document wDoc 
=  wApp.Documents.Add( ref   Nothing,  ref   Nothing,  ref   Nothing,  ref   Nothing);

            
if  (wApp  ==   null )
            {
                
throw   new  Exception( " 转换失败 " );
            }

            
try
            {
                
string  dirfile  =   "" ; // 目录位置
                dirfile  =  Path.GetDirectoryName(pathFileHHC); // 目录的绝对路径
                 string [] lines  =  File.ReadAllLines(pathFileHHC); // 读取hhc所有的行,这是为了找出里面的htm或html文件

                
string  quote  =   ""   +  ( char ) 34 ;
                
long  filenumber  =   0 ;

                
// 遍历每一行
                 foreach  ( string  TextLine  in  lines)
                {
                    
string  htmFile  =   null ;

                    
if  (TextLine.IndexOf( " .html " 0 >   0   ||  TextLine.IndexOf( " .htm " 0 >   0 ) // 如果这一行里面有.htm或者html.的字符串
                    {

                        
#region  以下代码是获取htm或者html文件名

                        
int  endQuote  =   0 ;
                        
if  (TextLine.IndexOf( " .html " 0 >   0 )
                        {
                            endQuote 
=  TextLine.IndexOf(quote, TextLine.IndexOf( " .html " 0 ));
                        }
                        
else
                        {
                            endQuote 
=  TextLine.IndexOf(quote, TextLine.IndexOf( " .htm " 0 ));
                        }
                        
int  quoteLoop  =   0 ;
                        quoteLoop 
=  endQuote  -   1 ;
                        
while  (TextLine.Substring(quoteLoop,  1 !=  quote)
                        {
                            quoteLoop 
=  quoteLoop  -   1 ;
                        }
                        htmFile 
=  TextLine.Substring(quoteLoop  +   1 , endQuote  -  quoteLoop  -   1 ); // 获取html文件的名字

                        
#endregion
                        
                        
                        htmFile 
=  dirfile  +   " \\ "   +  htmFile;

                        
bool  b  =   false ; // 是否存在html文件
                         try
                        {
                            b 
=  File.Exists(htmFile);
                        }
                        
catch  (Exception ex)
                        {
                        }
                        
if  (( ! b))
                        {
                            
continue ;
                        }
                        
// 将文件插入到word中
                        wApp.Selection.InsertParagraphAfter();
                        filenumber 
+=   1 ;
                        
if  (ProcessFile  !=   null )
                        {
                            ProcessFile(
this new  ProcessFileEventArgs(htmFile, filenumber));
                        }
                        
// InsertFile参数说明
                        
// 文件名: 必选的 String. 要被插入的文件名和路径。如果没有指定路径,Word默认为当前文件夹
                        
// Range: 可选的 Object. 如果指定的文件时word, 参数为bookmark(书签). 如果文件为其他类型(如Excel工作表), 参数为指定的一个单元或区域,如 R1C1:R3C4
                        
// 确定是否转换 可选 Object.如果值为 True,则 word 应用程序将在插入非“ Word 文档”格式的文档时提示对转换进行确认。.
                        
// 链接:  可选 Object. 如果值为 True,则可用 INCLUDETEXT 域插入该文档。
                        
// 附件: 可选 Object. 为 True 时将该文件作为附件插入电子邮件消息中。
                        wApp.Selection.InsertFile(htmFile,  ref  Nothing,  ref  Nothing,  ref  Nothing,  ref  Nothing);
                        
if  ((filenumber  %   10   ==   0 ))
                            wDoc.Save();
                    }
                }
                wDoc.Save();
// 保存word
                wDoc.Close( ref  Nothing,  ref  Nothing,  ref  Nothing); // 关闭
                wApp.Quit( ref  Nothing,  ref  Nothing,  ref  Nothing); // 释放

            }
            
catch  (Exception ex)
            {
            }
            
finally // 释放对象
            {
                
if  ((wDoc  !=   null ))
                {
                    Marshal.ReleaseComObject(wDoc);
                    wDoc 
=   null ;
                }

                Marshal.ReleaseComObject(wApp);
                wApp 
=   null ;
            }
        }

 

创建word对象

 

ExpandedBlockStart.gif 代码
///   <summary>
        
///  创建word对象
        
///   </summary>
        
///   <returns></returns>
         public   object  Word()
        {
            Microsoft.Office.Interop.Word.Application WordApp;
            
try
            {
                
                
// WordApp = new Microsoft.Office.Interop.Word.ApplicationClass(); // 如果是office2003和office2007用这样方法
                WordApp  =   new  Microsoft.Office.Interop.Word.Application(); // 如果是office2010,使用这个方法
            }
            
catch  (Exception e)
            {
                WordApp 
=   null ;
            }
            
return  WordApp;
        }

 

 

反编译导出类主要方法

 

ExpandedBlockStart.gif 代码
///   <summary>
        
///  feedback about processing 
        
///   </summary>
         public   event  EventHandler < ProcessFileEventArgs >  ProcessFileIntoWord; // 定义一个事件属性
         private  WordClass withEventsField_w  =   new  WordClass();
        
///   <summary>
        
///  通过这个类,我们可以转换为word,并且把事件传给调用者
        
///   </summary>     
         public  WordClass w
        {
            
get  {  return  withEventsField_w; }
            
set
            {
                
if  (withEventsField_w  !=   null ) // 如果不为null,撤销事件
                {
                    withEventsField_w.ProcessFile 
-=  w_ProcessFile;
                }
                withEventsField_w 
=  value;
                
if  (withEventsField_w  !=   null ) // 如果不为null,注册
                {
                    withEventsField_w.ProcessFile 
+=  w_ProcessFile;
                }
            }
        }
        
///   <summary>
        
///  主要函数:反编译、导出
        
///   </summary>
        
///   <param name="ChmFile"> 待反编译的CHM文件 </param>
        
///   <param name="DocFile"> word文件名 </param>
        
///   <remarks> word文件一定不存在 </remarks>
         public   void  DecompileAndExport( string  ChmFile,  string  DocFile)
        {
            
try
            {
                Decompile d 
=   new  Decompile(); // 实例化一个反编译类
                 string  strHHC  =  d.DecompileChm(ChmFile); // 获取hhc文件
                w.AddToWord(strHHC, DocFile); // 调用word类的添加到word中方法
            }
            
catch  (System.Runtime.InteropServices.COMException ex)
            {
                
// throw new clsError("Com exception:" + ex.Message, ErrorsOcurred.ComError);
            }

        }

 

 

 

我利用刚刚生成的baidu的CHM导出的word如图:

效果还是不错的,呵呵。如果你的CHM文件大的话,导出的时间可能会比较长一些。

 

PS:
1.如果你使用的是office2003或者office2007,需要修改类库项目下的WordClass类下Word方法,因为office2010的
Microsoft.Office.Interop.Word.ApplicationClass不再提供构造方法,而是提供Microsoft.Office.Interop.Word.Application()接口


2.如果在转换的工程中,始终没有反应,可以调试下,如果出现这样的错误,“因为没有打开的文档,所以这一命令无效”。

调试中不会弹出异常,但是将鼠标放到wApp对象中,查看的会发现那样的错误,原因是因为权限不够,可以采用如下方法解决:

运行dcomcnfg打开组件服务,依次展开"组件服务"->"计算机"->"我的电脑"->"DCOM配置"

找到"Microsoft Word应用程序",右键打开属性对话框,
点击"标识"选项卡,点击"标识"标签,选择"交互式用户"(此设置可能对计算机安全存在威胁,如不设置可以解决问题就不设置,点"下列用户",把管理员的用户administrator密码....正确填写进去也行)
点击"安全"选项卡,依次把"启动和激活权限","访问权限","配置权限",都选择为自定义,然后依次点击它们的编辑,把everyone添加进去,并加入所有的权限...
OK,解决此问题!
如果你的office是2010或者你的系统版本较高的话,很有可能遇到这样的问题。我的电脑是windows7+office2010,就遇到了这样的问题。

3.在反编译和在线生成CHM的时候会生成一些临时文件,如果不及时删掉的话,会造成空间的浪费。我们自己可以写一个简单的删除程序,这个应该很简单,如果不会的,可以参考我以前项目中的代码,http://www.cnblogs.com/alexis/archive/2010/07/03/1770409.html

 

PS:汗...(2010-09-30 12:40),忘了附源代码了 C#生成CHM(中级篇)

 

在下篇(应用篇)中,我将说说如何将这些技术运用到实际中。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值