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

可以向其他解决方案(包括其他 Microsoft Office 解决方案)公开 VSTO 外接程序中的对象。 如果 VSTO 外接程序提供了你希望使其他解决方案能够使用的服务,这一点非常有用。 例如,如果你有用于 Microsoft 办公室 Excel 的 VSTO 外接程序,该外接程序对 Web 服务中的财务数据执行计算,其他解决方案可以通过在运行时调用 Excel VSTO 外接程序来执行这些计算。

适用于: 本主题中的信息适用于 VSTO 外接程序项目。 有关详细信息,请参阅办公室应用程序和项目类型提供的功能。

此过程包括以下两个主要步骤:

  • 在 VSTO 外接程序中,向其他解决方案公开对象。

  • 在其他解决方案中,访问由 VSTO 外接程序公开的对象,然后调用对象的成员。

可在外接程序中调用代码的解决方案类型

可以将 VSTO 外接程序中的对象公开为以下类型的解决方案:

  • 在与 VSTO 外接程序相同的应用程序进程中加载的文档中的 Visual Basic for Applications (VBA) 代码。

  • 在与 VSTO 外接程序相同的应用程序进程中加载的文档级自定义项。

  • 使用 Visual Studio 中的 Office 项目模板创建的其他 VSTO 外接程序。

  • COM VSTO 外接程序(即直接实现 IDTExtensibility2 接口的 VSTO 外接程序)。

  • 在不同于 VSTO 外接程序的进程中运行的任何解决方案(这些类型的解决方案也称为 进程外客户端)。 其中包括使 Office 应用程序实现自动化的应用程序(例如 Windows 窗体或控制台应用程序),以及在其他进程中加载的 VSTO 外接程序。

向其他解决方案公开对象

若要向其他解决方案公开 VSTO 外接程序中的对象,请在 VSTO 外接程序中执行下列步骤:

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

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

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

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

建议通过执行以下步骤公开 IDispatch 接口:

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

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

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

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

  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枚举的 ClassInterfaceType AutoDispatch 或 AutoDual 值来公开 IDispatch 接口。 如果公开接口,则无需在单独的接口中声明方法。 不过,VBA 代码可以调用类中的任何公共方法和非静态方法,包括从基类(如 Object)获取的方法。 此外,使用早期绑定的进程外客户端不能调用你的类。

向进程外客户端公开类

如果要向进程外客户端公开 VSTO 外接程序中的类,则应从 StandardOleMarshalObject 派生该类,以确保进程外客户端可以调用公开的 VSTO 外接程序对象。 否则,尝试在进程外客户端中获取已公开对象的实例可能会意外失败。

此失败是因为必须在主 UI 线程上对办公室应用程序的对象模型进行所有调用,但从进程外客户端到对象的调用将到达任意 RPC(远程过程调用)线程。 .NET Framework 中的 COM 封送处理机制不会切换线程,而是尝试将对你的对象的调用封送到传入 RPC 线程(而不是主 UI 线程)中。 如果你的对象是从 StandardOleMarshalObject派生的类的实例,则对你的对象的传入调用会自动封送到用于创建公开对象的线程中,该线程将是主机应用程序的主 UI 线程。

有关在 办公室 解决方案中使用线程的详细信息,请参阅 办公室 中的线程支持。

重写 RequestComAddInAutomationService 方法

以下代码示例演示了如何重写 VSTO 外接程序中 RequestComAddInAutomationService 类中的 ThisAddIn 。 该示例假定你定义了一个名为要向其他解决方案公开的类 AddInUtilities 。 若要在较大演练的上下文中查看此代码,请参阅 演练:从 VBA 调用 VSTO 外接程序中的代码。

private AddInUtilities utilities;

protected override object RequestComAddInAutomationService()
{
    if (utilities == null)
        utilities = new AddInUtilities();

    return utilities;
}

加载 VSTO 外接程序后,用于办公室运行时的 Visual Studio 工具将调用该方法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 宏调用在名为 ExcelImportData 的 VSTO 外接程序中定义的名为ImportData的方法。 若要在较大演练的上下文中查看此代码,请参阅 演练:从 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 属性值强制转换为它实现的接口,然后可以在接口对象上调用公开的方法。 以下代码示例演示了如何从不同的 VSTO 外接程序中调用 ImportData 方法,这些外接程序是通过使用 Visual Studio 中的 Office 开发人员工具创建的。

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