Directives

[Previous] [Next]

7.1 Use On Error GoTo to trap unexpected errors.

Most error handlers are designed to trap errors that aren't anticipated at design time. The On Error GoTo statement is the most common way of designating an error handler. You should use this as the default in all of your procedures unless you have a specific reason to use a different scheme.

Incorrect:

  PrivateSub  imgEditor_MouseUp(Button  AsInteger  ,Shift  AsInteger  ,_ X  AsSingle  ,Y  AsSingle  )  '*Purpose:Iftheeditorisinselect(marquee)mode,display '*theEditshortcutmenuwhentheuserright-clicks '*theCanvas.   OnErrorResumeNext   '*Displaytheshortcutmenuonlyiftheuserclickedwith '*therightmousebutton.   If  Button=vbRightButton  Then   '*SeeiftheactivetooloftheCanvasobjectisthe '*marqueetool.   If  g_objCanvas.ToolIndex=bdMarquee  Then   '*DisplaytheEditshortcutmenuusingtheactive '*barcontrol.  Me.ActiveBar.Bands("puEdit").TrackPopup-1,-1  EndIf EndIf   '*TelltheCanvasobjecttostopitscurrentaction.  g_objCanvas.ActionEndButton,Shift,X,Y PROC_EXIT:  ExitSub   EndSub  

Correct:

  PrivateSub  imgEditor_MouseUp(Button  AsInteger  ,Shift  AsInteger  ,_ X  AsSingle  ,Y  AsSingle  )  '*Purpose:Iftheeditorisinselect(marquee)mode,display '*theEditshortcutmenuwhentheuserright-clicks '*theCanvas.   OnErrorGoTo  PROC_ERR  '*Displaytheshortcutmenuonlyiftheuserclickedwith '*therightmousebutton.   If  Button=vbRightButton  Then   '*SeeiftheactivetooloftheCanvasobjectisthe '*marqueetool.   If  g_objCanvas.ToolIndex=bdMarquee  Then   '*DisplaytheEditshortcutmenuusingtheactive '*barcontrol.  Me.ActiveBar.Bands("puEdit").TrackPopup-1,-1  EndIf EndIf   '*TelltheCanvasobjecttostopitscurrentaction.  g_objCanvas.ActionEndButton,Shift,X,Y PROC_EXIT:  ExitSub  PROC_ERR:  Call  ShowError(Me.Name,"imgEditor_MouseUp",Err.Number,_ Err.Description)  ResumeNext   EndSub  

7.2 Use On Error Resume Next to trap expected errors.

When you expect an error, such as Error 5 when you use SetFocus to move the cursor to a control on a form that is not fully loaded, or an error from a database action, use On Error Resume Next. But be careful ”using On Error Resume Next can be dangerous because it can cause run-time errors to go unnoticed. Do not use it as a panacea; if you do not expect an error, don't use it. Also, just because you expect an error within a procedure doesn't mean that you should use On Error Resume Next for the entire procedure. Use On Error GoTo to trap unexpected errors, but change the enabled error handler immediately before the line that could cause the expected error. After you have handled the expected error, include an On Error GoTo statement to enable the main error handler again.

When you write code to trap an expected error, be sure to document the code thoroughly. State specifically why you are using On Error Resume Next ”such as what error you expect and why.

Incorrect:

  PrivateSub  cmdCoverLetter_Click()  '*Purpose:Allowtheusertobrowseandselectacover '*pageforfaxing.   OnErrorResumeNext   Const  c_CancelChosen=32755  '*Usethecommondialogcontroltoallowtheuserto '*selectafile.   With  dlgOpenFile .fileName="*.cvp" .DefaultExt="cvp" .DialogTitle="SelectCoverPage" .Filter="AllFiles(*.*)*.*CoverPages(*.cvp)" .FilterIndex=2 .InitDir=App.Path  '*TellthecontroltogenerateanerrorifCancelisclicked.  .CancelError=  True   '*ShowtheOpenFiledialogboxandwaitfortheuserto '*selectafileorclickCancel.   .ShowOpen   '*Seeifanerrorwasgeneratedastheresultofthe '*userclickingCancel.   If  Err.Number=c_CancelChosen  Then   '*Cancelwasclicked;getout.   GoTo  PROC_EXIT  EndIf  txtCoverpage.Text=.fileName  EndWith  PROC_EXIT:  ExitSub EndSub  

Correct:

  PrivateSub  cmdCoverLetter_Click()  '*Purpose:Allowtheusertobrowseandselectacover '*pageforfaxing.   OnErrorGoTo  PROC_ERR  Const  c_CancelChosen=32755  '*Usethecommondialogcontroltoallowtheuserto '*selectafile.   With  dlgOpenFile .fileName="*.cvp" .DefaultExt="cvp" .DialogTitle="SelectCoverPage" .Filter="AllFiles(*.*)*.*CoverPages(*.cvp)" .FilterIndex=2 .InitDir=App.Path  '*TellthecontroltogenerateanerrorifCancelisclicked.  .CancelError=  True   '*IftheuserclicksCancel,arun-timeerroroccurs. '*Trapforthiserror.   OnErrorResumeNext   '*ShowtheOpenFiledialogboxandwaitfortheuserto '*selectafileorclickCancel.  .ShowOpen  '*Seeifanerrorwasgeneratedastheresultofthe '*userclickingCancel.   If  Err.Number=c_CancelChosen  Then   '*Cancelwasclicked;getout.   GoTo  PROC_EXIT  EndIf   '*Enablethemainerrorhandler.   OnErrorGoTo  PROC_ERR txtCoverpage.Text=.fileName  EndWith  PROC_EXIT:  ExitSub  PROC_ERR:  Call  ShowError(Me.Name,"cmdCoverLetter_Click",Err.Number,_ Err.Description)  ResumeNext EndSub  

7.3 Create consistent error handler blocks.

When you use On Error GoTo , it's important to use consistent error blocks. It's definitely best to use a central error handler, but if you don't use one, create error handlers like this typical error block:

 PROC_ERR: MsgBox"  ModuleName   ProcedureName  "&vbcrlf&"Error:"&_ Err.Number&vbCrLf&Err.Description,vbCritical  '*cleanupcodesuchasarollback   ResumeNext  '*orResume,orGoToPROC_EXIT 

If you're going to alert the user to the error, which is usually the best approach, the MsgBox statement should be the first statement of the error block. If the MsgBox statement is not the first statement, the Err object might be reset and the MsgBox statement won't return the proper error number and/or description ”for instance, if you branch to another procedure that enables an error handler. The only parts of the MsgBox statement that should be modified for each procedure are the procedure name and possibly the module name.

You can add code to the error block at your discretion, such as invoking a rollback on a database transaction. Of course, the necessary code will vary from procedure to procedure.

If you don't want to terminate a procedure as a result of an error, you must end the error block with Resume , Resume Next , or Resume <line>. To continue executing code starting at the line after the statement that caused the error, use Resume Next. If you believe the offending statement might now properly execute (such as when your error handler has corrected the problem), use Resume to send execution back to the statement that caused the error.

NOTE
If you use Resume at the end of an error block without correcting the offending error, you risk creating an endless loop in your code! The error will cause the error block to execute, which will return to the offending statement, which will cause the error, and so forth.

Creating a central error handler eliminates the necessity to micromanage the error handler in every procedure. However, if you don't use a central error handler, you must handle and display errors in a consistent manner.

Incorrect:

 PROC_ERR: MsgBox"Error!:"&Err.Number&vbCrLf&Err.Description  GoTo  PROC_EXIT PROC_ERR: MsgBoxErr.Number&vbCrLf&Err.Description  GoTo  PROC_EXIT 

Correct:

 PROC_ERR: MsgBoxMe.Name&"MyProcedure"&vbCrLf&Err.Number&vbCrLf&_ Err.Description  GoTo  PROC_EXIT PROC_ERR: MsgBox"MyModuleMyProcedure"&vbCrLf&Err.Number&vbCrLf&_ Err.Description  GoTo  PROC_EXIT 

Practical Application

7.3.1 Don't let code fall through to End Sub , End Function , or End Property. Generally, the error block should be the last section of code in a procedure. However, if you want the procedure to terminate at the end of the error block, don't just let the code run through to End Sub , End Function , or End Property. Remember that it's vitally important that each procedure have only one exit point ”see Chapter 3 ”so to terminate a procedure from the error block you should branch to the PROC_EXIT label.

Incorrect:

  PrivateSub  otToolbox_ToolSelected(Tool  As  Toolbox.cTool)  '*Purpose:Whenanewtoolisselectedfromthetoolbox, '*selectthecorrespondingtooloftheCanvasobject.   OnErrorGoTo  PROC_ERR  '*Iftheselectedtoolisthesameasthecurrenttool,getout.   If  Tool.Index=objCanvas.ToolIndex  ThenGoTo  PROC_EXIT  '*IftheselectedtooloftheCanvasisthemarqueeandan '*areaisselected,redisplaythemarquee.   If  objCanvas.ToolIndex=bdMarquee  Then   '*Iftheuserhasselectedanareawiththemarquee, '*triggerareset(repaint)ofthemarqueerectangle.   If  objCanvas.AreaSelected  Then  objCanvas.ResetMarquee  EndIf EndIf   '*SettheCanvasobjecttothenewtool.  objCanvas.ToolIndex=Tool.Index PROC_EXIT:  ExitSub  PROC_ERR:  Call  ShowError(Me.Name,"otToolbox_ToolSelected",Err.Number,_ Err.Description)  EndSub  

Correct:

  PrivateSub  otToolbox_ToolSelected(Tool  As  Toolbox.cTool)  '*Purpose:Whenanewtoolisselectedfromthetoolbox, '*selectthecorrespondingtooloftheCanvasobject.   OnErrorGoTo  PROC_ERR  '*Iftheselectedtoolisthesameasthecurrenttool,getout.   If  Tool.Index=objCanvas.ToolIndex  ThenGoTo  PROC_EXIT  '*IftheselectedtooloftheCanvasisthemarqueeandan '*areaisselected,redisplaythemarquee.   If  objCanvas.ToolIndex=bdMarquee  Then   '*Iftheuserhasselectedanareawiththemarquee, '*triggerareset(repaint)ofthemarqueerectangle.   If  objCanvas.AreaSelected  Then  objCanvas.ResetMarquee  EndIf EndIf   '*SettheCanvasobjecttothenewtool.  objCanvas.ToolIndex=Tool.Index PROC_EXIT:  ExitSub  PROC_ERR:  Call  ShowError(Me.Name,"otToolbox_ToolSelected",Err.Number,_ Err.Description)  GoTo  PROC_EXIT  EndSub  


Practical Standards for Microsoft Visual Basic
Practical Standards for Microsoft Visual Basic .NET (Pro-Developer)
ISBN: 0735613567
EAN: 2147483647
Year: 2000
Pages: 57

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net