zoukankan      html  css  js  c++  java
  • 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类来进行。

    代码
    /// <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)。

    代码
     /// <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(
    thisnew 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对象

    代码
    /// <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;
            }

    反编译导出类主要方法

    代码
    /// <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(中级篇)

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

  • 相关阅读:
    ASP.NET中常用的26个优化性能方法(转)
    代码整洁
    【在开发中常用的UI控件】
    【加法计算器--结果label不显示加值】
    【点击textfield的时候不出现键盘】
    【XCODE上的项目运行到模拟器上是一片空白】
    【xcode commit失败 please tell me who you are】
    【storyboard 上没有箭头的解决办法】
    【ios模拟器上没 home键,怎么返回的?】
    【这是一个JAVA开发者的博客~】
  • 原文地址:https://www.cnblogs.com/cxd4321/p/2201693.html
Copyright © 2011-2022 走看看