C#生成CHM文件(中级篇)
在上篇《C#生成CHM文件(入門篇)》中,我們利用微軟自帶的hhc.exe以編程的方式創建一個CHM文件,而且調用的是一個靜態的HMTL文件。
?
在中篇中,實現以下幾個目標
?1.將在線的網頁保存為CHM文件
?2.我們將對我們進行編譯的CHM文件進行反編譯,使用的還是微軟自帶的一個exe(hh.exe)。
?3.以編程的方式將CHM文件轉換為Word
?
在中篇中,把界面稍微調整了下,如下圖
?
?
一、將在線的網頁保存為CHM文件
?曾嘗試直接使用網址來編譯html文件,結果一直報錯,于是就放棄了。現在實現的方法的思想是這樣的:先將輸入的url地址的網頁保存到本地,然后利用上一篇中的方法生成CHM文件。不過經測試,這樣的效率還是比較低的,主要的花費在將htm文件下載到本地,如果帶寬不夠的話,將會很慢,不過總歸是種方法,大家如果有更好的解決方案,希望能告訴我。
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(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對象
?
代碼 ///?<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(中級篇)
?
在下篇(應用篇)中,我將說說如何將這些技術運用到實際中。
總結
以上是生活随笔為你收集整理的C#生成CHM文件(中级篇)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VTP冗余网络试验
- 下一篇: 网银安全恐慌“后遗症”凸显 肉鸡检测器下