I have two procedures procA and procB. procA is calling procB. An exception occurs within procB. I can handle the exception within procB, but i like to handle it within procA and this is what i did not get to work. I'm not very familiar with VB6 but i think this should be possible because MSDN says:
If an error occurs while an error handler is active (between the occurrence of the error and a Resume, Exit Sub, Exit Function, or Exit Property statement), the current procedure's error handler can't handle the error. Control returns to the calling procedure. If the calling procedure has an enabled error handler, it is activated to handle the error.
What i'm doing wrong?
Now the code fragments:
Private Sub procA()
On Error GoTo ErrHnd
...
procB obj
Exit Sub
ErrHnd:
MsgBox Err.Description, vbInformation, Me.caption
End Sub
Public Sub procB(ByRef rec As Object)
On Error GoTo ErrHnd
... Exception occurs within DAO Recordset Operation
Exit Sub
ErrHnd:
Select Case Err.Number
Case 3022
Err.Raise vbObjectError + 9999, Err.Source, "Error Text"
Case Else
...
End Select
End Sub
I also tried to turn off exception handling within procB (On Error Goto 0) but it seems that procA never gets the Exception.
Thanks for your help.
Edit: Additional information:
Exception Raised from DAO.Recordset Object.
I also tried to completele remove exception handling within procB with no effect.
procA exists in another file then procB (data.cls, frmListArtikel.frm).
Solution: I didn't know that it makes a difference how the programm is executed. If i start it from the IDE, the Exception does not get handled by procA. If i start the EXE (previously making it from the IDE) from the Explorer, the Exception gets handled as desired by procA.
You can only have one active error handler at a time. If you activate in procb, procb will handle.
you may also need to check your editor settings. choose the option "Tools > Options > General tab" "break in class module"
Code sample 1. you will receive error 6 in procA:
Private Sub Form_Load()
Call procA
End Sub
Private Sub procA()
On Error GoTo errhan
procB
Exit Sub
errhan:
Debug.Print "proca handle"
End Sub
Private Sub procB()
Err.Raise 6
End Sub
Code sample 2. You will receive error 7 in procA:
Private Sub Form_Load()
Call procA
End Sub
Private Sub procA()
On Error GoTo errhan
procB
Exit Sub
errhan:
Debug.Print "proca handle"
End Sub
Private Sub procB()
On Error GoTo errhan
Err.Raise 6
errhan:
Err.Raise 7
End Sub
Check your editor settings and choose the option "Tools > Options > General tab" "Break on Unhandled Errors"
check this link: http://www.fmsinc.com/tpapers/vbacode/debug.asp
Related
I must be overlooking something painfully obvious. The following code fails on the Next line with the error message "Expected end of statement":
Option Explicit
GetB
Sub GetB()
Dim i
For i = 1 to 2
Msgbox i
Next i
End Sub
Found it. The repetition of the loop variable ("i") in the Next statement, which is legal and optional in every other BASIC-like (B*SIC?) language, is illegal in VBS.
The code should read:
Option Explicit
GetB
Sub GetB()
Dim i
For i = 1 to 2
Msgbox i
Next
End Sub
What is the best way in VB6 to pass an error back to the calling function?
1 On Error Resume Next
2 ' do something
3 If Err.Number <> 3026 Or Err <> 0 Then ?????????
How would you send the error in Line 3 back to the calling function? Is the following the only way to achieve this?
errNum = Err.Number
On Error Goto 0
Err.Raise errNum
Use On Error GoTo and re-raise the error in the handler with Err.Raise.
Private Function DoSomething(ByVal Arg as String)
On Error GoTo Handler
Dim ThisVar as String
Dim ThatVar as Long
' Code here to implement DoSomething...
Exit Function
Handler:
Err.Raise Err.Number, , "MiscFunctions.DoSomething: " & Err.Description
End Function
You'll then be able to get the error number and description in the caller via Err.Number and Err.Description.
If the caller is also using On Error GoTo, you'll see them in the handler there.
If the caller is using On Error Resume Next, then you can still use those same variables inline.
I prefer the first option, using On Error Goto in all functions and subs, because it seems like the natural way to use VB6's built-in error raising features. You can also update the description in the called function's handler, like the example above, and get a pseudo call stack you can eventually log or display to yourself during debugging.
More VB6 error handling thoughts here:
Is it possible to retrieve the call stack programmatically in VB6?
How to clean up error handling in a function?
Why not add ByRef errorCode as Long to the called function's args and set it equal to Err.Number after ' do something
Or you could have a public field called ErrorCode as Long that you could set after ' do something
I have worked with a lot of industrial control APIs and both of these methods have been used.
You can easily send the error to the upper (calling) sub/function as long as the function that raises the error does not have (ON ERROR RESUME ---), that way, error handling is left in the upper level only. Otherwise you will have to handle the error inside the called function
Private Sub Command1_Click()
Dim test As Integer
On Error Resume Next
test = myFunction 'Calling a function that is known to have an error
If Err <> 0 Then
MsgBox "MyFunction failed because:" & Err.Description 'Error is passed
End If
End Sub
'--------------------------
Function myFunction() As Integer
Dim i As Integer
i = 1
i = 4 / 0 'This will raise an Error, and control returns to the calling sub
i = 2 'This will never get executed
myFunction = i
End Function
If you simply want to pass the error back to the original caller without handling it, then you want to remove any ON ERROR in the child function:
Public Sub ParentSub()
On Error GoTo ErrorHandler
' do something
Call ChildSub()
' do something
Exit Sub
ErrorHandler:
' handle the error here
End Sub
Public Sub ChildSub()
' do something
' if there is an error here, the error will be handled in ErrorHandler of ParentSub
End Sub
or if you want to handle it in both subs:
Public Sub ParentSub()
On Error GoTo ErrorHandler
' do something
Call ChildSub()
' do something
Exit Sub
ErrorHandler:
' handle the error here
End Sub
Public Sub ChildSub()
On Error GoTo ErrorHandler
' do something
Exit Sub
ErrorHandler:
' handle the error here and pass it back to the ParentSub to handle it as well
Err.Raise Err.Number
End Sub
In my VBA code, I get a runtime exception (say divide by zero) and after pressing 'End' in the error box, the VBA runtime gets stopped.
During this stop, my global Objects are getting cleared. I want these objects to retain their values. Because, when I start over again, since these objects are Nothing, I am having issues.
Is there any event in VBA which will get triggered when my runtime gets stopped?? Or is there any way to know whether VBA is still running or stopped?
In VBA, an unhandled exception clears global variables. So add error handlers to your VBA procedures.
Here is a transcript of a session in the Immediate window, using the 2 procedures included below.
MyGlobal = "foo"
Call DemoDivideByZero
? Chr(39) & MyGlobal & Chr(39)
''
MyGlobal = "foo"
Call DemoDivideByZero2
Error 11 (Division by zero) in procedure DemoDivideByZero2
? Chr(39) & MyGlobal & Chr(39)
'foo'
A procedure without an error handler ...
Public Sub DemoDivideByZero()
Debug.Print 2 / 0
End Sub
A version with an error handler ...
Public Sub DemoDivideByZero2()
Dim strMsg As String
On Error GoTo ErrorHandler
Debug.Print 2 / 0
ExitHere:
On Error GoTo 0
Exit Sub
ErrorHandler:
strMsg = "Error " & Err.Number & " (" & Err.Description _
& ") in procedure DemoDivideByZero2"
Debug.Print strMsg
GoTo ExitHere
End Sub
However I'm unsure whether including error handlers in your procedures will be enough to preserve your global variable values. I avoid using globals.
Which global objects do you have? At startup you need to initialise them.
Will an "Out of stack space" error be trapped by the VB6 error handler, or will it always result in a run-time error?
It will be trapped by the error handler.
Private Sub Form_Load()
Count2 0
End Sub
Private Sub Count2(ByVal Value As Long)
On Error GoTo x
Count2 Value + 1
Exit Sub
x:
MsgBox "stack depth " & Value
Err.Clear
End Sub
stack depth 3659
I came to some VBScript examples, and I saw the statement On Error Resume Next basically at the beginning of the script.
What does it do?
It basically tells the program when you encounter an error just continue at the next line.
It's worth noting that even when On Error Resume Next is in effect, the Err object is still populated when an error occurs, so you can still do C-style error handling.
On Error Resume Next
DangerousOperationThatCouldCauseErrors
If Err Then
WScript.StdErr.WriteLine "error " & Err.Number
WScript.Quit 1
End If
On Error GoTo 0
When an error occurs, the execution will continue on the next line without interrupting the script.
It means, when an error happens on the line, it is telling vbscript to continue execution without aborting the script. Sometimes, the On Error follows the Goto label to alter the flow of execution, something like this in a Sub code block, now you know why and how the usage of GOTO can result in spaghetti code:
Sub MySubRoutine()
On Error Goto ErrorHandler
REM VB code...
REM More VB Code...
Exit_MySubRoutine:
REM Disable the Error Handler!
On Error Goto 0
REM Leave....
Exit Sub
ErrorHandler:
REM Do something about the Error
Goto Exit_MySubRoutine
End Sub
It enables error handling. The following is partly from https://msdn.microsoft.com/en-us/library/5hsw66as.aspx
' Enable error handling. When a run-time error occurs, control goes to the statement
' immediately following the statement where the error occurred, and execution
' continues from that point.
On Error Resume Next
SomeCodeHere
If Err.Number = 0 Then
WScript.Echo "No Error in SomeCodeHere."
Else
WScript.Echo "Error in SomeCodeHere: " & Err.Number & ", " & Err.Source & ", " & Err.Description
' Clear the error or you'll see it again when you test Err.Number
Err.Clear
End If
SomeMoreCodeHere
If Err.Number <> 0 Then
WScript.Echo "Error in SomeMoreCodeHere:" & Err.Number & ", " & Err.Source & ", " & Err.Description
' Clear the error or you'll see it again when you test Err.Number
Err.Clear
End If
' Disables enabled error handler in the current procedure and resets it to Nothing.
On Error Goto 0
' There are also `On Error Goto -1`, which disables the enabled exception in the current
' procedure and resets it to Nothing, and `On Error Goto line`,
' which enables the error-handling routine that starts at the line specified in the
' required line argument. The line argument is any line label or line number. If a run-time
' error occurs, control branches to the specified line, making the error handler active.
' The specified line must be in the same procedure as the On Error statement,
' or a compile-time error will occur.
On Error Statement - Specifies that when a run-time error occurs, control goes to the statement immediately following the statement. How ever Err object got populated.(Err.Number, Err.Count etc)
On Error Resume Next means that On Error, It will resume to the next line to resume.
e.g. if you try the Try block, That will stop the script if a error occurred