【问题标题】:Can I use late binding to check the existence of a library before using it via early binding?在通过早期绑定使用库之前,我可以使用后期绑定来检查它的存在吗?
【发布时间】:2012-02-13 06:33:37
【问题描述】:

我喜欢在我的 VBA 项目中使用早期绑定,因为我喜欢在开发过程中自动完成方法名称等。我也喜欢知道如果我拼错了方法名,编译器会警告我的信心。

但是,要使用早期绑定,我需要添加对相关库的引用(例如,“Microsoft Scripting Runtime”)。这对于像这样的“标准”库来说很好,但有时我想使用用户机器上可能存在也可能不存在的库。

理想情况下,如果库不存在,我想显示一条有用的消息(例如“此计算机上未安装 xyz,因此无法使用此功能”)。如果我只使用 late 绑定,那么我可以这样做:

Dim o As Object
Set o = CreateObject("foo", "bar")

If o Is Nothing Then
    MsgBox "nope"
End If

但是,如果我添加了对库的引用以使用早期绑定,那么如果该库不存在,则在加载 VBA 项目时会出现编译错误。因此,none 的代码运行(包括检测库不存在的代码)。

有什么办法可以绕过这个 catch-22 吗?

【问题讨论】:

  • 我使用早期绑定来利用 Intellisense,然后转换为后期绑定以避免特定于版本的代码。
  • @JP:请参阅我对 mwolfe02 的回答 - 我认为这对我来说不是一个可行的解决方案,除非您有其他方法来实现它。
  • 我将所有声明放在每个过程的顶部,并使用适用于后期或早期绑定的 CreateObject。那么,简单地将所有早期绑定声明更改为后期绑定“作为对象”。但条件编译也可以。

标签: vba late-binding early-binding


【解决方案1】:

您可以创建一个类模块作为对象库的代理 --- 包装您的其他过程所需的所有方法、属性和常量。

所有这些过程都将以相同的方式使用代理类,因此您无需修改​​这些过程即可在早期绑定和后期绑定之间切换。 Intellisense 会向您展示您使用代理类公开的所有内容。

该类将是在早期绑定和后期绑定之间切换的单点控制。您提到 Excel 是一个例子:

#Const DevStatus = "PROD"
#If DevStatus = "DEV" Then
    Private objApp As Excel.Application
    Private objBook As Excel.Workbook
    Private objSheet As Excel.Worksheet
#Else 'assume PROD
    Private objApp As Object
    Private objBook As Object
    Private objSheet As Object
#End If

如果 Excel 可能未安装在任何用户的计算机上,您可以在类初始化期间检查其可用性。

Dim blnExcelAvailable As Boolean

Private Sub Class_Initialize()
    blnExcelAvailable = IsExcelAvailable()
End Sub

Private Function IsExcelAvailable() As Boolean
    Dim blnReturn As Boolean
    Dim objTest As Object

On Error GoTo ErrorHandler

    Set objTest = CreateObject("Excel.Application")
    blnReturn = True

ExitHere:
    On Error GoTo 0
    Set objTest = Nothing
    IsExcelAvailable = blnReturn
    Exit Function

ErrorHandler:
    blnReturn = False
    GoTo ExitHere
End Function

然后您的使用代理类的程序可以检查一个属性以查看 Excel 是否可用。

Public Property Get ExcelAvailable() As Boolean
    ExcelAvailable = blnExcelAvailable
End Property

我认为这种方法是可行的,并且满足您对 AFAICT 的要求。但是,我不确定这是否合理。回到 Excel 的示例,您可以对其对象模型的可管理子集执行类似的操作。但是,如果您需要它的全部或大部分方法、属性和常量,代理类将是一项艰巨的任务。

我个人不会使用这种方法。像 mwolfe02 和 JP 一样管理早期/晚期绑定对我来说工作量较小。描述。但是我的印象是,在你的情况下这会更加繁重,所以也许你愿意在这样的事情上比我付出更多的努力。

【讨论】:

  • 好主意。你 100% 正确,重复所有对象、方法和(尤其是)常量对于 Excel 之类的东西来说是一项艰巨的任务。然而,我以 Excel 为例是愚蠢的,因为我可以假设 Office 的存在 - 毕竟这是 VBA,如果代码正在运行,那么主机应用程序必须在场。对于我真正关心的那种小型库,您的技术将更加可行。谢谢!
  • +1 我真的很喜欢这个想法,但它似乎只适用于预定义的“Office”应用程序
  • @mehow 我的意思是一个 VBA 类来包装一个 COM 应用程序,因此应用程序将在该类中定义。 (这就是您所说的预定义吗?)以及针对不同应用程序的不同包装类。但这个概念并不局限于 Office 应用程序。其他支持 COM 的应用程序也应该可以工作。
  • @HansUp 是的,这是正确的。 (对不起,这可能是我的英语)。我现在已经重读了你的回答,是的,我收回了我关于限制的最后陈述。
【解决方案2】:

不是真的。

但是,我在开发中处理此问题的一种方法是有两个单独的声明行。我根据我是在做开发工作还是发布到生产环境来评论一个或另一个。您可以不理会其他所有内容(包括 CreateObject 行),然后您只需要记住切换注释行并添加/删除引用本身。

例如:

Dim o As foo.bar   'Comment out for production'
'Dim o As Object    ''Comment out for dev work'
Set o = CreateObject("foo", "bar")

If o Is Nothing Then
    MsgBox "nope"
End If

【讨论】:

  • 这还不错,只是我的项目很大,所以实际上会有数百个声明。每个 Excel.Range、每个 Word.Paragraph 等都必须有这个双重声明。
  • 我想我可以使用编译器常量并用#If LATE_BOUND Then ...括起来,这将使两种模式之间的切换更容易。但这确实会使代码变得混乱,因为现在每个声明都需要 5 行。
  • ... 并且这意味着我的所有方法和函数也有不同的声明。哎呀!
猜你喜欢
  • 2016-12-15
  • 1970-01-01
  • 2012-01-15
  • 1970-01-01
  • 2016-12-08
  • 2010-10-21
  • 1970-01-01
  • 1970-01-01
  • 2011-07-17
相关资源
最近更新 更多