views:

133

answers:

3

I have the following method that all the error handlers call:

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

It turns out that because I declare an error handler in this function On Error GoTo errHandle, VB6 clears the error before I am able to record it.

Is there a way to prevent the 'On Error GoTo errHandle' statement from clearing the error?

+2  A: 

You may be able to solve the problem by passing the values of the Err object into ToError as parameters.

Zian Choy
+3  A: 

An On Error statement will always clear the Err variable (Erl will also be reset to 0). In theory this means you could fix the problem by moving the On Error statement below the ToString = ... line (or removing the error handler in the ToError function altogether), but unfortunately that won't necessarily always work either.

Each component (DLL, ActiveX EXE, etc.) referenced by your project essentially gets its own Err instance in memory. So, if your MainApp.exe raises an error which gets passed to ToError (residing in a separate ErrorHandling.dll for example), the DLL won't see the Err variable that your EXE sees. They each have their own private Err variables.

There are a at least two ways around the problem that I can think of:

Method 1

As Zian Choy mentions, you could add additional parameters to your ToError function, one for each property of the Err object that you need access to.

Code

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

Example usage

You would then have to call like this from your error handlers like so, passing it all the relevant values from the current Err object, along with Erl:

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

If you also want App.Title, you're going to have to add an additional parameter to ToError for that as well, since App.Title will be equal to the App.Title of the project where the ToError method is defined, not the component where the error was raised. This is important if ToError is in a different project.

Method 2

You can make your ToError calls a little less verbose by passing the Err object itself as a parameter to the function, however the first thing your ToError function should do in this case is immediately store a copy of all the relevant properties you need since a subsequent On Error statement will clear the variable.

Code

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
   '...

Example Usage

ToError Err, Erl
Mike Spross
+1. Method 1 is effectively what we use, although we have one centralised routine that creates the string representation of the error and logs it. The `ToError` routine given in the question would be rather worthless if you had to pass in every item to be assembled in the error string.
MarkJ
@MarkJ: Completely agree. Ideally the method should both create the error string and log it to be worth having a method in the first place, instead of having to call separate logging code everywhere it's needed. We have a centralized `LogRuntimeError` method in our core library for this purpose.
Mike Spross
@Mike Spross, @MarkJ. The point of the On Error is to catch the massively unlikely scenario where Err is null or accessing Err properties causes an error. I've never seen this scenario, but my app is 24/7, so I can't afford any unhandled errors. The solution here does not do the trick.
AngryHacker
@AngryHacker: Unfortunately `On Error` is designed to always clear the current `Err` variable. This is just the way it works. The only real option, if you want to keep the `On Error` in your `ToError` method, is to do something similar to Method 1, where you explicitly pass all the error properties to your error handling function when an error occurs. There is no way to avoid the fact that `On Error` will clear the contents of `Err`.
Mike Spross
+1  A: 

There's no way to prevent On Error clearing the error.

  • You could just remove the error handling from ToError. It's so short and bland it's unlikely to ever experience an error.
  • It might be better to refactor the error handling so that this ToError code is inline in a general purpose error reporting routine, which performs logging or whatever is needed. Then use the techniques in Mike's answer.

BTW If anyone reading this is adding their error handlers manually, stop whatever you are doing and immediately get the free MZ-Tools package.

MarkJ