自動化是基於 COM/DCOM 的技術,讓一個應用程式(自動化客戶端)控制另一個應用程式(自動化伺服器)的物件,使用其提供的豐富功能。Microsoft Office 套件成員(Word、Excel、PowerPoint)皆為自動化伺服器。
| 角色 | 說明 | 範例 |
|---|---|---|
| 自動化伺服器 | 提供物件、方法、屬性供他人使用 | Word.Application、Excel.Application |
| 自動化客戶端 | 使用伺服器提供的物件、方法、屬性 | 我們的 VC++ 程式 |
| IDispatch 介面 | 通用介面,支援晚期綁定,跨語言呼叫 | 所有自動化物件皆實作此介面 |
msword9.h、msword9.cpp
// 主要類別對應
_Application → Word 應用程式
_Document → 文件物件
_Selection → 選取範圍
Documents → 文件集合
自動化參數傳遞使用 VARIANT,MFC 提供 COleVariant 包裝:
// 常用建構式
COleVariant vtOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); // 選擇性參數
COleVariant vtTrue((short)TRUE); // 布林值
COleVariant vtFalse((short)FALSE);
COleVariant vtFileName("C:\\Test.doc"); // 字串
COleVariant vtIndex(1); // 數值
CEditView(內建編輯控件)msword9.h
// WordAutomation.cpp
#include "stdafx.h"
#include "WordAutomation.h"
#include "msword9.h" // 類別向導產生的包裝類別
void CWordAutomationView::OnFileOpenWord()
{
CFileDialog dlg(TRUE, _T("doc"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
_T("Word 文件 (*.doc)|*.doc|所有檔案 (*.*)|*.*||"));
if (dlg.DoModal() != IDOK) return;
CString strFile = dlg.GetPathName();
ExtractWordContent(strFile);
}
void CWordAutomationView::ExtractWordContent(LPCTSTR lpszFilePath)
{
_Application wordApp; // Word 應用程式物件
_Document wordDoc; // 文件物件
_Selection wordSel; // 選取範圍物件
COleVariant vtOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
COleVariant vtFalse((short)FALSE);
COleVariant vtTrue((short)TRUE);
try {
// 1. 啟動 Word (若已執行則連接現有實例)
if (!wordApp.CreateDispatch(_T("Word.Application"))) {
AfxMessageBox(_T("無法啟動 Word!"));
return;
}
// 可見性設定(背景處理設為 FALSE)
wordApp.SetVisible(FALSE);
// 2. 開啟文件
COleVariant vtFile(lpszFilePath);
COleVariant vtConfirm(FALSE), vtReadOnly(FALSE), vtAddRecent(FALSE);
COleVariant vtPwdDoc, vtPwdTmpl, vtRevert(FALSE), vtWritePwdDoc, vtWritePwdTmpl;
COleVariant vtFormat((short)wdOpenFormatAuto);
wordDoc = wordApp.GetDocuments().Open(
vtFile, vtConfirm, vtReadOnly, vtAddRecent,
vtPwdDoc, vtPwdTmpl, vtRevert,
vtWritePwdDoc, vtWritePwdTmpl, vtFormat);
// 3. 全選內容
wordSel = wordApp.GetSelection();
wordSel.WholeStory(); // 等同 Ctrl+A
// 4. 複製到剪貼簿
wordSel.Copy();
// 5. 關閉文件(不儲存)
wordDoc.Close(vtFalse, vtOptional, vtOptional);
// 6. 退出 Word
wordApp.Quit(vtFalse, vtOptional, vtOptional);
// 7. 從剪貼簿取得內容並顯示
PasteFromClipboard();
} catch (COleException* e) {
TCHAR szErr[256];
e->GetErrorMessage(szErr, 255);
AfxMessageBox(CString(_T("OLE 錯誤:")) + szErr);
e->Delete();
} catch (CMemoryException* e) {
AfxMessageBox(_T("記憶體不足!"));
e->Delete();
} catch (...) {
AfxMessageBox(_T("未知錯誤!"));
}
}
void CWordAutomationView::PasteFromClipboard()
{
// 確保為 CEditView
CEditView* pView = DYNAMIC_DOWNCAST(CEditView, this);
if (pView) {
// 貼上剪貼簿內容到編輯控件
pView->OnEditPaste();
}
}
Word 內建 VBA 編輯器可錄製巨集,產生的程式碼直接對應自動化物件模型:
Macro1),開始錄製
Sub Macro1()
Documents.Open FileName:="Test.doc", ConfirmConversions:=False, _
ReadOnly:=False, AddToRecentFiles:=False, PasswordDocument:="", _
PasswordTemplate:="", Revert:=False, WritePasswordDocument:="", _
WritePasswordTemplate:="", Format:=wdOpenFormatAuto
Selection.WholeStory
Selection.Copy
End Sub
對應物件:Documents、Selection → VC++ 中為 wordApp.GetDocuments()、wordApp.GetSelection()
wordSel.GetFind().ClearFormatting();
wordSel.GetFind().GetReplacement().ClearFormatting();
wordSel.GetFind().Execute(
COleVariant(_T("舊文字")), // FindWhat
vtOptional, vtOptional, vtOptional, vtOptional, vtOptional,
vtOptional, vtOptional, vtOptional,
COleVariant(_T("新文字")), // ReplaceWith
COleVariant((short)wdReplaceAll) // Replace
);
COleVariant vtRange = wordSel.GetRange();
wordDoc.GetTables().Add(vtRange, 3, 4, vtOptional, vtOptional);
// 取得表格並填入資料
_Table table = wordDoc.GetTables().Item(1);
table.Cell(1, 1).GetRange().SetText(_T("標題1"));
table.Cell(1, 2).GetRange().SetText(_T("標題2"));
COleVariant vtSaveAs(_T("C:\\Output.html"));
COleVariant vtFormat((short)wdFormatHTML);
wordDoc.SaveAs(vtSaveAs, vtFormat, vtOptional, vtOptional,
vtOptional, vtOptional, vtOptional, vtOptional,
vtOptional, vtOptional, vtOptional, vtOptional,
vtOptional, vtOptional, vtOptional, vtOptional);
wordDoc.MailMerge().OpenDataSource(
COleVariant(_T("C:\\Data.xlsx")), vtOptional, vtOptional,
vtOptional, vtOptional, vtOptional, vtOptional,
COleVariant(_T("Sheet1$")), vtOptional, vtOptional);
wordDoc.MailMerge().Destination = wdSendToNewDocument;
wordDoc.MailMerge().Execute(vtOptional);
| 問題 | 原因 | 解決 |
|---|---|---|
| CreateDispatch 失敗 | Word 未安裝、ProgID 錯誤、權限不足 | 檢查註冊表 HKEY_CLASSES_ROOT\Word.Application、以管理員執行、修復 Office |
| 參數錯誤 (DISP_E_TYPEMISMATCH) | VARIANT 類型不匹配 | 嚴格對應 VBA 參數類型、使用正確 VT_* 常數 |
| 執行緒模型不匹配 | STA/MTA 不一致 | AfxOleInit() 初始化、確保主執行緒為 STA |
| Word 進程殘留 | 例外發生時未正確 Quit | 使用 try/catch/finally 確保釋放、或用智慧指標包裝 |
| 中文亂碼 | 字碼頁不匹配 | 設定 COleVariant 使用 VT_BSTR、確保專案為 Unicode |
_Application 指標wordApp.SetVisible(FALSE) 並停用螢幕更新 wordApp.SetScreenUpdating(FALSE)Word.Application 無版本 ProgID,或透過註冊表偵測安裝版本wordApp.SetAutomationSecurity(msoAutomationSecurityForceDisable)VC++ 透過自動化技術操作 Word 2000,核心在於:理解 COM/IDispatch 機制、善用類別向導產生包裝類別、參考 VBA 巨集探索物件模型、正確處理 VARIANT 參數與例外。掌握此技術可構建強大的文件處理、報表生成、格式轉換等企業級應用。