VB6中的集中式错误处理

5
我有以下方法,所有错误处理程序都会调用它:
Public Function ToError(strClass As String, strMethod As String) As String

    On Error GoTo errHandle

    ToError = "Err " & Err.Number & _
                      ", Src: " & Err.Source & _
                      ", Dsc: " & Err.Description & _
                      ", Project: " & App.Title & _
                      ", Class: " & strClass & _
                      ", Method: " & strMethod & _
                      ", Line: " & Erl

    Err.Clear

exitPoint:
   Exit Function

errHandle:
   oLog.AddToLog "Error in ToError Method: " & Err.Description, False
   Resume exitPoint
End Function

原来是因为在这个函数中声明了错误处理程序On Error GoTo errHandle,导致在我记录错误之前VB6就已经清除了错误。有什么方法可以防止'On Error GoTo errHandle'语句清除错误吗?

1
在调用On Error GoTo errHandler之前,将Err对象捕获到一个新实例中。然后引用这个新实例。 - gooch
1
@gooch 这并不起作用。引用也会被重置。 - AngryHacker
1
然后你可以尝试首先检查 Err == Nothing。 然后为每个属性分配本地字符串/整数。 - gooch
4个回答

7

On Error语句将始终清除Err变量(Erl也将重置为0)。理论上,这意味着您可以通过将On Error语句移动到ToString = ...行下面(或完全删除ToError函数中的错误处理程序)来解决问题,但不幸的是,这也不一定总是有效。

每个组件(DLL、ActiveX EXE等)在项目中引用的本质上都会在内存中获得自己的Err实例。因此,如果您的MainApp.exe引发了一个错误,并将其传递给ToError(例如驻留在单独的ErrorHandling.dll中),则DLL将无法看到您的EXE所看到的Err变量。它们各自拥有自己的私有Err变量。

我能想到至少两种解决问题的方法:

方法1

正如Zian Choy提到的那样,您可以向ToError函数添加额外的参数,每个参数对应于您需要访问的Err对象的一个属性。

代码

Public Function ToError( _
   ByVal strErrSource As String, _
   ByVal nErrNumber As Long, _
   ByVal sErrDescription As String, _
   ByVal nLineNumber As Long) As String

示例用法

然后,在您的错误处理程序中,您需要像这样调用它,传递当前 Err 对象以及所有相关值,以及 Erl

ToError Err.Source, Err.Number, Err.Description, Erl 

如果您还想要App.Title,那么您需要为ToError添加一个额外的参数,因为App.Title将等于定义ToError方法的项目的App.Title,而不是引发错误的组件的App.Title。如果ToError在另一个项目中,这一点非常重要。
方法2
您可以通过将Err对象本身作为参数传递给函数来使您的ToError调用变得更简洁,但是在这种情况下,您的ToError函数应该立即存储您需要的所有相关属性的副本,因为随后的On Error语句将清除该变量。 代码
Public Function ToError(ByVal oError As ErrObject, ByVal nLineNumber As Long) As String

   'Copy the important Err properties first, '
   'before doing anything else...            '

   Dim strErrSource As String
   Dim nErrNumber As Long
   Dim strErrDescription As String

   strErrSource = oError.Source
   nErrNumber = oError.Number
   strErrDescription = oError.Description

   On Error Goto errHandle

   'More code here
   '...

示例使用

ToError Err, Erl

1
+1. 方法1是我们实际使用的方法,尽管我们有一个集中的例程来创建错误的字符串表示并记录它。如果您必须传递每个要在错误字符串中组装的项目,则问题中提供的ToError例程将毫无价值。 - MarkJ
@MarkJ:完全同意。理想情况下,该方法应该同时创建错误字符串并记录它,这样才值得首先使用一个方法,而不是在需要时到处调用单独的日志记录代码。我们在核心库中有一个集中的“LogRuntimeError”方法来实现这个目的。 - Mike Spross
@MarkJ。On Error 的目的是捕获极不可能出现 Err 为空或访问 Err 属性会导致错误的情况。我从未见过这种情况,但我的应用程序是24/7运行的,因此我不能承受任何未处理的错误。这里的解决方案并不能解决问题。 - AngryHacker
@AngryHacker:不幸的是,On Error 设计为始终清除当前的 Err 变量。这就是它的工作方式。如果您想在 ToError 方法中保留 On Error,唯一的真正选项是执行类似于方法1的操作,在发生错误时显式传递所有错误属性到您的错误处理函数。无法避免 On Error 将清除 Err 的内容这一事实。 - Mike Spross

2

通过将 Err 对象的值作为参数传递到 ToError 中,您可能能够解决问题。


1

无法防止On Error清除错误。

  • 您可以从ToError中删除错误处理。它非常简短和平淡,不太可能出现错误。
  • 更好的方法是重构错误处理,使得这个ToError代码内联在一个通用的错误报告例程中,该例程执行日志记录或其他所需操作。然后使用Mike's answer中的技术。

顺便说一句,如果有人正在手动添加他们的错误处理程序,请停止您正在做的任何事情,并立即获取免费的MZ-Tools软件包。


0

您可以按照以下方式创建用户定义类型

Private Type TempErrObj
    ErrNumber As Integer
    ErrSource As String
    ErrDescription As String
End Type

稍后将ToError函数修改如下:

Public Function ToError() As String
    Dim iTempErr As TempErrObj
    iTempErr.ErrNumber = Err.Number
    iTempErr.ErrSource = Err.Number
    iTempErr.ErrDescription = Err.Description
    On Error GoTo errHandle

    ToError = "Err " & iTempErr.ErrNumber & _
                      ", Src: " & iTempErr.ErrSource & _
                      ", Dsc: " & iTempErr.ErrDescription & _
                      ", Project: " & App.Title & _
                      ", Line: " & Erl
    Err.Clear

exitPoint:
   Exit Function

errHandle:
    oLog.AddToLog "Error in ToError Method: " & Err.Description, False
   Resume exitPoint
End Function

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