为什么当VBE(代码窗口)未打开时,VBE.ActiveCodePane.CodeModule无法工作?

4
创建一个表单,运行以下代码。
MsgBox (VBE.ActiveCodePane.CodeModule)

并且出现了这个消息。

enter image description here

现在保存、关闭并重新打开数据库,然后看到这条消息:

运行时错误'91':对象变量或With块变量未设置

enter image description here

如果你打开Visual Basic Editor,它会再次运行。即使你关闭了VBE,它仍然运行。

但是当你关闭整个应用程序并重新打开它时,保持VBE关闭,你会收到错误信息。

为什么?这里发生了什么?


我在一个Workbook_Open()处理程序中遇到了问题,下面Bas Verlaat提供的...Activate解决方案很好地解决了它。奇怪的是,在这个错误中Err对象不可用,所以调试起来非常奇怪。 - Andreas Covidiot
4个回答

7

你引用了活动窗格对象。该对象在窗格被激活之前并未设置。因此,在打开VBE之前,该对象尚未设置。一旦关闭VBE,该对象仍然存在,因此仍然可以引用它。

要获取ActiveCodepane对象的句柄,而不需要打开VBE,可以通过激活VBComponent来实现,如下所示:

VBE.ActiveVBProject.VBComponents("Module1").Activate

您可以通过以下方式激活任何VBComponent。

4

当第一次打开应用程序时,如果关闭了VBE,则没有ActiveCodePane,您可以在加载表单时的条件语句中检查此情况:

If (Application.VBE.ActiveCodePane Is Nothing) Then MsgBox "ActiveCodePane is Nothing"
VBE是存在的,它的属性和方法可以使用,但是没有ActiveCodePane,这就是为什么会出现空引用异常的原因。如果您在保存和关闭之前关闭了所有CodePanes(除非有某种原因存在某个模块),那么仅打开VBE仍将产生错误。必须明确地打开CodePane,以设置“ActiveCodePane”属性。 Access and VBE are open, but no <code>CodePane</code> is open, therefore the <code>ActiveCodePane</code> is still Nothing 这很有道理。你试图通过ActiveCodePane属性访问什么?也许我可以帮忙找到一种解决方法?
编辑
假设在开发此表单和相关模块时,您将知道它们的名称,并且能够使用与@Bas Verlaat提到的不同的方法,而不是使用ActiveCodePane。或者,您可以循环遍历活动VBProject中的每个代码窗格,并尝试匹配名称或其他内容:
Option Compare Database
Option Explicit

Private vbProj As VBIDE.VBProject
Private vbComp As VBIDE.VBComponent
Private vbMod As VBIDE.CodeModule

Private Sub Command0_Click()

    Set vbProj = Application.VBE.ActiveVBProject

    For Each vbComp In vbProj.VBComponents
        MsgBox vbComp.CodeModule
    Next

End Sub

我正在尝试获取代码模块名称。我觉得有点奇怪的是,代码在开发过程中可以正常运行,但是当部署到生产环境时会出现问题,这也发生在我身上了。 - PBeezy
好的。我已经有一段时间没有看 VBE 的东西了。我会看看我能想出什么。 - Tyler StandishMan
我更新了我的答案,加入了一个简短的循环来获取CodePanes/CodeModules,无论VBE或任何CodePanes是否打开。我注意到Application.VBE.CodePanes实际上只是打开的代码窗格集合,而不是所有的。在我的编辑中发布的方法适用于之前未打开过VBE的情况。 - Tyler StandishMan
1
谢谢。这很棒。对于未来的读者,只需记得添加对Microsoft Visual Basic for Applications Extensibility 5.3的引用即可。 - PBeezy
好的,谢谢你提到了参考资料。如果这两个答案中有一个对你有帮助,你介意标记其中一个为答案,这样未来的读者就可以知道哪个答案最有用了吗? - Tyler StandishMan

2

正如Bas Verlaat所说,在打开VBE之前,对象尚未设置。

显然,当用户使用程序时,VBE不会打开。仅在开发和调试时引用Active Code Pane,并且永远不要在生产中使用。

例如,以下自定义错误消息非常适用于调试,但如果部署到生产环境中,则会失败。

ErrorHandler:
    MsgBox "Error " & Err.number & ": " & Err.Description & " in " & _
    VBE.ActiveCodePane.CodeModule, vbOKOnly, "Error"

0

方法

由于有时无法避免使用VBE功能,我通常的解决方案是...

  1. 确保初始化/激活相关工作簿的VB项目(组件)
  2. 确保在打开它们后初始化/激活其他工作簿的VB项目(组件)(如果它们的VBE属性/代码可能在后续过程中相关)

VbeInit用法

为此,可以调用以下代码:

  • 在某个事件的开头调用VbeInit(例如Workbook_Open()事件),以及
  • 每当打开一个相关的工作簿时(例如使用Workbooks.Open(...)),调用VbeInit someOpenedWorkbook

示例情况

对于上述简单情况,它起作用。 更复杂的情况是,您依赖于工作簿中表格的CodeName。 例如。

  • 如果用户被允许重新命名一些工作表,但这些工作表仍应通过它们的CodeName在VB应用程序中得到唯一标识,
  • 这样的工作表(例如作为模板工作表)将被复制(sheet.Copy ...)到其他工作簿中。

然后,只有当工作表的VBComponent已被激活(例如通过myVBComponent.Activate或在VBE中打开包含源工作表的工作簿)时,才会复制工作表的CodeName

VbeInit过程

Procedure VbeInit(Optional wb As Workbook)

    With Application.VBE
        Dim pj As VBProject:  For Each pj In .VBProjects
            'ignore unsaved (=> fully initialized) workbooks
            If Not wb Is Nothing Then If wb.FullName <> VBProjFilename(pj) Then GoTo continue

            Dim c As VBComponent:  For Each c In pj.VBComponents
                c.Activate
            Next c

continue:
        Next pj
    End With

End Procedure


Function VBProjFilename(pj As VBProject) As String
    On Error Resume Next  'leave result empty if workbook (code) not saved yet
    VBProjFilename = pj.Filename
End Function

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接