利用COM組件實現對WORD書籤各類操做大全,看這一篇就夠了

  有個需求是,程序導出一份word報告,報告中有各類各樣的表格,導出時還須要插入圖片。web

  腦海中迅速閃過好幾種組件,openxml組件,com組件,npoi。爲了減小程序畫複雜表格,咱們選用了com組件+word模板的方式,程序只須要對word中的書籤進行賦值便可。服務器

  不知道這幾種組件的(或者還有其餘寫入word的組件能夠推薦)優缺點各是什麼,還請各路大拿評論區指點一二。app

  com組件惟一讓人不爽的就是他過於依賴word,由於版本帶來的不兼容問題,及各類會生成WORD半途會崩潰的問題.並且很難解決。ide

  不說這麼悲傷的事情了,反正坑都踩了,文章後面我會附上各類深坑的解決方案,今天主要分享的是com組件寫入word的各類操做。ui

 1.書籤賦值spa



     ///
<summary> /// 給特定書籤賦值 /// </summary> /// <param name="bookMarkName"></param> /// <param name="value"></param> public void EditTable(string bookMarkName, string value, Document doc) { try { if (!doc.Bookmarks.Exists(bookMarkName)) return; object s = bookMarkName; Range rng = doc.Bookmarks.get_Item(ref s).Range; rng.Text = value; } catch (Exception e) { KillwordProcess(); throw e; } }

2.獲取指定書籤的範圍3d


 

     /// <summary>
        /// 獲取指定書籤的Range /// </summary>
        /// <param name="bookMarkName">書籤名稱</param>
        public Range GetBookMarkRange(string bookMarkName, Document doc) { object oBookMarkName = bookMarkName; return doc.Bookmarks.get_Item(ref oBookMarkName).Range; }

3.添加書籤調試


 

/// <summary>
        /// 添加書籤 /// </summary>
        /// <param name="bookMarkName">書籤名</param>
        /// <param name="activeRange">要添加書籤的範圍</param>
        public void AddBookMark(string bookMarkName, Range activeRange, Document doc) { object oActiveRange = activeRange; doc.Bookmarks.Add(bookMarkName, ref oActiveRange); }

4.複製書籤內容到另外一個書籤日誌


 

     /// <summary>
        /// 複製書籤內容至另外一書籤 /// </summary>
        /// <param name="sourceBookMarkName">源書籤</param>
        /// <param name="toBookMarkName">目標書籤</param>
        public void CopyRange(string sourceBookMarkName, string toBookMarkName, Document doc) { object oSourceBookMarkName = sourceBookMarkName; object oToBookMarkName = toBookMarkName; Range roRange = CopyRange(doc.Bookmarks.get_Item(ref oSourceBookMarkName).Range, doc.Bookmarks.get_Item(ref oToBookMarkName).Range); doc.Bookmarks.get_Item(ref oToBookMarkName).Delete(); AddBookMark(toBookMarkName, roRange, doc); } /// <summary>
        /// 複製選定範圍內容至另外一範圍 /// </summary>
        /// <param name="sourceRange">源範圍</param>
        /// <param name="activeRange">目標範圍</param>
        public Range CopyRange(Range sourceRange, Range activeRange) { try { lock (copyLock) { sourceRange.Copy(); activeRange.Paste(); } return activeRange; } catch { KillwordProcess(); throw; } }

5.打開word文件code


 

/// <summary>
        /// 打開文件 /// </summary>
        /// <param name="Path">文件路徑及文件名</param>
        /// <param name="IsVisible">是否可見</param>
        public void OpenWord(string Path, bool IsVisible, Document doc) { object oMissing = System.Reflection.Missing.Value; GUIDCaption = Guid.NewGuid().ToString(); app.Visible = IsVisible;//是否實時預覽 app.Caption = GUIDCaption; object oPath = Path; doc = app.Documents.Open(ref oPath, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing); }

6.表格縱向合併


 

/// <summary>
        /// 縱向合併 /// </summary>
        /// <param name="bookMarkName"></param>
        /// <param name="tableIndex"></param>
        /// <param name="row_a">開始行號</param>
        /// <param name="col_a">開始列號</param>
        /// <param name="row_b">結束行號</param>
        /// <param name="col_b">結束列號</param>
        public void MergeColumnCell(string bookMarkName, int tableIndex, int row_a, int col_a, int row_b, int col_b, Document doc) { try { object oBookMarkName = bookMarkName; Range activeRange = doc.Bookmarks.get_Item(ref oBookMarkName).Range; var newTable = activeRange.Tables[tableIndex]; newTable.Cell(row_a, col_a).Merge(newTable.Cell(row_b, col_b)); } catch (Exception e) { KillwordProcess(); throw e; } }

7.插入圖片


 

 
 
    /// <summary>
        /// 插入圖片
        /// </summary>
        /// <param name="bookMarkName"></param>
        /// <param name="fileName">圖片路徑</param>
        /// <param name="type">圖片版式:四周型,嵌入型,環繞型</param>
      public void InsertPicture(string bookMarkName, string fileName, WdWrapType type)
 { try { if (!doc.Bookmarks.Exists(bookMarkName)) { return; } object oBookMarkName = bookMarkName; Microsoft.Office.Interop.Word.Range activeRange = doc.Bookmarks.get_Item(ref oBookMarkName).Range; object linkToFile = false; object saveWithDocument = true; InlineShape inlineShape = doc.InlineShapes.AddPicture(fileName, ref linkToFile, ref saveWithDocument, activeRange); inlineShape.ConvertToShape().WrapFormat.Type = type; } catch (Exception ex) { KillwordProcess(); //記錄日誌
                AppCommon.AppLogger.WriteLog("插入圖片,錯誤爲:" + ex.ToString(), ((int)AppCommon.Unitity.AppChannelEnmu.SS).ToString()); } }

 8.設置圖片大小


 

/// <summary>
        /// 設置圖片大小 /// </summary>
        /// <param name="filePath"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public string SetPicture(string filePath, int width, int height) { Bitmap bm = new Bitmap(filePath); Bitmap thumb = new Bitmap(width, height); Graphics g = Graphics.FromImage(thumb); g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.DrawImage(bm, new System.Drawing.Rectangle(0, 0, width, height), new System.Drawing.Rectangle(0, 0, bm.Width, bm.Height), GraphicsUnit.Pixel); g.Dispose(); string path = ConfigurationManager.AppSettings["MapPath"].ToString() + "/Assets/internal/img/new.png"; thumb.Save(path, System.Drawing.Imaging.ImageFormat.Png); bm.Dispose(); thumb.Dispose(); return path; }

9.書籤範圍內添加一行


 

/// <summary>
        /// 在書籤範圍內插入一行到指定表中 /// </summary>
        /// <param name="BookMarkName">書籤名稱</param>
        /// <param name="tableIndex">表的索引</param>
        /// <param name="rowIndex">插入行的位置</param>
        public void InsertRow(string bookMarkName, int tableIndex, int rowIndex) { try { if (!doc.Bookmarks.Exists(bookMarkName)) { return; } object oBookMarkName = bookMarkName; Microsoft.Office.Interop.Word.Range activeRange = doc.Bookmarks.get_Item(ref oBookMarkName).Range; InsertRow(activeRange, tableIndex, rowIndex); } catch (Exception e) { KillwordProcess(); throw e; } } /// <summary>
        /// 在所選範圍內插入一行到指定表中 /// </summary>
        /// <param name="activeRange">範圍對象</param>
        /// <param name="tableIndex">所選範圍內表的索引</param>
        /// <param name="rowIndex">插入行的位置</param>
        public void InsertRow(Microsoft.Office.Interop.Word.Range activeRange, int tableIndex, int rowIndex) { try { object NumRows = 1; activeRange.Tables[tableIndex].Rows[rowIndex].Select(); doc.ActiveWindow.Panes[1].Selection.InsertRowsBelow(ref NumRows); } catch (Exception e) { KillwordProcess(); throw e; } }

10.刪除書籤範圍內容


 

/// <summary>
        /// 刪除書籤範圍內容 /// </summary>
        /// <param name="bookMarkName">書籤名</param>
        public void DeleteBookMarkRange(string bookMarkName) { try { object oBookMarkName = bookMarkName; if (doc.Bookmarks.Exists(bookMarkName)) { DeleteRange(doc.Bookmarks.get_Item(ref oBookMarkName).Range); } } catch (Exception e) { KillwordProcess(); throw e; } } /// <summary>
        /// 刪除所選範圍內容 /// </summary>
        /// <param name="activeRange">所選範圍對象</param>
        public void DeleteRange(Range activeRange) { try { if (null != activeRange) { object oMissing = Missing.Value; activeRange.Delete(ref oMissing, ref oMissing); foreach (Table dTable in activeRange.Tables) { dTable.Delete(); } } } catch (Exception e) { KillwordProcess(); throw e; } }

11.刪除書籤範圍的行


 

/// <summary>
        /// 在書籤範圍內指定表刪除行 /// </summary>
        /// <param name="bookMarkName">書籤名稱</param>
        /// <param name="tableIndex">表索引</param>
        /// <param name="rowIndex">行號</param>
        public void DeleteRow(string bookMarkName, int tableIndex, int rowIndex) { try { object oBookMarkName = bookMarkName; if (doc.Bookmarks.Exists(bookMarkName)) { Microsoft.Office.Interop.Word.Range activeRange = doc.Bookmarks.get_Item(ref oBookMarkName).Range; DeleteRow(activeRange, tableIndex, rowIndex); } } catch (Exception e) { KillwordProcess(); throw e; } } /// <summary>
        /// 在所選範圍內指定表刪除行 /// </summary>
        /// <param name="activeRange">所選範圍對象</param>
        /// <param name="tableIndex">表索引</param>
        /// <param name="rowIndex">行號</param>
        public void DeleteRow(Microsoft.Office.Interop.Word.Range activeRange, int tableIndex, int rowIndex) { try { if (activeRange.Tables[tableIndex].Rows.Count >= rowIndex) { activeRange.Tables[tableIndex].Rows[rowIndex].Delete(); } } catch (Exception e) { KillwordProcess(); throw e; } }

12.插入分頁符


 

public static void InsertBreak(Document doc, string bookmark) { object oBookMarkName = bookmark; if (doc.Bookmarks.Exists(bookmark)) { object pBreak = (int)WdBreakType.wdPageBreak; doc.Bookmarks.get_Item(ref oBookMarkName).Range.InsertBreak(ref pBreak); } //object oBookMarkName = bookmark; //Range perRange = doc.Bookmarks.get_Item(ref oBookMarkName).Range; //object oEnd = perRange.End; //object oWdBreak = (int)WdBreakType.wdPageBreak; //doc.Range(ref oEnd, ref oEnd).InsertBreak(ref oWdBreak); //doc.Range(ref oEnd, ref oEnd).InsertParagraph();
        }

13.結束word進程

異常的時候必定要執行此方法,不然,word進程就會被遺留在內存中,後續若是繼續執行,會積累更多的進程,致使進程卡死,內存飆升。

/// <summary>
        /// 結束word進程 /// </summary>
        private void KillwordProcess() { try { Process[] myProcesses; //DateTime startTime;
                myProcesses = Process.GetProcessesByName("WINWORD"); //經過進程窗口標題判斷
                foreach (Process myProcess in myProcesses) { if (null != GUIDCaption && GUIDCaption.Length > 0 && myProcess.MainWindowTitle.Equals(GUIDCaption)) { myProcess.Kill(); } } } catch (Exception e) { AppCommon.AppLogger.WriteLog("結束Word,錯誤爲:" + e.ToString(), ((int)AppCommon.Unitity.AppChannelEnmu.SS).ToString()); throw e; } }

 14.刪除空行

這段代碼厲害了,是用來精確控制的,你能夠用它獲取到word的每一寸區域,這樣你想在哪裏寫值就在哪裏寫。下面這段代碼是用來刪除書籤範圍上方的空行的,代碼中會判斷上方是空行的區域,

若是上方區域有文字,則

iEnd爲文字所在行-1,
range.Start表示該書籤區域開頭所在的行
titleRange就是要刪除的空行區域
/// <summary>
        /// 刪除Range 上面的空行 /// </summary>
        /// <param name="range"></param>
        /// <param name="holdblank">下面保留幾個空行,默認保留一個</param>
        public void DeleteRangeUpBlankRow(Document doc, Range range, int holdblank = 1) { try { int iStart = range.Start - holdblank; int iEnd = range.Start - holdblank; object oStart = range.Start - holdblank; object oEnd = range.Start - holdblank; Range titleRange = doc.Range(ref oStart, ref oEnd); //獲取標題範圍 從表格範圍起始位置開始 每次循環範圍向前增長1
                while (true) { iStart = iStart - 1; titleRange.SetRange(iStart, iEnd); if (iStart < 0 || IsTitleRangeOver(titleRange)) { titleRange.SetRange(iStart + 1, iEnd); break; } } //刪除空行 
                object oMissing = Missing.Value; titleRange.Delete(ref oMissing, ref oMissing); } catch (Exception e) { KillwordProcess(); throw e; } } /// <summary>
/// 判斷要刪除表的標題範圍是否超出 /// </summary>
/// <param name="titleRange"></param>
/// <returns></returns>
public bool IsTitleRangeOver(Range titleRange) {   if (titleRange.Tables.Count > 0)//範圍內包含表格
  {     return true;   }   if (titleRange.Paragraphs[1].PageBreakBefore == 1)//有分頁符
  {     return true;   }   if (!string.IsNullOrEmpty(titleRange.Text.Trim()))//內容不爲空了
  {     return true;   }   return false; }
 
常見錯誤及處理方案:

1.報告生成期間異常:System.Runtime.InteropServices.COMException (0x8001010A): 消息篩選器顯示應用程序正在使用中。 (異常來自 HRESULT:0x8001010A (RPC_E_SERVERCALL_RETRYLATER))

  解決方案:出現這種錯誤有限檢查COM組件權限是否正常,檢查步驟:

(1)打開組件服務

 

 

 (2)打開DCOM配置

 

 (3)找到word97-2003

 

(4)按照如圖依次配置


(5)通常這裏咱們選擇用戶名密碼 的方式,這個密碼必須在web.Config中進行配置

<identity impersonate="true" userName="服務器登陸名" password="服務器登錄密碼" />

 

  2.System.Runtime.InteropServices.COMException (0x800A1735): 集合所要求的成員不存在。

  解決方案:這個是程序錯誤,只要調試代碼便可發現錯誤。

3.System.Runtime.InteropServices.COMException (0x800A1710): 沒法編輯 Range。

  解決方案:這個說明編輯某個區域的時候,超出了範圍,或者找不到這個區域範圍,這個也是代碼的問題,須要仔細查找,不是很好定位。

 

-------------------------------------------(正文完)-----------------------------------------------------

 

還有一些其餘的問題沒有收集,你們遇到了能夠在評論區發出來,我能幫你們解答的必定盡我所能!

 

好啦,今天的分享就到這裏……

 

向着高級,進發!

相關文章
相關標籤/搜索