Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VBA - Error handling with multiple forms

Tags:

forms

vba

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:

  1. raiseError - a function that simply raises an error
  2. mainForm - a form with one button - upon being clicked opens up addClientForm
  3. addClientForm - a form which raises the error via raiseError
  4. showMainForm - a caller which shows a mainForm

The code is really simple,

Module Error

Public Sub raiseError()
  Call Err.Raise(2048, "errorSource", "errorDescription")
End Sub

MainForm

Private Sub cbAddClientForm_Click()
  Dim xAddClientForm As New addClientForm: Call xAddClientForm.Show
End Sub

AddClientForm

Private Sub UserForm_Initialize()
  Call raiseError
End Sub

Caller

Public Sub caller()
  On Error GoTo ErrorHandler

  Dim xMainForm As New mainForm: Call xMainForm.Show

ErrorExit:
  Exit Sub

ErrorHandler:
  Call MsgBox("Error appeared", vbOKOnly)
  On Error Resume Next
  GoTo ErrorExit

End Sub

The 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 ErrorHandler in 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

  1. Why is this happening
  2. How can this be solved, i.e. how can I trap error raised by forms such that the user is not thrown into VBEditor?

ANY help or workaround is MUCH appreciated. Daniel

like image 375
Daniel Bencik Avatar asked Mar 08 '26 17:03

Daniel Bencik


1 Answers

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.

Module1

Public Sub caller()

  Dim xMainForm As New MainForm
  xMainForm.Show

End Sub

MainForm

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

ClientForm

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"
    ' https://stackoverflow.com/q/26589039/3198973
End Sub

Public Sub raiseError()
  Err.Raise 2048, TypeName(Me), "errorDescription"
End Sub
like image 90
RubberDuck Avatar answered Mar 10 '26 07:03

RubberDuck