本文原创,转载请注明出处:http://blog.csdn.net/banket004
通过参考网上的文章,再加上自己的摸索,走了不少弯路,终于用VS2010开发出MS Office 2007的插件.特写此文以作备忘.(记性太差,之前开发过一次,后来再开发又忘了怎么用^ _^)
下面以开发Excel插件为例,其他office插件开发过程类似.
如果不需要支持MFC,可参考此文章http://blogs.msdn.com/b/jensenh/archive/2006/12/08/using-ribbonx-with-c-and-atl.aspx的方法,开发更简便,本人已实验过.
首先创建一个支持MFC的ATL DLL解决方案,界面如下:
在"Allow merging of proxy/stub code"和"Support MFC"两个选项前打勾,然后点击"Finish",到此最原始的解决方案已经建成.接着通过类向导给项目增加一个"ATL Simple Object"类.除了输入类名之外,"ISupportErrorInfo"选项可选可不选,其他默认即可,如下图:
接下来在上面创建的ATL类Cexceladdin中实现库"Microsoft Add-In Designer<1.0>"中的"_IDTExtensibility2"接口,后面需要用到此接口中的"OnConnection","OnDisconnection","OnAddInsUpdate","OnStartupComplete"和"OnBeginShutdown"方法.这四个方法是宿主(Office软件)运行时加载和卸载插件相关的.
以上操作用"Implement Interface Wizard"即可完成,如下图:
编译一下,没有什么错误.到这里还不能在Excel软件的界面看到插件,还需要实现下面另一个接口,也是我花费最多时间摸索的地方.
还是在类Cexceladdin中实现接口,通过接口实现向导,选择"Microsoft Office 12.0 Object Library<2.4> "库(office 2007版本对应的就是12),添加"IRibbonExtensibility"接口.如下图:
添加好接口之后,再编译,会出现以下错误信息:
1>d:\my documents\visual studio 2010\projects\2007exceladdin\2007exceladdin\stdafx.h(41): warning C4278: 'RGB': identifier in type library 'C:\Program Files\Common Files\Microsoft Shared\OFFICE12\MSO.DLL' is already a macro; use the 'rename' qualifier
1>d:\my documents\visual studio 2010\projects\2007exceladdin\2007exceladdin\stdafx.h(41): warning C4278: 'RGB': identifier in type library 'C:\Program Files\Common Files\Microsoft Shared\OFFICE12\MSO.DLL' is already a macro; use the 'rename' qualifier
1>d:\my documents\visual studio 2010\projects\2007exceladdin\2007exceladdin\stdafx.h(41): warning C4278: 'RGB': identifier in type library 'C:\Program Files\Common Files\Microsoft Shared\OFFICE12\MSO.DLL' is already a macro; use the 'rename' qualifier
1>d:\my documents\visual studio 2010\projects\2007exceladdin\2007exceladdin\stdafx.h(41): warning C4278: 'RGB': identifier in type library 'C:\Program Files\Common Files\Microsoft Shared\OFFICE12\MSO.DLL' is already a macro; use the 'rename' qualifier
1>d:\my documents\visual studio 2010\projects\2007exceladdin\2007exceladdin\stdafx.h(41): warning C4278: 'RGB': identifier in type library 'C:\Program Files\Common Files\Microsoft Shared\OFFICE12\MSO.DLL' is already a macro; use the 'rename' qualifier
1>d:\my documents\visual studio 2010\projects\2007exceladdin\2007exceladdin\debug\mso.tlh(2082): error C2011: 'IAccessible' : 'struct' type redefinition
1> c:\program files\microsoft sdks\windows\v7.0a\include\oleacc.h(556) : see declaration of 'IAccessible'
1>d:\my documents\visual studio 2010\projects\2007exceladdin\2007exceladdin\debug\mso.tlh(2169): error C2504: 'IAccessible' : base class undefined
根据错误信息的提示,大概意思是说"Iaccessible"这个结构体重复定义了.只要把stdafx.h文件中的
#import "C:\Program Files\Common Files\Microsoft Shared\OFFICE12\MSO.DLL" raw_interfaces_only, raw_native_types, no_namespace, named_guids, auto_search
改成
#import "C:\Program Files\Common Files\Microsoft Shared\OFFICE12\MSO.DLL" raw_interfaces_only, raw_native_types, no_namespace, named_guids, auto_search rename("IAccessible", "IMSOAccessible")
即可消除此错误.
将GetCustomUI的实现改成以下:
STDMETHOD(GetCustomUI)(BSTR RibbonID, BSTR * RibbonXml)
{
if (!RibbonXml)
return E_POINTER;
*RibbonXml = SysAllocString(
_T("")
_T(" ")
_T(" ")
_T(" " )
_T(" " )
_T(" ")
_T(" ")
_T(" ")
_T(" ")
_T(" ")
);
return (*RibbonXml ? S_OK : E_OUTOFMEMORY);
}
同时先把_IDTExtensibility2接口对应的4个方法"OnConnection"等改成如下:
STDMETHOD(OnConnection)(LPDISPATCH Application, ext_ConnectMode ConnectMode, LPDISPATCH AddInInst, SAFEARRAY * * custom)
{
return S_OK;
}
STDMETHOD(OnDisconnection)(ext_DisconnectMode RemoveMode, SAFEARRAY * * custom)
{
return S_OK;
}
STDMETHOD(OnAddInsUpdate)(SAFEARRAY * * custom)
{
return S_OK;
}
STDMETHOD(OnStartupComplete)(SAFEARRAY * * custom)
{
return S_OK;
}
STDMETHOD(OnBeginShutdown)(SAFEARRAY * * custom)
{
return S_OK;
}
return E_NOTIMPL;
return S_OK;
HKCR
{
NoRemove CLSID
{
ForceRemove {0F1D173C-61FE-44E6-BBA2-7D16D37C9DAC} = s 'exceladdin Class'
{
ForceRemove Programmable
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
TypeLib = s '{D4E1923A-0EF0-42B2-B00E-32978D0E8C66}'
Version = s '1.0'
}
}
}
HKCU
{
Software
{
Microsoft
{
Office
{
Excel
{
Addins
{
'My2007exceladdin.exceladdin'
{
val FriendlyName = s 'Excel2007 Addin'
val Description = s 'Excel2007 Addin'
val LoadBehavior = d '00000003'
val CommandLineSafe = d '00000001'
}
}
}
}
}
}
}
HKCR
{
My2007exceladdin.exceladdin.1 = s 'ExcelAddin Class'
{
CLSID = s '{0F1D173C-61FE-44E6-BBA2-7D16D37C9DAC}'
}
My2007exceladdin.exceladdin = s 'ExcelAddin Class'
{
CLSID = s '{0F1D173C-61FE-44E6-BBA2-7D16D37C9DAC}'
CurVer = s 'My2007exceladdin.exceladdin.1'
}
NoRemove CLSID
{
ForceRemove {0F1D173C-61FE-44E6-BBA2-7D16D37C9DAC} = s 'exceladdin Class'
{
ForceRemove Programmable
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
TypeLib = s '{D4E1923A-0EF0-42B2-B00E-32978D0E8C66}'
Version = s '1.0'
}
}
}
注意红色部分,别改错了,不然也是插件运行不起来的.到这里插件就可以显示了.晒一下效果图:
虽然可以运行了,但按钮点击会出错,接下来也是麻烦事....
==========================================>>
首先, 通过向导在接口Iexceladdin中增加参数为IDispatch*的OnStart方法, 这个方法在GetCustomUI函数中的onAction调用到.大致如图:
接下来在OnStart方法中添加测试代码,方便测试此方法是否有执行到.在此示例中直接添加弹窗提示,如下:
STDMETHODIMP Cexceladdin::OnStart(IDispatch* RibbonControl)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: Add your implementation code here
MessageBox(NULL, _T("Test"), _T("Excel"), MB_OK);
return S_OK;
}
最后,打开"exceladdin.h"文件,找到映射宏代码部分,增加"COM_INTERFACE_ENTRY2(IDispatch, Iexceladdin)", 如下代码所示:
BEGIN_COM_MAP(Cexceladdin)
COM_INTERFACE_ENTRY(Iexceladdin)
COM_INTERFACE_ENTRY2(IDispatch, Iexceladdin)//此语句不会自动添加,需手动添加,否则Ribbon的按钮无法映射对应的函数
COM_INTERFACE_ENTRY2(IDispatch, _IDTExtensibility2)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
COM_INTERFACE_ENTRY(_IDTExtensibility2)
COM_INTERFACE_ENTRY(IRibbonExtensibility)
END_COM_MAP()
注:由于第一次发文章,前面的截图没先保存再上传,而是直接粘贴上来,导致截图丢失.如果哪个步骤不清楚,欢迎交流.
示例代码下载地址:http://download.csdn.net/detail/banket004/5891395
本文参考以下文章:
http://www.vckbase.com/index.php/wv/1442
http://www.vckbase.com/index.php/wv/1452