从 VBA 中调用文档级自定义项中的代码
您可以配置 Word 或 Excel 的文档级项目,以便文档中的 Visual Basic for Applications (VBA) 代码能够调用自定义项程序集中的代码。 此方法可用于以下情况:
您希望使用与某个文档相关联的文档级自定义项中的功能扩展同一文档中的现有 VBA 代码。
您希望将您使用文档级自定义项开发的服务提供给能够通过在文档中编写 VBA 代码来访问服务的最终用户。
**适用于:**本主题中的信息适用于以下应用程序的文档级项目:Excel 2007 和 Excel 2010;Word 2007 和 Word 2010。有关更多信息,请参见按 Office 应用程序和项目类型提供的功能。
Visual Studio 中的 Office 开发工具可为应用程序级外接程序提供相似的功能。 如果在开发外接程序,您可以从其他 Microsoft Office 解决方案中调用外接程序中的代码。 有关更多信息,请参见从其他 Office 解决方案调用应用程序级外接程序中的代码。
提示
此功能无法在 Word 模板项目中使用。 它只能在 Word 文档、Excel 工作簿或 Excel 模板项目中使用。
要求
您的项目必须满足以下要求,然后您才能使 VBA 代码调入自定义项程序集:
文档必须具有以下文件扩展名之一:
对于 Word:.docm 或 .doc
对于 Excel:.xlsm、.xltm、.xls 或 .xlt
文档必须已经包含其中有 VBA 代码的 VBA 项目。
必须在不提示用户启用宏的情况下允许文档中的 VBA 代码运行。 通过在 Word 或 Excel 的“信任中心”设置中将 Office 项目的位置添加到受信任位置列表中,可以信任要运行的 VBA 代码。
Office 项目必须至少包含一个公共类,该类包含一个或多个您要向 VBA 公开的公共成员。
可以向 VBA 公开方法、属性和事件。 公开的类可以是宿主项类(比如 Word 的 ThisDocument 或 Excel 的 ThisWorkbook 和 Sheet1)或您在项目中定义的其他类。 有关宿主项的更多信息,请参见宿主项和宿主控件概述。
使 VBA 代码能够调入自定义项程序集
可通过两种不同方式向文档中的 VBA 代码公开自定义项程序集中的成员:
可以向 VBA 公开 Visual Basic 项目中某个宿主项类的成员。 若要这样做,请在设计器中打开宿主项(即文档、工作表或工作簿),并在**“属性”**窗口中将宿主项的 EnableVbaCallers 属性设置为 True。 Visual Studio 会自动执行所需的全部工作以使 VBA 代码能够调用类成员。
可以向 VBA 公开 Visual C# 项目中任何公共类的成员或 Visual Basic 项目中非宿主项类的成员。 利用此选项,您可以更自由地选择向 VBA 公开哪些类,但此选项同时需要更多的手动步骤。
为此,您必须执行下列主要步骤:
向 COM 公开该类。
重写项目中宿主项类的 GetAutomationObject 方法以返回要向 VBA 公开的类的实例。
将项目中任何宿主项类的 ReferenceAssemblyFromVbaProject 属性设置为 True。 这会将自定义项程序集的类型库嵌入程序集,并将对该类型库的引用添加到文档中的 VBA 项目。
有关详细说明,请参见如何:向 VBA 公开 Visual Basic 项目中的代码和如何:向 VBA 公开 Visual C# 项目中的代码。
EnableVbaCallers 和 ReferenceAssemblyFromVbaProject 属性仅在设计时在**“属性”**窗口中提供;无法在运行时使用这些属性。 若要查看这些属性,请在 Visual Studio 中打开宿主项的设计器。 有关当您设置这些属性时 Visual Studio 执行的具体任务的更多信息,请参见宿主项属性执行的任务。
提示
如果工作簿或文档尚未包含 VBA 代码,或者如果运行文档中的 VBA 代码时不信任该代码,则在将“EnableVbaCallers”或“ReferenceAssemblyFromVbaProject”属性设置为“True”时将收到一条错误消息。 这是因为在这种情况下 Visual Studio 无法修改文档中的 VBA 项目。
使用 VBA 代码中的成员调入自定义项程序集
在您对项目进行配置以使 VBA 代码能够调入自定义项程序集后,Visual Studio 会将以下成员添加到文档中的 VBA 项目中:
对于所有项目,Visual Studio 都会添加一个名为 GetManagedClass 的全局方法。
对于您在其中使用 EnableVbaCallers 属性公开宿主项类成员的 Visual Basic 项目,Visual Studio 还会将一个名为 CallVSTOAssembly 的属性添加到 VBA 项目中的 ThisDocument、ThisWorkbook、Sheet1、Sheet2 或 Sheet3 模块中。
您可以使用 CallVSTOAssembly 属性或 GetManagedClass 方法来访问您向项目中的 VBA 代码公开的类的公共成员。
提示
在开发和部署解决方案时,可在若干不同的文档副本中添加 VBA 代码。 有关更多信息,请参见向文档中添加 VBA 代码的准则。
在 Visual Basic 项目中使用 CallVSTOAssembly 属性
使用 CallVSTOAssembly 属性来访问您添加到宿主项类的公共成员。 例如,下面的 VBA 宏将调用一个名为 MyVSTOMethod 的方法,该方法是在 Excel 工作簿项目的 Sheet1 类中定义的。
Sub MyMacro()
Sheet1.CallVSTOAssembly.MyVSTOMethod()
End Sub
与直接使用 GetManagedClass 方法相比,使用此属性,可以更加方便地调入自定义项程序集。 CallVSTOAssembly 返回一个对象,该对象表示您向 VBA 公开的宿主项类。 所返回对象的成员和方法参数出现在 IntelliSense 中。
CallVSTOAssembly 属性具有一个类似于以下代码的声明。 此代码假定您已向 VBA 公开了名为 ExcelWorkbook1 的 Excel 工作簿项目中的 Sheet1 宿主项类。
Property Get CallVSTOAssembly() As ExcelWorkbook1.Sheet1
Set CallVSTOAssembly = GetManagedClass(Me)
End Property
使用 GetManagedClass 方法
若要使用全局 GetManagedClass 方法,请传入与宿主项类对应的 VBA 对象,该宿主项类包含 GetAutomationObject 方法的重写。 然后,使用返回的对象访问您向 VBA 公开的类。
例如,下面的 VBA 宏将调用一个名为 MyVSTOMethod 的方法,该方法是在 Excel 工作簿项目(名为 ExcelWorkbook1)的 Sheet1 宿主项类中定义的。
Sub CallVSTOMethod
Dim VSTOSheet1 As ExcelWorkbook1.Sheet1
Set VSTOSheet1 = GetManagedClass(Sheet1)
VSTOSheet1.MyVSTOMethod
End Sub
GetManagedClass 方法具有以下声明。
GetManagedClass(pdispInteropObject Object) As Object
此方法返回一个对象,该对象表示您向 VBA 公开的类。 所返回对象的成员和方法参数出现在 IntelliSense 中。
向文档中添加 VBA 代码的准则
可在若干不同的文档副本中添加可调入文档级自定义项的 VBA 代码。
在开发和测试解决方案时,对于当您在 Visual Studio 中调试或运行项目时将打开的文档(即位于生成输出文件夹中的文档),您可以在其中编写 VBA 代码。 但是,在下次生成项目时,添加到此文档中的任何 VBA 代码将被覆盖,因为 Visual Studio 会将生成输出文件夹中的文档替换为主项目文件夹中文档的副本。
如果要保存在调试或运行解决方案时添加到文档的 VBA 代码,请将 VBA 代码复制到项目文件夹内的文档中。 有关生成过程的更多信息,请参见 Office 解决方案生成过程概述。
当准备好部署解决方案时,您可以在三个主要文档位置中添加 VBA 代码。
开发计算机上的项目文件夹中
如果您能够完全控制文档中的 VBA 代码和自定义项代码,则此位置非常方便。 由于文档位于开发计算机上,因此,如果更改自定义项代码,您可以轻松地修改 VBA 代码。 当您生成、调试和发布解决方案时,添加到此文档副本的 VBA 代码将保留在文档中。
当文档在设计器中处于打开状态时,您无法向其中添加 VBA 代码。 必须首先关闭设计器中的文档,然后在 Word 或 Excel 中直接打开文档。
警告
如果添加在文档打开时运行的 VBA 代码,在少数情况下,此代码可能会损坏文档,或使文档无法在设计器中打开。
在发布或安装文件夹中
某些情况下,将 VBA 代码添加到发布或安装文件夹中的文档可能比较适合。 例如,如果 VBA 代码是由其他开发人员在未安装 Visual Studio 的计算机上编写和测试的,则您可以选择此选项。
如果用户直接从发布文件夹中安装解决方案,您必须在每次发布解决方案时将 VBA 代码添加到文档。 当您发布解决方案时,Visual Studio 会覆盖发布位置中的文档。
如果用户从不同于发布文件夹的安装文件夹中安装解决方案,您可以避免在每次发布解决方案时向文档中添加 VBA 代码。 当准备将发布更新从发布文件夹移到安装文件夹时,请将除文档外的所有文件复制到安装文件夹。
在最终用户计算机上
如果最终用户是 VBA 开发人员并且将要调入您在文档级自定义项中提供的服务,则您可以告诉他们如何通过在其文档副本中使用 CallVSTOAssembly 属性或 GetManagedClass 方法来调用您的代码。 发布解决方案更新时,不会覆盖最终用户计算机上的文档中的 VBA 代码,因为发布更新不会修改该文档。
宿主项属性执行的任务
当您使用 EnableVbaCallers 和 ReferenceAssemblyFromVbaProject 属性时,Visual Studio 会执行几组不同的任务。
EnableVbaCallers
当您在 Visual Basic 项目中将宿主项的 EnableVbaCallers 属性设置为 True 时,Visual Studio 将执行下列任务:
它将 ComClassAttribute 和 ComVisibleAttribute 特性添加到宿主项类。
它将重写宿主项类的 GetAutomationObject 方法。
它将宿主项的 ReferenceAssemblyFromVbaProject 属性设置为 True。
当您将 EnableVbaCallers 属性重新设置为 False 时,Visual Studio 将执行下列任务:
它将从 ThisDocument 类中移除 ComClassAttribute 和 ComVisibleAttribute 特性。
它将从宿主项类中移除 GetAutomationObject 方法。
提示
Visual Studio 不会自动将 ReferenceAssemblyFromVbaProject 属性重新设置为 False。 您可以使用“属性”窗口将此属性手动设置为 False。
ReferenceAssemblyFromVbaProject
当 Visual Basic 或 Visual C# 项目中任何宿主项的 ReferenceAssemblyFromVbaProject 属性设置为 True 时,Visual Studio 将执行下列任务:
它将为自定义项程序集生成一个类型库,并将类型库嵌入程序集。
它会在文档内的 VBA 项目中添加对以下类型库的引用:
自定义项程序集的类型库。
Microsoft Visual Studio Tools for Office Execution Engine 9.0 类型库。 此类型库包括在 Visual Studio Tools for Office Runtime中。
将 ReferenceAssemblyFromVbaProject 属性重新设置为 False 时,Visual Studio 将执行下列任务:
它从文档内的 VBA 项目中移除类型库引用。
它从程序集中移除嵌入的类型库。
疑难解答
下表列出了一些常见错误以及修复错误的建议。
Error |
建议 |
---|---|
设置了 EnableVbaCallers 或 ReferenceAssemblyFromVbaProject 属性后,一条错误消息指明文档未包含 VBA 项目,或者您没有访问文档中的 VBA 项目的权限。 |
确保项目中的文档至少包含一个 VBA 宏、VBA 项目具有运行所需的足够信任级别,并且 VBA 项目未受密码保护。 |
设置了 EnableVbaCallers 或 ReferenceAssemblyFromVbaProject 属性后,一条错误消息指明缺少 GuidAttribute 声明或该声明已损坏。 |
确保 GuidAttribute 声明位于项目内的 AssemblyInfo.cs 或 AssemblyInfo.vb 文件中,并且此特性设置为有效的 GUID。 |
设置了 EnableVbaCallers 或 ReferenceAssemblyFromVbaProject 属性后,一条错误消息指明 AssemblyVersionAttribute 指定的版本号无效。 |
确保项目内 AssemblyInfo.cs 或 AssemblyInfo.vb 文件中的 AssemblyVersionAttribute 声明设置为有效的程序集版本号。 有关有效的程序集版本号的信息,请参见 AssemblyVersionAttribute 类。 |
重命名自定义项程序集后,调入自定义项程序集的 VBA 代码停止工作。 |
如果在向 VBA 代码公开自定义项程序集的名称后更改了该名称,则文档中的 VBA 项目和自定义项程序集之间的链接将断开。 若要修复此问题,请在项目中将 ReferenceFromVbaAssembly 属性设置为 False 并随后设置回 True,然后,将 VBA 代码中对旧程序集名称的任何引用替换为新程序集名称。 |
请参见
任务
如何:向 VBA 公开 Visual Basic 项目中的代码
演练:在 Visual Basic 项目中调用 VBA 中的代码