views:

568

answers:

6

I frequently encounter this situation in my VB6 applications

Private Sub DoSomething

  On Error Goto err1

  Call ProcessLargeBatch1
  Call ProcessLargeBatch2
  '... more ...'

  Exit Sub

err1:
  Call Cleanup 'Specific for DoSomething'
  Call HandleError 'General error handling: Logging, message box, ...'

End Sub

The Cleanup procedure sometimes reverts actions, rolls back a transaction, deletes temporary files, and so on. In most cases this operation can also fail.

What do I do in this case? I'd add an On Error Resume Next into the error handler but that deletes the existing Err object. Adding an error handler to Cleanup has the same problem.

What is the best way to ensure that the original errors still gets processed/logged?

EDIT: One additional problem is that I also want to notify the user of the error. Sometimes it is important, that the cleanup happens fast and I don't want the message box block the application for a long time and do the cleanup after the user acknowledges the error.

+1  A: 

Log your error first. Then do an On Error Resume Next. Have your cleanup encapsulated in methods that have their own error handling. This should be yourbest bet.

Charles Graham
Thank you. Unfortunately that doesn't always help me. I've added an explanation to my question.
DR
+1  A: 

I really really don't like error handlers. This is what I do;

  • Create a Error class or module that contains all properties that the built in one contains, as well as a CopyError-method that fills these properties from the err-object.
  • Watch for errors where they can appear:

.

' lots of code that will probably work
On Error Resume Next
Open "c:\filethatdoesntexist.txt" For Input As #1
Error.CopyError
On Error Goto 0
Select Case Error.Number
    Case 53'File doesn't exist
        ' handle that error here
    Case 0
        ' no error
    Case Else
        ' Just throw the error on
        Err.Raise Error.Number, Error.Description, ...
End Select
' more code that will probably work
svinto
A small improvement: You could replace the `Err.Raise...` line with a `Raise` method in your `Error` class that does the same thing, to same some typing.
Mike Spross
+2  A: 

Firstly, read all the information out of the Err object that you will need, i.e. number, description, etc., then clear the error and do what you want.

Change the way you inform the user to use the values you have cached, and not to use the Err object itself.

Patrick McDonald
+1  A: 

If I can handle all errors in one place, I'll usually put in into a structure something like this:

Public Sub SubThatShouldHandleErrors()
Const ROUTINE_NAME = "SubThatShouldHandleErrors"
On Error Goto Catch

    ' "normal" processing here...

Finally:
    ' non-error case falls through to here
    ' perform clean-up that must happen even when an error occurred
    On Error Goto 0 ' reset: not really needed any more, but it makes me feel more comfortable
    Exit Sub

Catch:
    ' Error handling here, I may have logging that uses ROUTINE_NAME
    Resume Finally

End Sub

If I need more than one error-handler, I'll try very hard to restructure my code to make that not be the case but if absolutely necessary I'll write a custom handler; my template is only a guideline.

Mike Woodhouse
+1  A: 

From your example you are doing the cleanup properly. Your HandleError should only log the error not do any UI. The UI is handled up at the form level.

What you need to when an error occurs is

  1. Clean Up
  2. Log the Error
  3. Raise the Error Again via Err.Raise

This will work it's way up the call stack to the event that called the original code. Then the sequence will become

  1. Clean Up
  2. Log the Error
  3. Display the the Error Notification Dialog

Note that your Error Logging can be intelligent in that subsequent logs of the same error can just add to the recorded call stack.

You want to make sure that EVERY event has a error handler. Not every procedures needs one but definitely every event. Unhandled errors in a event will cause a VB6 application to shut down unexpectedly.

RS Conley
Although this doesn't exactly help your suggestion has worked wonders! I now have a much more sophisticated and robust error handling, including a (pseudo) stack trace. (You didn't mention caching the Err object, which was the solution to my original question, hence I accepted Patricks answer)
DR
Glad to be of help.
RS Conley
A: 

How do u build a stack trace . The Scenario we r facing is We hav error handlers in all the functions of our library We use a single object for logging which is passed to all the libraries used by the App Except in any UI Event . If there is any error in any function we trap the error in error handler and Append the function nane to a string ad raise the error again with the Apended string as source and in the UI event we log the Error and description this way we are able to get a stack trace kind of structure in our logs. BUT if we try to do any clean up for eg. set ObjUser = Nothing The class terminate event of the ObjUser is fired now if I put any error handler here the previous err description is cleared and now even if I raise error from here I can not get the stack trace. Nd as suggested in may websites Error handling is must in Class terminate and event procedures.