4

I have several Class Modules in my Workbook. One of public functions in Class Module 1 relies on data from a function in Class Module 2, this happens four times. In the event that the object is missing from Class 2 the program crashes (as expected). I am having difficulty debugging the code properly as it seems that I can only exit the program from the main subroutine. I would prefer to kill the program from the Class function, but I don't know if that is possible (we can squash this here if it is). I am currently using On Error statements in the main subroutine, but these don't execute in a timely manner because the function in Class 1 gets data from Class 2 four times.

Class Module 1 Function

Function oload(ByVal pload As Double, ByVal cord As cCordCol, ByVal grid As cGridCol)

' cord is a scripting.dictionary of Class Module Objects (cCord)
' grid is a scripting.dictionary of Class Module Objects (cGrid)

  n1 = grid.Item(pg1).toGlobal(cord)
  n2 = grid.Item(pg2).toGlobal(cord)
  n3 = grid.Item(pg3).toGlobal(cord)
  n4 = grid.Item(pg4).toGlobal(cord)

' do something here

oload = sum_Ploads

End Function

Above the n1 thru n4 is where I am calling on the public function of Class Module 2.

Below is the Class Module 2 Function

Function toGlobal(ByVal cord As cCordCol)

On Error Resume Next
ctype = cord.Item(Me.cord1).sys

' Missing Coordinate System Error
If Err.Number <> 0 Then
  i = MsgBox("The definition of Coordinate " & Me.cord1 & " was missing from the Bulk Data " & Chr(10) & _
             "File. Include this Coord in the .bdf and re-execute the program.", vbOKOnly, "Runtime Error")

' *** TERMINATE MAIN SUBROUTING HERE ***

End If

This will raise a message box indicating that an object was missing, specifically the (me.cord1) part - this is an item in a scripting.dictionary. I want to terminate the program here.

The main subroutine (greatly reduced) is here:

Sub main()

  ' lookup Element ID, Calc OLOAD, Sum Load Set OLOAD
  On Error GoTo PROC_ERR
  If dict_quad.Exists(EID) Then dict_oload.Item(LS).add_to_oload (dict_quad.Item(EID).oload(pload, dict_cord, dict_grid))
  If dict_tria.Exists(EID) Then dict_oload.Item(LS).add_to_oload (dict_tria.Item(EID).oload(pload, dict_cord, dict_grid))

PROC_ERR:
If Err.Number <> 0 Then Exit Sub

End Sub

I have a lot of nested operations here. You can see the "goto" statement won't execute until the "oload" function is complete. The "oload" function calls upon the "toGlobal" function four times before it finishes its calculations.

How can I terminate the subroutine after the first occurance of a missing object in the "toGlobal" function?

1
  • I've not completely read through this yet, but (in general) my classes raise errors and my main routine listens for them. Commented Jan 7, 2015 at 20:54

1 Answer 1

5

Your On Error Resume Next statement is swallowing the error in toGlobal and preventing it from "bubbling up" the call stack. One option you have is to "re-throw" the error. Doing this in VBA is a bit kludgier than other languages, but is still possible.

For example, you can change the toGlobal function to something like the following:

Function toGlobal(ByVal cord As cCordCol)

On Error Resume Next
ctype = cord.Item(Me.cord1).sys

' Missing Coordinate System Error
If Err.Number <> 0 Then
  i = MsgBox("The definition of Coordinate " & Me.cord1 & " was missing from the Bulk Data " & Chr(10) & _
             "File. Include this Coord in the .bdf and re-execute the program.", vbOKOnly, "Runtime Error")

' *** TERMINATE MAIN SUBROUTING HERE ***
    'Save info from the error object (it will get cleared in the On Error statement below)
    Dim ErrNum As Long: ErrNum = Err.Number
    Dim ErrMsg As String: ErrMsg = Err.Description
    Dim ErrSrc As String: ErrSrc = Err.Source

    'Reset error handling to allow errors to bubble up the call stack
    On Error Goto 0    

    '"Re-throw" the error
    Err.Raise ErrNum, "toGlobal:" & ErrSrc, ErrMsg

End If

The other option is to just remove your On Error Resume Next statement from your class module so that the error simply bubbles up naturally. This is the approach that I would generally take unless there was some compelling reason to stray from it.

Sign up to request clarification or add additional context in comments.

3 Comments

Good answer, I've used this technique many times. I'd add though that setting the Error source to something like "method name:" & Err.Source allows you to show the logic path that caused the error.
Thanks, @jac, I updated my answer to incorporate your suggestion.
That did it!!! When I step through the code it jumps from the Err.Raise line up to the main sub. It bypasses the first Class Module function. It is so sudden I don't fully understand how or why it works, but it works. Thank you so much.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.