首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 操作 Word 自動化完整指南:Interop 開啟、編輯、列印與清理資源

     編輯:關於C語言

前言

雖然現代 Office 開發推薦使用 Open XML SDK 或 Office.js 增益集,但透過 COM 自動化模型 (Microsoft.Office.Interop.Word) 仍是快速原型、舊系統維護、伺服器端批次轉檔的實用選擇。本文系統整理 Word Application、Document、Range、Selection 核心物件模型,並提供完整的建立、編輯、存檔、列印、資源釋放最佳實務。

環境準備

  1. Visual Studio 專案 → 參考 → 加入參考 → COM → Microsoft Word 16.0 Object Library (版本號依安裝 Office 而異)。
  2. 引用命名空間:using Word = Microsoft.Office.Interop.Word;
  3. 專案屬性 → Build → 勾選 Allow unsafe code (非必要),Prefer 32-bit 取消勾選 (若 Office 為 64-bit)。

核心物件生命週期管理

public class WordAutomation : IDisposable
{
    private Word.Application _app;
    private Word.Document _doc;
    private bool _disposed;

    public WordApplication()
    {
        _app = new Word.Application();
        _app.Visible = false; // 批次處理建議 false,除錯時改 true
        _app.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone; // 抑制彈窗
    }

    // 建立新文件
    public void CreateNewDocument()
    {
        _doc = _app.Documents.Add(
            Template: Type.Missing,
            NewTemplate: Type.Missing,
            DocumentType: Word.WdNewDocumentType.wdNewBlankDocument,
            Visible: false);
    }

    // 開啟現有文件
    public void OpenDocument(string path)
    {
        _doc = _app.Documents.Open(
            FileName: path,
            ReadOnly: false,
            Visible: false);
    }

    // 存檔並關閉
    public void SaveAndClose(string savePath = null)
    {
        if (_doc != null)
        {
            object saveChanges = Word.WdSaveOptions.wdSaveChanges;
            object originalFormat = Word.WdOriginalFormat.wdWordDocument;
            object routeDoc = Type.Missing;

            if (!string.IsNullOrEmpty(savePath))
                _doc.SaveAs2(FileName: savePath);
            else
                _doc.Save();

            _doc.Close(ref saveChanges, ref originalFormat, ref routeDoc);
            ReleaseComObject(_doc);
            _doc = null;
        }
    }

    // 結束 Word 進程
    public void Quit()
    {
        if (_app != null)
        {
            object saveChanges = Word.WdSaveOptions.wdDoNotSaveChanges;
            _app.Quit(ref saveChanges, ref Type.Missing, ref Type.Missing);
            ReleaseComObject(_app);
            _app = null;
        }
    }

    // === 內容操作範例 ===
    public void InsertTextAtStart(string text) => _doc.Words.First.InsertBefore(text);
    public void InsertTextAtEnd(string text) => _doc.Words.Last.InsertAfter(text);

    public int GetCharacterCount() => _doc.Characters.Count;

    public void SelectAndCutRange(int start, int end)
    {
        Word.Range range = _doc.Range(start, end);
        range.Select();
        range.Cut();
    }

    public void ApplyNumberingToFirstTwoParagraphs()
    {
        if (_doc.Paragraphs.Count >= 2)
        {
            Word.ListTemplate listTemplate = _app.ListGalleries[Word.WdListGalleryType.wdNumberGallery]
                .ListTemplates[1]; // 內建編號樣板 1
            object continuePrev = true;
            _doc.Paragraphs[1].Range.ListFormat.ApplyListTemplate(listTemplate, ref continuePrev);
            _doc.Paragraphs[2].Range.ListFormat.ApplyListTemplate(listTemplate, ref continuePrev);
        }
    }

    // === COM 物件釋放 ===
    private void ReleaseComObject(object obj)
    {
        try
        {
            if (obj != null && Marshal.IsComObject(obj))
                Marshal.ReleaseComObject(obj);
        }
        catch { }
        finally { obj = null; }
    }

    public void Dispose()
    {
        if (!_disposed)
        {
            SaveAndClose();
            Quit();
            GC.Collect();
            GC.WaitForPendingFinalizers();
            _disposed = true;
        }
    }
}

關鍵物件模型說明

物件用途常用成員
ApplicationWord 應用程式本身Documents, Visible, Quit, ListGalleries, ActiveDocument
Document單一 .docx 檔案Words, Characters, Paragraphs, Sections, Tables, Save(), Close(), Range()
Range連續文字區域 (不等於選取區)Start, End, Text, InsertBefore/After, Select(), Cut(), Copy(), Paste(), ListFormat
Selection使用者目前選取區 (含游標)TypeText(), TypeParagraph(), MoveLeft/Right/Up/Down(), Font, ParagraphFormat
Words 集合文件/範圍/選取區內的單字 (含標點、段落符)Count, First, Last, Item[index]
Characters 集合逐字元集合Count, Item[index]
Paragraphs 集合段落集合Count, Item[index], Range, Format, Style
ListFormat段落編號/項目符號格式ApplyListTemplate(), RemoveNumbers(), ListLevelNumber

常見操作範例

1. 批次轉 PDF

public void ConvertToPdf(string sourcePath, string pdfPath)
{
    using (var wa = new WordAutomation())
    {
        wa.OpenDocument(sourcePath);
        wa._doc.SaveAs2(pdfPath, Word.WdSaveFormat.wdFormatPDF);
        wa.SaveAndClose();
    }
}

2. 郵件合併 (Mail Merge)

public void MailMerge(string templatePath, string outputPath, DataTable data)
{
    using (var wa = new WordAutomation())
    {
        wa.OpenDocument(templatePath);
        wa._doc.MailMerge.OpenDataSource(/* 連接字串或暫存 CSV */);
        wa._doc.MailMerge.Execute();
        wa._doc.SaveAs2(outputPath);
        wa.SaveAndClose();
    }
}

3. 插入表格並填入資料

public void InsertTable(DataTable dt)
{
    Word.Range range = _doc.Range(_doc.Content.End - 1, _doc.Content.End - 1);
    Word.Table table = _doc.Tables.Add(range, dt.Rows.Count + 1, dt.Columns.Count);
    table.Borders.Enable = 1;

    // 標題列
    for (int c = 0; c < dt.Columns.Count; c++)
        table.Cell(1, c + 1).Range.Text = dt.Columns[c].ColumnName;

    // 資料列
    for (int r = 0; r < dt.Rows.Count; r++)
        for (int c = 0; c < dt.Columns.Count; c++)
            table.Cell(r + 2, c + 1).Range.Text = dt.Rows[r][c].ToString();
}

資源洩漏防範:五大鐵律

  1. 所有 COM 物件變數用完即釋放:Marshal.ReleaseComObject(obj),不可只設 null。
  2. 避免「雙重點」語法:_app.ActiveDocument.Paragraphs[1].Range.Text = "x" 會產生兩個隱含 COM 物件 (ActiveDocument、Paragraphs) 無法釋放。應拆解為區域變數並逐一釋放。
  3. 迴圈內操作 COM 物件:每次迴圈結束呼叫 ReleaseComObject,或使用 for (int i = count; i >= 1; i--) 反向迴圈配合釋放。
  4. 關閉文件前存檔:doc.Close(SaveChanges) 避免殘留 Word 進程。
  5. 最後呼叫 GC:GC.Collect(); GC.WaitForPendingFinalizers(); 強制清理 RCW (Runtime Callable Wrapper)。

伺服器端/服務部署注意事項

  • Word 自動化 不支援 非互動式服務帳戶 (如 IIS AppPool、Windows Service) 執行,會遇到 DCOM 權限、視窗站台、授權彈窗等問題。
  • 生產環境轉檔請改用 Open XML SDK、LibreOffice headless、商用轉檔服務 (如 Aspose.Words、Docentric)。
  • 若必須用 Interop,需設定 DCOM 權限 (dcomcnfg) 允許服務帳號啟動 Word,並確保桌面互動權限。

結語

Word Interop 提供最完整的文件操作能力 (分頁、列印、郵件合併、複雜排版),但伴隨 COM 物件管理複雜度與部署限制。掌握 Range 而非 Selection 進行非 UI 操作、嚴格釋放 COM 物件、評估替代方案,是專業開發者的必修課。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved