VB6中处理错误的更好方法是什么?

15

我有一个VB6应用程序,我想在其中添加一些良好的错误处理功能,以便告知我出现错误的具体位置和原因,请问有什么好的方法可以实现这个功能?


我还将两个单独的“error”和“handling”标签更改为“error-handling”。 - Onorio Catenacci
7个回答

31
首先,获取MZTools for Visual Basic 6,它是免费且非常有价值的。其次,在每个函数上添加自定义错误处理程序(是的,每个函数都需要)。我们使用的错误处理程序看起来像这样:
On Error GoTo {PROCEDURE_NAME}_Error

{PROCEDURE_BODY}

    On Error GoTo 0
    Exit {PROCEDURE_TYPE}

{PROCEDURE_NAME}_Error:

   LogError "Error " & Err.Number & " (" & Err.Description & ") in line " & Erl & _
            ", in procedure {PROCEDURE_NAME} of {MODULE_TYPE} {MODULE_NAME}"

然后创建一个LogError函数,将错误记录到磁盘。接下来,在发布代码之前,为每个函数添加行号(这也内置于MZTools中)。从现在开始,您将通过错误日志了解发生的所有情况。如果可能的话,还应上传错误日志并实时检查它们。这是VB6中处理意外全局错误的最佳方法(其中之一),但实际上只应用于查找意外错误。如果您知道在某种情况下可能会出现错误,请捕获特定错误并进行处理。如果您知道某个部分发生错误会导致不稳定性(文件IO、内存问题等),请警告用户,并知道您处于“未知状态”,可能会发生“糟糕的事情”。显然要使用友好的术语向用户提供信息,但不要让他们感到恐惧。

Kris--我希望我能给你两个赞,因为那是一个非常好的答案! - Onorio Catenacci
此外,假设原始帖子的作者按照您所说的来执行,任何调用程序都将对发生错误毫不知情,并继续处理。那么,您如何从错误中恢复? - Darrel Miller
1
+1,但我建议在错误处理程序中将错误抛回给调用者。否则,调用者将继续在不知情的情况下执行该例程,并可能导致更严重的问题。显然,事件处理程序不应该抛出异常,否则它们会使应用程序崩溃。 - MarkJ
@NeoTechni - 这篇文章已经超过13年了... 13年前免费发布,我很惊讶它仍然可用。即使在13年前使用VB6也是一个糟糕的想法,现在已经过去20年没有更新更是一个更糟糕的想法。 - Kris Erickson
我使用VB6编写一个处理大量事务的程序,并使用dot NET编写一个伴随应用程序,仅将Win10通知转发到VB6应用程序。运行我的程序的VB6 IDE使用的RAM比dot NET伴随程序少。在这种情况下,性能很重要,因为它是实时OCR引擎。所以dot NET不适用。 - NeoTechni
显示剩余4条评论

15

一种不需要额外模块的简单方法,适用于类模块:

在每个函数/子程序之前进行预处理:

On Error Goto Handler

处理程序/向上冒泡:

Handler:
  Err.Raise Err.Number, "(function_name)->" & Err.source, Err.Description

看吧,小区堆栈跟踪。


+1 不错的想法。而且你可以使用免费的MZTools自动添加这个样板代码。 - MarkJ

4

我使用自己编写的 Error.bas 模块,使得报告和重新抛出错误变得更加简便。

以下是它的内容(由于篇幅原因进行了编辑):

Option Explicit

Public Sub ReportFrom(Source As Variant, Optional Procedure As String)
    If Err.Number Then
        'Backup Error Contents'
        Dim ErrNumber As Long: ErrNumber = Err.Number
        Dim ErrSource As String: ErrSource = Err.Source
        Dim ErrDescription As String: ErrDescription = Err.Description
        Dim ErrHelpFile As String: ErrHelpFile = Err.HelpFile
        Dim ErrHelpContext As Long: ErrHelpContext = Err.HelpContext
        Dim ErrLastDllError As Long: ErrLastDllError = Err.LastDllError
    On Error Resume Next
        'Retrieve Source Name'
        Dim SourceName As String
        If VarType(Source) = vbObject Then
            SourceName = TypeName(Source)
        Else
            SourceName = CStr(Source)
        End If
        If LenB(Procedure) Then
            SourceName = SourceName & "." & Procedure
        End If
        Err.Clear
        'Do your normal error reporting including logging, etc'
        MsgBox "Error " & CStr(ErrNumber) & vbLf & "Source: " & ErrSource & vbCrLf & "Procedure: " & SourceName & vbLf & "Description: " & ErrDescription & vbLf & "Last DLL Error: " & Hex$(ErrLastDllError)
        'Report failure in logging'
        If Err.Number Then
            MsgBox "Additionally, the error failed to be logged properly"
            Err.Clear
        End If
    End If
End Sub

Public Sub Reraise(Optional ByVal NewSource As String)
    If LenB(NewSource) Then
        NewSource = NewSource & " -> " & Err.Source
    Else
        NewSource = Err.Source
    End If
    Err.Raise Err.Number, NewSource, Err.Description, Err.HelpFile, Err.HelpContext
End Sub

报告错误非常简单:

Public Sub Form_Load()
On Error Goto HError
    MsgBox 1/0
    Exit Sub
HError:
    Error.ReportFrom Me, "Form_Load"
End Sub

重新抛出错误只需使用新源调用Error.Reraise即可。
虽然在编译时使用符号调试信息可以从调用堆栈中检索SourceProcedure参数,但这不足以在生产应用程序中使用。

不错的想法,但你应该在示例Form_Load程序中将Exit Sub放在“HError:”上面。 - MarkJ
好的发现,MarkJ!为了完整起见,我已经添加了。 - rpetrich
正如我在这个问题的另一个版本中指出的那样:我看到一个很大的缺点。现在,如果我这样做,所有运行时错误都将被处理。调试器不会在错误位置停止应用程序。相反,它将在堆栈下方的某个其他过程中停止在错误处理程序内部。因此,这种方法有助于解决生产环境中没有调试器的问题,但会破坏与VB6 IDE的正常工作。 - Tomek Szpakowicz
在IDE中进行调试时,应始终将其设置为在所有错误处中断(当然,这假定正常的程序流程不会生成错误)。 - rpetrich

3

当出现错误时跳转到指定标签

Err

对象.

这里有一个教程在这里.


@symbiont,谢谢,我现在已经用另一个替换了它,但由于VB6的年龄越来越老,链接可能会越来越少。 - Joe Skora
谢谢。是的,你当然是对的。不幸的是,有时我不得不在工作中使用它(希望它很快就会消失哈哈)。 - symbiont
在访问链接时收到了“由于技术原因,该站点已离线”的消息。 - clamum
@clamum 谢谢,目前看起来这只是暂时的,但如果它不回来,我会尝试更新答案。 - Joe Skora

1
使用于
dim errhndl as string
on error goto errhndl
errhndl:
msgbox "Error"

1
请描述您的答案。 - warunapww
有时候你会遇到一个错误,你想要跳过它,但如果你使用“在错误时继续”,你甚至不知道出现了错误。我喜欢使用这个的原因是它可以继续执行,但会告诉你出现了错误。 - user6749825

1

是的,请听从Kris的建议并获取MZTools。

您可以添加行号以划分复杂过程的区域,ERL将在错误处理程序中报告它们,以跟踪导致错误的区域。

10
    ...group of statements
20
    ...group of statements
30
    ...and so on

0
使用 On Error 语句和 Err 对象。

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