Error Handling Questions

J

JamesJ

I'm finally facing up to he fact I have no error handling in my db and want to implement it.
From what I've read from my books and on the web, implementing it seems like a daunting
tasks if one has no error handling. I really didn't get much out of what I read and hopefully
someone will point me to a web site for info or answer my questions.

1) Does every function, procedure or sub need error trapping? I, for instance have the following
in the On Open of a form:
Me!fieldname.SetFocus.
I can understand that if I remove the field from the form it might trigger an error, but come on.
I have, and I'm guessing, at least 50 functions, procedures or subs in my db. That estimate
is probably on the low side.

2) Is there any generic error handling routines that can be called from, say the on open of a form
instead of creating error handling for every one of a forms subs?

3) Do I need to trap for errors I suspect might occur? But then if I was able to that I probably wouldn't need
error handling.

Thanks,
James
 
S

Stefan Hoffmann

hi James,

I'm finally facing up to he fact I have no error handling in my db and want to implement it.
From what I've read from my books and on the web, implementing it seems like a daunting
tasks if one has no error handling.
Use the mztools.com VBA plug-in. It provides an error handling template
you can implement with a single click.
1) Does every function, procedure or sub need error trapping? I, for
instance have the following
in the On Open of a form:
Me!fieldname.SetFocus.
I can understand that if I remove the field from the form it might
trigger an error, but come on.
You don't need error handling in this case as it will raise a compile error.
2) Is there any generic error handling routines that can be called from,
say the on open of a form
instead of creating error handling for every one of a forms subs?
Not really. You have the Form Error event which will catch the errors
which may happen on normal operations. VBA errors are not caught by it.
3) Do I need to trap for errors I suspect might occur? But then if I was
able to that I probably wouldn't need
error handling.
E.g.

Private Sub cmdFoo_Click()

Dim rs As DAO.Recordset

Set rs = CurrentDb.OpenRecordset("...", dbOpenSnapshot)
' do something with rs
rs.Close
Set rs = Nothing

End Sub

You don't need an error handler in a single mdb, no front-end/back-end
splitting. But if you're using a split design storing the back-end on a
file server then you need it for trapping network errors.

While it is okay in some cases to ignore the error here, you have also
to consider running your application as a compiled mde. In a mde an
unhandled error results in the shut-down of the application.

The best practice is defensive programming: Test all preconditions and
continue only if they are all met.

You may find there are two kinds of operations: One which may fail, but
have no effect on the data integrity and logic state of your
application. Use On Local Error Resume Next in these cases. In all other
cases use an explicit error handler.


mfG
--> stefan <--

p.s. newsgroups are a text medium, please turn off the HTML composition
of your news client.
 
D

Dennis

JamesJ

Welcome to the club. You have a couple of good questions that I would like
to hear the answer to.

Here is the error handling code that I've come up with from read on the web
and the different MVP sites.

1. As far as every function - I don't put error traping in EVERY fuction or
sub because some prodcedures are just 1 line long where I set a variable. I
hope someone can give you a rule of thumb, but I have a feeling you are going
to have to develop your own rule of thumg.

Here is my error handing code that I put in each procedure / function, where
appropriate:


Private Sub cbSquadOff_Click()
On Error GoTo Err_cbSquadOff_Click

.... my code .....

Exit_cbSquadOff_Click:
Exit Sub

Err_cbSquadOff_Click:
Call BaseUtil.Dsp_Err_Msg(Err.Number, Err.Description, "cbSquadOff_Click
")
Resume Exit_cbSquadOff_Click

End Sub


There here is the code I have in a module called BaseUtil (hence the Call
BaseUtil.Dsp_Err_Msg).

I can optionally write the error message out to tblErrorLog if I set the
local variable boolShowMsg to True or the global variable gboolMbShowAll to
True.

Public Sub Dsp_Err_Msg(lngErrNo As Long, strErrDesc As String, strMbTitle As
String)
On Error GoTo Err_Dsp_Err_Msg

' This routine will displays and record an error messages from the On Err
routines.
' It will NOT display selected the following error messages:
' 2501 - Run Command Cancel

Dim boolShowMsg As Boolean
Dim dbErrLog As Database
Dim rstErrLog As Recordset
Dim strFrmName As String
Dim strCtlName As String
Dim strCtlNameText As String
Dim lngOrigErrNo As Long
Dim strOrigErrDesc As String

Const intRunCmdCancel As Integer = 2501 ' Err # for Run Cmd Cancelled
err msg.

' Set the values of the different values

lngOrigErrNo = lngErrNo ' Save original error number
and desc
strOrigErrDesc = strErrDesc
On Error Resume Next ' Added trap to avoid Fault
when screen is blank
strFrmName = Screen.ActiveForm.Name ' Get Form name
strCtlNameText = ""
If Nz(strFrmName, "") <> "" Then ' Get control name
strCtlName = Nz(Screen.ActiveControl.Name, "")
If strCtlName <> "" Then
strCtlNameText = "And in the control " & strCtlName & vbCrLf
End If
End If
On Error GoTo Err_Dsp_Err_Msg ' Resume the On Error normal
trap

' Generate the error message display information

boolShowMsg = True
gstrMbTitle = strMbTitle
glngMbButton = vbOKOnly + vbExclamation
If Err.Number > 0 Then
gstrMbText = "The following error occurred in " & strFrmName & vbCrLf
gstrMbText = gstrMbText & "Within the module " & strMbTitle & vbCrLf
gstrMbText = gstrMbText & strCtlNameText & vbCrLf
gstrMbText = gstrMbText & "Err No. '" & lngOrigErrNo & "'" & vbCrLf
gstrMbText = gstrMbText & "Err Desc: " & strOrigErrDesc
Else
gstrMbText = vbCrLf & strOrigErrDesc & vbCrLf
End If

' If the error number is one of the ones we are not supposed to display,
then
' turn off the Show Message flag

boolShowMsg = True
Select Case lngErrNo
Case intRunCmdCancel ' Do not show Run Command
Cancelled
boolShowMsg = False
End Select

' Display message if we are to display the message or the Show All flag
set to true

If boolShowMsg Or gboolMbShowAll Then
gintMbResp = MsgBox(gstrMbText, glngMbButton, gstrMbTitle) '
Display msg
'
Set dbErrLog = CurrentDb()
Set rstErrLog = dbErrLog.OpenRecordset("tblErrorLog")

rstErrLog.AddNew
rstErrLog!CurrForm = strFrmName
rstErrLog!CurrCtl = strCtlName
rstErrLog!NoForms = Forms.Count
rstErrLog!CurrUser = ""
rstErrLog!DateTime = Now()
rstErrLog!CallingProc = strMbTitle
rstErrLog!ErrNo = lngOrigErrNo
rstErrLog!ErrDesc = strOrigErrDesc
rstErrLog.Update
rstErrLog.Close

Set rstErrLog = Nothing
Set dbErrLog = Nothing
End If

Exit_Dsp_Err_Msg:

gboolMbShowAll = False ' Reset the show all
messages flag

Exit Sub


Err_Dsp_Err_Msg:

' An error occured above, so display the error message below

gstrMbTitle = "BaseUtil.Dps_Err_Msg - " & gstrMbTitle
gstrMyString = "Dsp Err No '" & Err.Number & "' and Dsp Err Desc " &
Err.Description
gstrMbText = gstrMyString & vbCrLf & gstrMbText
gintMbResp = MsgBox(gstrMbText, glngMbButton, gstrMbTitle)

Resume Exit_Dsp_Err_Msg

End Sub
 
J

JamesJ

This a a split db but both are on my local HDD
I'll into the VBA in.

Thanks much,
James
 
J

JamesJ

Thanks for the info,
James

Dennis said:
JamesJ

Welcome to the club. You have a couple of good questions that I would
like
to hear the answer to.

Here is the error handling code that I've come up with from read on the
web
and the different MVP sites.

1. As far as every function - I don't put error traping in EVERY fuction
or
sub because some prodcedures are just 1 line long where I set a variable.
I
hope someone can give you a rule of thumb, but I have a feeling you are
going
to have to develop your own rule of thumg.

Here is my error handing code that I put in each procedure / function,
where
appropriate:


Private Sub cbSquadOff_Click()
On Error GoTo Err_cbSquadOff_Click

.... my code .....

Exit_cbSquadOff_Click:
Exit Sub

Err_cbSquadOff_Click:
Call BaseUtil.Dsp_Err_Msg(Err.Number, Err.Description,
"cbSquadOff_Click
")
Resume Exit_cbSquadOff_Click

End Sub


There here is the code I have in a module called BaseUtil (hence the Call
BaseUtil.Dsp_Err_Msg).

I can optionally write the error message out to tblErrorLog if I set the
local variable boolShowMsg to True or the global variable gboolMbShowAll
to
True.

Public Sub Dsp_Err_Msg(lngErrNo As Long, strErrDesc As String, strMbTitle
As
String)
On Error GoTo Err_Dsp_Err_Msg

' This routine will displays and record an error messages from the On
Err
routines.
' It will NOT display selected the following error messages:
' 2501 - Run Command Cancel

Dim boolShowMsg As Boolean
Dim dbErrLog As Database
Dim rstErrLog As Recordset
Dim strFrmName As String
Dim strCtlName As String
Dim strCtlNameText As String
Dim lngOrigErrNo As Long
Dim strOrigErrDesc As String

Const intRunCmdCancel As Integer = 2501 ' Err # for Run Cmd Cancelled
err msg.

' Set the values of the different values

lngOrigErrNo = lngErrNo ' Save original error
number
and desc
strOrigErrDesc = strErrDesc
On Error Resume Next ' Added trap to avoid Fault
when screen is blank
strFrmName = Screen.ActiveForm.Name ' Get Form name
strCtlNameText = ""
If Nz(strFrmName, "") <> "" Then ' Get control name
strCtlName = Nz(Screen.ActiveControl.Name, "")
If strCtlName <> "" Then
strCtlNameText = "And in the control " & strCtlName & vbCrLf
End If
End If
On Error GoTo Err_Dsp_Err_Msg ' Resume the On Error
normal
trap

' Generate the error message display information

boolShowMsg = True
gstrMbTitle = strMbTitle
glngMbButton = vbOKOnly + vbExclamation
If Err.Number > 0 Then
gstrMbText = "The following error occurred in " & strFrmName &
vbCrLf
gstrMbText = gstrMbText & "Within the module " & strMbTitle &
vbCrLf
gstrMbText = gstrMbText & strCtlNameText & vbCrLf
gstrMbText = gstrMbText & "Err No. '" & lngOrigErrNo & "'" &
vbCrLf
gstrMbText = gstrMbText & "Err Desc: " & strOrigErrDesc
Else
gstrMbText = vbCrLf & strOrigErrDesc & vbCrLf
End If

' If the error number is one of the ones we are not supposed to display,
then
' turn off the Show Message flag

boolShowMsg = True
Select Case lngErrNo
Case intRunCmdCancel ' Do not show Run Command
Cancelled
boolShowMsg = False
End Select

' Display message if we are to display the message or the Show All flag
set to true

If boolShowMsg Or gboolMbShowAll Then
gintMbResp = MsgBox(gstrMbText, glngMbButton, gstrMbTitle) '
Display msg
'
Set dbErrLog = CurrentDb()
Set rstErrLog = dbErrLog.OpenRecordset("tblErrorLog")

rstErrLog.AddNew
rstErrLog!CurrForm = strFrmName
rstErrLog!CurrCtl = strCtlName
rstErrLog!NoForms = Forms.Count
rstErrLog!CurrUser = ""
rstErrLog!DateTime = Now()
rstErrLog!CallingProc = strMbTitle
rstErrLog!ErrNo = lngOrigErrNo
rstErrLog!ErrDesc = strOrigErrDesc
rstErrLog.Update
rstErrLog.Close

Set rstErrLog = Nothing
Set dbErrLog = Nothing
End If

Exit_Dsp_Err_Msg:

gboolMbShowAll = False ' Reset the show all
messages flag

Exit Sub


Err_Dsp_Err_Msg:

' An error occured above, so display the error message below

gstrMbTitle = "BaseUtil.Dps_Err_Msg - " & gstrMbTitle
gstrMyString = "Dsp Err No '" & Err.Number & "' and Dsp Err Desc " &
Err.Description
gstrMbText = gstrMyString & vbCrLf & gstrMbText
gintMbResp = MsgBox(gstrMbText, glngMbButton, gstrMbTitle)

Resume Exit_Dsp_Err_Msg

End Sub
 
J

Jack Leach

Here's my take:

NEVER expect to have figured for all errors. In note of that, you should
have error handling in every sub/function. Or at least, you should
understand that when there is no error handling in a procedure, the error is
carried back through the calling procedures until an error handler is found,
or, until the last calling procedure is found. If none of these have error
handling, you will see the halt code error dialog box. Realize that if you
get this box, your code is now in what they call a "broken" state, and
depending on the complexity of your project, this could have a devastating
effect to your data. Hardly worth the risk IMHO.

That said, the ONLY time I leave error handling out of a procedure is when I
have a specific reason to do so (when I want the error handled by the calling
procedure instead of the current procedure). And this is not very often
(unless you're in the habit of writing class modules).

When you start expanding on your project and getting into using global
variables or properties that store core data for the session, you don't want
there to be any chance whatsoever that this data might get messed up (which
it will on an unhandled error), because that could seriously mess some things
up. So yes, my advice is to include it on every procedure. You'd be amazed
at what crazy errors access can spit out, sometimes even months after
testing/using the app.

1) Does every function, procedure or sub need error trapping? I, for instance have the following
in the On Open of a form:
Me!fieldname.SetFocus.
I can understand that if I remove the field from the form it might trigger an error, but come on.

What if, 6 months down the road, you do some editing to the app and
reconstruct the underlying query of the form, and that field is no longer
available? Are you sure you will remember that when the time comes? Are you
willing to go through and check all of your lines of code manually to make
sure you've got everything covered before you accidentally screw something
up? (and btw, you can't set the focus to a field, rather you set it to the
control that the field is bound to).

2) Is there any generic error handling routines that can be called from, say the on open of a form
instead of creating error handling for every one of a forms subs?

No, but there's a free tool that makes it extremely easy (after setting up
you can have error handling in every procedure in your app in about
10minutes). Go to www.mztools.com and download the addin. It's priceless.

3) Do I need to trap for errors I suspect might occur? But then if I was able to that I probably wouldn't need
error handling.

Again, the major point here is that you will never think of every error that
will happen, no matter how good you are. It's just the way it is... As far
as trapping errors you suspect might occur, there's two schools of thought on
that, the first is to handle the case outside of the error handler (as an
if/then condition in the procedure), the second is to handle it within the
error handler itself. Either way, you should be account for "expected"
errors. "Unexpected" errors are the ones that cause the real problems and
raise the requirement for good error handling.


There's umpteen different ways that people tend to go about handling
errors... I've been through a lot of them, from global functions to handle
logging and notifying of errors, down to a few lines in each procedure. IME,
large global functions to handle all sorts of errors are generally a pain.
What happens if you get an error inside you error handler? At one point I
had a global handler set up that would log the error, and, depending on the
source of the error, would roll back the app to a particular state (such as
user logged out, or restart, or close the active form, etc). It theory its a
great idea, but the extra pains you have to go through to make sure it will
never fail is a complete nightmare.

FWIW, the handler that I've settled on after a few years trying different
things is this one:


Public Function SomeFunc() As Datatype
On Error Goto Err_Proc:
'-----
your sub here

'-----
Exit_Proc:
Exit Function
Err_Proc:
Select Case Err.Number
Case Else
MsgBox Err.Number & ": " & Err.Description
End Select
Resume Next
Resume
End Function



the above gives you a base that can be inserted into any procedure, and the
Select Case statement allows you to handle expected errors easily without
having to change anything other than adding a Case # line.



All in all, I think error handling is extremely important for any even
halfway serious work. It's the backbone of your application. Even if you
just tool around with Access to keep your CD collection at the house, you
will never regret having taken the time to set up SOME sort of handling.
mztools lets you insert a handler at the click of a button.


For further reading, do a google search on "Chip Pearson Error Handling"...
he goes through everything from top to bottom (written for excel but
applicable to any office vba host app).


hth


--
Jack Leach
www.tristatemachine.com

"I haven''t failed, I''ve found ten thousand ways that don''t work."
-Thomas Edison (1847-1931)
 
P

PieterLinden via AccessMonster.com

Jack said:
Here's my take:

sorry for appearing to hijack this conversation... Just wondering, though...
doesn't MZTools allow you to basically modify the new Sub/Function template
to include basic error handling? (I'd check but I'm rebuilding my computer...
sorry!) At any rate, MZTools is a great tool for VBA, and free!

Thanks for the link... I like it and I've only just started reading it...
(Makes me wonder when/if VBA will ever have Java-like error handling...)
 
J

Jack Leach

MZTools will add the handling to an empty procedure or to one that already
has code. Adding to one that already has code sometimes comes up with a
formatting problem because it tends to misplace the existing code if you
don't set it up right. But a little formatting with the procedure header and
error handling for MZ and you can get it to enter seamlessly.

The nice thing about MZ is that you can have it do anything for you... a
base procedure looks like this:

Sub SubName()

End Sub


and you set up any sort of template you would like to be entered as a
header/handler.

As an alternative, it has a copy/paste clipboard with ctrl+#shortcuts for
them, so if you have a different setup for a Sub than a Function, you can get
a little more functionality out of it.


There's better solutions, that will handle any number of function
datatype/return formats, etc etc, but for a free addin MZtools has always
been my only choice for this stuff.


--
Jack Leach
www.tristatemachine.com

"I haven't failed, I've found ten thousand ways that don't work."
-Thomas Edison (1847-1931)
 
S

Stuart McCall

Hello Jack

PMFJI. In this code:
Resume Next
Resume
End Function

Just curious; why the Resume statement immediately following a Resume Next?

For the benefit of others reading this, Resume Next means 'resume execution
at the line following the one that caused the error', whereas Resume on its
own means 'resume execution at the line which caused the error'.
 
R

Rob Parker

The Resume Next line is probably being used to do just that (from the error
handler). The usefulness of the Resume statement is that, if you enter
debug mode when the error occurs, you can right-click on that line, then
choose Set Next Statement, hit F8 (for Step Into), and it will take you to
the line of code where the error occurred. I find it extremely useful on
occassion - I've got it coded at the bottom of my MZ-Tools error-handler
template.

HTH,

Rob
 
S

Stuart McCall

Rob Parker said:
The Resume Next line is probably being used to do just that (from the
error handler).

Yes it is. I only copied the last part.
The usefulness of the Resume statement is that, if you enter debug mode
when the error occurs, you can right-click on that line, then choose Set
Next Statement, hit F8 (for Step Into), and it will take you to the line
of code where the error occurred.

Neat trick - thanks for sharing.

I find it extremely useful on
occassion - I've got it coded at the bottom of my MZ-Tools error-handler
template.

It's in mine too, now. :)
 
J

Jack Leach

Typo...

s/b

Resume Exit_Proc:
Resume



The second Resume is to drag/drop the atcive line to, so you can jump back
in a stepthrough and evaluate the offending line in debug mode.

PMFJI?

--
Jack Leach
www.tristatemachine.com

"I haven''t failed, I''ve found ten thousand ways that don''t work."
-Thomas Edison (1847-1931)
 
J

John W. Vinson

The usefulness of the Resume statement is that

That's why I love doing this: I keep learning new things that I never knew
before but I can use. Thanks Rob!
 
S

Stuart McCall

Jack Leach said:
Typo...

s/b

Resume Exit_Proc:
Resume

Yep, that looks better :)
The second Resume is to drag/drop the atcive line to, so you can jump back
in a stepthrough and evaluate the offending line in debug mode.

I echo John V's sentiment re always learning. Thanks.

Pardon Me For Jumping In (not as commonly used these days, more's the pity)
In 'thowd days of Bulletin boards, some sysops would jump all over *you* if
you didn't include something like that. T'weren't civil to jump in without.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top