當軟件開發(fā)者考慮擴展Microsoft Office時,最常想到方法就是是使用VB了。實際上,用C++和ATL擴展Office是相當容易的。
我將向你演示如何建立項目以及如何把Office插件作為COM對象注冊到Office中去。(本文用Outlook來作為插件的主程序。)
項目的建立
讓我們建立一個新的ATL項目。首先,添加一個叫著Plugin的簡單COM對象。用類向導把_IDTExtensibility2接口添加到Plugin類中。(別忘了選中IsupportErrorInfo復選框。)
類向導會把下述方法添加到Plugin類中:OnConnection、OnDisconnection、OnAddinsUpdate、
OnStartupComplete、OnBeginShutdown。本文只處理OnConnection和OnDisconnection方法。
然后,在Plugin頭文件中創(chuàng)建一個類型定義(typedef,它只是用來簡化代碼的),如下所示:
#define APPID 102
class CPlugin;
typedef IDispEventImpl<APPID, CPlugin, &DIID_ApplicationEvents,
&LIBID_Outlook,9,0> OutLookSink;
我們現(xiàn)在需要在Plugin類的繼承列表中添加OutLookSink類:
class ATL_NO_VTABLE CPlugin :
???????public IPlugin,
???????public IDispatchImpl<_IDTExtensibility2,
&__uuidof(_IDTExtensibility2),
???????????????&LIBID_AddInDesignerObjects,
/* wMajor = */ 1, /* wMinor = */ 0>,
????public OutLookSink
在Plugin.h文件中為Mso9.dll和Msoutl9.olb引入聲明,如下所示:
#import "C:\Program Files\Common Files\Designer\msaddndr.dll"
\
raw_interfaces_only, \
raw_native_types, no_namespace, named_guids, auto_search
#import "C:\Program Files\Microsoft Office\Office\mso9.dll" \
rename_namespace("Office") named_guids
#import "C:\Program Files\Microsoft \
?Office\Office\msoutl9.olb" \
rename_namespace("Outlook"), raw_interfaces_only, \
?named_guids
using namespace Office;
using namespace Outlook;
注意,你需要按照你的系統(tǒng)中的文件路徑來修正上面那些被引入文件的路徑。
你必須把Office擴展作為COM組件注冊到Office中去。Visual C++自動產(chǎn)生.rgs文件來控制COM注冊。我們將需要添加額外的項目加到.rgs文件來支持Office的自動注冊。
在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office鍵下,有若干個子鍵,每一個子鍵對應于系統(tǒng)中安裝的每一個Office應用程序。在這些鍵中有插件關鍵字(add-in
key)。
為了在Office中注冊我們的COM對象,我們需要在插件鍵中添加新鍵。在HKEY_CURRENT_USER下同樣有對應的樹來控制單個用戶的插件,而HKEY_LOCAL_MACHINE控制整個機器的插件。
下面是.rgs文件中Outlook的插件注冊碼:
HKCU
{
????NoRemove Software
????{
????????NoRemove Microsoft
????????{
????????????NoRemove
Office
????????????{
????????????????NoRemove
Outlook
????????????????{
????????????????????NoRemove
Addins
????????????????????{
????????????????????????ForceRemove
OutlookDemo.Plugin.1
????????????????????????{
????????????????????????????val
FriendlyName = s 'Outlook Plugin'
????????????????????????????val
Description = s 'An Outlook plugin'
????????????????????????????val
LoadBehavior = d 3
????????????????????????????val
CommandLineSafe = d 0
????????????????????????}
????????????????????????
????????????????????}
????????????????}
????????????}
????????}
????}
}
這套注冊項是為特定用戶注冊插件的,為了把插件設置為整個系統(tǒng)范圍之內可用,只需把HKCU改為HKLM。
LoadBehavior的值控制了主程序運行后插件的行為。為了讓主程序開始運行后插件自動運行,把LoadBehavior的值設置為3。如果想讓用戶手工載入插件,就把LoadBehavior設置為8。
如果你編譯了這個項目,你就有了一個Outlook 插件;這個插件實際上沒有做任何事,但是它的確是一個可以工作的插件。
我們現(xiàn)在向這個插件添加一些功能。首先,添加一個新的成員變量: ?????_ApplicationPtr
m_pApp; 然后設置OnConnection方法: ????STDMETHOD(OnConnection)(LPDISPATCH
Application,
??????????????????????????????????????????????????????
?????ext_ConnectMode ConnectMode,
??????????????????????????????????????????????????????
?????LPDISPATCH AddInInst,
??????????????????????????????????????????????????????
?????SAFEARRAY * * custom)
????{
?????????????HRESULT
rslt = S_OK;
?????????????try{
??????????????????m_pApp
= Application;
?????????????????
OutLookSynch::DispEventAdvise(m_pApp);
?????????????}catch(_com_error
&e){
?????????????????
OutputDebugString(e.ErrorMessage());
????????????????????????????????????rslt
= E_UNEXPECTED;????????????????
?????????????}
?????????????return
rslt;
????} 再設置與之對應的OnDisconnection方法,如下所示: ??? STDMETHOD(OnDisconnection)(ext_DisconnectMode
RemoveMode,SAFEARRAY
* * custom)
??????{
?????????????????HRESULT
rslt = S_OK;
?????????????????try{
??????????????????????
OutLookSynch::DispEventUnadvise(m_pApp);
?????????????????}catch(_com_error
&e){
??????????????????????
OutputDebugString(e.ErrorMessage());
???????????????????????rslt
= E_UNEXPECTED;
?????????????????}
?????????????????return
rslt;
????}
現(xiàn)在我們可以收到好幾種事件,例如,OnNewMail事件。得到事件的信息以及它們的ID的最好方法就是打開MSVC工具菜單上的OLE/COM觀察器(viewer)。 - 進入File菜單并選擇View Typelib。
- 瀏覽Msoutl9.olb文件。
- Scroll down ApplicationEvents的dispinterface。注意OnNewMail事件的ID號為0x0000f003.。
- 向Cplugin類添加一個叫著OnNewMail的方法。
- 建立一個Sink映射來把OnNewMail方法關聯(lián)到OnNewMail事件。
????BEGIN_SINK_MAP(CPlugin)
??????????????SINK_ENTRY_EX(APPID,
Outlook::DIID_ApplicationEvents, /
0x0000f003, OnNewMail)
????END_SINK_MAP() 現(xiàn)在我們只需要完成OnNewMail事件處理函數(shù)了。 ????void _stdcall OnNewMail(){
???????????MessageBox(NULL,
"New Mail", NULL, MB_OK);
????} 如果你想消除這些討厭的彈出式對話框(由該項目所創(chuàng)建),那么最簡單方法就是遵循下面的步驟: - 進入Outlook的Tools | Options菜單項。
- 選擇Other標簽。
- 點擊Advanced Options按鈕。
- 點擊COM 的插件按鈕。
- 選中Outlook的Plugin項并點擊Remove。
如你所見,Office的COM插件實現(xiàn)起來相對來說并不麻煩甚至可以說很輕松。創(chuàng)建一個COM Office插件最困難的計算出所有參數(shù)的初值。不過一旦你發(fā)現(xiàn)可以在OLE/COM查看器中得到這些信息,這也就不成問題了。
|