国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

使用VC++ ATL實現Office的COM插件

2019-11-17 05:44:48
字體:
來源:轉載
供稿:網友

  本文介紹了一種使用VC++ ATL(Active Template Library),利用IDTExtensibility2接口,為Microsoft Word加入功能簡單的COM插件(addin),加入工具欄按鈕和菜單等可視部件,并為其加入響應事件的方法,并在最后簡單說明了實現與Office宏混合編程的方法。

  說到Office相關的編程,大家首先想到的可能是VBA(Visual Basic for application),事實上, ATL也是一種很好的工具。這里介紹的就是一種基于ATL的Office編程方法,實現的功能很簡單,僅僅是一個示例,步驟如下:

  1、在visual C++編程環境下,利用向導生成一個名為WordAddin的ATL COM Appwizard工程:

  在向導的第一個對話框中server type單選框選擇默認的服務器類型Dynamic Link Library(DLL),下面的三個復選框中選擇Allow merging of PRoxy-stub code選項。然后單擊Finish,這樣一個空的ATL project就產生了(如圖 一)。

使用VC++ ATL實現Office的COM插件(圖一)
點擊查看大圖

圖一

  2、插入我們的ATL object:

  選擇菜單Insert—>Insert new ATL object,出現new ATL object向導對話框,左邊的category列表中選擇object,右邊相應的選擇simple object,單擊下一步(Next)(如圖 二):

使用VC++ ATL實現Office的COM插件(圖二)
圖二

  在第二個對話框names屬性頁的“Short Name:”中填入Addin(如圖三):

使用VC++ ATL實現Office的COM插件(圖三)
圖三

  在Attribute屬性頁中,選中Support IsupportErrorInfo復選框,單擊OK(如圖四):

使用VC++ ATL實現Office的COM插件(圖四)
圖四

  這樣就產生了一個類名為WordAddin的ATL COM object,編譯(build)該工程看是否一切正常。

  2、用IDTExtensibility2實現CAddin類:

   IDTExtensibility2是定義在MSADDin Designer typelibrary(MSADDNDR.dll/MSADDNDR.tlb)中的庫文件,該文件一般在C:/Program Files/Common Files/Designer目錄下。IDTExtensibility2 庫提供了 5 個可用來操縱插件以及宿主應用程序的事件: OnConnection、OnDisconnection、OnAddInsUpdate、OnStartupComplete 和 OnBeginShutdown。這些事件的具體功能和用法可查閱MSDN。用向導來實現IDTExtensibility2接口:切換到classview頁,右鍵點擊Caddin類,在彈出的菜單中選擇Implement Interface,出現Implement Interface對話框,選擇Add Tylpelib按鈕(如圖 五):

使用VC++ ATL實現Office的COM插件(圖五)
圖五

  (單擊OK,)在出現的Browse Typelibraries對話框中選擇Microsoft Add-in Designer(1.0) (如圖六):

使用VC++ ATL實現Office的COM插件(圖六)
圖六

  單擊OK,在AddinDesigNerobjects屬性頁中選擇IDTExtensibility2(如圖七):


使用VC++ ATL實現Office的COM插件(圖七)
圖七

  再單擊OK。這樣向導就在ATL COM object中添加了IDTExtensibility2的5個具體事件,并對他們進行了一些默認的初始設置,同時還更新了COM_INTERFACE_MAP()。
  4、注冊插件到它的宿主程序:

  打開文件視圖FileView—>Resource File中的Addin.rgs文件,加入以下代碼:

HKCU
{
 Software
 {
  Microsoft
  {
   Office
   {
    Word
    {
     Addins
     {
      ''WordAddin.Addin''
      {
       val FriendlyName = s ''WORD Custom Addin''
       val Description = s ''Word Custom Addin''
       val LoadBehavior = d ''00000003''
       val CommandLineSafe = d ''00000001''
      }
     }
    }
   }
  }
 }
}
  5、重新編譯(build)該工程注冊我們的插件。

  6、運行,選擇Executable File為word 2000,注重要選擇正確的路徑,假如運行成功,則插件已經加入到word中。

  7、給插件添加菜單和按鈕:

  這里簡單的介紹一下Office 的命令條:在Office中,菜單欄、工具欄和彈出式菜單都叫做命令條(Command Bar對象)。所有這些種類的命令條中都可以包括其他命令條和不限數量的控件,如相對工具欄這個命令條而言,按鈕就是它的控件。有的控件(如菜單)本身又是命令條,可以多級嵌套。所有的命令條可用一個CommandBars集合控制。CommandBars集合是一個通用的可共享且可編程的對象,通過它的Add()方法可以為其添加一個CommandBar 對象(即命令條),而每個 CommandBar 對象都有一個CommandBarControls 集合,這個集合里包含了這個命令條里的所有控件。使用 CommandBar 對象的 Controls 屬性可引用命令條中的控件。

  現在給word加入一個工具條及其按鈕和一個菜單:

  首先在工程中加入office和Word的類型庫,在stdafx.h文件中加入以下代碼:

#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("Word"), raw_interfaces_only, named_guids
using namespace Outlook;
  注重:一定要把路徑改為和office的安裝路徑一致。

  在Word對象模型中,Application對象是代表整個工程的最高級對象,我們可以用它的GetCommandBars方法得到CommandBars對象,由于CommandBars對象是Word所有工具條和菜單項的集合,所以就可以通過調用它的Add方法添加新的工具條。然后為工具條添加新的按鈕,其實方法一樣簡單,我們可以調用CommandBar的GetControls方法得到工具條的CommandBarControls集合,如前所說,CommandBarControls集合是該工具條所有控件的集合,按鈕自然是其中之一,那么接下來我們就可以通過調用CommandBarControls集合的Add方法添加一個新的按鈕了。下面是具體的實現代碼:

CComQIPtr<_Application> spApp(Application);

ATLASSERT(spApp);
m_spApp = spApp;
HRESULT hr = AppEvents::DispEventAdvise(m_spApp);

if(FAILED(hr))
 return hr;

CComPtr <Office::_CommandBars> spCmdBars;
CComPtr <Office::CommandBar> spCmdBar;
hr = m_spApp->get_CommandBars(&spCmdBars);

if(FAILED(hr))
 return hr;

ATLASSERT(spCmdBars);

// now we add a new toolband to Word
// to which we''ll add 2 buttons
CComVariant vName("WordAddin");
CComPtr 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);
m_spButton = 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
// Word''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);
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"));
spCmdButton2->put_OnAction(OLESTR("MYMacro1"));

//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);
spCmdButton2->put_OnAction(OLESTR("MYMacro2"));

  添加菜單項的過程與之相類似:

  首先通過調用CommandBars集合的get_ActiveMenuBar()方法得到一個CommandBar對象,這個對象代表當前的工程中的活動菜單,然后調用CommandBar的GetControls得到當前菜單的控件集合。嘗試在Word的“格式”菜單(第5個菜單)中加入新的菜單項,調用CommandBarControls的GetItem(5)得到需要的“格式”菜單項,它也是一個CommandBarControls集合,(前面曾經提到,控件集是可以嵌套的),這樣就可以通過調用它的Add方法添加新的菜單項了。具體的實現代碼如下:

_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 Word''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;
  這時運行程序,可以看到添加的按鈕和菜單項已經出現在Word中,還需要為其加入響應事件,這樣才能真正的通過插件擴展Word的功能。

  8、為我剛加入的按鈕加入其響應事件:

  ATL為COM對象的Idispatch接口提供了兩個模板類:IDispEventImpl<>和IDispEventSimpleImpl<>,選擇IDispEventSimpleImpl<>,因為它不需要額外的類型庫信息,從IDispEventSimpleImpl<>繼續一個類:

class ATL_NO_VTABLE CAddin :
public CComObjectRootEx < CComSingleThreadModel>,
.....

public IDispEventSimpleImpl<1,CAddin,
&__uuidof(Office::_CommandBarButtonEvents>
  聲明按鈕點擊事件的回調函數:


void __stdcall OnClickButton(Idispatch * /*Office::_CommandBarButton**/ Ctrl,VARIANT_BOOL * CancelDefault);
  用_ATL_SINK_INFO結構描述回調的參數信息:打開CAddin.h文件,在其最上加入以下聲明:

extern _ATL_FUNC_INFO OnClickButtonInfo;(注重一定聲明為外部變量)
  然后打開CAddin.cpp文件為其加入以下定義:

_ATL_FUNC_INFO OnClickButtonInfo ={CC_STDCALL,VT_EMPTY,2,{VT_DISPATCH,VT_BYREF VT_BOOL}};
  加入按鈕點擊事件的具體實現:

void __stdcall CAddin::OnClickButton(IDispatch*
/*Office::_CommandBarButton* */ Ctrl,
VARIANT_BOOL * CancelDefault)
{
 USES_CONVERSION;
 CComQIPtr pCommandBarButton(Ctrl);

 //the button that raised the event. Do something with this...
 MessageBox(NULL, "Clicked Button1", "OnClickButton", MB_OK);
}
  在接口映射宏中加入以下信息:

BEGIN_SINK_MAP(CAddin)
SINK_ENTRY_INFO(1, __uuidof(Office::_CommandBarButtonEvents),
/*dispid*/ 0x01,
OnClickButton, &OnClickButtonInfo)
END_SINK_MAP()
  最后在分別在CAddin 類的 OnConnection() 和OnDisconnection()中調用DispEventAdvise() 和 DispEventUnadvise()連接和斷開連接消息來源。

  到這里就實現了一個簡單的COM插件,運行程序,點擊工具欄上新加入的按鈕,就可以彈出("Clicked Button1")消息框。

  假如熟悉VBA編程,就可以把編寫的宏作為按鈕響應事件,只需調用按鈕的put_OnAction()方法:

spCmdButton->put_OnAction(OLESTR("YourMacroName"));

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 汕尾市| 崇礼县| 大兴区| 福鼎市| 威海市| 鸡西市| 沙河市| 招远市| 土默特右旗| 涿鹿县| 和田县| 海淀区| 扶风县| 开江县| 临江市| 满洲里市| 穆棱市| 疏勒县| 贺兰县| 宜阳县| 东乌珠穆沁旗| 长治县| 台江县| 米泉市| 靖安县| 大荔县| 临泽县| 双流县| 福泉市| 双牌县| 蒙阴县| 罗定市| 炉霍县| 保康县| 龙海市| 河源市| 辉县市| 拉孜县| 阿克苏市| 金寨县| 登封市|