用VS2010开发支持MFC的office插件

本文原创,转载请注明出处: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("       

同时先把_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;

此时最功能最简单的插件基本完成,但这个插件还不知道他的宿主是谁,是Excel还是Word?这个需要修改一下"exceladdin.rgs"文件,它是负责往注册表注册插件信息的.此文件原始内容大致如下:

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'
		}
	}
}

根据文章http://www.vckbase.com/index.php/wv/1442里面的描述,针对Excel插件,往文件添加以下代码:

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'
						}
					}
				}
			}
		}
	}
}

编译之后,运行excel 2007,没发现这个插件.看来还是少了什么.经过对以上参考文章源代码的研究,发现文章里少讲了一部分,还需要在rgs文件里的HKCR部分增加代码,修改后是这样子:

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调用到.大致如图:

用VS2010开发支持MFC的office插件_第1张图片

接下来在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()

到这里按钮的事件基本完成,编译之后,再次打开Excel2007,点击那个大大的笑脸,即可看到熟悉的窗口.

用VS2010开发支持MFC的office插件_第2张图片


注:由于第一次发文章,前面的截图没先保存再上传,而是直接粘贴上来,导致截图丢失.如果哪个步骤不清楚,欢迎交流.

示例代码下载地址:http://download.csdn.net/detail/banket004/5891395

本文参考以下文章:

http://www.vckbase.com/index.php/wv/1442

http://www.vckbase.com/index.php/wv/1452

http://blogs.msdn.com/b/jensenh/archive/2006/12/08/using-ribbonx-with-c-and-atl.aspx


你可能感兴趣的:(VC开发)