Compartilhar via


Error Handling in VBScript, Part One

OK, enough about the Peloponnesian war -- a number of readers have asked me questions about error handling in VBScript recently, so I think I'll talk about it a bit for the next few days.

Today, I want to very carefully describe what the error handling semantics are in the language, because there is some confusion over how exactly it works. There are two statements that affect error handling in VBScript:

On Error Resume Next
On Error Goto 0

The meaning of the first seems clear -- if you get an error, ignore it and resume execution on the next statement. But as we'll see, there are some subtleties. But before that, what the heck is up with the second statement?

The second statement turns off 'resume next' mode if it is on. Yes, the syntax is ridiculous -- something like On Error Raise would be a whole lot more clear. But for historical purposes, this is what we're stuck with. Visual Basic has an error handling mode which VBScript does not -- VB can branch to a labeled or numbered statement. (Remember line numbers? Those were the days!) To tell VB that you no longer wish to branch to that statement, you give zero, an invalid line number. C'est super-beaucoup-de-fromage, n'est-ce pas? But we're stuck with it now.

The subtlety in the "resume next" mode is best illustrated with an example.

Const InvalidCall = 5
Print "Global code start"
Blah1
Print "Global code end"
Sub Blah1()
On Error Resume Next
Print "Blah1 Start"
Blah2
Print "Blah1 End"
End Sub
Sub Blah2()
Print "Blah2 Start"
Err.Raise InvalidCall
Print "Blah2 End"
End Sub

This prints out

Global code start
Blah1 Start
Blah2 Start
Blah1 End
Global code end

Hold on a minute -- when the error happened, Blah1 had already turned 'resume next' mode on. The next statement after the error raise is Print "Blah2 End" but that statement never got executed. What's going on?

What's going on is that the error mode is on a per-procedure basis, not a global basis. (If it were on a global basis, all kinds of bad things could happen -- think about how you'd have to design a program to have consistent error handling in a world where that setting is global, and you'll see why it's per-procedure.) In this case, Blah2 gets an error. Blah2 is not in 'resume next' mode, so it aborts itself, records that there was an error situation, and returns to its caller. The caller sees the error, but the caller is in 'resume next' mode, so it resumes.

In short, the propagation model for errors in VBScript is basically the same as traditional structured exception handling -- the exception is thrown up the stack until someone catches it, or the program terminates. However, the error information that can be thrown, and the semantics of the catcher are quite a bit weaker than, say, JScript's structured exception handling.

Also, remember that the 'next' in 'resume next' mode is the next statement. Consider these two programs, for example. Do they have the same semantics?

On Error Resume Next
Temp = CInt(Foo.Bar(123))
Blah Temp
Print "Done"

On Error Resume Next
Blah CInt(Foo.Bar(123))
Print "Done"

No! If Foo.Bar raises an error, then the first one passes Empty to Blah. The second one never calls Blah at all if an error is raised, because it resumes to the next statement.

You can get into similar trouble with other constructs. For example, these do have the same semantics:

On Error Resume Next
If Blah Then
Print "Hello"
End If
Print "goodbye"

On Error Resume Next
If Blah Then Print "Hello"
Print "goodbye"

If Blah raises an error then it resumes on the Print "Hello" in either case. You can also get into trouble with loops:

On Error Resume Next
For index = 1 to Blah
Print TypeName(index)
Next
Print "Goodbye"

If Blah raises an error, this resumes into the loop, not after the loop. This prints out

Empty
Goodbye

Be careful! Next time I'll talk a bit about ways to avoid these gotchas, the semantics of the Err object, and general philosophies of error handling.

Comments

  • Anonymous
    August 19, 2004
    Fantabulous!
    Keep it up!

  • Anonymous
    August 19, 2004
    Ditto!

  • Anonymous
    September 02, 2004
    The comment has been removed

  • Anonymous
    October 29, 2007
    Thanks - that's the only useful explaination I've read.

  • Anonymous
    December 10, 2007
    This is probably the best explanation I've seen so far. Everything I read about VBScript going back a few years said it was impossible to swith the error handling off after an On Error Resume Next in VBScript (but not VB) but this seems to contradict this... Thanks

  • Anonymous
    December 11, 2007
    I suppose that "everything" did not include the documentation. :-)   (http://msdn2.microsoft.com/en-us/library/53f3k80h.aspx That's probably where you should have started.

  • Anonymous
    January 18, 2008
    Hi, Very good explanation. Thanks Regards Jayasimha

  • Anonymous
    February 11, 2008
    Nice work helps a lot in understanding.

  • Anonymous
    December 09, 2008
    It's ok but where is the "Next time I'll talk a bit about ways to avoid these gotchas..."  - there is nothing in next chapters about how to work with Blah if "IF...ELSE" block is bigger that one string... except "Use the right tool for the job". Is there any solution? Thanx, Ivan B.

  • Anonymous
    December 17, 2008
    Good Explanation!!!!!!!!!!!!!!

  • Anonymous
    January 22, 2009
    Explanation is Good and it is easy to understand.

  • Anonymous
    March 24, 2009
    How do i go to the next part of the topic?

  • Anonymous
    March 30, 2009
    Part2: http://blogs.msdn.com/ericlippert/archive/2004/08/23/218974.aspx Part3: http://blogs.msdn.com/ericlippert/archive/2004/08/25/error-handling-in-vbscript-part-three.aspx

  • Anonymous
    March 03, 2010
    Thanks to this article I was able to debug the error handling related problems in my code.

  • Anonymous
    September 06, 2010
    Thankyou! Why can't all coding tutorials be this indepth, interesting and explanitory? I completely understand the whole thing now!

  • Anonymous
    November 11, 2010
    But I want to hear more about the Peloponnesian war....

  • Anonymous
    September 13, 2011
    Hi - Two questions:

  1. If you turn "On Error Resume Next" on within a function or subroutine, does it only be on within that context, or will it stay in affect until you turn it off?
  2. When you set the name of a function equal to a value, does that return control back to the calling context, or does it keep going until it reaches the "End Function" statement?