tags:

views:

1145

answers:

8

I have some code with various "On Error Goto" error handlers in a few places to handle some broken third party hardware. I was getting an overflow error (read from the Err variable) in a routine that doesn't have an error trap but is called by a routine that does. I always thought error traps were only valid in the routine they were declared, but it looks like an error in a subroutine can cause it to go to the calling function's error trap.

So I turned off the calling function's error trap and found my overflow and all is well. But before I did that, I spent some time trying to find a programatic way to get VB to return to its default error handling inside that routine (so I wouldn't have to modify outside code to debug), but I couldn't. The only error commands I could find:

  On Error GoTo [label]
  On Error Resume Next
  On Error Goto 0
  On Error GoTo -1

all turn on the manual error handling - is there a way to turn it off (back to the VB6 default)?

A: 

/Tools/Options/General/Error Handling

le dorfier
A: 
on error goto 0

Should be what you want... It should cause the error to the thrown, and in turn probably unwind up to the RTL...

It's been a long time, but I'm pretty sure that's what you want.

on error resume next

will just continue to the next statement, so you NEED to have plenty of

if err.Number <> 0 then

statements in your code where errors CAN occur...

LarryF
Not correct LarryF. On Error Goto 0 disables the error handler in the routine itself, but then the runtime looks back up the call stack for any active error handler. If there is one, it will handle the error.
MarkJ
Opps.. My bad. I must have been thinking of vbScript, which would behave as described.. Or, at least it used to. (I don't know what the latest version is, and if it's even changed recently..)
LarryF
+1  A: 

There is a handy right-click menu that lets you turn error handling on and off. Just right-click on a code window and select Toggle, then you can choose "Break on all errors". This will have the effect of disabling all your "On Error" statements.

Alex Warren
A: 

Have to agree with LarryF, On Error Goto 0 should turn off explicit error-handling that has been turned on by On Error Resume Next. Functions and subroutines do have their own scope for this though. From Dr. Scripto at Microsoft:

Putting On Error Resume Next at the beginning of the script, as we often do, makes it apply to the entire body of the script. But, as we'll see in later examples, its scope does not include functions or subroutines. If you want to handle errors within a function or subroutine, you must also include On Error Resume Next in each of them before checking the Err object.

You can turn error-handling off with On Error GoTo 0. So it's possible to turn error-handling on with On Error Resume Next just before you want to check the Err object, and turn it off after with On Error GoTo 0.

brism
Erm, but Dr Scripto is talking about VBScript, and the question is about VB6
MarkJ
+1  A: 

Here is what I do:

First turn on error handling like this if necessary in your Sub Main() or Sub Form_Load() Sub:

'-- turn on error handling
'
On Error GoTo 0
'
'-------------------------

Now errors will be turned on.

Next, Use the On Error Resume Next and On Error GoTo {label} commands in combination with the Err object. Here is an example of emulating a try/catch/finally:

Function MyFunction() as String

'-- start of error block
'
 On Error Goto Catch
   ' do something here that might cause an error
   MyFunction = "IT WORKED"
   Goto Finally

   Catch:
   ' error occured - do something else
   MyFunction = Err.Description
   Err.Clear

 Finally:
   ' put your finally code here

 '
 '-- end of error block

End Function
OneNerd
+1 You might need On Error Resume Next in the "Finally" block in case the error interferes with the setup of whatever needs tearing down. And I don't understand why you have put the On Error Goto 0 in the Form_Load/Sub Main?
MarkJ
A: 

There is no "On Error GoTo -1" so I have no idea where you got that.

VB6 exception handling is covered very thoroughly in the manual.

Bob
I think that's a VB.NET statement:http://msdn.microsoft.com/en-us/library/5hsw66as(VS.80).aspx
Ant
+3  A: 

This is explained thoroughly in the VB6 manual under Error Handling Hierarchy. On Error Goto 0 disables the error handler in the current procedure, not in the procedures that called it.

If an error occurs in a procedure and this procedure doesn't have an enabled error handler, Visual Basic searches backward through the pending procedures in the calls list — and executes the first enabled error handler it finds. If it doesn't encounter an enabled error handler anywhere in the calls list, it presents a default unexpected error message and halts execution.

As others have said, you can go to Tools-Options-General tab and choose Break on all errors. That effectively disables all your On Error statements - the IDE will break immediately on every error.

That can be irritating if your VB6 code throws errors as part of normal operation. For instance when you check whether a file exists, or when the user presses cancel in a common dialogue. You don't want the IDE to break every time on those lines. But you might have boilerplate error handlers in all your event handling procedures, to stop the program crashing out on unexpected errors. But they are a nuisance when you're debugging problems because the IDE doesn't break on the line with the error. One trick is to switch off those error handlers when running in the IDE, but keep them in the built executable. You do it like this.

Drop these functions into a module.

Public Function InIDE() As Boolean 
  Debug.Assert Not TestIDE(InIDE) 
End Function 

Private Function TestIDE(Test As Boolean) As Boolean 
  Test = True 
End Function

Then you can write your error handlers like this.

Private Sub Form_Load() 
  If Not InIDE() Then On Error Goto PreventCrashes 
  <lots of code> 
  Exit Sub 

PreventCrashes: 
  <report the error> 
End Sub

Pinched from here. Another tip - use the free add-in MZTools to automatically add these boilerplate error handlers. For production-quality code, you could go further and put an error handler in every routine to create a ghetto stack trace. You might also log the errors immediately in every error handler.

EDIT: Ant has correctly pointed out that On Error Goto -1 is a VB.Net statement and isn't valid in VB6.

EDIT: Arvo and OneNerd have written answers with some interesting discussion of emulating Finally teardown blocks in VB6 error handling. The discussion in this question is also worth a look.

MarkJ
+1  A: 

There's clear and simple way to reset error status - use keyword Resume. There are three possibilities:

Resume
Resume Next
Resume <Label>

Resume continues execution at errored line, Resume Next at next line and least talked Resume Label continues at label. Very useful to create try-catch-finally like constructs in VB6. Borrowed and modified from OneNerd answer:

Function MyFunction() as String

'-- start of error block
'
 On Error Goto Catch
   ' do something here that might cause an error
   MyFunction = "IT WORKED"
   Goto Finally

   Catch:
   ' error occured - do something else
   MyFunction = Err.Description
   Err.Clear
   Resume Finally          ''added to clear error status

 Finally:
   On Error Resume Next    ''added to avoid repeated errors
   ' put your finally code here

 '
 '-- end of error block

End Function

Simple Err.Clear doesn't help, if some subsequential error occurs in Finally block; Resume Finally does reset internal error state though.

Arvo
On Error Resume Next also resets internal error state so Err.Clear and Resume Finally are redundant. Personally think Goto Finally is clearer. Most important of all, put Err.Clear or On Error Goto 0 just before the End Function otherwise any error state from Finally block goes back to the caller!!
MarkJ
On Error Resume Next itself (after error) doesn't reset error state. I just tested to be 100% sure, really.
Arvo