VSTO学习笔记(三) 开发Office 2010 64位COM加载项
一、加载项简介
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
这个位置是针对于特定用户的,也是推荐的位置。在该位置注册的COM加载项将出现在Office中的COM加载项对话框中:
在该位置,有几项是必备的。
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下创建几个注册表项:
2、HKEY_LOCAL_MACHINE\Software\Microsoft\Office\Excel\AddIns
这个位置是针对于所有用户的,但是这些加载项对用户隐藏,即不会出现在COM加载项对话框中。
这些注册表项如果纯手工写将会非常麻烦,而且容易出错,幸运的是,Visual Studio提供了一组模板来方便的创建Office加载项,但是我们还是应该理解这些注册表项及其代表含义。
四、理解IDTExtensibility2接口
所有Office应用程序都是用IDTExtensibility2接口与COM加载项进行通信,该接口提供了一种通用的初始化机制,并具有在Office应用程序的对象模型中传递数据的能力,因此COM加载项可以与Office应用程序通信。
IDTExtensibility2接口并不复杂,但是对于标注COM加载项的加载顺序,以及它在何处影响我们编写的代码来说,此接口至关重要。Office在对COM加载项进行实例化时,会创建主Connect类,注意不能用Connect的构造函数创建类的实例,应该用OnConnection方法;类似的,加载项的关闭不能调用析构函数,而要用OnDisconnection方法。
五、ExcelCOMAddInDemo
现在我们来动手开发一个简单的Excel COM Add-In.
1、新建一个Share Add-In项目:
2、在弹出的项目向导中,点击【Next】:
3、选择你所熟悉的语言,点击【Next】:
4、选择COM 加载项的目标宿主,点击【Next】:
5、输入Add-In的名称和描述,点击【Next】:
6、选择"启动时加载",点击【Next】:
7、点击【Finish】:
8、项目建立完成后会自动添加一个安装项目,它会负责安装生成的COM加载项,处理注册表的信息等,无需我们手动参与。
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 here.
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 Excel 2010 XLL SDK 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、设置项目属性:
在【Build】标签中,将【Platform】设置为:Active(x64),取消【Register for COM】的选择:
在【Debug】标签中,将【Platform】设置为:Active(x64),同时将【Start Action】设置为Excel的安装路径,这样做可以启动Excel来调试COM Add-In:
配置编译选项:
配置安装项目属性:
10、我们要做的是在Excel 的Ribbon中添加一个按钮,点击后弹出一则欢迎信息。
首先添加引用:
Microsoft.Office.Interop.Excel
System.Windows.Forms
打开Connect.cs,添加如下代码:
{
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开发的内容,及其与其他技术的整合。