在上篇《C#生成CHM檔案(入門篇)》中,我們利用微軟自帶的hhc.exe以程式設計的方式建立一個CHM檔案,而且調用的是一個靜态的HMTL檔案。
在中篇中,實作以下幾個目标
1.将線上的網頁儲存為CHM檔案
2.我們将對我們進行編譯的CHM檔案進行反編譯,使用的還是微軟自帶的一個exe(hh.exe)。
3.以程式設計的方式将CHM檔案轉換為Word
在中篇中,把界面稍微調整了下,如下圖
<a target="_blank" href="http://blog.51cto.com/attachment/201105/225129887.jpg"></a>
一、将線上的網頁儲存為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();
<a target="_blank" href="http://blog.51cto.com/attachment/201105/225313584.jpg"></a>
二、反編譯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>
/// <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)。
/// 添加到word中
/// <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對象
/// 建立word對象
/// <returns></returns>
public object Word()
Microsoft.Office.Interop.Word.Application WordApp;
//WordApp = new Microsoft.Office.Interop.Word.ApplicationClass();//如果是office2003和office2007用這樣方法
WordApp = new Microsoft.Office.Interop.Word.Application();//如果是office2010,使用這個方法
catch (Exception e)
WordApp = null;
return WordApp;
反編譯導出類主要方法
/// feedback about processing
public event EventHandler<ProcessFileEventArgs> ProcessFileIntoWord;//定義一個事件屬性
private WordClass withEventsField_w = new WordClass();
/// 通過這個類,我們可以轉換為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;
/// 主要函數:反編譯、導出
/// <param name="ChmFile">待反編譯的CHM檔案</param>
/// <param name="DocFile">word檔案名</param>
/// <remarks>word檔案一定不存在</remarks>
public void DecompileAndExport(string ChmFile, string DocFile)
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如圖:
<a target="_blank" href="http://blog.51cto.com/attachment/201105/225628425.jpg"></a>
效果還是不錯的,呵呵。如果你的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,就遇到了這樣的問題。
在下篇(應用篇)中,我将說說如何将這些技術運用到實際中。
<a href="http://down.51cto.com/data/2358199" target="_blank">附件:http://down.51cto.com/data/2358199</a>
本文轉自xshf12345 51CTO部落格,原文連結:http://blog.51cto.com/alexis/573999,如需轉載請自行聯系原作者