原文:
一、加载项简介
Office提供了多种用于扩展Office应用程序功能的模式,常见的有:
1、Office 自动化程序(Automation Executables)
2、Office加载项(COM or Excel Add-In)
3、Office文档代码或模板(Code Behind an Office Document or Template)
4、Office 智能标签(Smart Tags)
本次我们将学习使用VSTO 4.0编写一个简单的Office COM 加载项,构建于Office 2010 x64.
本系列所有示例代码均在 Visual Studio 2010 Ultimate RC 和 Office 2010 Professional Plus Beta x64 中测试通过。
二、为什么要使用加载项
Office加载项提供了一种扩展应用程序核心功能的机制,由此添加的功能可以在整个应用程序或单个应用程序中使用,极大的扩充了Office的应用领域:
1、扩展现有功能:对于特定需求,特别是和业务紧密相关的需求,如果能够以加载项的方式在Office中解决,那么将节省软件成本、培训成本等。
2、数据整合:随着Office由办公平台正式转变为一个计算平台之后,将Office与其他平台进行整合的需求也变得愈来愈频繁。如将Web服务器中数据导入到Excel中,将SAP系统中数据导入到Excel中,生成日报表等。
三、COM加载项的工作原理
要使用COM加载项,必须要在注册表中写入相应的信息。Office 要判断使用哪些加载项时,以Excel为例,需要查看注册表中的两个位置:
(PS:推荐一个注册表编辑器Registry Workshop,功能很强大,支持64位,可以在下载)
1、HKEY_CURRENT_USER\Software\Microsoft\Office\Excel\AddIns
![](https://yqfile.alicdn.com/img_3c25d42d9dcb569316f2fc06b64c0350.png)
这个位置是针对于特定用户的,也是推荐的位置。在该位置注册的COM加载项将出现在Office中的COM加载项对话框中:
![](https://yqfile.alicdn.com/img_9e9fea50f59d4c65a18368432225ae2b.png)
在该位置,有几项是必备的。
1)FriendlyName:字符串值,包含了显示在COM对话框中的COM加载项的名称;
2)Description:字符串值,包含了COM加载项的简短描述信息;
3)LoadBehavior:DWORD类型,用于描述COM加载项的加载方式,通常设置为3(1 + 2).
值 | 描述 |
0 | 断开,不加载COM加载项 |
1 | 连接,加载 COM加载项 |
2 | 启动时加载,主应用程序启动时加载并连接COM加载项 |
8 | 需要时加载,主应用程序需要(触发加载事件)时加载并连接COM加载项 |
16 | 首次连接,用户注册加载项后,首次运行主应用程序时加载并连接COM加载项 |
除了上面的三个,还需要在HKEY_CLASSES_ROOT\CLSID下创建几个注册表项:
![](https://yqfile.alicdn.com/img_c0ba79e4285bfc79ab80dce4bbba5111.png)
2、HKEY_LOCAL_MACHINE\Software\Microsoft\Office\Excel\AddIns
这个位置是针对于所有用户的,但是这些加载项对用户隐藏,即不会出现在COM加载项对话框中。
这些注册表项如果纯手工写将会非常麻烦,而且容易出错,幸运的是,Visual Studio提供了一组模板来方便的创建Office加载项,但是我们还是应该理解这些注册表项及其代表含义。
四、理解IDTExtensibility2接口
所有Office应用程序都是用IDTExtensibility2接口与COM加载项进行通信,该接口提供了一种通用的初始化机制,并具有在Office应用程序的对象模型中传递数据的能力,因此COM加载项可以与Office应用程序通信。
![](https://yqfile.alicdn.com/img_5fbf454ac499054f4164c7d2fa835675.png)
IDTExtensibility2接口并不复杂,但是对于标注COM加载项的加载顺序,以及它在何处影响我们编写的代码来说,此接口至关重要。Office在对COM加载项进行实例化时,会创建主Connect类,注意不能用Connect的构造函数创建类的实例,应该用OnConnection方法;类似的,加载项的关闭不能调用析构函数,而要用OnDisconnection方法。
![](https://yqfile.alicdn.com/img_d286c826b706ec1b5d3423a1b343aa21.png)
五、ExcelCOMAddInDemo
现在我们来动手开发一个简单的Excel COM Add-In.
1、新建一个Share Add-In项目:
![](https://yqfile.alicdn.com/img_c754f7fc05cd14468f2f049c9c3b8bfd.png)
2、在弹出的项目向导中,点击【Next】:
![](https://yqfile.alicdn.com/img_9c5bdf750f14ddba1831141872d25eb4.png)
3、选择你所熟悉的语言,点击【Next】:
![](https://yqfile.alicdn.com/img_bc3b2028ac94f93ffb8714026fbf3210.png)
4、选择COM 加载项的目标宿主,点击【Next】:
![](https://yqfile.alicdn.com/img_f5a46e8e13af339eadab9b53e806eda1.png)
5、输入Add-In的名称和描述,点击【Next】:
![](https://yqfile.alicdn.com/img_bca7f59d29949c50c656c4d16da6c2fc.png)
6、选择"启动时加载",点击【Next】:
![](https://yqfile.alicdn.com/img_034aaf025cab93f4e2ef08efc9aa690b.png)
7、点击【Finish】:
![](https://yqfile.alicdn.com/img_4fc07ab58241feaf6da9d0e439e5dc4b.png)
8、项目建立完成后会自动添加一个安装项目,它会负责安装生成的COM加载项,处理注册表的信息等,无需我们手动参与。
![](https://yqfile.alicdn.com/img_1979ecc19b76a9f8f6314c6bf75ef04c.png)
64-bit Support and Code Compatibility
Office 2010 will ship in both 32- and 64-bit versions. 64-bit is particularly significant to some Excel applications, which hit a wall today in terms of available memory address space. This is an important topic in itself, which we have covered .
Excel workbooks can be freely opened and edited in both 32- and 64-bit Excel; there is nothing architecture specific in a saved workbook. For custom code solutions, however, 64-bit Excel introduces some challenges:
- ActiveX controls need to be ported – they need a 64-bit version to work in a 64-bit process. This includes Microsoft's own controls, of which many have been ported. We are evaluating the popularity and criticality of the remaining ones for possible porting.
- COM add-ins, similarly, need to be compiled for 64-bit in order to work in 64-bit Excel.
- XLL add-ins also need to be compiled for 64-bit, and the new supports that.
- VBA: Embedded VBA code gets re-compiled when the containing Excel workbook is opened on a new platform; 64-bit Excel now includes a 64-bit version of VBA. So most VBA code just works in 64-bit. However, a subset of VBA solutions needs some tweaking. It has to do with declarations and calls to external APIs with pointers/handles in the parameter list. VBA7, the new version of VBA that ships with Office 2010, supports the development of code that can run in both 32- and 64-bit Office.
摘自Excel 2010官方博客,可以看出,在Office 2010 x64中,必须编写64位的COM Add-In.
这不是问题,稍后我们将看到如何编译64位的COM Add-In和生成64位的安装文件。
9、设置项目属性:
![](https://yqfile.alicdn.com/img_3a68673e2fc5f6efca785decc4066f2b.png)
在【Build】标签中,将【Platform】设置为:Active(x64),取消【Register for COM】的选择:
![](https://yqfile.alicdn.com/img_28ecb2fbeacbf15cfd82dce6138830c3.png)
在【Debug】标签中,将【Platform】设置为:Active(x64),同时将【Start Action】设置为Excel的安装路径,这样做可以启动Excel来调试COM Add-In:
![](https://yqfile.alicdn.com/img_42bb2aa30fd15eb5b8e7dc3e3b7a87f3.png)
配置编译选项:
![](https://yqfile.alicdn.com/img_78470f18801064bc217057a07a1458ea.png)
![](https://yqfile.alicdn.com/img_95284ab09442cb10b2f5a8a8e9df4c04.png)
配置安装项目属性:
![](https://yqfile.alicdn.com/img_9229f9fb74af21b9ae4d31e23e40f441.png)
10、我们要做的是在Excel 的Ribbon中添加一个按钮,点击后弹出一则欢迎信息。
首先添加引用:
Microsoft.Office.Interop.Excel
System.Windows.Forms
打开Connect.cs,添加如下代码:
代码 namespace ExcelCOMAddInDemo{ using System; using Extensibility; using System.Runtime.InteropServices; using Microsoft.Office.Interop.Excel; using Microsoft.Office.Core; using System.Windows.Forms; #region Read me for Add-in installation and setup information. // When run, the Add-in wizard prepared the registry for the Add-in. // At a later time, if the Add-in becomes unavailable for reasons such as: // 1) You moved this project to a computer other than which is was originally created on. // 2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in. // 3) Registry corruption. // you will need to re-register the Add-in by building the ExcelCOMAddInDemoSetup project, // right click the project in the Solution Explorer, then choose install. #endregion /// <summary> /// The object for implementing an Add-in. /// </summary> /// <seealso class='IDTExtensibility2' /> [GuidAttribute( " DDC49E0C-03FE-4134-9829-65EF0351CECE " ), ProgId( " ExcelCOMAddInDemo.Connect " )] public class Connect : Object, Extensibility.IDTExtensibility2 { private Microsoft.Office.Interop.Excel.Application applicationObject; private Microsoft.Office.Core.COMAddIn addInInstance; private CommandBarButton simpleButton; /// <summary> /// Implements the constructor for the Add-in object. /// Place your initialization code within this method. /// </summary> public Connect() { } /// <summary> /// Implements the OnConnection method of the IDTExtensibility2 interface. /// Receives notification that the Add-in is being loaded. /// </summary> /// <param term='application'> /// Root object of the host application. /// </param> /// <param term='connectMode'> /// Describes how the Add-in is being loaded. /// </param> /// <param term='addInInst'> /// Object representing this Add-in. /// </param> /// <seealso class='IDTExtensibility2' /> public void OnConnection( object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom) { applicationObject = application as Microsoft.Office.Interop.Excel.Application; addInInstance = addInInst as Microsoft.Office.Core.COMAddIn; } /// <summary> /// Implements the OnDisconnection method of the IDTExtensibility2 interface. /// Receives notification that the Add-in is being unloaded. /// </summary> /// <param term='disconnectMode'> /// Describes how the Add-in is being unloaded. /// </param> /// <param term='custom'> /// Array of parameters that are host application specific. /// </param> /// <seealso class='IDTExtensibility2' /> public void OnDisconnection(Extensibility.ext_DisconnectMode disconnectMode, ref System.Array custom) { } /// <summary> /// Implements the OnAddInsUpdate method of the IDTExtensibility2 interface. /// Receives notification that the collection of Add-ins has changed. /// </summary> /// <param term='custom'> /// Array of parameters that are host application specific. /// </param> /// <seealso class='IDTExtensibility2' /> public void OnAddInsUpdate( ref System.Array custom) { } /// <summary> /// Implements the OnStartupComplete method of the IDTExtensibility2 interface. /// Receives notification that the host application has completed loading. /// </summary> /// <param term='custom'> /// Array of parameters that are host application specific. /// </param> /// <seealso class='IDTExtensibility2' /> public void OnStartupComplete( ref System.Array custom) { CommandBars commandBars; CommandBar standardBar; commandBars = applicationObject.CommandBars; // Get the standard CommandBar from Word standardBar = commandBars[ " Standard " ]; try { // try to reuse the button is hasn't already been deleted simpleButton = (CommandBarButton)standardBar.Controls[ " Excel COM Addin " ]; } catch (System.Exception) { // If it's not there add a new button simpleButton = (CommandBarButton)standardBar.Controls.Add( 1 ); simpleButton.Caption = " Excel COM Addin " ; simpleButton.Style = MsoButtonStyle.msoButtonCaption; } // Make sure the button is visible simpleButton.Visible = true ; simpleButton.Click += new _CommandBarButtonEvents_ClickEventHandler(simpleButton_Click); standardBar = null ; commandBars = null ; } /// <summary> /// Implements the OnBeginShutdown method of the IDTExtensibility2 interface. /// Receives notification that the host application is being unloaded. /// </summary> /// <param term='custom'> /// Array of parameters that are host application specific. /// </param> /// <seealso class='IDTExtensibility2' /> public void OnBeginShutdown( ref System.Array custom) { } void simpleButton_Click(CommandBarButton ctrl, ref bool cancelDefault) { MessageBox.Show( " Welcome to COM Add In " ); } }} 声明了一个CommandBarButton的实例,然后将其添加到CommandBar中,并关联了一个Click事件,输出一则欢迎信息。
11、编译成功后,安装生成的setup.exe,执行安装:
12、安装成功后,打开Excel,会在【Add-In】中发现我们新添加的按钮:
六、调试COM加载项
1、通过前面的设置为Excel启动来进行调试,这也是首先的方法,很方便。
2、可以通过附加Excel进程的方式来进行调试:
七、小结
本次主要学习了COM 加载项的开发流程,对使用托管代码开发COM组件有了初步的认识,尤其是IDTExtensibility2接口,在VSTO开发中占据重要地位,理解其与COM交互的过程是很有必要的。其次是64位COM加载项的部署问题,与32位传统加载项有些区别,请注意区别对待。后续篇章会继续深入介绍VSTO开发的内容,及其与其他技术的整合。