My application has several forms which call each other. I ran into a problem with error handling and since the project is too large to post here, I created the smallest subset of the code that still reproduces the problem. The file can be found here
Components of the problem:
raiseError- a function that simply raises an error
mainForm- a form with one button - upon being clicked opens up
addClientForm- a form which raises the error via
showMainForm- a caller which shows a
The code is really simple,
Public Sub raiseError()
Call Err.Raise(2048, "errorSource", "errorDescription")
Private Sub cbAddClientForm_Click()
Dim xAddClientForm As New addClientForm: Call xAddClientForm.Show
Private Sub UserForm_Initialize()
Public Sub caller()
On Error GoTo ErrorHandler
Dim xMainForm As New mainForm: Call xMainForm.Show
Call MsgBox("Error appeared", vbOKOnly)
On Error Resume Next
caller shows a
mainForm and once the user clicks the button, an
addClientForm is initialized which causes a call to
raiseError. The problem is that
caller does not catch the error! Instead, the error raised in
raiseError is treated as an unhandled error! That means that an ugly messageBox comes up and shoves the user right into the code in VBEditor - this is what I want to avoid.
I fiddled around with various setups of this problem and as long as there is not a sequence of forms where one calls the other, the error handling works as expected. In the attached file, all investigations are written into different modules along with the tested hypothesis.
So the questions are
ANY help or workaround is MUCH appreciated.
I can't say for certain why this is happening. I can't quite grok it myself, but there is a bit of a work around. You can declare the
ClientForm WithEvents and catch the errors there by listening for a custom
OnError event that gets raised from within the
ClientForm itself. Note that you can't do this for the
MainForm because you can't declare a variable
WithEvents inside of a module. It has to be a class.
The big downfall here is that you need to manually redirect errors in the client form to it's
OnError event and then have a Event procedure for each client form that you expect to handle errors from. The other downfall is you can't "hear" events raised in the
Class_Intialize event procedure.
So, all in all, you may want to consider handling any errors locally in the client form.
Public Sub caller() Dim xMainForm As New MainForm xMainForm.Show End Sub
Option Explicit Private WithEvents xClientForm As ClientForm Private Sub cbAddClientForm_Click() Set xClientForm = New ClientForm xClientForm.Show End Sub Private Sub xClientForm_OnError(Err As ErrObject) MsgBox Err.Number & ": " & Err.Description & vbNewLine & Err.Source & " raised an error.", vbCritical, "Error" End Sub
Option Explicit Public Event OnError(Err As ErrObject) Private Sub UserForm_Click() On Error GoTo ErrHandler: raiseError Exit Sub ErrHandler: RaiseEvent OnError(Err) End Sub Private Sub UserForm_Initialize() ' can't raise events from initialize, they won't be "heard" ' http://stackoverflow.com/q/26589039/3198973 End Sub Public Sub raiseError() Err.Raise 2048, TypeName(Me), "errorDescription" End Sub