Office2000下內部COM外掛的程式設計實現(之二) (轉)
在應用中,儘管選單和工具欄按鈕看上去不太一樣,但實質上它們是相同型別的。Commanars集合包含程式中的所有命令條,如:工具條和選單條。每一個CommandBars集合都有一個CommandBar物件和它對應,CommandBar 物件可以包含其它的 CommandBar 物件,這些物件是作為按鈕或選單命令來用的。每一個CommandBar都將透過CommandBarControls 物件被引用,CommandBarControls又可以包含一組CommandBarControl物件。每一個CommandBarControl可以包含一個CommandBar物件,並可以透過它來存取屬性。每一個CommandBarControl物件,實際是對應CommandBarControls中的控制元件集合。CommandBarControl可以有三種表現形式:
l 彈出式(CommandBopup):相當於選單條的一個選單項。
l 組合框(CommandBarComboBox):類似於工具條中組合框控制元件。它包括一個工具欄和緊接著工具欄的一個下拉箭頭。單擊該按鈕,將顯示出更多的帶圖示的選單命令。
l 按鈕(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
結構來回撥引數資訊,最終透過
DispEventAdvise
和
DispEventUnadvise
來與源介面連線或斷開。實現方法如下:
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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Word2000/XP中內部COM外掛的程式設計實現 (轉)程式設計
- Excel2000/XP和PowerPoint2000/XP下內部COM外掛的實現 (轉)Excel
- JavaNio程式設計實現phonegap外掛websocketJava程式設計Web
- 使用VC++ ATL實現iStylePDF的COM外掛C++
- [前端外掛] js返回頂部 效果實現前端JS
- 在VC++ 6.0下利用訊息實現內部程式通訊 (轉)C++
- 程式設計師偷懶指南 — 用chrome外掛實現前端資訊推送程式設計師Chrome前端
- 程式設計師偷懶指南 -- 用chrome外掛實現前端資訊推送程式設計師Chrome前端
- 無外掛Vim程式設計技巧程式設計
- 程式設計師必備的 chrome 外掛及下載安裝程式設計師Chrome
- KVO的內部實現
- 前端程式設計提高之旅(一)----外掛前端程式設計
- PHP外掛系統的實現(七):外掛案例PHP
- Elasticsearch實現自定義排序外掛(轉載)Elasticsearch排序
- google內部使用的良好程式設計習慣Go程式設計
- Java設計模式實現之二--策略模式Java設計模式
- Linux守護程式的程式設計實現(轉)Linux程式設計
- PHP外掛系統的實現(五):觸發外掛PHP
- mysqldump的內部實現原理MySql
- gostring的內部實現Go
- 好程式設計師技術分享jQuery實現類似fullpage外掛的全屏滾動效果程式設計師jQuery
- C++程式設計思想筆記之二 (轉)C++程式設計筆記
- Java程式設計師必備的Intellij外掛Java程式設計師IntelliJ
- 關於繼承內部類——java程式設計思想示例程式分析; (轉)繼承Java程式設計
- 座標曲線的程式設計實現 (轉)程式設計
- 用 Thunk 實現 COM 的掛鉤
- Nimda程式設計內幕 (轉)程式設計
- javascript實現的微信分享外掛JavaScript
- jQuery實現的cookie操作外掛jQueryCookie
- 外掛化設計二
- 外掛化設計三
- 使用Microsoft Agent的COM介面程式設計(轉)ROS程式設計
- Linux下應用程式開發:QT的內部程式通訊(轉)LinuxQT
- [外掛擴充套件]返回頂部ReturnTop外掛套件
- 透過Domino COM實現Web的痕跡保留設計思路 (轉)Web
- HashMap的內部實現機制HashMap
- 在Linux作業系統中實現內部程式通訊(轉)Linux作業系統
- 深入講解 Lotus Notes 外掛程式設計程式設計