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

使用 VC6.0 開發 Word 增益集 (Office 2000/XP/2003 通用)

     編輯:關於VC++

前言:COM 增益集架構的核心優勢

Office 應用程式透過 COM 增益集機制實現功能擴展。增益集實作 _IDTExtensibility2 介面,經由登錄機碼被宿主應用程式 (Word/Excel/Outlook) 發現並載入。相較於 VBA 巨集或 VSTO,COM 增益集具備:效能優異 (原生代碼)、版本獨立 (二進位相容)、部署靈活 (註冊即用)、安全性可控 (代碼簽章) 等優勢。本文以 VC6.0 ATL COM 專案為基礎,詳細演示 Word 2003 增益集的完整開發流程,涵蓋專案建立、介面實作、登錄部署、類型庫匯入、UI 建立 (工具列/按鈕/圖示) 以及事件處理。

開發環境與前置需求

  • Visual C++ 6.0 (SP5+ 推薦)
  • Office 2000/XP/2003 任一版本 (範例以 2003 為準)
  • Platform SDK (含 atlbase.h、atlcom.h 等)

步驟一:建立 ATL COM DLL 專案

  1. File → New → Projects → ATL COM AppWizard,專案名稱 WordAddin。
  2. 精靈第一步:Server Type 選 Dynamic Link Library (DLL),直接 Finish。

ATL COM AppWizard 專案類型選擇

步驟二:插入 ATL 簡單物件實作增益集核心類別

  1. ClassView 右鍵 → Insert → New ATL Object。
  2. Categories 選 Objects,右側選 Simple Object,Next。
  3. Short Name 輸入 Connect (自動生成 CConnect、IConnect、Connect 等)。
  4. Attributes 頁保持預設:Apartment Threading、Dual Interface、Support ISupportErrorInfo。Finish。

ATL Object Wizard Simple Object

ATL Object Wizard Names

步驟三:實作 _IDTExtensibility2 介面

  1. ClassView 中 CConnect 右鍵 → Implement Interface。
  2. 按 Add TypeLib → 選擇 Microsoft Add-in Designer 1.0 (通常在 msaddndr.dll 或 Office 安裝目錄)。
  3. 介面清單中勾選 _IDTExtensibility2,OK。

Implement Interface

Add TypeLib

Select Microsoft Add-in Designer

Select _IDTExtensibility2

精靈自動生成五個空實作:

  • OnConnection:增益集載入時呼叫,建立 UI、初始化資源。
  • OnDisconnection:卸載時呼叫,清理 UI、釋放資源。
  • OnAddInsUpdate:增益集集合變更通知。
  • OnStartupComplete:宿主啟動完成通知。
  • OnBeginShutdown:宿主開始關閉通知。

步驟四:登錄部署——讓 Word 發現增益集

編輯專案的 .rgs 登錄腳本檔案,在 HKCU 下建立鍵值:

HKCU
{
    Software
    {
        Microsoft
        {
            Office
            {
                Word
                {
                    Addins
                    {
                        'WordAddin.Connect'      // 【關鍵】ProgID:專案名.類別名
                        {
                            val FriendlyName = s 'Word Custom Addin'
                            val Description  = s 'Word Custom Addin'
                            val LoadBehavior = d '3'   // 0x03 = 載入時啟動 | 使用者手動啟動
                            val CommandLineSafe = d '1'
                        }
                    }
                }
            }
        }
    }
}

三大注意事項:

  1. Office 下的子鍵決定宿主:Word/Excel/Outlook 等。
  2. Addins 下的鍵名必須等於 ProgID (專案名.類別名),切勿照抄範例。
  3. 所有字串值與鍵名均使用單引號 (英文半形),非雙引號。

步驟五:匯入 Office 類型庫,獲得強型別介面

在 stdafx.h 加入:

// Office 核心類型庫 (命令列、命令欄等)
#import "C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE11\\mso.dll" \
    rename_namespace("Office") named_guids exclude("Pages")
using namespace Office;

// VBA 延伸類型庫 (選用,視需求)
#import "C:\\Program Files\\Common Files\\Microsoft Shared\\VBA\\VBA6\\VBE6EXT.olb" \
    rename_namespace("VBE6")
using namespace VBE6;

// Word 應用程式類型庫
#import "C:\\Program Files\\Microsoft Office\\OFFICE11\\MSWORD.OLB" \
    rename("ExitWindows", "ExitWindowsEx") \
    rename_namespace("Word") raw_interfaces_only named_guids exclude("Pages")
using namespace Word;

路徑說明:OFFICE11 對應 Office 2003;2002 為 OFFICE10,2000 為 OFFICE9。實際部署時建議使用相對路徑或環境變數。

編譯一次驗證類型庫匯入是否成功 (生成 .tlh/.tli)。

步驟六:在 OnConnection 建立自訂工具列與按鈕

STDMETHODIMP CConnect::OnConnection(IDispatch* Application, ext_ConnectMode ConnectMode,
                                     IDispatch* AddInInst, VARIANT* custom) {
    // 1. 取得 Word Application 介面
    CComQIPtr spApp(Application);
    if (!spApp) return E_FAIL;

    // 2. 取得命令欄集合
    CComPtr spCmdBars;
    HRESULT hr = spApp->get_CommandBars(&spCmdBars);
    if (FAILED(hr)) return hr;

    // 3. 建立新工具列
    CComVariant vName("MyAddinToolbar");
    CComVariant vPos(1);            // msoBarTop
    CComVariant vEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);
    CComVariant vTrue(VARIANT_TRUE);
    CComPtr spNewBar;
    spNewBar = spCmdBars->Add(vName, vPos, vEmpty, vTrue);

    // 4. 取得控制項集合並加入按鈕
    CComPtr spControls;
    spControls = spNewBar->GetControls();
    CComVariant vType(1);           // msoControlButton
    CComPtr spCtrl;
    spCtrl = spControls->Add(vType, vEmpty, vEmpty, vEmpty, vTrue);

    // 5. 轉為按鈕介面並設定屬性
    CComQIPtr spBtn(spCtrl);
    spBtn->PutStyle(Office::msoButtonIconAndCaption);
    spBtn->PutCaption(OLESTR("MyAddin"));
    spBtn->PutEnabled(VARIANT_TRUE);
    spBtn->PutTooltipText(OLESTR("測試增益集按鈕"));
    spBtn->PutTag(OLESTR("MyAddinBtn"));

    // 6. 設定按鈕圖示:從資源載入位圖 → 剪貼簿 → PasteFace
    HBITMAP hBmp = (HBITMAP)::LoadImage(_Module.GetResourceInstance(),
        MAKEINTRESOURCE(IDB_BITMAP), IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);
    ::OpenClipboard(NULL);
    ::EmptyClipboard();
    ::SetClipboardData(CF_BITMAP, (HANDLE)hBmp);
    ::CloseClipboard();
    ::DeleteObject(hBmp);
    hr = spBtn->PasteFace();
    if (FAILED(hr)) return hr;

    // 7. 顯示工具列並保存按鈕指標供事件處理使用
    spNewBar->PutVisible(VARIANT_TRUE);
    m_spCmdButton = spBtn;  // 類別成員:CComPtr m_spCmdButton;

    return S_OK;
}

Word 增益集工具列按鈕效果

步驟七:實作按鈕點擊事件 (Connection Point / Sink)

Office 按鈕事件為 _CommandBarButtonEvents 介面 (dispid 0x01 = Click)。ATL 使用 IDispEventSimpleImpl 處理發散介面事件。

1. 類別繼承鏈加入 Sink

class ATL_NO_VTABLE CConnect :
    public CComObjectRootEx,
    public CComCoClass,
    public IDispatchImpl,
    public IDispEventSimpleImpl<1, CConnect, &__uuidof(Office::_CommandBarButtonEvents)>
{
    // ...
};

2. 宣告回呼簽章資訊 (_ATL_FUNC_INFO)

在 Connect.h:

extern _ATL_FUNC_INFO OnClickInfo;

在 Connect.cpp:

_ATL_FUNC_INFO OnClickInfo = { CC_STDCALL, VT_EMPTY, 2, { VT_DISPATCH, VT_BYREF | VT_BOOL } };

3. Sink Map 映射事件

BEGIN_SINK_MAP(CConnect)
    SINK_ENTRY_INFO(1, __uuidof(Office::_CommandBarButtonEvents), 0x01, OnClickButton, &OnClickInfo)
END_SINK_MAP()

4. 實作事件處理函數

// Connect.h
void __stdcall OnClickButton(IDispatch* pDispCtrl, VARIANT_BOOL* pCancelDefault);

// Connect.cpp
void __stdcall CConnect::OnClickButton(IDispatch* /*pDispCtrl*/, VARIANT_BOOL* /*pCancelDefault*/) {
    MessageBox(NULL, _T("增益集按鈕被點擊!"), _T("WordAddin"), MB_OK | MB_ICONINFORMATION);
}

5. 建立/斷開事件連接

在 OnConnection 尾部:

// 1 是 SINK_MAP 中的 ID
DispEventAdvise(m_spCmdButton, &__uuidof(Office::_CommandBarButtonEvents));

在 OnDisconnection:


DispEventUnadvise(m_spCmdButton, &__uuidof(Office::_CommandBarButtonEvents));

步驟八:OnDisconnection 清理資源

STDMETHODIMP CConnect::OnDisconnection(ext_DisconnectMode RemoveMode, VARIANT* custom) {
    // 斷開事件
    if (m_spCmdButton) {
        DispEventUnadvise(m_spCmdButton, &__uuidof(Office::_CommandBarButtonEvents));
        m_spCmdButton.Release();
    }
    // 移除工具列 (可選,視 LoadBehavior 決定)
    return S_OK;
}

除錯與驗證技巧

  1. 註冊 DLL:編譯後執行 regsvr32 WordAddin.dll。
  2. 啟動 Word:工具列應自動出現。若未出現,檢查「工具」→「自訂」→「工具列」是否列出「MyAddinToolbar」。
  3. 附加除錯器:VC6.0 → Build → Start Debug → Attach to Process → 選擇 WINWORD.EXE,在 OnConnection 設中斷點驗證載入流程。
  4. 登錄檢查:regedit 確認 HKCU\Software\Microsoft\Office\Word\Addins\WordAddin.Connect 鍵值正確。

版本相容性說明

Office 版本類型庫路徑關鍵字ProgID 範例
Office 2000 (9.0)OFFICE9WordAddin.Connect
Office XP (10.0)OFFICE10WordAddin.Connect
Office 2003 (11.0)OFFICE11WordAddin.Connect

同一組原始碼,僅需調整 #import 路徑與註冊機碼的 Office 版本段,即可支援三個版本。建議使用安裝程式 (如 InstallShield) 自動偵測版本並寫入正確路徑。

常見坑點與解決方案

  • 按鈕無反應:未正確建立/斷開 Sink 連接,或 SINK_ENTRY_INFO 的 ID/dispid 不符。
  • 工具列不顯示:LoadBehavior 非 3,或命令欄名稱衝突,或 PutVisible(VARIANT_TRUE) 遺漏。
  • 圖示不顯示:位圖資源 ID 錯誤、未 LR_LOADMAP3DCOLORS、剪貼簿操作失敗。
  • 卸載崩潰:OnDisconnection 中未 Release 介面指標、未 Unadvise 事件、順序錯誤。
  • 多文件環境:按鈕事件的 pDispCtrl 參數可 QueryInterface 取得 _CommandBarButton,進而獲取 Parent 命令欄與宿主視窗,實現上下文感知操作。

結語

透過 ATL COM 實作 _IDTExtensibility2,配合 Office 物件模型操作命令欄與應用程式邏輯,即可構建高效能、緊密整合的 Word 增益集。本文涵蓋從專案建立、介面實作、登錄部署、類型庫匯入、UI 建構到事件處理的完整閉環,並針對版本相容與常見錯誤給出實戰方案。掌握此技術棧,可輕鬆擴展至 Excel、Outlook 等所有 Office 宿主應用。

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