IN THE SPOTLIGHT: MDE to MDB Conversion Service
(also supports: ACCDE to ACCDB, ADE to ADP, etc)
IN THE SPOTLIGHT: Access Database Repair Service
An in-depth repair service for corrupt Microsoft Access files
IN THE SPOTLIGHT: vbWatchdog
VBA error handling just got easier...
" vbWatchdog is off the chart. It solves a long standing problem of how to consolidate error handling into one global location and avoid repetitious code within applications. "
- Joe Anderson,
Microsoft Access MVP
Meet Shady, the vbWatchdog mascot watching over your VBA code →
(courtesy of Crystal Long, Microsoft Access MVP)
IN THE SPOTLIGHT: vbMAPI
An Outlook / MAPI code library for VBA, .NET and C# projects
Get emails out to your customers reliably, and without hassle, every single time.
Use vbMAPI alongside Microsoft Outlook to add professional emailing capabilities to your projects.
IN THE SPOTLIGHT: Code Protector
Standard compilation to MDE/ACCDE format is flawed and reversible.
Bookmarks are a new feature introduced with SimplyVBA Global Error Handler v1.2.
In this context, a bookmark is simply a label that you can define in a VB subroutine - the label itself doesn't affect the running code in the local procedure. In this sense, a bookmark is the same as normal VBA labels.
Normal VBA labels are defined like this:
Public Sub Example() On Error GoTo LocalErrorHandler ' Code here Exit Sub LocalErrorHandler: ' This is a normal VBA line label MsgBox Err.Description End Sub
From a global error handling perspective, normal VB labels are very limited as we can't 'see' these labels from within our global error handling procedure when an error occurs. If we could 'see' the labels and jump to them conditionally from within our global error handler, wouldn't that be cool?...
Bookmarks allow us to do just that.
Instead of defining normal VB labels, we can instead define ErrEx bookmarks and then conditionally jump to these bookmarks from inside our global error handler by using some extra methods provided by the ErrEx object.
' This is defined in your global error handler module (or any standard module) Public Const BOOKMARK_ONERROR As Long = 5 Public Sub Example() ' Code here Exit Sub ErrEx.Bookmark = BOOKMARK_ONERROR MsgBox Err.Description End Sub
The first thing you will notice is that there is no 'On Error Goto XYZ' and the reason is simple: When an error occurs, our global error handler will be jumping to the line below BOOKMARK_ONERROR for us, so there is no longer any need for specific local error handling to be set.
ErrEx.Bookmark is a write-only property of data-type Long (numeric). In this example we have chosen a bookmark value of 5 to uniquely identify our bookmark, but you can choose any value for this example as long as the values are unique if you define more than one bookmark.
We suggest that you define bookmarks as constants in a standard VB module - keeping the constants in the same module as your global error handler is probably a good idea.
To jump to a bookmark location from within a global error handler, we use the ErrEx.SetBookmarkAsOnErrorGoto method:
ErrEx.SetBookmarkAsOnErrorGoto(BookmarkID As Long) As Boolean
Public Sub MyGlobalErrorHandler() If ErrEx.SetBookmarkAsOnErrorGoto(BOOKMARK_ONERROR) = True Then ' The developer has set a BOOKMARK_ONERROR bookmark, so jump to that. Exit Sub Else ' The developer hasn't defined a BOOKMARK_ONERROR bookmark in this procedure, ' so we will deal with the error here ErrEx.State = ErrEx.ShowErrorDialog End If End Sub
In our example BookmarkID is the value BOOKMARK_ONERROR (5). What this call effectively does is set 'On Error Goto BOOKMARK_ONERROR' for the error, and since the error has already occurred (since we are inside a global error handler when calling this), then once your global error handler has completed (Exit Sub), the program flow will be set just beneath the bookmark - at the "MsgBox Err.Description" line.
The return value indicates whether or not the procedure of error actually had that bookmark or not.
If it returns TRUE then the bookmark exists and program flow will continue to that bookmark upon leaving the global error handler.
If it returns FALSE then the procedure of error does not have that particular bookmark set and the program flow is not changed.
From within your global error handler you can also determine the current bookmark that is active. We use the ErrEx.CurrentBookmark property:
ErrEx.CurrentBookmark As Variant
The return value of this read-only property is the BookmarkID for you to compare to your constant values, or an Empty variant if no bookmark is currently active.
This is particularly useful for writing bookmarks for 'cleanup' routines where for example, you might always want 'On Error Resume Next' to be assumed:
Public Sub Example() Dim objRcdSet As DAO.Recordset ErrEx.Bookmark = BOOKMARK_CLEANUP objRcdSet.Close ' Recordset wasn't open - this will cause an exception, but it's ignored Set objRcdSet = Nothing ' because we are within the BOOKMARK_CLEANUP bookmark End Sub
Public Const BOOKMARK_CLEANUP As Long = 6 Public Sub MyGlobalErrorHandler() ' Check if the error occurred in the BOOKMARK_CLEANUP section of code If ErrEx.CurrentBookmark = BOOKMARK_CLEANUP Then ErrEx.State = OnErrorResumeNext Exit Sub End If ' Show the error dialog ErrEx.ShowErrorDialog If ErrEx.SetBookmarkAsOnErrorGoto(BOOKMARK_CLEANUP) = True Then ' The developer has set a BOOKMARK_CLEANUP bookmark, so jump to that. Exit Sub Else ' The developer hasn't defined a BOOKMARK_CLEANUP bookmark in this procedure ' so we will end abruptly here ErrEx.State = OnErrorEnd End If End Sub
To jump to a bookmark location from within a local procedure, we use the ErrEx.GoToBookmark method:
ErrEx.GoToBookmark(BookmarkID As Long)
In our example BookmarkID is the value BOOKMARK_CLEANUP (6). This call is a replacement for 'Goto XYZ' which is used when working with normal VBA labels.
Public Sub Example()
Dim objRcdSet As DAO.Recordset
ErrEx.Bookmark = BOOKMARK_CLEANUP
objRcdSet.Close ' If the recordset wasn't open, this will cause an exception
Set objRcdSet = Nothing
Exit Sub
ErrEx.Bookmark = BOOKMARK_ONERROR
MsgBox Err.Description
ErrEx.GoToBookmark BOOKMARK_CLEANUP
End Sub
Although there are no implicit restrictions on what values you can assign to the constants for BookmarkIDs, we advise using actual error numbers if you want to provide a simplified form of local error handling.
For example, if you want to assign a local error handler for handling a division-by-zero error, we could define it like this:
Public Const BOOKMARK_CLEANUP = -1 ' *** Read comments below *** Public Const BOOKMARK_ONERROR_DIVBYZERO As Long = 11 ' 11 is the ErrEx.Number for division by zero errors Public Sub Example() Dim objRcdSet As DAO.Recordset Debug.Print 1/0 ErrEx.Bookmark = BOOKMARK_CLEANUP objRcdSet.Close ' If the recordset wasn't open, this will cause an exception Set objRcdSet = Nothing Exit Sub ErrEx.Bookmark = BOOKMARK_ONERROR_DIVBYZERO Resume Next End Sub Public Sub MyGlobalErrorHandler() ' Check if the error occurred in the BOOKMARK_CLEANUP section of code If ErrEx.CurrentBookmark = BOOKMARK_CLEANUP Then ' It did - so just ignore it and continue ErrEx.State = OnErrorResumeNext Exit Sub End If ' In this example ErrEx.Number will be 11 which is BOOKMARK_ONERROR_DIVBYZERO If ErrEx.SetBookmarkAsOnErrorGoto(ErrEx.Number) = True Then ' The procedure of error has designated a bookmark for handling this type of error Exit Sub Else ' The error is not handled locally, so we will handle it here... ErrEx.ShowErrorDialog If ErrEx.SetBookmarkAsOnErrorGoto(BOOKMARK_CLEANUP) = True Then ' The developer has set a BOOKMARK_CLEANUP bookmark, so jump to that. Exit Sub Else ' The developer hasn't defined a BOOKMARK_CLEANUP bookmark in this procedure, so we will end abruptly here ErrEx.State = OnErrorEnd End If End If End Sub
By using BookmarkIDs in this way, you can add new bookmarks without needing to change the global error handler code - just assign the new global constant to the value of an error number and use it in your local error handlers.
*** The only situation you need to be aware of when implementing it this way is that for non-error handling bookmarks (like BOOKMARK_CLEANUP) you must assign values to these bookmark constants that are unlikely to ever be valid error numbers (to avoid number conflicts). We advise using low negative numbers as these are rarely used for VBA error numbers.
Let's take an example:
We want to deal with a specific type of error locally (rather than in the global handler) and also ensure that all local variables are properly cleaned up.
Prior to using bookmarks we might have written something like this:
Public Function ChangeProperty(stPropName As String, PropType As DAO.DataTypeEnum, vPropVal As Variant) As Boolean On Error GoTo LocalErrorHandler Dim Db As DAO.Database Dim Prop As DAO.Property Set Db = CurrentDb Db.Properties.Delete stPropName Db.Properties.Delete stPropName ' Causes an error because the property doesn't exist Set Prop = Db.CreateProperty(stPropName, PropType, vPropVal, True) Db.Properties.Append Prop ChangeProperty = True Cleanup: On Error Resume Next ' Ignore errors when cleaning up. Set Prop = Nothing Set Db = Nothing Exit Function LocalErrorHandler: ' Handle local specific errors here: Const conItemNotFoundInCollectionError As Long = 3265 Select Case Err.Number Case conItemNotFoundInCollectionError ' We will ignore the 'property does not exist' error Resume Next End Select ErrEx.CallGlobalErrorHandler ' Call the global error handler to deal with unhandled errors Resume Cleanup ' After showing the error dialog, we will clean up End Function
By using the new bookmarks features of the SimplyVBA Global Error Handler, we can now cut down this code considerably:
(Assume the global error handler is set up as per Using error numbers as BookmarkIDs)
Public Const BOOKMARK_CLEANUP As Long = -1 ' -1 to avoid conflicts with normal error numbers Public Const BOOKMARK_ONERROR_ITEMNOTFOUNDINCOLLECTION As Long = 3265 Public Function ChangeProperty(stPropName As String, PropType As DAO.DataTypeEnum, vPropVal As Variant) As Boolean Dim Db As DAO.Database Dim Prop As DAO.Property Set Db = CurrentDb Db.Properties.Delete stPropName Db.Properties.Delete stPropName ' Causes an error because the property doesn't exist Set Prop = Db.CreateProperty(stPropName, PropType, vPropVal, True) Db.Properties.Append Prop ChangeProperty = True ErrEx.Bookmark = BOOKMARK_CLEANUP Set Prop = Nothing Set Db = Nothing Exit Function ErrEx.Bookmark = BOOKMARK_ONERROR_ITEMNOTFOUNDINCOLLECTION Resume Next End Function
Also check out the BookmarksSample.mdb included with v1.2 and above of the installed application.
Unlike normal VB labels, Bookmarks are not checked at compile time. For this reason, we have provided a simple tool in the Add-ins menu that can be run after compiling to ensure that;
1) There are no duplicate bookmarks defined in the same local procedure.
2) If ErrEx.GoToBookmark is used in a local procedure, then the bookmark that is referenced by it has actually been defined.
This tool only does a very simplistic text based check of the source code, but this is sufficient in most circumstances.
To run the tool, go to the VBE Window, Add-ins menu > SimplyVBA Global Error Handler > Verify Bookmarks Usage
iTech Masters | VAT: GB202994606 | Terms | Sitemap | Newsletter