Office2000下內部COM外掛的程式設計實現(之二) (轉)

worldblog發表於2007-12-13
Office2000下內部COM外掛的程式設計實現(之二) (轉)[@more@] 

在應用中,儘管選單和工具欄按鈕看上去不太一樣,但實質上它們是相同型別的。Commanars集合包含程式中的所有命令條,如:工具條和選單條。每一個CommandBars集合都有一個CommandBar物件和它對應,CommandBar 物件可以包含其它的 CommandBar 物件,這些物件是作為按鈕或選單命令來用的。每一個CommandBar都將透過CommandBarControls 物件被引用,CommandBarControls又可以包含一組CommandBarControl物件。每一個CommandBarControl可以包含一個CommandBar物件,並可以透過它來存取屬性。每一個CommandBarControl物件,實際是對應CommandBarControls中的控制元件集合。CommandBarControl可以有三種表現形式:

彈出式(CommandBopup):相當於選單條的一個選單項。

組合框(CommandBarComboBox):類似於工具條中組合框控制元件。它包括一個工具欄和緊接著工具欄的一個下拉箭頭。單擊該按鈕,將顯示出更多的帶圖示的選單命令。

按鈕(CommandBarButton)相當於標準的工具欄按鈕,即帶有圖示的按鈕。:namespace prefix = o ns = "urn:schemas--com:office:office" />

 

在下面的示例程式中,我們將在2K中新建一個工具條並在其上新增二個按鈕,並且在其選單“工具”中新建一個選單條,這些操作都可以在OnConnection介面涵數中完成。

首先,我們需要在工程中匯入Office和Outlook型別庫,可以在Stdafx.h中加入下面語句(注意:其中路徑可根據Office所裝路徑自行設定):

// 匯入工程所需Office2K及Outlook2K型別庫

#import "e:Program FilesMicrosoft OfficeOfficemso9.dll" rename_namespace("Office"), named_guids

using namespace Office;

 

#import "e:Program FilesMicrosoft OfficeOfficeMSOUTL9.olb" rename_namespace("Outlook"), raw_interfaces_only, named_guids

using namespace Outlook;

 

其次,讓我們來在Outlook中新建一個工具條,並且在其上新增兩個按鈕。

程式碼如下:

// 裝缷時處理

  STDMETHOD(OnConnection)(IDispatch * Application, ext_ConnectMode ConnectMode, IDispatch * AddInInst, SAFEARRAY * * custom)

  {

  CComPtr < Office::_CommandBars> spCmdBars;

 

  // Outlook應用介面_Application

  CComQIPtr <:_application> spApp(Application);

  SERT(spApp);

 

  // 獲取CommandBars介面

  CComPtr<:_explorer> spExplorer;  

  spApp->ActiveExplorer(&spExplorer);

  HRESULT hr = spExplorer->get_CommandBars(&spCmdBars);

  if(FAILED(hr))

  return hr;

  ATLASSERT(spCmdBars);

 

  // 新增一個工具條及其上兩個點陣圖按鈕

  CComVariant vName("新增Outlook2K工具條外掛");

  CComPtr <:commandbar> spNewCmdBar;

 

  // 新增工具條位置

  CComVariant vPos(1);

 

  CComVariant vTemp(VARIANT_TRUE); // 臨時 

  CComVariant vEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR); 

  // 用Add方法在指定位置新增一工具條並讓spNewCmdBar指向它

  spNewCmdBar = spCmdBars->Add(vName, vPos, vEmpty, vTemp);

 

  // 獲取新增工具條的CommandBarControls,從而在其上新增按鈕

  CComPtr < Office::CommandBarControls> spBarControls;

  spBarControls = spNewCmdBar->GetControls();

  ATLASSERT(spBarControls);

 

  //MsoControlType::msoControlButton = 1

  CComVariant vToolBarType(1);

  //顯示工具條

  CComVariant vShow(VARIANT_TRUE);

 

  CComPtr < Office::CommandBarControl> spNewBar;

  CComPtr < Office::CommandBarControl> spNewBar2;

 

  // 用CommandBarControls中的Add方法新增第一個按鈕,並讓spNewBar指向它

  spNewBar = spBarControls->Add(vToolBarType, vEmpty, vEmpty, vEmpty, vShow);

  ATLASSERT(spNewBar);

  // 用CommandBarControls中的Add方法新增第二個按鈕,並讓spNewBar2指向它

  spNewBar2 = spBarControls->Add(vToolBarType, vEmpty, vEmpty, vEmpty, vShow);

  ATLASSERT(spNewBar2);

 

  // 為每一個按鈕指定_CommandBarButton介面,從面可以指定按鈕的顯示風格等

  CComQIPtr < Office::_CommandBarButton> spCmdButton(spNewBar);

  CComQIPtr < Office::_CommandBarButton> spCmdButton2(spNewBar2);

 

  ATLASSERT(spCmdButton);

  ATLASSERT(spCmdButton2);

 

  // 設定點陣圖按鈕風格,點陣圖為32x32大小,將其放入剪下板中用PasteFace()貼在指定按鈕上

  HBITMAP hBmp =(HBITMAP)::LoadImage(_Module.GetReInstance(),

  MAKEINTRESOURCE(IDB_BITMAP),IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);

 

    ::OpenClipboard(NULL);

  ::EmptyClipboard();

  ::SetClipboardData(CF_BITMAP, (HANDLE)hBmp);

  ::CloseClipboard();

  ::Delete(hBmp); 

 

  // 貼上前設定顯示風格

  spCmdButton->PutStyle(Office::msoButtonIconAndCaption);

 

  hr = spCmdButton->PasteFace();

  if (FAILED(hr))

  return hr;

 

  spCmdButton->PutVisible(VARIANT_TRUE);

  spCmdButton->PutCaption(OLESTR("按鈕1"));

  spCmdButton->PutEnabled(VARIANT_TRUE);

  spCmdButton->PutTooltipText(OLESTR("按鈕1提示資訊"));

  spCmdButton->PutTag(OLESTR("按鈕1標誌"));

 

  // 顯示新增工具條

  spNewCmdBar->PutVisible(VARIANT_TRUE);

 

  // 設定第二個工具條按鈕風格

  spCmdButton2->PutStyle(Office::msoButtonIconAndCaption);

 

  // 第二個按鈕指定點陣圖為Outlook2K中預先定義的點陣圖

  spCmdButton2->PutFaceId(1760); 

 

  spCmdButton2->PutVisible(VARIANT_TRUE);

  spCmdButton2->PutCaption(OLESTR("按鈕2"));

  spCmdButton2->PutEnabled(VARIANT_TRUE);

  spCmdButton2->PutTooltipText(OLESTR("按鈕2提示資訊"));

  spCmdButton2->PutTag(OLESTR("按鈕2標誌"));

  spCmdButton2->PutVisible(VARIANT_TRUE);

 

  m_spButton = spCmdButton;

  m_spButton2 = spCmdButton2;

  ……

 

接著,讓我們在選單“工具”中新建一個選單條。

程式碼如下:

  _bstr_t bstrNewMenuText(OLESTR("新增選單條"));

  CComPtr < Office::CommandBarControls> spCmdCtrls;

  CComPtr < Office::CommandBarControls> spCmdBarCtrls;

  CComPtr < Office::CommandBarPopup> spCmdPopup;

  CComPtr < Office::CommandBarControl> spCmdCtrl;

 

  CComPtr < Office::CommandBar> spCmdBar;

 

  // 透過CommandBar獲取Outlook主選單

  hr = spCmdBars->get_ActiveMenuBar(&spCmdBar);

  if (FAILED(hr))

  return hr;

 

  // 獲取選單條的CommandBarControls

  spCmdCtrls = spCmdBar->GetControls();

  ATLASSERT(spCmdCtrls);

 

  // 在第5個"工具"選單下新增一選單條

  CComVariant vItem(5);

  spCmdCtrl= spCmdCtrls->GetItem(vItem);

  ATLASSERT(spCmdCtrl);

 

  IDispatchPtr spDisp;

  spDisp = spCmdCtrl->GetControl();

 

  // 獲取選單條CommandBarPopup介面

    CComQIPtr < Office::CommandBarPopup> ppCmdPopup(spDisp); 

  ATLASSERT(ppCmdPopup);

 

  spCmdBarCtrls = ppCmdPopup->GetControls();

  ATLASSERT(spCmdBarCtrls);

 

  CComVariant vMenuType(1); // 控制元件型別 - menu

  CComVariant vMenuPos(6); 

  CComVariant vMenuEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);

  CComVariant vMenuShow(VARIANT_TRUE); // 選單將顯示

  CComVariant vMenuTemp(VARIANT_TRUE); // 臨時 

 

 

  CComPtr < Office::CommandBarControl> spNewMenu;

  // 用Add方法建立新的選單條

  spNewMenu = spCmdBarCtrls->Add(vMenuType, vMenuEmpty, vMenuEmpty, vMenuEmpty, vMenuTemp);

  ATLASSERT(spNewMenu);

 

  spNewMenu->PutCaption(bstrNewMenuText);

  spNewMenu->PutEnabled(VARIANT_TRUE);

  spNewMenu->PutVisible(VARIANT_TRUE);

 

  // 利用CommandBarButton來在選單條前顯示點陣圖

  CComQIPtr < Office::_CommandBarButton> spCmdMenuButton(spNewMenu);

  ATLASSERT(spCmdMenuButton);

  spCmdMenuButton->PutStyle(Office::msoButtonIconAndCaption);

 

  // 同新增工具條第一個按鈕點陣圖相同方法

  spCmdMenuButton->PasteFace();

 

  // 顯示選單

  spNewMenu->PutVisible(VARIANT_TRUE);

 

  m_spMenu = spCmdMenuButton;

 

這樣,透過在Outlook中透過上面提到的方法載入COM外掛,就可以看到如圖一所示的介面效果了,但是點選時沒有響應,最後就讓我們來解決這個問題。

工具條按鈕CommandBarButton派發介面的響應事件是_CommandBarButtonEvents。ATL提供了二種模板類IDispEventImpl<>IDispEventSimpleImpl<>來實現介面事件的接收,這裡我們使用IDispEventSimpleImpl來實現(因為它不需要額外的型別庫資訊)。它需要設定SINK(接收)對映,透過_ATL_SINK_INFO結構來回撥引數資訊,最終透過DispEventAdviseDispEventUnadvise來與源介面連線或斷開。實現方法如下:

1.  COutlookAddin繼承類中加入IDispEventSimpleImpl繼承,程式碼如下:

class ATL_NO_VTABLE COutlookAddin :

  public CComObjectEx,

  ……

  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 COutlookAddin::OnClickButton1(IDispatch* /*Office::_CommandBarButton* */ Ctrl,VARIANT_BOOL * CancelDefault)

{

  USES_CONVERSION;

  CComQIPtr<:_commandbarbutton> pCommandBarButton(Ctrl);

 

  HINSTANCE result=Execute(NULL, _T("open"), _T(""), NULL,NULL, SW_SHOW);

}

 

5.  最後,開啟或斷開與介面的連線。方法如下:

l  在OnConnection介面涵數的最後部分,加入下面程式碼來開啟連線:

CommandButton1Events::DispEventAdvise((IDispatch*)m_spButton);

l  在OnDinnection介面涵數中,加入下面程式碼來斷開連線:

CommandButton1Events::DispEventUnadvise((IDispatch*)m_spButton);

 

到此就完成一個Office內部外掛的最小需求了,大家可以編譯後開啟Outlook2000看看效果如何,詳細程式碼可參看文章所帶示例原始碼,內有詳細註釋。

 

參考文獻:

Building an Office2K addin with VC++/ATL -- Amit Dey

ATL開發指南(第二版) – Tom Armstrong & Ron Patton

 

聯絡方式:

地址:陝西省西安市勞動路2號院六單元

郵編:710082

編者E:">jingzhou_xu@163.net

未來工作室(Future Studio)


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992419/,如需轉載,請註明出處,否則將追究法律責任。

相關文章