2

我编写了一个 VBA 程序,它在 上创建Workbook_Open一个将错误写入错误日志的文件流。如果我遇到致命错误(因此需要停止宏的执行),程序会执行一条End语句,突然停止宏。我知道这个解决方案不是一个理想的解决方案,但是如果我有几个函数很深(即一个函数调用了另一个函数调用了另一个函数,并且第三个函数产生错误)。退出发生错误的函数只会影响该特定函数,导致可能出现无效数据、意外单元格值等。

但是这种方法给我带来了另一个问题——End执行时它会破坏我的所有对象,包括错误流。因此,当用户执行新操作并遇到致命错误时,他们会收到 VBA 运行时错误(91: Object ... not set),因为代码写入现在设置为的文件流Nothing.

有没有更好的方法来结束宏(从而避免错误后的意外行为)而不丢失我的所有对象?官方的 VBA 文档没有帮助。提前致谢。

4

4 回答 4

3

结尾:

立即终止执行。本身从来不需要,但可以放置在过程中的任何位置以结束代码执行、关闭使用 Open 语句打开的文件以及清除变量。执行时,End 语句会重置所有模块中的所有模块级变量和所有静态局部变量。

这个工作簿模块:

Public fileSystem As FileSystemObject
Public errorStream As TextStream

Private Sub Workbook_Open()

    Set fileSystem = New FileSystemObject
    Set errorStream = fileSystem.CreateTextFile("c:\temp\error.log", True)

End Sub

标准模块:

Public Sub First()
    If (Not ThisWorkbook.errorStream Is Nothing) Then
        Debug.Print VBA.TypeName(ThisWorkbook.errorStream)
    End If

    End
    ' Exit Sub
End Sub

Public Sub Second()
    If (Not ThisWorkbook.errorStream Is Nothing) Then
        Debug.Print VBA.TypeName(ThisWorkbook.errorStream)
    End If
End Sub

当“First”方法首先执行“End”,然后是“Second”方法时,errorStream 将是 Nothing。代替'End' 使用'ExitSub',则变量不会被重置。

或者,您可以在 Thisworkbook 类模块中将错误流变量设为私有并添加属性,如果变量为 Nothing,它将创建流。高温高压

这个工作簿模块:

Private m_errorStream As TextStream
Private Const FILE_PATH_NAME As String = "c:\temp\error.log"

Public Property Get ErrorStream() As TextStream
    If (m_errorStream Is Nothing) Then
        Dim fileSystem As FileSystemObject
        Set fileSystem = New FileSystemObject
        If (fileSystem.FileExists(FILE_PATH_NAME)) Then
            Set m_errorStream = fileSystem.GetFile(FILE_PATH_NAME).OpenAsTextStream
        Else
            Set m_errorStream = fileSystem.CreateTextFile(FILE_PATH_NAME, False)
        End If
    End If

    Set ErrorStream = m_errorStream
End Property

标准模块:

Public Sub First()
    If (Not ThisWorkbook.ErrorStream Is Nothing) Then
        Debug.Print VBA.TypeName(ThisWorkbook.ErrorStream)
    End If

    End
End Sub

Public Sub Second()
    If (Not ThisWorkbook.ErrorStream Is Nothing) Then
        Debug.Print VBA.TypeName(ThisWorkbook.ErrorStream)
    End If
End Sub
于 2013-08-01T14:53:11.183 回答
0

使用顶级错误处理程序,并且只在您想要处理的例程中捕获错误而不完全中止

演示:

Option Explicit

Sub test()
On Error GoTo Top_Error_Handler
Debug.Print "Error handled in sub routine: test1"
test1
Debug.Print "Error NOT handled in sub routine: test2"
test2
Exit Sub

Top_Error_Handler:
MsgBox "Top Level Error Handler: Error Number:" & Err.Number _
     & ":" & Err.Description

End Sub

Sub test1()
On Error Resume Next
Debug.Print 1 / 0

End Sub

Sub test2()
Debug.Print 1 / 0
End Sub

如您所见,错误处理test1覆盖了主程序中的处理,因此不会引发错误。在第二个 Sub,test2中,没有错误处理,因此信息被传递给前一个程序来处理(如果该程序被其他东西调用,它将向上传递链),并且错误可以干净由您的主要例程处理以整齐地关闭所有内容。

于 2013-08-01T14:56:15.103 回答
0

在模块级别声明变量,而不是在函数中。在 VBA 中,默认情况下,您会在左侧的项目导航中看到各种工作表。工作表下方是一个名为“Modules”的文件夹:如果您没有看到“Module1”或作为该文件夹子级的变体,请右键单击该文件夹并选择“Insert\Module”。
这些对你来说应该是持久的。

于 2013-08-01T14:04:49.813 回答
0

也许尝试Exit而不是End

如果你试图退出一个函数

Function a()

If blahblah.. Then
    Exit Function
End If

End Function

我不确定您的对象是如何在哪些模块上声明和处理的,所以......如果您可以发布代码,它可能会有很大帮助。

于 2013-08-01T14:12:04.280 回答