I've spent the last two days trying to better understand VBA error handling and still have issues with what is actually going on. The text below describes some of the realisations I've made and embedded in amongst the description are some questions. I'm really after people to help me refine my understanding and give me some pointers. I've got a hang of the usual basics and I'm trying to focus more on the subtle features.
I look forwards to any answers you have!
It is important to realise there are two distinct things that happen when an error occurs in VBA.
The error object is instanciated and has it's properties set (ie err.number, err.desciption, err.source etc)
The next line to be executed changes.
Which line is executed next is determined by the last "On Error Goto" statement that was executed - if any.
These are separate but highly related topics and you will write, what is in effect, distinct but interwoven code to manage them both.
When ANY error occurs or you use Err.Raise the Err object is ALWAYS set up. Even if "On Error Resume next" or any other On error statement has been used.
So code like this could ALWAYS be used:
Dim i as integer
On error resume next
i = 100/0 ' raises error
if err.number <> 0 then
' respond to the error
end if
It is really important to realise that when the error object has a non zero value for err.number an exception has been raised AND that if you then try and execute any "On Error Goto " statement doing so will itself raise an error and execution will be passed to any code that called the current procedure. (Or where the procedure not called by any code the usual VBA error dialogue is given). So in this example scenario below "On Error Goto ALabel1" would NOT change the next line to be the line with Label1: on it.
eg
Sub ErrorTest()
Dim dblValue As Double
On Error GoTo ErrHandler1
dblValue = 1 / 0
ErrHandler1:
debug.print "Exception Caught"
debug.print Err.Number
On Error GoTo ALabel1
dblValue = 1 / 0 '' THIS LINE ACTUALLY WILL RAISE AN unhandled ERROR!
Exit sub
ALabel1:
debug.print "Again caught it."
End Sub
Once the err.number property is set to non zero, you can reset it to zero by using
On Error Goto -1
Note that Err.Clear also resets it to zero but it is actually equivalent to:
On Error Goto -1
On Error Goto 0
ie Err.Clear removes an "On Error Goto" that is currently in place. So therefore it is mostly best to use:
On Error Goto -1
as using Err.clear you would often need to add an extra line to re-instate the error handler that was in place or another one anyway.
Err.Clear
On Error Goto MyErrorHandlerLabel
"Alternatively, you can set the error number to zero (Err.Number = 0), but is not as effective as the Clear method since it does not clear the description property." (From MSDN pages)
I read the next paragraph on MSDN I think and don't understand how it can be the case as if the error object is instantiated (ie err.number <> 0) , it's values are passed to any calling procedure when End Sub is executed.
Q1: Help!
"It is worth noting that Err.Clear is implicitly carried out by VBA whenever it executes any type of Resume statement, Exit Sub, Exit Function, Exit Property, or any On Error statement." (From MSDN pages)
You can also set the error object it to whatever number you like using
Err.Raise Number:=, Source:=, Description:=
Err.Raise is very important as it allows you to propagate an error to the calling program and unlimately all the way "up" to the top level program that is dealing with the user. You can also raise your own error numbers known as "user defined errors". This provide a means of telling the calling program that it could not continue for some reason (ie an unexpected error occurred or a business rule was broken).
In this way the calling procedure get to decide what to do about the error, not the procedure where the error happened (which doesn't understand anything about what the user is in the middle of doing, where as the very top most calling program does!)
Q2: Am I right about this?
Q3: Would you raise user defined exceptions for this purpose?
You can control which line of code is executed next using statements like
On Error Goto ALabelName
On Error Goto ANonZeroLineNumber
and
On Error Goto 0
On Error Goto 0 is a special case as it in effect says "within the current scope (typically a sub or function), in the event that an error happens pass the error object back to the code that called the current sub or function, don't execute any more code in the current sub or function.
Using simply error handling in VBA is pretty straight forwards, but often find myself tying myself in knots when things get trickier.
Not having the commonly used TRY CATCH statement that SQL Server and VBA have is a shame, so I've successfully managed to simulate this now here:
I hope the above post will give you some more insight into the experiments I've been doing if you're interested, and help you understand why I'm struggling.
In short although there are some useful sites out there Like:
http://www.cpearson.com/excel/errorhandling.htm
but, I feel I could do with some more guidance.
Harvey
On Error GoTo -1
is equivalent to aResume ...
statement except that it doesn't Goto anywhere. – D_Bester