-1

I'm trying to create a centralized error handler. I'm using vbObjectError as recommended. But i can't figure out how to compose a conditional which can determine if my error is native or custom.

The desired IsCustomErr should work without modification even if i later add additional custom errors to the enum.

Enum CustomEr
          LaidEgg = vbObjectError
          UserEaten
          Paused
          Cancelled
End Enum


Sub Test
          On Error Goto HANDLER
          Err.Raise LaidEgg
          Exit Sub
HANDLER:
          GlobalHandler
End Sub


Sub GlobalHandler
          If IsCustomErr Then MsgBox "Custom"
End Sub


Function IsCustomErr()As Boolean
' ONE OF THESE?
          With Err
                    IsCustomErr = .Number < 0
                    IsCustomErr = .Number >= vbObjectError
                    IsCustomErr = (.Number >= vbObjectError) And (.Number < 0)
                    IsCustomErr = .Number Or vbObjectError
                    IsCustomErr = TwosComplement(.Number) Or TwosComplement(vbObjectError)
          End With
End Function
9
  • 1
    Might be useful to add an example of how you raise your custom errors Commented Dec 9, 2021 at 19:03
  • @TimWilliams Done. Commented Dec 9, 2021 at 19:06
  • 1
    Why not IsCustomErr = (.Number = CustomEr.LaidEgg) ? Commented Dec 9, 2021 at 19:35
  • @TimWilliams Thx, but you're hardcoding only one error into your code. The function should work with all custom errors (even if more are added later). Commented Dec 9, 2021 at 19:52
  • OK then maybe check here under "enumerating a VBA enum" - analystcave.com/vba-enum-using-enumerations-in-vba Commented Dec 9, 2021 at 19:57

2 Answers 2

2

This seems viable:

Enum CustomEr
    [_First]
    laidegg
    UserEaten
    paused
    Cancelled
    [_Last]
End Enum

Sub Test1()
    Debug.Print "Test1"
    On Error GoTo HANDLER
    Err.Raise vbObjectError + laidegg
    Exit Sub
HANDLER:
    GlobalHandler
End Sub

Sub Test2()
    Debug.Print "Test2"
    On Error GoTo HANDLER
    Debug.Print 1 / 0
    Exit Sub
HANDLER:
    GlobalHandler
End Sub

Sub GlobalHandler()
    Debug.Print "Custom?", IsCustomErr()
End Sub

Function IsCustomErr() As Boolean
    Dim v As Long
    For v = CustomEr.[_First] To CustomEr.[_Last]
      If (Err.Number - vbObjectError) = v Then
           IsCustomErr = True
           Exit For
      End If
    Next v
End Function


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

3 Comments

Clever! You're using the [_Last} trick. Nice! I would say this is my fallback (and a viable one). But still hoping for a solution which accounts for the native number ranges.
@johnywhy what do you mean by native number ranges? you mean you want to test if the Err.Number is one of microsoft's error numbers? In that post you linked me, you already printed out every existing error number. Just set your Enum to a series of numbers that aren't already claimed. Tim Williams' answer is exactly what you're looking for.
@Toddleson "native number ranges?" -- Microsoft created a mechanism to isolate custom errors from native errors. "add your error code to vbObjectError to ensure your number is not in conflict with built-in error numbers" tinyurl.com/ycku4t6f . I want to make use of that. tinyurl.com/2p8neau3 , tinyurl.com/4s57jp72. "Just set your Enum to numbers that aren't claimed." -- i think we cannot assume that Microsoft will never add more errors to VB, Excel, or Windows. Also, i'm not confident my error-listing code finds all. -- i'm unclear on the native range. Maybe need 2's complement.
1

Too much to fit as a comment, but this is working for me:

Enum CustomEr
          LaidEgg = vbObjectError
          UserEaten
          Paused
          Cancelled
End Enum

Function IsCustomErr() As Boolean
    IsCustomErr = Err.Number >= CustomEr.LaidEgg And Err.Number <= CustomEr.Cancelled
End Function

Sub Example()

    On Error Resume Next
    Err.Raise CustomEr.UserEaten
    Debug.Print IsCustomErr
    'True
    
    Err.Clear
    
    Err.Raise 1
    Debug.Print IsCustomErr
    'False
End Sub

A possible reason that it doesn't work for you might be that you are Ending execution before moving to the handler. From the article on the Err Object:

The Err object's properties are reset to zero or zero-length strings ("") after an Exit Sub, Exit Function, Exit Property, or Resume Next statement within an error-handling routine.

Another potential issue is that vbObjectError is -2147221504 so by checking Err.Number >= vbObjectError you will return True for every number larger than vbObjectError which is basically all of them.

9 Comments

Thx! but my error isn't getting cleared. That's not the issue. I'm not ending execution before the handler.
Please try with an enum as in my example, and test with one of the custom errors other than the one that equals vbObjectError.
@johnywhy I have updated my answer to use your Enum. I still am able to correctly return True and False. Maybe there is an issue with the code that creates the error, add that to your post and I will try to find any issues.
Clever workaround, but if i later decide to add additional custom errors, your code will break. You're giving IsCustomErr knowledge that it wouldn't have. >= CustomEr.LaidEgg And Err.Number <= CustomEr.Cancelled requires that IsCustomErr have knowledge of the last custom error number. It can't have knowledge of the last one, since the last one may change.
@johnywhy Yes, I couldn't come up with a good solution to trim the values to the ones in the Enum, without referencing the Enum. I suppose you could safely say something like "Greater or Equal to LaidEgg and Less than LaidEgg + 1000" which would mean you can add many more values to the Enum without needing to edit the Function.
|

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.