用VC6.0編寫Word外掛程式(Office2K、XP、03)
作者:hjphy
最近因為工作的需要,學習了一下Office外掛程式的編寫方法。在走了不少彎路以後,最後終於把編寫外掛程式的原理給搞清楚了,不敢獨享,拿出來跟大家共用一下。下面就以Word 2003為例,向大家簡單介紹一下。
第一步,利用嚮導產生一個ATL COM AppWizard的新工程。
圖1
在嚮導的第一個對話方塊中,伺服器類型選擇Dynamic Link Library(DLL),然後單擊Finish即可。
圖2
然後,選取菜單Insert->New ATL Object項,在彈出的ATL對象嚮導對話方塊中選中相應Objects對應右側的Simple Object選項,點擊下一步。
圖3
在彈出的對話方塊中ShortName中輸入相應名稱,點確定完成插入ATL對象。
圖4
這樣一個簡單的基於ATL的COM組件工程就建立成功了。
第二步,通過匯入類型庫來實現_IDTExtensibility2介面。在ClassView中的新加的類上點滑鼠右鍵,在彈出的右鍵菜單中選Implement Interface項。
圖5
在彈出的實現介面對話方塊中點擊Add Typelib
圖6
在彈出的Browse Type Libraries對話方塊中,選取Microsoft Add-in Designer(1.0)子項,點OK按鈕
圖7
在彈出的介面列表對話方塊中選中_IDTExtensibility2介面,點OK按鈕完成匯入
這樣的話,系統將會自動為你產生空的五個所需介面函數,分別是OnConnection、OnDisconnection、OnAddInsUpdate、OnStartupComplete、OnBeginShutdown。
第三步,通過上面的兩個步驟,我們的外掛程式架構已經形成,但是Office怎麼知道啟動的時候要來把我們的外掛程式Load起來呢?Office的不同組件,例如Word、Excel、Outlook等怎麼知道去Load自己的外掛程式呢?答案就是在註冊表中加入相應的索引值。開啟檔案視圖FileView—>Resource File中的rgs檔案,加入以下代碼:
HKCU{Software{Microsoft{Office{Word{Addins{''TestAddin.SimAddin''{val FriendlyName = s ''WORD Custom Addin''val Description = s ''Word Custom Addin''val LoadBehavior = d ''00000003''val CommandLineSafe = d ''00000001''}}}}}}}
以上代碼由三個需要注意的地方:
1. Office下面的那個子項代表了這個外掛程式是屬於那個組件,Word、Excel、Outlook等等。
2. Addins下面的那個子項要寫成你添加的COM組件的名字,千萬不要照著我的工程的名字照抄。
3. 所有的值兩邊加的都是單引號,而且要用英文下的單引號,不能用雙引號。
這樣一個Office外掛程式的架構才算完成,你可以在OnConnection函數中加一些測試代碼,看看有沒有執行到,如果執行成功才能繼續,否則檢查上面的步驟有沒有錯誤。
第四步,同時需要import兩個office的檔案,一個是MSO.dll,另一個是MSWORD.OLB。這兩個檔案可以在以下位置找到(具體位置與office安裝路徑有關):
C:\Program Files\Common Files\Microsoft Shared\OFFICE11
C:\Program Files\Microsoft Office\OFFICE11
然後在stdafx.h中加入如下語句:
#import "C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE11\\mso.dll"\rename_namespace("Office") named_guids,exclude("Pages")using namespace Office;#import "C:\\Program Files\\Common Files\\Microsoft Shared\\VBA\\VBA6\\VBE6EXT.olb" rename_namespace("VBE6")using namespace VBE6;#import "C:\\Program Files\\Microsoft Office\\OFFICE11\\MSWORD.OLB" rename("ExitWindows","ExitWindowsEx")#import "C:\\Program Files\\Microsoft Office\\OFFICE11\\MSWORD.OLB"\rename_namespace("Word"), raw_interfaces_only, named_guids ,exclude("Pages")using namespace Word;
加完以上代碼以後一定要編譯一下,看看是否能夠成功。引入這兩個檔案的原因,主要是為了引入一些變數類型,為後面的建立UI作準備。
最後一步,編寫代碼。在OnConnection加入如下代碼:
CComPtr < Office::_CommandBars> spCmdBars;CComQIPtr <Word::_Application> spApp(Application);ATLASSERT(spApp);HRESULT hr = spApp->get_CommandBars(&spCmdBars);if(FAILED(hr))return hr;ATLASSERT(spCmdBars);CComVariant vName("MyAddin");CComPtr <Office::CommandBar> spNewCmdBar;CComVariant vPos(1);CComVariant vTemp(VARIANT_TRUE);CComVariant vEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);spNewCmdBar = spCmdBars->Add(vName, vPos, vEmpty, vTemp);CComPtr < Office::CommandBarControls> spBarControls;spBarControls = spNewCmdBar->GetControls();ATLASSERT(spBarControls);CComVariant vToolBarType(1);CComVariant vShow(VARIANT_TRUE);CComPtr < Office::CommandBarControl> spNewBar;spNewBar = spBarControls->Add(vToolBarType, vEmpty, vEmpty, vEmpty, vShow);ATLASSERT(spNewBar);CComQIPtr < Office::_CommandBarButton> spCmdButton(spNewBar);ATLASSERT(spCmdButton);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);spCmdButton->PutStyle(Office::msoButtonIconAndCaption);hr = spCmdButton->PasteFace();if (FAILED(hr))return hr;spCmdButton->PutVisible(VARIANT_TRUE);spCmdButton->PutCaption(OLESTR("myAddin"));spCmdButton->PutEnabled(VARIANT_TRUE);spCmdButton->PutTooltipText(OLESTR("test1"));spCmdButton->PutTag(OLESTR("test1"));spNewCmdBar->PutVisible(VARIANT_TRUE);m_spCmdButton = spCmdButton;
這樣,再次開啟word,就可以看到一所示的介面效果了。
圖9
但是點擊時沒有響應,最後就讓我們來解決這個問題。
1. 在COutlookAddin繼承類中加入IDispEventSimpleImpl繼承,代碼如下:
class ATL_NO_VTABLE COutlookAddin :public CComObjectRootEx<CComSingleThreadModel>,……public IDispEventSimpleImpl<1,COutlookAddin,&__uuidof(Office::_CommandBarButtonEvents)>
2. 聲明_ATL_SINK_INFO結構回調參數資訊。在OutlookAddin.h檔案中加入下面語句:
// 按鈕事件響應資訊聲明extern _ATL_FUNC_INFO OnClickButtonInfo;
在OutlookAddin.cpp檔案中加入定義語句,如下:
// 按鈕事件響應資訊定義_ATL_FUNC_INFO OnClickButtonInfo ={CC_STDCALL,VT_EMPTY,2,{VT_DISPATCH,VT_BYREF| VT_BOOL}};
3. 加入Sink映射,如下:
EGIN_SINK_MAP(COutlookAddin)SINK_ENTRY_INFO(1, __uuidof(Office::_CommandBarButtonEvents),/*dispid*/0x01, OnClickButton1, &OnClickButtonInfo)SINK_ENTRY_INFO(2, __uuidof(Office::_CommandBarButtonEvents),/*dispid*/0x01, OnClickButton2, &OnClickButtonInfo)SINK_ENTRY_INFO(3, __uuidof(Office::_CommandBarButtonEvents),/*dispid*/0x01, OnClickMenu, &OnClickButtonInfo)END_SINK_MAP()
4. 加入事件函數。在OutlookAddin.h中加入聲明:
void __stdcall OnClickButton1(IDispatch * /*Office::_CommandBarButton**/Ctrl,VARIANT_BOOL * CancelDefault);
在OutlookAddin.cpp中加入實現:
// 工具條按鈕1點擊事件響應函數
void __stdcall CWordAddin::OnClickButton1(IDispatch */*Office::_CommandBarButton**/ Ctrl,VARIANT_BOOL * CancelDefault){MessageBox(NULL, "hello", "world", MB_OK);}
5. 最後,開啟或斷開與介面的串連。方法如下
在OnConnection介面函數的最後部分,加入下面代碼來開啟串連:
綜上所述,編寫一個簡單的office的外掛程式,其實並不難,只要按照步驟一步一步進行,肯定能成功,如果大家在使用過程中有什麼疑問,歡迎一起探討。