可以将 VSTO 外接程序中的对象公开给其他解决方案,包括其他Microsoft Office 解决方案。 如果您的 VSTO 外接程序提供服务,并且您希望启用其他解决方案使用这些服务,这将非常有用。 例如,如果你有用于 Microsoft Office Excel 的 VSTO 外接程序,该外接程序对 Web 服务中的财务数据执行计算,则其他解决方案可以通过在运行时调用 Excel VSTO 外接程序来执行这些计算。
适用于: 本主题中的信息适用于 VSTO 外接程序项目。 有关详细信息,请参阅 Office 应用程序和项目类型提供的功能。
此过程有两个主要步骤:
在 VSTO 外接程序中,向其他解决方案公开对象。
在另一个解决方案中,访问 VSTO 外接程序公开的对象,并调用该对象的成员。
可在外接程序中调用代码的解决方案类型
可以将 VSTO 外接程序中的对象公开为以下类型的解决方案:
文档中的 Visual Basic for Applications(VBA)代码在与您的 VSTO 外接程序相同的应用程序进程中加载。
与 VSTO 外接程序相同的应用程序进程中加载的文档级自定义。
使用 Visual Studio 中的 Office 项目模板创建的其他 VSTO 外接程序。
COM VSTO 外接程序(即直接实现 IDTExtensibility2 接口的 VSTO 外接程序)。
在与 VSTO 外接程序不同的进程中运行的任何解决方案(这些类型的解决方案也命名 为进程外客户端)。 其中包括用于自动化 Office 应用程序的应用程序,例如 Windows 窗体或控制台应用,以及在不同进程中加载的 VSTO 加载项。
向其他解决方案公开对象
若要向其他解决方案公开 VSTO 外接程序中的对象,请在 VSTO 外接程序中执行以下步骤:
定义要向其他解决方案公开的类。
重写
ThisAddIn类中的RequestComAddInAutomationService方法。 返回要向其他解决方案公开的类的实例。
定义要向其他解决方案公开的类
至少,要公开的类必须是公共的,它必须将 ComVisibleAttribute 属性设置为 true,并且必须公开 IDispatch 接口。
公开 IDispatch 接口的建议方法是执行以下步骤:
定义一个接口,该接口声明要向其他解决方案公开的成员。 可以在 VSTO 外接程序项目中定义此接口。 但是,如果要向非 VBA 解决方案公开该类,则可能需要在单独的类库项目中定义此接口,以便调用 VSTO 外接程序的解决方案可以引用接口,而无需引用 VSTO 外接程序项目。
将此 ComVisibleAttribute 特性应用于此接口,并将此属性设置为 true。
修改类以实现此接口。
将ClassInterfaceAttribute属性应用于类,并将此属性设置为枚举的 ClassInterfaceType 值。
如果要向外部进程客户端暴露此类,您可能还需要执行以下操作:
从 StandardOleMarshalObject派生类。 有关详细信息,请参阅 向进程外客户端公开类。
在定义接口的项目中设置 COM 互操作注册 属性。 仅当希望使客户端能够使用早期绑定调用 VSTO 外接程序时,此属性才是必需的。
下面的代码示例演示了一个
AddInUtilities类,其中有一个ImportData方法可以被其他解决方案调用。 若要在较大演练的上下文中查看此代码,请参阅 演练:从 VBA 调用 VSTO 外接程序中的代码。[ComVisible(true)] public interface IAddInUtilities { void ImportData(); } [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] public class AddInUtilities : IAddInUtilities { // This method tries to write a string to cell A1 in the active worksheet. public void ImportData() { Excel.Worksheet activeWorksheet = Globals.ThisAddIn.Application.ActiveSheet as Excel.Worksheet; if (activeWorksheet != null) { Excel.Range range1 = activeWorksheet.get_Range("A1", System.Type.Missing); range1.Value2 = "This is my data"; } } }
向 VBA 公开类
执行上述步骤时,VBA 代码只能调用在接口中声明的方法。 VBA 代码无法调用类中的其他任何方法,包括类从基类获取的方法,例如 Object。
或者,可以通过将ClassInterfaceAttribute属性设置为枚举的AutoDispatch或AutoDual值来公开ClassInterfaceType接口。 如果公开接口,则无需在单独的接口中声明方法。 但是,VBA 代码可以调用类中的任何公共和非静态方法,包括从基类(例如 Object)获取的方法。 此外,使用早期绑定的进程外客户端无法调用您的类。
向进程外客户端公开类
如果要向进程外客户端公开 VSTO 外接程序中的类,则应继承 StandardOleMarshalObject 类,以确保进程外客户端可以调用公开的 VSTO 外接程序对象。 否则,尝试在进程外客户端中获取公开对象的实例可能会意外失败。
此失败是因为对 Office 应用程序的对象模型的所有调用都必须在主 UI 线程上进行,但从进程外客户端到对象的调用将到达任意 RPC(远程过程调用)线程。 .NET Framework 中的 COM 封送处理机制不会切换线程,而是尝试封送传入 RPC 线程上对您的对象的调用,而非主 UI 线程。 如果对象是派生自 StandardOleMarshalObject的类的实例,则对对象的传入调用会自动封送到创建公开对象的线程,该线程将是主机应用程序的主 UI 线程。
有关在 Office 解决方案中使用线程的详细信息,请参阅 Office 中的线程支持。
重写 RequestComAddInAutomationService 方法
在 VSTO 外接程序的ThisAddIn类中,下面的代码示例演示了如何重写RequestComAddInAutomationService。 该示例假定你定义了一个名为要向其他解决方案公开的类 AddInUtilities 。 若要在较大演练的上下文中查看此代码,请参阅 演练:从 VBA 调用 VSTO 外接程序中的代码。
private AddInUtilities utilities;
protected override object RequestComAddInAutomationService()
{
if (utilities == null)
utilities = new AddInUtilities();
return utilities;
}
加载 VSTO 外接程序后,Visual Studio Tools for Office 运行时将调用该方法 RequestComAddInAutomationService 。 运行时将返回的对象分配给表示 VSTO 外接程序的对象 COMAddIn.Object 属性 COMAddIn 。 此 COMAddIn 对象可用于其他 Office 解决方案和自动化 Office 的解决方案。
从其他解决方案访问对象
若要在 VSTO 外接程序中调用公开的对象,请在客户端解决方案中执行以下步骤:
获取表示公开的 VSTO 外接程序的 COMAddIn 对象。 客户端可以通过 Office 主机应用程序的对象模型中的
Application.COMAddIns属性来访问所有可用的 VSTO 外接程序。访问对象的 COMAddIn COMAddIn.Object 属性。 此属性从 VSTO 外接程序返回公开的对象。
调用暴露对象的成员。
对于 VBA 客户端和非 VBA 客户端,使用 COMAddIn.Object 属性的返回值的方式有所不同。 对于进程外客户端,需要额外的代码以避免可能的竞争条件。
在 VBA 解决方案中访问对象
下面的代码示例演示如何使用 VBA 调用由 VSTO 外接程序公开的方法。 此 VBA 宏调用在名为 ImportData 的 VSTO 外接程序中定义的名为的方法。 若要在较大演练的上下文中查看此代码,请参阅 演练:从 VBA 调用 VSTO 外接程序中的代码。
Sub CallVSTOMethod()
Dim addIn As COMAddIn
Dim automationObject As Object
Set addIn = Application.COMAddIns("ExcelImportData")
Set automationObject = addIn.Object
automationObject.ImportData
End Sub
从非 VBA 解决方案访问对象
在非 VBA 解决方案中,必须将 COMAddIn.Object 属性值强制转换为它实现的接口,然后可以在接口对象上调用公开的方法。 下面的代码示例演示如何从使用 Visual Studio 中的 Office 开发人员工具创建的其他 VSTO 外接程序调用 ImportData 该方法。
object addInName = "ExcelImportData";
Office.COMAddIn addIn = Globals.ThisAddIn.Application.COMAddIns.Item(ref addInName);
ExcelImportData.IAddInUtilities utilities = (ExcelImportData.IAddInUtilities)addIn.Object;
utilities.ImportData();
在此示例中,如果尝试将 COMAddIn.Object 属性的值强制转换为AddInUtilities类而不是IAddInUtilities接口,代码将引发InvalidCastException。