问题描述:

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

网友答案:

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

Public Sub raiseError()
  Err.Raise 2048, TypeName(Me), "errorDescription"
End Sub
相关阅读:
Top