从其他 Office 解决方案中调用 VSTO 外接程序的代码

可以将 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 外接程序中执行以下步骤:

  1. 定义要向其他解决方案公开的类。

  2. 重写ThisAddIn类中的RequestComAddInAutomationService方法。 返回要向其他解决方案公开的类的实例。

定义要向其他解决方案公开的类

至少,要公开的类必须是公共的,它必须将 ComVisibleAttribute 属性设置为 true,并且必须公开 IDispatch 接口。

公开 IDispatch 接口的建议方法是执行以下步骤:

  1. 定义一个接口,该接口声明要向其他解决方案公开的成员。 可以在 VSTO 外接程序项目中定义此接口。 但是,如果要向非 VBA 解决方案公开该类,则可能需要在单独的类库项目中定义此接口,以便调用 VSTO 外接程序的解决方案可以引用接口,而无需引用 VSTO 外接程序项目。

  2. 将此 ComVisibleAttribute 特性应用于此接口,并将此属性设置为 true

  3. 修改类以实现此接口。

  4. ClassInterfaceAttribute属性应用于类,并将此属性设置为枚举的 ClassInterfaceType 值。

  5. 如果要向外部进程客户端暴露此类,您可能还需要执行以下操作:

    • 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 外接程序中调用公开的对象,请在客户端解决方案中执行以下步骤:

  1. 获取表示公开的 VSTO 外接程序的 COMAddIn 对象。 客户端可以通过 Office 主机应用程序的对象模型中的 Application.COMAddIns 属性来访问所有可用的 VSTO 外接程序。

  2. 访问对象的 COMAddIn COMAddIn.Object 属性。 此属性从 VSTO 外接程序返回公开的对象。

  3. 调用暴露对象的成员。

    对于 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