Is a Resume always required after On Error handling ? Would it cause stack error to skip it by supressing the Resume line in the below example ?
Sub MySub
on error goto Hell
DoThis
DoThat
Otherstuff
Adios:
Exit Sub
Hell:
MsgBox Err.Description, vbCritical, "Error " & Err.Number
Resume Adios 'is this line required ?
Exit Sub
The Resume statement instructs VBA to resume execution at a specified point in the code. You can use Resume only in an error handling block; any other use will cause an error. Moreover, Resume is the only way, aside from exiting the procedure, to get out of an error handling block. Do not use the Goto statement to direct code execution out of an error handling block. Doing so will cause strange problems with the error handlers.
The Resume statement takes three syntactic form:
Resume
Resume Next
Resume <label>
Used alone, Resume causes execution to resume at the line of code that caused the error. In this case you must ensure that your error handling block fixed the problem that caused the initial error. Otherwise, your code will enter an endless loop, jumping between the line of code that caused the error and the error handling block. The following code attempts to activate a worksheet that does not exist. This causes an error (9 - Subscript Out Of Range), and the code jumps to the error handling block which creates the sheet, correcting the problem, and resumes execution at the line of code that caused the error.
On Error GoTo ErrHandler:
Worksheets("NewSheet").Activate
Exit Sub
ErrHandler:
If Err.Number = 9 Then
' sheet does not exist, so create it
Worksheets.Add.Name = "NewSheet"
' go back to the line of code that caused the problem
Resume
End If
The second form of Resume is Resume Next . This causes code execution to resume at the line immediately following the line which caused the error. The following code causes an error (11 - Division By Zero) when attempting to set the value of N. The error handling block assigns 1 to the variable N, and then causes execution to resume at the statement after the statement that caused the error.
On Error GoTo ErrHandler:
N = 1 / 0
Debug.Print N
Exit Sub
ErrHandler:
N = 1
' go back to the line following the error
Resume Next
The third form of Resume is Resume <label>: . This causes code execution to resume at a line label. This allows you to skip a section of code if an error occurs. For example,
On Error GoTo ErrHandler:
N = 1 / 0
code that is skipped if an error occurs
Label1:
more code to execute
Exit Sub
ErrHandler:
go back to the line at Label1:
Resume Label1:
All forms of the Resume clear or reset the Err object.
found this on
http://www.cpearson.com/excel/errorhandling.htm
Resume is not required you can call it if you like. Leaving it out of the example above will not cause any problems - the subroutine will just complete at the final Exit Sub.
Related
I wrote some examples to highlight what my issue in understanding is.
1. Example: This works as expected. The error is getting handled via the Goto Statement and the error handling is returned to normal behavior arfterwards
Sub ErrorHandlingWithoutLoop()
Debug.Print "Before Error"
On Error GoTo errorHandler
Error (1)
' If no Error occured, the ErrorHandling procedure is skipped
GoTo skip
errorHandler:
Debug.Print "Handle Error"
On Error GoTo 0
skip:
Debug.Print "After Error"
'Raise Error to see if error Handling is resumed to normal behavior
Error (14)
End Sub
VBA returns:
Before Error
Handle Error
After Error
And the Error Handling is returned to normal, visible by the thrown error (14)
Example 2: I would expect this sub to run through just fine and just throw an error in the last line with error (14).
However in the second loop with n=2, the error handling doesnt work as intended. Why?
Sub ErrorHandlingWithLoop()
Debug.Print "Before Error"
For n = 1 To 10
On Error GoTo errorHandler
Error (1)
' If no Error occured, the ErrorHandling procedure is skipped
GoTo skip
errorHandler:
Debug.Print "Handle Error", n
On Error GoTo 0
skip:
Debug.Print "After Error", n
Next n
'Raise Error to see if error Handling is resumed to normal behavior
' -> This wont be reached though
Error (14)
End Sub
VBA returns:
Before Error
Handle Error 1
After Error 1
The execution of the code stops in the second loop with n=2 with a thrown error of 1. The Error 14 at the end is not thrown
Example 3: I know I can fix this behaviour by adding a "resume skip" statement. However I dont understand why this is necessary?
Sub ErrorHandlingWithLoopFixed()
Debug.Print "Before Error"
For n = 1 To 10
On Error GoTo errorHandler
Error (1)
' If no Error occured, the ErrorHandling procedure is skipped
GoTo skip
errorHandler:
Debug.Print "Handle Error", n
On Error GoTo 0
Resume skip
skip:
Debug.Print "After Error", n
Next n
'Raise Error to confirm that error Handling is resumed to normal behavior
Error (14)
End Sub
VBA returns:
Before Error
Handle Error 1
After Error 1
Handle Error 2
After Error 2
Handle Error 3
After Error 3
Handle Error 4
After Error 4
Handle Error 5
After Error 5
Handle Error 6
After Error 6
Handle Error 7
After Error 7
Handle Error 8
After Error 8
Handle Error 9
After Error 9
Handle Error 10
After Error 10
And the Error Handling is returned to normal, visible by the thrown error (14)
So why is the Resume skip necessary?!
Thanks for any help=)
Edit:
!Bonus Example!3: Interestingly, if I add a On Error Goto -1, then the for-loop loops infinitely. Why is that? I cant make a rhyme of that...
Sub ErrorHandlingWithLoop()
Debug.Print "Before Error"
For n = 1 To 10
On Error GoTo errorHandler
Error (1)
' If no Error occured, the ErrorHandling procedure is skipped
GoTo skip
errorHandler:
Debug.Print "Handle Error", n
On Error GoTo -1
skip:
Debug.Print "After Error", n
Next n
'Raise Error to see if error Handling is resumed to normal behavior
' -> This wont be reached though
Error (14)
End Sub
VBA returns:
Before Error
Handle Error 1
After Error 1
Handle Error 2
After Error 2
Handle Error 3
After Error 3
Handle Error 4
After Error 4
Handle Error 5
After Error 5
Handle Error 6
After Error 6
Handle Error 7
After Error 7
Handle Error 8
...
...
...
This continues on and on until Excel crashes.
Any help on this as well?
Personally, I would not follow the example you provide to deal with error handling. Instead I would encapsulate the action that might result in an error in its own function which returns true or false depending on whether or not the action was successful or not. The value returned by the action is passed out of the function using a ByRef parameter.
Sub ErrorHandlingWithLoopFixed()
Debug.Print "Before Error"
Dim myResult as Variant
For n = 1 To 10
If Not TryAction( myResult) then
Debug.Print "An error occurred"
Stop ' or exit function or whatever
end if
' Continue processing myResult
Next n
'Raise Error to confirm that error Handling is resumed to normal behavior
Error (14)
End Sub
Public Function TryAction( ByRef opResult) as Boolean
On Error Resume Next
opResult = ' the action
TryAction = err.number = 0
On Error Goto 0
Exit Function
As you can see from above, the code is much easier to follow and there are no problems with jumping in and out of the scope of a For loop.
For example 2: the reason you need Resume skip is that an error handler only "handles" once and gets deactivated. After that you must activate it again which is exactly what resume does.
Paul Kelly names this: "reseting the mouse trap", because like a mouse trap an error handler gets deactivated when used, and you need to activate it manually for it to work again.
All these can perform that task (activate the mouse trap): resume label, resume next, on error goto -1. Also On Error Resume Next takes care of the reactivation itself (you don't need to do it manually for that one).
For the bonus the reason for the infinite loop is that you have an error right befor the end, but no Exit Sub before it. So whenever you reach that error you'll be thrown back in the error handler, which you've put in the loop. A safer way is to have your error handlers at the end, after an exit sub.
I'm using GoTo for error handling in an Access module and am getting a type mismatch error on the Procedures.HandleError call.
I tested to see if err is an Error:
Exit Sub
catch:
If IsError(err) Then
MsgBox "yes"
Else
MsgBox "no"
End If
Procedures.HandleError "ctrCreateSubject, frm_OnCreate", err, True
End Sub
and the MsgBox displays no and I can't figure out why. I'm using the same syntax in other places without problems
Can anyone help?
Let me expand a bit on my comment with an example.
The On Error GoTo statement will take care of the IsError() part since the procedure will jump to the catch label, only if there's an error. Therefore, if we do jump into the error handler, then we definitely have an error.
A sample error handler:
Sub Whatever()
On Error GoTo catch
'do something
Leave:
Exit Sub
catch:
'If we hit this point, then we definitely have an error.
'At this point, we can query the error number if we want to take action based on the error.
If Err.Number = xxxx Then
Msgbox "Error " & xxxx
End If
Resume Leave
End Sub
Then, there's another approach if you want to suspend the error handler and then query if an error occurred.
On Error Resume Next
'do something
If Err.Number <> 0
'An error occurred
End If
Which we can then clear if we want to do this again later on on our method.
Err.Clear
Lastly, keep in mind Err is a global object so you don't need to create an instance. Further info on MSDN: Err object
In a Word I am running a macro which triggers Error dialog sometimes. In PHP there I am used to use #command syntax which causes that in case of error the error is not printed to the output. Is there something similar to prevent the VBA debugger stop working?
My code is
Documents.Add.Content.Paste
and I want to create code, which would test if the result is valid, without breaking the debugger and printing the error, In the case that it failed, I would create timer 1s, and try the command again.
Edit:
Current code:
On Error GoTo ErrHandler
Documents.Add.Content.Paste
If False Then
ErrHandler:
' Add a delay
Dim tmpStart
tmpStart = Timer
Do
DoEvents
Loop While (tmpStart + 1) > Timer
Documents.Add.Content.Paste
End If
Currently error happens at line #11: 4605 - property not available because clipboard is empty or damaged
In your sub-routine or function, insert as the first line:
On Error Resume Next
Or if you want to handle the error:
On Error Goto ErrHandler
If False Then
ErrHandler:
MsgBox Err.Description
Exit Sub ' Or Exit Function
End If
In the below code Errorhandler correctly takes care of first error when I enter a workbook that is not open or any random string. But when I click on retry and again enter a random name I get "Subscript out of Range" error # Workbooks(workbookname). Activate.
Can anyone help me why it is happening and how can I make it work. I have tried a lot of things. But nothing is working. This code is part of a larger program.
Sub test()
Dim workbkname As String
On Error GoTo Errorhandler
Retry:
workbookname = InputBox("Enter workbook name:", _
"Name Enrty")
If StrPtr(workbookname) = 0 Then
MsgBox ("Aborting Program")
End
End If
Workbooks(workbookname).Activate
Exit Sub
Errorhandler:
Response = MsgBox("Workbook " & workbookname & " not found", vbRetryCancel)
If Response = 4 Then
GoTo Retry
End If
End Sub
The issue here is that the VBA Error Handler does not clear the error once given a directive like GoTo. As a result, the code thinks that it has encountered an error within your error handling routine and thus throws the error up the stack.
In order to clear the error, you must either call Resume with a place to resume (either Resume alone to run the erroneous code again, Resume Next to resume the line of code following the error, or Resume can be called followed by a label, as below:
Sub ErrTest
On Error Goto ErrHndl
For i = 0 to 5
a = 1/i
nextiLabel:
Next i
Exit Sub
ErrHndl:
Resume nextiLabel
End Sub
You can also use Err.Clear() to remove the error, but that is less recommended.
See here for more info: Error Handling in Excel
I have a very simple VBA code that should try to open a nonexistent file, send me to an error handler, then back to my code in an infinite loop (intentionally).
However, the compiler only catches the error the first time, then breaks on the second pass.
I have tried every combination of On Error statements to send it back on the second pass, but nothing seems to work.
Here is the code:
Sub TestError()
On Error GoTo errError
lblError:
On Error GoTo errError
'Code that should raise an error and send to errError
Excel.Application.Workbooks.Open ("lakdfjldkj")
Exit Sub
errError:
MsgBox "Code didn't break"
GoTo lblError
End Sub
Is there something I'm missing, or is this a bug?
Don't test this unless you are at peace with having to kill Excel, or add an extra condition for looping
Use Resume to... well... resume processing after the error handler.
Sub TestError()
On Error GoTo errError
'Code that should raise an error and send to errError
Excel.Application.Workbooks.Open "lakdfjldkj"
Exit Sub
errError:
MsgBox "Code didn't break"
Resume
End Sub
I have used code like this to access a certain worksheet, if it is not found then the error handler creates one with the correct name and then resumes the processing.
You need to clear the error message by using:
Err.Clear
Source: https://msdn.microsoft.com/en-us/library/hh2zczch(v=vs.90).aspx
Basically it still thinks you're handling the error, and hasn't reset the handling mechanism, so it doesn't re-trigger until you clear it.
(Resume also clears the Error as well, as you can note by the reference above).
I have tested, it is possible to type :
Resume label1 (line label)
Resume next
Resume 110 (line number)