程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 用VC6.0編寫Word插件(Office2K、XP、03)

用VC6.0編寫Word插件(Office2K、XP、03)

編輯:關於VC++

最近因為工作的需要,學習了一下Office插件的編寫方法。在走了不少彎路以後,最後終於把編寫插件的原理給搞清楚了,不敢獨享,拿出來跟大家共享一下。下面就以Word 2003為例,向大家簡單介紹一下。

第一步,利用向導生成一個ATL COM AppWizard的新工程。

圖1

在向導的第一個對話框中,服務器類型選擇Dynamic Link Library(DLL),然後單擊Finish即可。

圖2

然後,選取菜單Insert->New ATL Object項,在彈出的ATL對象向導對話框中選中相應Objects對應右側的Simple Object選項,點擊下一步。

圖3

在彈出的對話框中ShortName中輸入相應名稱,點確定完成插入ATL對象。

圖4

這樣一個簡單的基於ATL的COM組件工程就建立成功了。

第二步,通過導入類型庫來實現_IDTExtensibility2接口。在ClassView中的新加的類上點鼠標右鍵,在彈出的右鍵菜單中選Implement Interface項。

圖5

在彈出的實現接口對話框中點擊Add Typelib

圖6

在彈出的Browse Type Libraries對話框中,選取Microsoft Add-in Designer(1.0)子項,點OK按鈕

圖7

在彈出的接口列表對話框中選中_IDTExtensibility2接口,點OK按鈕完成導入

這樣的話,系統將會自動為你生成空的五個所需接口函數,分別是OnConnection、OnDisconnection、OnAddInsUpdate、OnStartupComplete、OnBeginShutdown。

第三步,通過上面的兩個步驟,我們的插件框架已經形成,但是Office怎麼知道啟動的時候要來把我們的插件Load起來呢?Office的不同組件,例如Word、Excel、Outlook等怎麼知道去Load自己的插件呢?答案就是在注冊表中加入相應的鍵值。打開文件視圖FileView—>Resource File中的rgs文件,加入以下代碼:

HKCU
{
Software
{
Microsoft
{
Office
{
Word
{
Addins
{
''TestAddin.SimAddin''
{
val FriendlyName = s ''WORD Custom Addin''
val Description = s ''Word Custom Addin''
val LoadBehavior = d ''00000003''
val CommandLineSafe = d ''00000001''
}
}
}
}
}
}
}

以上代碼由三個需要注意的地方:

1. Office下面的那個子項代表了這個插件是屬於那個組件,Word、Excel、Outlook等等。

2. Addins下面的那個子項要寫成你添加的COM組件的名字,千萬不要照著我的工程的名字照抄。

3. 所有的值兩邊加的都是單引號,而且要用英文下的單引號,不能用雙引號。

這樣一個Office插件的框架才算完成,你可以在OnConnection函數中加一些測試代碼,看看有沒有執行到,如果執行成功才能繼續,否則檢查上面的步驟有沒有錯誤。

第四步,同時需要import兩個office的文件,一個是MSO.dll,另一個是MSWORD.OLB。這兩個文件可以在以下位置找到(具體位置與office安裝路徑有關):

C:\Program Files\Common Files\Microsoft Shared\OFFICE11

C:\Program Files\Microsoft Office\OFFICE11

然後在stdafx.h中加入如下語句:

#import "C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE11\\mso.dll"
\
rename_namespace("Office") named_guids,exclude("Pages")
using namespace Office;
#import "C:\\Program Files\\Common Files\\Microsoft Shared\\VBA\\VBA6\\VBE6EXT.olb" rename_namespace("VBE6")
using namespace VBE6;
#import "C:\\Program Files\\Microsoft Office\\OFFICE11\\MSWORD.OLB" rename("ExitWindows","ExitWindowsEx")
#import "C:\\Program Files\\Microsoft Office\\OFFICE11\\MSWORD.OLB"
\
rename_namespace("Word"), raw_interfaces_only, named_guids ,exclude("Pages")
using namespace Word;

加完以上代碼以後一定要編譯一下,看看是否能夠成功。引入這兩個文件的原因,主要是為了引入一些變量類型,為後面的創建UI作准備。

最後一步,編寫代碼。在OnConnection加入如下代碼:

CComPtr < Office::_CommandBars> spCmdBars;
CComQIPtr <Word::_Application> spApp(Application);
ATLASSERT(spApp);
HRESULT hr = spApp->get_CommandBars(&spCmdBars);
if(FAILED(hr))
return hr;
ATLASSERT(spCmdBars);
CComVariant vName("MyAddin");
CComPtr <Office::CommandBar> spNewCmdBar;
CComVariant vPos(1);
CComVariant vTemp(VARIANT_TRUE);
CComVariant vEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);
spNewCmdBar = spCmdBars->Add(vName, vPos, vEmpty, vTemp);

CComPtr < Office::CommandBarControls> spBarControls;
spBarControls = spNewCmdBar->GetControls();
ATLASSERT(spBarControls);

CComVariant vToolBarType(1);
CComVariant vShow(VARIANT_TRUE);
CComPtr < Office::CommandBarControl> spNewBar;
spNewBar = spBarControls->Add(vToolBarType, vEmpty, vEmpty, vEmpty, vShow);
ATLASSERT(spNewBar);

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

HBITMAP hBmp =(HBITMAP)::LoadImage(_Module.GetResourceInstance(),
MAKEINTRESOURCE(IDB_BITMAP),IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);

::OpenClipboard(NULL);
::EmptyClipboard();
::SetClipboardData(CF_BITMAP, (HANDLE)hBmp);
::CloseClipboard();
::DeleteObject(hBmp);

spCmdButton->PutStyle(Office::msoButtonIconAndCaption);
hr = spCmdButton->PasteFace();
if (FAILED(hr))
return hr;

spCmdButton->PutVisible(VARIANT_TRUE);
spCmdButton->PutCaption(OLESTR("myAddin"));
spCmdButton->PutEnabled(VARIANT_TRUE);
spCmdButton->PutTooltipText(OLESTR("test1"));
spCmdButton->PutTag(OLESTR("test1"));
spNewCmdBar->PutVisible(VARIANT_TRUE);

m_spCmdButton = spCmdButton;

這樣,再次打開word,就可以看到如圖一所示的界面效果了。

圖9

但是點擊時沒有響應,最後就讓我們來解決這個問題。

1. 在COutlookAddin繼承類中加入IDispEventSimpleImpl繼承,代碼如下:

class ATL_NO_VTABLE COutlookAddin :
public CComObjectRootEx<CComSingleThreadModel>,
……
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 CWordAddin::OnClickButton1(IDispatch *
/*Office::_CommandBarButton**/ Ctrl,VARIANT_BOOL * CancelDefault)
{
MessageBox(NULL, "hello", "world", MB_OK);
}

5. 最後,打開或斷開與接口的連接。方法如下

在OnConnection接口函數的最後部分,加入下面代碼來打開連接:

在OnConnection接口函數的最後部分,加入下面代碼來打開連接:

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

在OnDisconnection接口函數中,加入下面代碼來斷開連接:

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

綜上所述,編寫一個簡單的office的插件,其實並不難,只要按照步驟一步一步進行,肯定能成功,如果大家在使用過程中有什麼疑問,歡迎一起探討。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved