青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

(轉(zhuǎn)載)使用VC++/ATL創(chuàng)建一個(gè)Office2K AddIn Com 組件

原文:http://www.xaradio.com/errorpages/GeneralError.htm?aspxerrorpath=/ShowFAQ.aspx


作者:Amit Dey 譯:劉濤
近來(lái),我寫(xiě)了一個(gè)outlook2000的Addin Com作為我建立CRM 工具的工程的一部分。當(dāng)我為這個(gè)工程寫(xiě)代碼的時(shí)候,我想這可能是一個(gè)很好的題目,因?yàn)槲以趇nternet上找到的與Office相關(guān)的資料大部分是VB/VBA 相關(guān)的,幾乎沒(méi)有與ATL相關(guān)的。
在這篇文章里的代碼并沒(méi)有進(jìn)行優(yōu)化,為了使讀者便于跟隨,我盡量將它寫(xiě)的淺顯易懂。我寫(xiě)這篇文章花了一些時(shí)間,并且也盡了我的最大努力,萬(wàn)一還存在什么錯(cuò) 誤,請(qǐng)爽快的給我發(fā)封郵件。如果你喜歡這篇文章或者覺(jué)得它讀起來(lái)很有趣,并給我一個(gè)高的評(píng)價(jià)或是發(fā)郵件告訴我你的看法,我將非常高興。謝謝!

概況:
通過(guò)這篇文章,我們將會(huì)了解怎樣使用純ATL Com 對(duì)象編寫(xiě)Outlook2000/2K+ COM addin程序。我們將從寫(xiě)一個(gè)最基本的Com AddIn程序開(kāi)始。接下來(lái)我將向你們展示怎樣將標(biāo)準(zhǔn)的界面元素比如工具欄或是菜單項(xiàng)加入到outlook中去,并響應(yīng)他們的事件。緊接著,我們要為Outlook's Tools->Options加入我們自己編寫(xiě)的屬性表。接著我們將看一些相關(guān)的注冊(cè)鍵和ATL向?qū)У囊恍┓浅S杏玫奶卣鞑⑶覍W(xué)習(xí)有效地使用他們。
雖然我們寫(xiě)的是一個(gè)Outlook2000 COM addin的程序。但是Office2000的應(yīng)用程序,比如Word,Access等等,他們的Com AddIn的寫(xiě)法是非常相似的。除了注冊(cè)鍵和接口,其余的部分基本上是一樣的。
我假設(shè)你是一個(gè)VC++ Com的開(kāi)發(fā)人員,并且也有一些基于ATL的組件開(kāi)發(fā)和OLE/自動(dòng)化方面的經(jīng)驗(yàn),盡管這也不是必須的。創(chuàng)建和測(cè)試這個(gè)AddIn程序,你必須安裝Office2000,至少有outlook2000。程序代碼使用VC++ 6.0 sp3+/ATL3.0創(chuàng)建,使用的操作系統(tǒng)是:安裝了Office2000的Windows2000。

開(kāi)始:
Office AddIn 是一個(gè)可以動(dòng)態(tài)擴(kuò)充和增強(qiáng)的Com 自動(dòng)化組件,可以控制任何的Office應(yīng)用程序。微軟的Office2000和以后的版本都支持創(chuàng)建Add_Ins的一個(gè)新的、統(tǒng)一的應(yīng)用設(shè)計(jì)架構(gòu)。AddIn通常都被置于一個(gè)ActiveX動(dòng)態(tài)庫(kù)中(進(jìn)程內(nèi)服務(wù)器),并且能被用戶(hù)動(dòng)態(tài)的從主程序中引導(dǎo)和卸載。
Office AddIn 必須實(shí)現(xiàn) _IDTExtensibility2 接口。IDTExtensibility2接口定義于MSADDin Designer typelibrary (MSADDNDR.dll/MSADDNDR.tlb)文件中。一般在/Program Files/Common Files/Designer目錄下。
接口象這樣定義:
enum {
ext_cm_AfterStartup = 0,
ext_cm_Startup = 1,
ext_cm_External = 2,
ext_cm_CommandLine = 3
} ext_ConnectMode;

enum {
ext_dm_HostShutdown = 0,
ext_dm_UserClosed = 1
} ext_DisconnectMode;

...
...
...

interface _IDTExtensibility2 : IDispatch {
[id(0x00000001)]
HRESULT OnConnection(
[in] IDispatch* Application,
[in] ext_ConnectMode ConnectMode,
[in] IDispatch* AddInInst,
[in] SAFEARRAY(VARIANT)* custom);
[id(0x00000002)]
HRESULT OnDisconnection(
[in] ext_DisconnectMode RemoveMode,
[in] SAFEARRAY(VARIANT)* custom);
[id(0x00000003)]
HRESULT OnAddInsUpdate([in] SAFEARRAY(VARIANT)* custom);
[id(0x00000004)]
HRESULT OnStartupComplete([in] SAFEARRAY(VARIANT)* custom);
[id(0x00000005)]
HRESULT OnBeginShutdown([in] SAFEARRAY(VARIANT)* custom);
};
所有的Com AddIn繼承于IDTExtensibility2,而且必須實(shí)現(xiàn)他的五個(gè)方法。
當(dāng)AddIn被引導(dǎo)和卸載的時(shí)候,OnConnection 和 OnDisconnection, 就像他們的名字顯示的一樣。AddIn程序可以被引導(dǎo),也可以在應(yīng)用程序使用過(guò)程中被用戶(hù)啟動(dòng)或者通過(guò)自動(dòng)化和enumerator ext_Connect 指示連接到那些模塊。當(dāng)一組Com AddIn組件被改變,那么OnAddinsUpdate被調(diào)用。OnStartupComplete 只有在應(yīng)用程序使用過(guò)程中啟動(dòng)Com AddIn組件時(shí)才被調(diào)用,如果AddIn在主應(yīng)用程序被關(guān)掉的時(shí)候斷開(kāi)與主應(yīng)用程序的連接,那么OnBeginShutdown 被調(diào)用。

注冊(cè)AddIn組件:
使用主應(yīng)用程序注冊(cè)AddIn組件,我們需要在注冊(cè)表目錄:
HKEY_CURRENT_USER\Software\Microsoft\Office\<TheOfficeApp>\Addins\<ProgID> 下創(chuàng)建兩個(gè)子鍵,這里ProgID指的是Addin Com對(duì)象的唯一標(biāo)識(shí)符。別的入口通過(guò)AddIn提供的關(guān)于他自己的信息和制定的引導(dǎo)選項(xiàng)給主應(yīng)用程的是:
FriendlyName – 字符串 – 主應(yīng)用程序顯示的這個(gè)AddIn程序的名字。
Description – 字符串 – 對(duì)AddIn的描述.
LoadBehavior - DWORD 值. –一個(gè)決定AddIn怎樣被主應(yīng)用程序引導(dǎo)的值的組合。 設(shè)置成 0x03 表示主應(yīng)用程序啟動(dòng)時(shí)引導(dǎo),設(shè)置成0x08表示由用戶(hù)來(lái)激活。
CommandLineSafe - DWORD 值. 0x01(TRUE) 或者 0x00(FALSE).
對(duì)于所有值和可選項(xiàng)的完整描述,請(qǐng)參考MSDN。

創(chuàng)建一個(gè)小的Com AddIn:
現(xiàn)在我們了解了足夠的知識(shí),應(yīng)該朝前一步編寫(xiě)一個(gè)小的Outlook2K COM addin。創(chuàng)建一個(gè)新的ATL COM Appwizard 工程,命名為OutlookAddin。記住如果你把他命名成別的,他可能會(huì)不能運(yùn)行(開(kāi)個(gè)玩笑)。
在向?qū)У牡谝粋€(gè)對(duì)話框中接收默認(rèn)的服務(wù)器類(lèi)型Dynamic Link Library(DLL),檢查Allow merging of proxy-stub code,選擇這個(gè)可選項(xiàng),點(diǎn)擊完成。接著點(diǎn)擊OK,產(chǎn)生工程文件。
下一步,點(diǎn)擊Insert->New ATL Object菜單項(xiàng),通過(guò)從Category中選擇Objects從Objects列表中選擇Simple Object插入一個(gè)ATL simple object到工程中。點(diǎn)擊Next,輸入”AddIn”作為ShortName,在屬性表里選上Support ISupportErrorInfo。接受剩下的默認(rèn)選項(xiàng),然后點(diǎn)擊OK。
到現(xiàn)在為止,向?qū)б呀?jīng)給我們了一個(gè)置于動(dòng)態(tài)鏈接庫(kù)中的自動(dòng)化兼容的、DispInterface-savvy的進(jìn)程內(nèi)的Com對(duì)象。默認(rèn)的情況下,一個(gè)加到Com對(duì)象上的指定注冊(cè)值的注冊(cè)腳本文件被提交給我們。Build這個(gè)工程,看看一切是否運(yùn)行良好。
如果你想我一樣雄心勃勃,起碼在繼續(xù)往下進(jìn)行前還應(yīng)該編譯你工程中的.idl文件。現(xiàn)在就去做吧。
接下來(lái)我們?yōu)锳ddIn寫(xiě)一些特定的代碼去實(shí)現(xiàn)IDTExtensibility2 接口。在類(lèi)視圖里,我們?cè)贑AddIn類(lèi)上右鍵點(diǎn)擊,選擇Implement Interface,這將帶出ATL Implement Interface 向?qū)А|c(diǎn)擊Add Typelib,在Browse Typelibraries對(duì)話框里向下滾動(dòng),選上Microsoft Add-in Designer(1.0),點(diǎn)擊OK。在AddinDesignerObjects列表中選擇_IDTExtensibility2接口點(diǎn)擊OK。
向?qū)镮DTExtensibility2接口的五個(gè)方法中每一個(gè)生成默認(rèn)的實(shí)現(xiàn),將他們加到CAddIn類(lèi)中,并且更新 COM_INTERFACE_MAP()宏。當(dāng)然在加有些有用的代碼之前每個(gè)方法都只會(huì)返回E_NOTIMPL。現(xiàn)在,為ComAddIn進(jìn)行必要的注 冊(cè),我們的Com AddIn已經(jīng)就緒了。
使用主應(yīng)用程序注冊(cè)我們的Addin組件。如果是outlook2000,打開(kāi)工程的AddIn.rgs注冊(cè)腳本文件。把下面的代碼加到文件的結(jié)尾。
HKCU
{
Software
{
Microsoft
{
Office
{
Outlook
{
Addins
{
'OutlookAddin.Addin'
{
val FriendlyName = s 'ADOutlook2K Addin'
val Description = s 'ATLCOM Outlook Addin'
val LoadBehavior = d '00000008'
val CommandLineSafe = d '00000000'
}
}
}
}
}
}
}
既然我們希望在程序啟動(dòng)的時(shí)候AddIn被引導(dǎo),那么LoadBehavior設(shè)置為3。現(xiàn)在Build這個(gè)工程。如果一切順利,那么將會(huì)創(chuàng)建成功并且注 冊(cè)了這個(gè)AddIn。為了測(cè)試這個(gè)AddIn,我們要運(yùn)行這個(gè)工程并輸入完整的outlook.exe的完整的路徑(\Program Files\Microsoft Office\Office\Outlook.exe),或者在注冊(cè)了這個(gè)DLL之后從VC++IDE環(huán)境外運(yùn)行outlook。如果你的AddIn被成 功的注冊(cè)了,那么在outlook里,點(diǎn)擊Tools->Options,在Other頁(yè)點(diǎn)擊Advanced Options->COM Addins,我們的AddIn應(yīng)該已經(jīng)出現(xiàn)在可獲得的AddIns的列表中。字符串是我們?cè)谀_本中為'FriendlyName'指定的值。
AddIn可以被編寫(xiě)來(lái)執(zhí)行各種不同的任務(wù)。典型的,包括為outlook添加一些界面元素,比如工具條和菜單項(xiàng),而且用戶(hù)可以控制AddIn。通過(guò)點(diǎn)擊這個(gè)工具條按鈕和菜單項(xiàng),用戶(hù)可以實(shí)現(xiàn)AddIn的功能。接下來(lái)我們將制作這樣一個(gè)工具條和附加的菜單項(xiàng)。

命令與征服:
在Office應(yīng)用程序中,菜單和工具條被組合在一個(gè)名叫“CommandBars “的完全可編程的集合中。CommandBars通常是可共享可編程的對(duì)象,并且作為所有的office應(yīng)用程序的一部分被暴露。CommandBars 代表一個(gè)同一的機(jī)制,通過(guò)他可以將單個(gè)的工具條和菜單項(xiàng)加到相應(yīng)的應(yīng)用程序里。每一個(gè)CommandBars由幾個(gè)獨(dú)立的CommandBar對(duì)象組成。 每一個(gè)CommandBar又由CommandBarControl對(duì)象集合組成,這個(gè)集合被叫做CommandBarControls。
CommandBarControls代表了一個(gè)復(fù)雜的對(duì)象和組成它的子對(duì)象層次。一個(gè)CommandBarControl能被包含在一個(gè) CommandBar中,并且通過(guò)控件的CommandBar屬性訪問(wèn)。最后每一個(gè)在控件的CommandBarControls集合中的 CommandBarControl即可能是CommandBarComboBox、CommandBarButton(工具條按鈕)也可能是 CommandBarPopup(彈出式菜單)。我很希望我能畫(huà)出一個(gè)代表這個(gè)對(duì)象層次的圖例,但是我很不擅長(zhǎng)這個(gè)(我很誠(chéng)實(shí)!)。我保證在MSDN中一 定有關(guān)于MS Office CommandBars描述的圖例。
在我們的AddIn里,我想加入以下的界面元素:
? 在一個(gè)新的工具條里加入兩個(gè)位圖按鈕。
? 在“Tool“菜單里添加一個(gè)新的帶位圖的彈出式菜單項(xiàng)。
首先,我們應(yīng)該將office和outlook的類(lèi)型庫(kù)導(dǎo)入到我們的工程中。我們打開(kāi)stdAfx.h,然后添加以下語(yǔ)句:
#import "C:\Program Files\Microsoft Office\Office\mso9.dll" \
rename_namespace("Office") named_guids
using namespace Office;

#import "C:\Program Files\Microsoft Office\Office\MSOUTL9.olb"
rename_namespace("Outlook"), raw_interfaces_only, named_guids
using namespace Outlook;
注意:你應(yīng)該改變這些路徑,是他們匹配你安裝的office的路徑。
好了,現(xiàn)在讓我們來(lái)看看代碼。首先式ToolBand和ToolBar Button。
在outlook模塊里,Application 對(duì)象位于代表整個(gè)應(yīng)用程序的對(duì)象層次的最頂層。通過(guò)他的ActiveExplorer 方法我們可以得到代表當(dāng)前窗口的Explorer對(duì)象。下來(lái)我們使用GetCommandBars方法得到CommandBars對(duì)象(他是 outlook工具條和菜單項(xiàng)的集合)。我們使用CommandBars集合的Add方法加上相應(yīng)的參數(shù)就可以添加一個(gè)新的工具條。如果想向工具條中加入 按鈕只需要得到工具條的CommandBarControls集合,接著調(diào)用他的Add方法。最后我們?yōu)槟切?duì)應(yīng)于按鈕的 CommandBarButton對(duì)象(我們可以用它來(lái)設(shè)置按鈕的風(fēng)格和別的屬性,比如標(biāo)題、提示和文本等等)。
代碼片斷如下:
STDMETHODIMP CAddin::OnConnection(IDispatch * Application,
ext_ConnectMode ConnectMode,
IDispatch * AddInInst, SAFEARRAY * * custom)
{

CComPtr < Office::_CommandBars> spCmdBars;
CComPtr < Office::CommandBar> spCmdBar;

// QI() for _Application
CComQIPtr <Outlook::_Application> spApp(Application);
ATLASSERT(spApp);
// get the CommandBars interface that represents Outlook's
//toolbars & menu items

CComPtr<Outlook::_Explorer> spExplorer;
spApp->ActiveExplorer(&spExplorer);

HRESULT hr = spExplorer->get_CommandBars(&spCmdBars);
if(FAILED(hr))
return hr;
ATLASSERT(spCmdBars);

// now we add a new toolband to Outlook
// to which we'll add 2 buttons
CComVariant vName("OutlookAddin");
CComPtr <Office::CommandBar> spNewCmdBar;

// position it below all toolbands
//MsoBarPosition::msoBarTop = 1
CComVariant vPos(1);

CComVariant vTemp(VARIANT_TRUE); // menu is temporary
CComVariant vEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);
//Add a new toolband through Add method
// vMenuTemp holds an unspecified parameter
//spNewCmdBar points to the newly created toolband
spNewCmdBar = spCmdBars->Add(vName, vPos, vEmpty, vTemp);

//now get the toolband's CommandBarControls
CComPtr < Office::CommandBarControls> spBarControls;
spBarControls = spNewCmdBar->GetControls();
ATLASSERT(spBarControls);

//MsoControlType::msoControlButton = 1
CComVariant vToolBarType(1);
//show the toolbar?
CComVariant vShow(VARIANT_TRUE);

CComPtr < Office::CommandBarControl> spNewBar;
CComPtr < Office::CommandBarControl> spNewBar2;

// add first button
spNewBar = spBarControls->Add(vToolBarType, vEmpty, vEmpty, vEmpty, vShow);
ATLASSERT(spNewBar);
// add 2nd button
spNewBar2 = spBarControls->Add(vToolBarType, vEmpty, vEmpty, vEmpty, vShow);
ATLASSERT(spNewBar2);

_bstr_t bstrNewCaption(OLESTR("Item1"));
_bstr_t bstrTipText(OLESTR("Tooltip for Item1"));

// get CommandBarButton interface for each toolbar button
// so we can specify button styles and stuff
// each button displays a bitmap and caption next to it
CComQIPtr < Office::_CommandBarButton> spCmdButton(spNewBar);
CComQIPtr < Office::_CommandBarButton> spCmdButton2(spNewBar2);

ATLASSERT(spCmdButton);
ATLASSERT(spCmdButton2);

// to set a bitmap to a button, load a 32x32 bitmap
// and copy it to clipboard. Call CommandBarButton's PasteFace()
// to copy the bitmap to the button face. to use
// Outlook's set of predefined bitmap, set button's FaceId to //the
// button whose bitmap you want to use
HBITMAP hBmp =(HBITMAP)::LoadImage(_Module.GetResourceInstance(),
MAKEINTRESOURCE(IDB_BITMAP1),IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);

// put bitmap into Clipboard
::OpenClipboard(NULL);
::EmptyClipboard();
::SetClipboardData(CF_BITMAP, (HANDLE)hBmp);
::CloseClipboard();
::DeleteObject(hBmp);
// set style before setting bitmap
spCmdButton->PutStyle(Office::msoButtonIconAndCaption);

HRESULT hr = spCmdButton->PasteFace();
if (FAILED(hr))
return hr;

spCmdButton->PutVisible(VARIANT_TRUE);
spCmdButton->PutCaption(OLESTR("Item1"));
spCmdButton->PutEnabled(VARIANT_TRUE);
spCmdButton->PutTooltipText(OLESTR("Tooltip for Item1"));
spCmdButton->PutTag(OLESTR("Tag for Item1"));

//show the toolband
spNewCmdBar->PutVisible(VARIANT_TRUE);

spCmdButton2->PutStyle(Office::msoButtonIconAndCaption);

//specify predefined bitmap
spCmdButton2->PutFaceId(1758);

spCmdButton2->PutVisible(VARIANT_TRUE);
spCmdButton2->PutCaption(OLESTR("Item2"));
spCmdButton2->PutEnabled(VARIANT_TRUE);
spCmdButton2->PutTooltipText(OLESTR("Tooltip for Item2"));
spCmdButton2->PutTag(OLESTR("Tag for Item2"));
spCmdButton2->PutVisible(VARIANT_TRUE);

//..........
//..........
//code to add new menubar to be added here
//read on
//..........
我們用相似的方法來(lái)給outlook的Tools菜單添加菜單項(xiàng),我們照以下方法做。CommandBars的ActiveMenuBar屬性返回一個(gè)表 示在Application容器中活動(dòng)的菜單。我們通過(guò)GetControls方法找到活動(dòng)的菜單控件集合。我們想要加入一個(gè)彈出式的菜單項(xiàng)到 outlook的Tools菜單(第6個(gè)菜單項(xiàng)),我們從Activemenubars控件集合中可以找到第6個(gè)菜單項(xiàng),直接調(diào)用Add方法創(chuàng)建一個(gè)新的 菜單項(xiàng)并且將他連接到Tools菜單。這里沒(méi)有什么新東西。
相應(yīng)的代碼片斷如下所示:
//......
//code to add toolbar here
//......

_bstr_t bstrNewMenuText(OLESTR("New Menu Item"));
CComPtr < Office::CommandBarControls> spCmdCtrls;
CComPtr < Office::CommandBarControls> spCmdBarCtrls;
CComPtr < Office::CommandBarPopup> spCmdPopup;
CComPtr < Office::CommandBarControl> spCmdCtrl;

// get CommandBar that is Outlook's main menu
hr = spCmdBars->get_ActiveMenuBar(&spCmdBar);
if (FAILED(hr))
return hr;
// get menu as CommandBarControls
spCmdCtrls = spCmdBar->GetControls();
ATLASSERT(spCmdCtrls);

// we want to add a menu entry to Outlook's 6th(Tools) menu //item
CComVariant vItem(5);
spCmdCtrl= spCmdCtrls->GetItem(vItem);
ATLASSERT(spCmdCtrl);

IDispatchPtr spDisp;
spDisp = spCmdCtrl->GetControl();

// a CommandBarPopup interface is the actual menu item
CComQIPtr < Office::CommandBarPopup> ppCmdPopup(spDisp);
ATLASSERT(ppCmdPopup);

spCmdBarCtrls = ppCmdPopup->GetControls();
ATLASSERT(spCmdBarCtrls);

CComVariant vMenuType(1); // type of control - menu
CComVariant vMenuPos(6);
CComVariant vMenuEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);
CComVariant vMenuShow(VARIANT_TRUE); // menu should be visible
CComVariant vMenuTemp(VARIANT_TRUE); // menu is temporary


CComPtr < Office::CommandBarControl> spNewMenu;
// now create the actual menu item and add it
spNewMenu = spCmdBarCtrls->Add(vMenuType, vMenuEmpty, vMenuEmpty,
vMenuEmpty, vMenuTemp);
ATLASSERT(spNewMenu);

spNewMenu->PutCaption(bstrNewMenuText);
spNewMenu->PutEnabled(VARIANT_TRUE);
spNewMenu->PutVisible(VARIANT_TRUE);

//we'd like our new menu item to look cool and display
// an icon. Get menu item as a CommandBarButton
CComQIPtr < Office::_CommandBarButton> spCmdMenuButton(spNewMenu);
ATLASSERT(spCmdMenuButton);
spCmdMenuButton->PutStyle(Office::msoButtonIconAndCaption);

// we want to use the same toolbar bitmap for menuitem too.
// we grab the CommandBarButton interface so we can add
// a bitmap to it through PasteFace().
spCmdMenuButton->PasteFace();
// show the menu
spNewMenu->PutVisible(VARIANT_TRUE);

return S_OK;
}
點(diǎn)擊F5,如果一切都沒(méi)問(wèn)題,那么工程將成功建立,并且你將第一次看見(jiàn)你的AddIn程序的運(yùn)行。現(xiàn)在我們運(yùn)行outlook來(lái)測(cè)試我們的AddIn。在'Executable for Debug'對(duì)話框,設(shè)置outlook可執(zhí)行程序的當(dāng)前路徑,現(xiàn)在我們準(zhǔn)備測(cè)試。在outlook中點(diǎn)擊Tools->Option,點(diǎn)擊Other頁(yè)面,點(diǎn)擊Advanced Options。在Advanced Option對(duì)話框中,點(diǎn)擊Com AddIns 按鈕。接著從可獲得的AddIns列表中選擇我們的AddIn并點(diǎn)擊OK。當(dāng)我們的AddIn被引導(dǎo),一個(gè)停靠工具條將被創(chuàng)建,你也可以看到你加入到Tools菜單的菜單項(xiàng)。
他們就在那里!一個(gè)有你寫(xiě)的AddIn的outlook,一個(gè)帶有很酷的工具條和新的菜單項(xiàng)的擴(kuò)展的outlook!感謝ATL!你的小于50Kb的AddIn同樣提供了輕量級(jí)的有意義的Com服務(wù)。享受這一刻吧!

單單放置兩個(gè)工具條按鈕和一個(gè)菜單項(xiàng)并沒(méi)有什么用處,除非我們寫(xiě)命令處理代碼和響應(yīng)他們的事件。現(xiàn)在我們回到正題。當(dāng)然在這里,點(diǎn)擊不同的按鈕和菜單項(xiàng),我們緊緊彈出簡(jiǎn)單的對(duì)話框。這就是你添加AddIn功能的地方。從CRM 工具、自動(dòng)聯(lián)系管理、郵件通知、郵件過(guò)濾到高級(jí)的文檔管理到各種各樣的應(yīng)用,Com AddIns可以執(zhí)行各種各樣的任務(wù)的驗(yàn)證。
CommandBarButton控件暴露了一個(gè)點(diǎn)擊事件(當(dāng)用戶(hù)點(diǎn)擊一個(gè)Command Bar 按鈕時(shí)觸發(fā))。當(dāng)用戶(hù)點(diǎn)擊工具條按鈕或者是點(diǎn)擊菜單項(xiàng)的時(shí)候我們將使用這個(gè)事件去運(yùn)行代碼。對(duì)于這些,我們的Com AddIn對(duì)象不得不處理_CommandBarButtonEvents事件。點(diǎn)擊事件被聲明如下:
//...
//....Office objects typelibrary
//....

[id(0x00000001), helpcontext(0x00038271)]
void Click(
[in] CommandBarButton* Ctrl,
[in, out] VARIANT_BOOL* CancelDefault);

//....
//...
我們不得不做所有我們能做的事情去實(shí)現(xiàn)那些將被事件源通過(guò)規(guī)范的連接點(diǎn)協(xié)議調(diào)用的接收器接口(無(wú)論什么時(shí)候一個(gè)工具條按鈕或菜單項(xiàng)被點(diǎn)擊)。通過(guò)回調(diào)函數(shù)我們可以得到一個(gè)源CommandBarButton 對(duì)象的指針和一個(gè)用來(lái)接受和取消默認(rèn)操作的布爾值。就像實(shí)現(xiàn)一個(gè)dispatch接收器接口一樣,那也不是什么新東西,作為一個(gè)ATL程序員你可能要花一段時(shí)間去做這些。
但是對(duì)于那些非初始化的,ATL為ATLCom對(duì)象提供兩個(gè)模板類(lèi)IDispEventImpl<> 和 IDispEventSimpleImpl<> ,這為IDispatch接口提供了實(shí)現(xiàn)。我更喜歡用輕量級(jí)的IDispEventSimpleImpl,因?yàn)樗恍枰硗獾念?lèi)型庫(kù)信息。你的類(lèi)緊緊源于 IDispEventSimpleImpl<>。建立你的接收器映射,通過(guò)_ATL_SINK_INFO結(jié)構(gòu)體設(shè)置你的回調(diào)參數(shù),最后調(diào)用 DispEventAdvise 和 DispEventUnadvise從源接口連接和斷開(kāi)。對(duì)于我們的工具條按鈕和菜單項(xiàng),如果我們要寫(xiě)一個(gè)單一的回調(diào)函數(shù)來(lái)處理所有的事件,那么,一旦我 們有一個(gè)指向觸發(fā)事件的CommandBarButton的指針,我們可以使用GetCaption去得到這個(gè)按鈕的文本,在這個(gè)基礎(chǔ)上,我們可以執(zhí)行一 些選擇性的動(dòng)作。但是對(duì)于這個(gè)例子,我們?yōu)槊恳粋€(gè)事件編寫(xiě)一個(gè)回調(diào)函數(shù)。
下面是編寫(xiě)的步驟:
使你的類(lèi)繼承于IDispSimpleEventImpl-第一個(gè)參數(shù)是封裝在ActiveX控件中的子窗口的ID。但是對(duì)于我們來(lái)說(shuō),它可以是任何預(yù)先定義的唯一標(biāo)識(shí)事件源的整數(shù)(在這里指的是第一個(gè)工具條按鈕)。
class ATL_NO_VTABLE CAddin :
public CComObjectRootEx < CComSingleThreadModel>,
.....
.....
public IDispEventSimpleImpl<1,CAddin,&__uuidof(Office::_CommandBarButtonEvents>
建立回調(diào)函數(shù)-第一個(gè)我們定義的,如下所示:
void __stdcall OnClickButton(IDispatch * /*Office::_CommandBarButton**/ Ctrl,VARIANT_BOOL * CancelDefault);
接下來(lái)我們使用_ATL_SINK_INFO結(jié)構(gòu)去描述回調(diào)參數(shù)。打開(kāi)AddIn.h文件,在文件頂部添加如下聲明:
? extern _ATL_FUNC_INFO OnClickButtonInfo;
接著打開(kāi)AddIn.cpp,添加如下定義:
? _ATL_FUNC_INFO OnClickButtonInfo ={CC_STDCALL,VT_EMPTY,2,{VT_DISPATCH,VT_BYREF | VT_BOOL}};
OnClickButton是非常基礎(chǔ)的,就像下面的:
? void __stdcall CAddin::OnClickButton(IDispatch* /*Office::_CommandBarButton* */ Ctrl,
? VARIANT_BOOL * CancelDefault)
? {
? USES_CONVERSION;
? CComQIPtr<Office::_CommandBarButton> pCommandBarButton(Ctrl);
? //the button that raised the event. Do something with this...
? MessageBox(NULL, "Clicked Button1", "OnClickButton", MB_OK);
?
? }
我們使用ATL宏BEGIN_SINK_MAP() 和 END_SINK_MAP()建立接收器消息映射。接收器消息映射由SINK_ENTRY_XXX組成。接收器消息映射提供定義事件的Dispatch ID和處理他的成員函數(shù)。
? BEGIN_SINK_MAP(CAddin)
? SINK_ENTRY_INFO(1, __uuidof(Office::_CommandBarButtonEvents),/*dispid*/ 0x01,
? OnClickButton, &OnClickButtonInfo)
? END_SINK_MAP()
現(xiàn)在每一件事情都到位了,我們不得不使用DispEventAdvise() and DispEventUnadvise()連接和斷開(kāi)事件源.我們的CAddIn類(lèi)的OnConnection() 和OnDisconnection()僅僅是替代了這些。對(duì)于DispEventAdvise() and DispEventUnadvise()的參數(shù)分別是事件源上的任何的接口和任何被期望的事件源上的接口。
//connect to event source in OnConnection
// m_spButton member variable is a smart pointer to _CommandBarButton
// that is used to cache the pointer to the first toolbar button.

DispEventAdvise((IDispatch*)m_spButton,&DIID__CommandBarButtonEvents);

//when I'm done disconnect from the event source
//some where in OnDisconnection()

DispEventUnadvise((IDispatch*)m_spButton);
為我們的命令按鈕和菜單項(xiàng)實(shí)現(xiàn)Dispatch 接收器是很相似的,寫(xiě)處理代碼并且連接和斷開(kāi)他們就像上面的描述。如果每一步都進(jìn)行的暢通無(wú)阻,在你Rebuild你的程序并且運(yùn)行它。無(wú)論什么時(shí)候,按鈕和菜單項(xiàng)被點(diǎn)擊,你的回調(diào)函數(shù)將被執(zhí)行。

添加屬性頁(yè):
在這篇文章里我們最后要學(xué)會(huì)去做的是添加我們自己的“Option“屬性頁(yè)到outlook的Tools->Option的屬性表中。
下來(lái)我們要加一個(gè)頁(yè)到outlook的option菜單里作為我們我們的AddIn的一部分。我們將象ActiveX控件一樣實(shí)現(xiàn)實(shí)現(xiàn)屬性頁(yè)。當(dāng)用戶(hù)點(diǎn)擊 Tools->Option菜單項(xiàng),應(yīng)用程序?qū)ο蟀l(fā)出一個(gè)OptionsPagesAdd事件(通過(guò)outlook對(duì)象模塊中的 _ApplicationEvents接口)。
dispinterface ApplicationEvents
{
....

[id(0x0000f005), helpcontext(0x0050df87)]
void OptionsPagesAdd([in] PropertyPages* Pages);
....
}

[
odl,
uuid(00063080-0000-0000-C000-000000000046),
helpcontext(0x0053ec78),
dual,
oleautomation
]
....
....

interface PropertyPages : IDispatch {
[id(0x0000f000), propget, helpcontext(0x004deb87)]
HRESULT Application([out, retval] _Application** Application);
....
....

[id(0x0000005f), helpcontext(0x00526624)]
HRESULT Add([in] VARIANT Page,
[in, optional] BSTR Title);

[id(0x00000054), helpcontext(0x00526625)]
HRESULT Remove([in] VARIANT Index);
};

OptionsPagesAdd事件傳遞給我們我們一個(gè)PropertyPages Dispatch接口,他的Add方法用來(lái)添加頁(yè)。Add方法的參數(shù)是我們的控件的ProgID和新的頁(yè)的標(biāo)題文本。相似的,我們調(diào)用Remove()方法和要?jiǎng)h除頁(yè)的索引來(lái)刪除頁(yè)。
現(xiàn)在我們來(lái)加一個(gè)ActiveX復(fù)合控件。我們點(diǎn)擊Insert->new ATL Object.從Category中選擇Controls,從Object列表中選擇Lite Composite Control,點(diǎn)擊OK。在ShortName中輸入PropPage,在屬性頁(yè)面選上Support ISupportErrorInfo選項(xiàng)。點(diǎn)擊Ok,接受所有的默認(rèn)選項(xiàng)。
現(xiàn)在我們要來(lái)實(shí)現(xiàn)PropertyPage接口。在類(lèi)視圖里右鍵點(diǎn)擊CPropPage,選擇Implement Interface,點(diǎn)擊Add TypeLib按鈕。選中Microsoft Outlook 9.0 Object Library 點(diǎn)擊OK。從接口列表中選擇PropertyPage點(diǎn)擊OK。
向?qū)ё詣?dòng)為PropertyPage接口添加三個(gè)方法:Apply()、Get_Dirty()、GetPageInfo() 。現(xiàn)在做下面的修改,在Com Map中把這一行:
COM_INTERFACE_ENTRY(IDispatch)
改成:
COM_INTERFACE_ENTRY2(IDispatch,IPropPage)
以排除不明確的地方。
接下來(lái)實(shí)現(xiàn)IDispatch,我們使用IDispatchImpl<>模板類(lèi)。我們?cè)贑PropPage類(lèi)的聲明部分用以下代碼:
public IDispatchImpl < Outlook::PropertyPage,&__uuidof(Outlook::PropertyPage),
&LIBID_OUTLOOKADDINLib>
替換掉:
class ATL_NO_VTABLE CPropPage :
public CComObjectRootEx<CComSingleThreadModel>,
public IDispatchImpl<IPropPage, &IID_IPropPage, &LIBID_TRAILADDINLib>,
....
....
public PropertyPage
從PropPage.h文件的頂部刪掉多余的#import語(yǔ)句。類(lèi)型庫(kù)已經(jīng)在stdAfx.h中導(dǎo)入了,因此這里沒(méi)有必要再導(dǎo)入。
下來(lái)我們要連接和斷開(kāi)ApplicationEvents接口,并為他寫(xiě)回調(diào)函數(shù)。你已經(jīng)知道該做什么了。我們?cè)俅问褂? IDispEventSimpleImpl<>為ApplicationEvents建立Dispatch接收器,更新接收器映射,為 OptionsAddPage事件寫(xiě)回調(diào)函數(shù)。因?yàn)槲覀兌啻问褂昧薎DispEventSimpleImpl<>, 我們?yōu)槊恳粋€(gè)接口事件使用TypeDef。代碼片段如下:
extern _ATL_FUNC_INFO OnOptionsAddPagesInfo;

class ATL_NO_VTABLE CAddin :
....
....
public IDispEventSimpleImpl<4,CAddin,&__uuidof(Outlook::ApplicationEvents)>
{
public:
//typedef for applicationEvents sink implementation
typedef IDispEventSimpleImpl</*nID =*/ 4,CAddin,
&__uuidof(Outlook::ApplicationEvents)> AppEvents;
....
....
....
BEGIN_SINK_MAP(CAddin)
....
SINK_ENTRY_INFO(4,__uuidof(Outlook::ApplicationEvents),
/*dispid*/0xf005,OnOptionsAddPages,&OnOptionsAddPagesInfo)
END_SINK_MAP()

public:
//callback method for OptionsAddPages event
void __stdcall OnOptionsAddPages(IDispatch *Ctrl);
};

//in PropPage.cpp file

_ATL_FUNC_INFO OnOptionsAddPagesInfo = (CC_STDCALL,VT_EMPTY,1,{VT_DISPATCH}};

void __stdcall CAddin::OnOptionsAddPages(IDispatch* Ctrl)
{
CComQIPtr<Outlook::PropertyPages> spPages(Ctrl);
ATLASSERT(spPages);

//ProgId of the propertypage control
CComVariant varProgId(OLESTR("OutlookAddin.PropPage"));

//tab text
CComBSTR bstrTitle(OLESTR("OutlookAddin"));

HRESULT hr = spPages->Add((_variant_t)varProgId,(_bstr_t)bstrTitle);
if(FAILED(hr))
ATLTRACE("\nFailed adding propertypage");
}
最后,在OnConnection和OnDisConnection里,調(diào)用DispEventAdvise 和 DispEventUnadvise連接和斷開(kāi)ApplicationEvents。現(xiàn)在一切就緒,我們ReBuild工程。下來(lái)點(diǎn)擊F5,點(diǎn)擊 Outlook的Tools->Options菜單。你應(yīng)該看見(jiàn)了我們新加的頁(yè)。但是當(dāng)我們點(diǎn)擊這個(gè)新的頁(yè),一個(gè)對(duì)話框?qū)⒊霈F(xiàn)告訴我們屬性頁(yè)不能被 顯示。發(fā)生了什么?難道我們的辛苦勞動(dòng)白費(fèi)了?
發(fā)生這個(gè)情況的原因是:盡管我們的屬性頁(yè)創(chuàng)建了,但是outlook并沒(méi)有得到關(guān)于這個(gè)頁(yè)的鍵盤(pán)行為的任何信息。IOleControl的 GetControlInfo方法的ATL的默認(rèn)實(shí)現(xiàn)返回E_NOTIMPL,因此包容器無(wú)法為這個(gè)屬性頁(yè)和包容器處理?yè)翩I事件。因此我們的頁(yè)不能被顯 示。修改這個(gè)問(wèn)題,只需重載GetControlInfo()方法,讓他返回S_OK。
在.PropPage.h里添加如下聲明:
STDMETHOD(GetControlInfo)(LPCONTROLINFO lpCI);
我們?cè)赑ropPage.cpp文件里重載GetControlInfo()方法,僅僅將返回值改為S_OK,代碼如下:
STDMETHODIMP CPropPage::GetControlInfo(LPCONTROLINFO lpCI)
{
return S_OK;
}
就是這些了。現(xiàn)在再次Build工程,點(diǎn)擊outlook的tools->Option,激活我們的頁(yè),現(xiàn)在我們的屬性頁(yè)應(yīng)該正確無(wú)誤的顯示了。
我們的學(xué)習(xí)要結(jié)束了。我們能在office里我們能做的事情無(wú)窮無(wú)盡。因?yàn)樵谝粋€(gè)AddIn里你可以獲得父應(yīng)用程序的內(nèi)部對(duì)象模塊,你能做所有主應(yīng)用程序能做的事,或者更多。另外你也能使用別的接口比如MS Assistant(并不直接關(guān)聯(lián)到應(yīng)用程序)。沒(méi)有做不到的只有想不到的。


posted on 2007-06-20 16:58 迷宮の未來(lái) 閱讀(2187) 評(píng)論(0)  編輯 收藏 引用


只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


<2025年9月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

導(dǎo)航

統(tǒng)計(jì)

常用鏈接

留言簿(10)

隨筆檔案

文章檔案

最新隨筆

搜索

積分與排名

最新隨筆

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一区二区三区欧美成人| 亚洲激情专区| 久久亚洲国产成人| 久久精品观看| 久热re这里精品视频在线6| 久久免费视频一区| 欧美激情久久久久| 欧美性理论片在线观看片免费| 国产精品国产三级国产a| 国产欧美视频一区二区三区| 国模精品一区二区三区| 在线成人av网站| 亚洲免费观看在线观看| 亚洲免费视频观看| 久久综合国产精品台湾中文娱乐网| 免费欧美高清视频| 一本一本久久| 久久久久久穴| 国产精品久久久久三级| 亚洲国产精品激情在线观看| 亚洲视频一区在线观看| 六月天综合网| 亚洲免费人成在线视频观看| 久久综合色8888| 国产精品视频一二三| 亚洲人成网站999久久久综合| 亚洲欧美精品一区| 91久久黄色| 亚洲欧美日韩视频二区| 麻豆成人精品| 黑人一区二区三区四区五区| 在线综合欧美| 亚洲国产一成人久久精品| 性xx色xx综合久久久xx| 亚洲国产高清高潮精品美女| 亚洲视频在线观看免费| 欧美亚洲在线视频| 亚洲国产日韩一区二区| 欧美一区二区三区日韩| 国产精品大全| 亚洲一区二区毛片| 亚洲国产婷婷香蕉久久久久久99| 欧美一区二区日韩| 国产精品热久久久久夜色精品三区 | 99综合精品| 老司机一区二区| 性色一区二区| 国产欧美在线视频| 亚洲欧美日韩国产一区| 亚洲久久一区| 欧美日韩综合一区| 日韩视频一区二区三区在线播放免费观看 | 久久一区精品| 国内精品美女av在线播放| 亚洲欧美乱综合| a4yy欧美一区二区三区| 欧美啪啪成人vr| 99综合视频| 亚洲另类一区二区| 欧美视频日韩视频| 午夜性色一区二区三区免费视频 | 亚洲免费精品| 欧美日韩精品一二三区| 亚洲精品日本| 日韩午夜电影av| 欧美日韩综合久久| 亚洲一区二区三区在线视频| 一区二区欧美亚洲| 国产精品日日摸夜夜摸av| 午夜在线视频一区二区区别| 亚洲一区一卡| 国产一区二区三区奇米久涩| 老司机一区二区三区| 女人天堂亚洲aⅴ在线观看| 亚洲精品老司机| 亚洲图片在区色| 国产一区二区三区高清| 欧美大秀在线观看| 欧美日韩在线播放三区| 午夜精彩国产免费不卡不顿大片| 亚洲女女做受ⅹxx高潮| 欧美精品一区二区三区在线播放| 亚洲国产一区二区三区在线播| 欧美激情一区二区在线| 国产视频观看一区| 欧美日本在线| 亚洲欧美不卡| 久久久久se| 99视频精品在线| 亚洲网在线观看| 影音先锋另类| 亚洲免费观看在线视频| 国产三级欧美三级| 亚洲国产精品毛片| 国产精品美女久久| 欧美韩日亚洲| 国产精品日韩精品| 欧美成人午夜剧场免费观看| 欧美国产欧美亚洲国产日韩mv天天看完整 | 欧美大片免费观看在线观看网站推荐| 亚洲日本中文字幕| 亚洲一区二区三区四区视频| 加勒比av一区二区| 日韩午夜电影在线观看| 黑人一区二区| 在线视频免费在线观看一区二区| 激情久久久久| 这里只有精品视频在线| 在线免费不卡视频| 亚洲自拍高清| 一本色道久久综合一区| 久久久夜夜夜| 欧美伊久线香蕉线新在线| 欧美精品激情在线观看| 久久人91精品久久久久久不卡| 欧美日韩亚洲网| 亚洲第一精品在线| 伊人精品视频| 久久国产精品高清| 久久精品国产免费观看| 国产精品成人观看视频国产奇米| 91久久久久久| 亚洲日韩欧美视频一区| 久久夜色撩人精品| 麻豆国产精品777777在线 | 欧美日韩成人一区| 亚洲国产另类久久久精品极度| 永久免费毛片在线播放不卡| 亚洲欧美国产高清va在线播| 亚洲一区二区三区高清不卡| 欧美日韩免费观看一区三区| 欧美成人免费在线视频| 韩国av一区| 欧美影院成人| 久久国产精品网站| 国产日韩在线不卡| 欧美一区二区三区久久精品茉莉花| 在线中文字幕一区| 欧美日韩午夜在线视频| 亚洲精品在线三区| 亚洲天天影视| 国产精品人人做人人爽| 亚洲一区二区欧美| 久久精品国产在热久久| 久久伊人免费视频| 国产欧美在线观看一区| 999亚洲国产精| 日韩一级大片在线| 欧美mv日韩mv国产网站| 免费高清在线视频一区·| 国产午夜精品全部视频在线播放 | 亚洲欧美成人一区二区在线电影| 一区二区三区黄色| 国产精品久久久久久久久久久久久久 | 在线视频精品一| 欧美一区二区高清| 国产一区欧美| 免费看av成人| 亚洲黄色影院| 亚洲专区在线视频| 国产婷婷97碰碰久久人人蜜臀| 久久精品中文字幕一区二区三区| 欧美成人一区二区三区| 亚洲视频www| 好看的日韩视频| 欧美欧美全黄| 久久se精品一区精品二区| 欧美激情一区| 午夜精品久久久久久久久| 黄色在线一区| 欧美日韩亚洲一区二| 久久久国产成人精品| 亚洲毛片在线免费观看| 久久久精品一区| 中日韩美女免费视频网址在线观看 | 亚洲国产欧美国产综合一区| 99re66热这里只有精品4| 国产精品久久久久久久久久久久久久| 欧美在线观看一区| 亚洲理论在线观看| 免费在线国产精品| 亚洲免费网址| 日韩写真视频在线观看| 国产视频一区二区三区在线观看| 欧美成人精品在线观看| 亚洲欧美激情视频在线观看一区二区三区 | 欧美区二区三区| 亚洲欧美日产图| 久久亚洲精品视频| 亚洲一区二区三区视频| 亚洲第一二三四五区| 国产精品一卡| 欧美日韩网址| 欧美精品国产精品日韩精品| 欧美在线影院| 午夜一区在线| 亚洲一区日韩在线| 国产精品99久久久久久宅男| 亚洲激情啪啪| 欧美国产高潮xxxx1819|