演练:在 Visual C# 项目中调用 VBA 中的代码

此演练演示如何从工作簿的 Visual Basic for Applications (VBA) 代码调用 Microsoft Office Excel 文档级自定义项中的方法。该过程包括三个基本步骤:向 Sheet1 宿主项类添加方法,向工作簿中的 VBA 代码公开方法,然后从工作簿的 VBA 代码中调用该方法。

**适用于:**本主题中的信息适用于以下应用程序的文档级项目:Excel 2013 和 Excel 2010;Word 2013 和 Word 2010。有关更多信息,请参见按 Office 应用程序和项目类型提供的功能

虽然此演练具体使用的是 Excel,但其中所阐释的概念同样适用于 Word 的文档级项目。

本演练阐释了以下任务:

  • 创建一个包含 VBA 代码的工作簿。

  • 使用 Excel 的“信任中心”信任工作簿的位置。

  • 向 Sheet1 宿主项类添加方法。

  • 提取 Sheet1 宿主项类的接口。

  • 向 VBA 代码公开此方法。

  • 从 VBA 代码中调用方法。

说明说明

以下说明中的某些 Visual Studio 用户界面元素在计算机上出现的名称或位置可能会不同。您安装的 Visual Studio 版本以及使用的设置决定了这些元素。有关更多信息,请参见Visual Studio 设置

系统必备

您需要以下组件来完成本演练:

-

Visual Studio 2012 的一个版本,其中包含 Microsoft Office 开发工具。有关更多信息,请参见[将计算机配置为开发 Office 解决方案](bb398242\(v=vs.110\).md)。
  • Excel 2013 或 Excel 2010。

创建包含 VBA 代码的工作簿

第一步是创建一个启用宏的工作簿,该工作簿包含简单的 VBA 宏。工作簿必须已经包含 VBA 代码,然后您才能向 VBA 公开自定义项中的代码。否则,Visual Studio 无法修改 VBA 项目以使 VBA 代码能够调入自定义项程序集。

如果您已经拥有一个包含要使用的 VBA 代码的工作簿,则可以跳过此步骤。

创建包含 VBA 代码的工作簿

  1. 启动 Excel。

  2. 将活动文档另存为名为 WorkbookWithVBA 的**“启用宏的 Excel 工作簿(*.xlsm)”**。将它保存到一个方便的位置,比如桌面。

  3. 在功能区上,单击**“开发人员”**选项卡。

    说明说明

    如果看不到“开发人员”选项卡,您必须首先显示该选项卡。有关更多信息,请参见如何:在功能区上显示“开发人员”选项卡

  4. 在**“代码”组中,单击“Visual Basic”**。

    将打开 Visual Basic 编辑器。

  5. 在**“项目”窗口中,双击“ThisWorkbook”**。

    将打开 ThisWorkbook 对象的代码文件。

  6. 向代码文件中添加以下 VBA 代码。此代码定义一个不执行任何操作的简单函数。此函数的唯一用途是确保 VBA 项目存在于工作簿中。这对此演练中的后续步骤是必需的。

    Sub EmptySub()
    End Sub
    
  7. 保存文档并退出 Excel。

创建项目

现在,您可以创建一个 Excel 文档级项目,这个项目使用您以前创建的、启用宏的工作簿。

创建新项目

  1. 启动 Visual Studio。

  2. 在**“文件”菜单上指向“新建”,再单击“项目”**。

  3. 在模板窗格中,展开 visual C#,然后展开 Office/SharePoint

  4. 选择 Office 加载项 节点。

  5. 在项目模板列表中,选择 Excel 2010 工作簿Excel 2013 工作簿 项目。

  6. 在**“名称”**框中,键入 CallingCodeFromVBA。

  7. 单击**“确定”**。

    会打开**“Visual Studio Tools for Office 项目向导”**。

  8. 选择**“复制现有文档”,并在“现有文档的完整路径”**框中,指定之前创建的 WorkbookWithVBA 工作簿的位置。如果您正在使用自己的启用宏的工作簿,则改为指定此工作簿的位置。

  9. 单击**“完成”**。

    Visual Studio 将在设计器中打开 WorkbookWithVBA 工作簿,并将**“CallingCodeFromVBA”项目添加到“解决方案资源管理器”**中。

信任工作簿的位置

在可以向工作簿中的 VBA 代码公开解决方案中的代码之前,必须信任要运行的工作簿中的 VBA。有若干方法可用来执行此操作。在此演练中,您将通过在 Excel 的**“信任中心”**中信任工作簿的位置来完成此任务。

信任工作簿的位置

  1. 启动 Excel。

  2. 单击**“文件”**选项卡。

  3. 单击**“Excel 选项”**按钮。

  4. 在类别窗格中单击**“信任中心”**。

  5. 在详细信息窗格中单击**“信任中心设置”**。

  6. 在类别窗格中单击**“受信任位置”**。

  7. 在细节窗格中单击**“添加新位置”**。

  8. 在**“Microsoft Office 受信任位置”**对话框中,浏览到包含 CallingCodeFromVBA 项目的文件夹。

  9. 选择**“同时信任此位置的子文件夹”**。

  10. 在**“Microsoft Office 受信任位置”对话框中,单击“确定”**。

  11. 在**“信任中心”对话框中,单击“确定”**。

  12. 在**“Excel 选项”对话框中单击“确定”**。

  13. 退出 Excel

向 Sheet1 类中添加方法

既然设置了 VBA 项目,请向可从 VBA 代码中调用的 Sheet1 宿主项类中添加一个公共方法。

向 Sheet1 类中添加方法

  1. 在**“解决方案资源管理器”中右击“Sheet1.cs”,然后单击“查看代码”**。

    Sheet1.cs 文件将在代码编辑器中打开。

  2. 向 Sheet1 类中添加下面的代码。CreateVstoNamedRange 方法在指定的范围创建一个新的 NamedRange 对象。此方法还会为 NamedRangeSelected 事件创建事件处理程序。稍后在此演练中,您将从文档的 VBA 代码中调用 CreateVstoNamedRange 方法。

    private Microsoft.Office.Tools.Excel.NamedRange namedRange1;
    
    public void CreateVstoNamedRange(Excel.Range range, string name)
    {
        if (!this.Controls.Contains(name))
        {
            namedRange1 = this.Controls.AddNamedRange(range, name);
            namedRange1.Selected += new Excel.DocEvents_SelectionChangeEventHandler(
                    namedRange1_Selected);
        }
        else
        {
            MessageBox.Show("A named range with this specific name " +
                "already exists on the worksheet.");
        }
    }
    
    private void namedRange1_Selected(Microsoft.Office.Interop.Excel.Range Target)
    {
        MessageBox.Show("This named range was created by Visual Studio " +
            "Tools for Office.");
    }
    
  3. 将下面的方法添加到 Sheet1 类中。此方法将重写 GetAutomationObject 方法,以返回 Sheet1 类的当前实例。

    protected override object GetAutomationObject()
    {
        return this;
    }
    
  4. 在 Sheet1 类声明的第一行前面应用下列特性。这些特性使类对于 COM 可见,但不生成类接口。

    [System.Runtime.InteropServices.ComVisible(true)]
    [System.Runtime.InteropServices.ClassInterface(
        System.Runtime.InteropServices.ClassInterfaceType.None)]
    

提取 Sheet1 类的接口

在能够向 VBA 代码公开 CreateVstoNamedRange 方法之前,您必须创建一个定义此方法的公共接口,并且必须向 COM 公开此接口。

提取 Sheet1 类的接口

  1. 在 Sheet1.cs 代码文件中,单击 Sheet1 类中的任意位置。

  2. 在**“重构”菜单上,单击“提取接口”**。

  3. 在**“提取接口”对话框的“选择构成接口的公共成员”**框中,单击 CreateVstoNamedRange 方法项。

  4. 单击**“确定”**。

    Visual Studio 将生成一个名为 ISheet1 的新接口,并修改 Sheet1 类的定义,以使其实现 ISheet1 接口。Visual Studio 还将在代码编辑器中打开 ISheet1.cs 文件。

  5. 在 ISheet1.cs 文件中,将 ISheet1 接口声明替换为以下代码。此代码使 ISheet1 接口成为公共接口,并且应用 ComVisibleAttribute 特性以使该接口对于 COM 可见。

    [System.Runtime.InteropServices.ComVisible(true)]
    public interface ISheet1
    {
        void CreateVstoNamedRange(Microsoft.Office.Interop.Excel.Range range, string name);
    }
    
  6. 生成项目。

向 VBA 代码公开方法

若要向工作簿中的 VBA 代码公开 CreateVstoNamedRange 方法,请将 Sheet1 宿主项的**“ReferenceAssemblyFromVbaProject”属性设置为“True”**。

向 VBA 代码公开方法

  1. 在**“解决方案资源管理器”**中双击 Sheet1.cs。

    WorkbookWithVBA 文件将在设计器中打开,并显示 Sheet1。

  2. 在**“属性”窗口中,选择“ReferenceAssemblyFromVbaProject”属性,并将值更改为“True”**。

  3. 在显示的消息中单击**“确定”**。

  4. 生成项目。

从 VBA 代码中调用方法

现在可以从工作簿的 VBA 代码中调用 CreateVstoNamedRange 方法。

说明说明

在此演练中,将在调试项目时向工作簿中添加 VBA 代码。在下次生成项目时,添加到此文档中的 VBA 代码将被覆盖,因为 Visual Studio 会将生成输出文件夹中的文档替换为主项目文件夹中文档的副本。如果要保存 VBA 代码,可以将它复制到项目文件夹内的文档中。有关更多信息,请参见结合 VBA 和文档级自定义项

从 VBA 代码中调用方法

  1. 按 F5 运行项目。

  2. 在**“开发人员”选项卡上的“代码”组中,单击“Visual Basic”**。

    将打开 Visual Basic 编辑器。

  3. 在**“插入”菜单上,单击“模块”**。

  4. 向新模块添加以下代码。

    此代码调用自定义项程序集中的 CreateTable 方法。宏通过使用全局 GetManagedClass 方法来访问您向 VBA 代码公开的 Sheet1 宿主项类,从而访问此方法。GetManagedClass 方法是您之前在此演练中设置**“ReferenceAssemblyFromVbaProject”**属性时自动生成的。

    Sub CallVSTOMethod()
        Dim VSTOSheet1 As CallingCodeFromVBA.Sheet1
        Set VSTOSheet1 = GetManagedClass(Sheet1)
        Call VSTOSheet1.CreateVstoNamedRange(Sheet1.Range("A1"), "VstoNamedRange")
    End Sub
    
  5. 按 F5。

  6. 在打开的工作簿中,单击**“Sheet1”上的单元格“A1”**。验证是否出现消息框。

  7. 退出 Excel 而不保存更改。

后续步骤

在以下主题中,您可以了解有关从 VBA 调用 Office 解决方案中的代码的更多信息:

请参见

任务

如何:向 VBA 公开 Visual Basic 项目中的代码

如何:向 VBA 公开 Visual C# 项目中的代码

演练:在 Visual Basic 项目中调用 VBA 中的代码

其他资源

结合 VBA 和文档级自定义项

对文档级自定义项进行编程