WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

Samples from Users
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

Critical Error Handler


I have a critical error handler that doesn't work too badly. It traps all errors, shows them in my own dialog box, lets the users continue if they really want to, and has a button to half-assed show the source. It works OK in most cases, although the detection of filename isn't quite reliable.

Take a look at the attached source and see if you can use it.

Wade www.wademan.com

;=============================================================================================================
; This script creates a critical error handler that will handle all critical errors in your main script but
; will NOT handle errors in UDFs unless you explicitely turn on error handling in the UDF using IntControl73.
;
; I have this code at the top of a file WbtLib.wbt that I include in every WinBatch I ever write.  Every
; script file starts with
;
;  #Include "C:\Tools\WbtLib.wbt"
;
; The script starts off with some general initialization, initiates this error handler, and then defines a
; bunch of UDFS.  You can either #Include this file, or cut-n-paste this into the top of your own lib file.
;
; For comments or questions, go to my webpage at www.wademan.com and you can find my email address there.
; Sorry, I never post it publicly.
;=============================================================================================================

;=============================================================================================================
; Define a global error handler.  Unfortunately, we have to do it with this lame GOTO style label, but you
; can't have everything.  The IntControl(73 tells the caller to initiate an error handler.  Once you call
; it, all errors go to the magic label :WBEerrorHandler below.  You can call as a Gosub or Goto.  I use the
; Gosub method, and give the user a chance to quit or carry on and take their chances despite the error.
;
; Once I've defined the error handler, I use GOTO to get around the error code itself.  In my real library,
; all my shared UDFs follow the error handler.
;=============================================================================================================
IntControl(73, 2, 0, 0, 0)
Goto EndErrorHandler


;=============================================================================================================
; Critical errors do a GOSUB to this magic label.  We call a critical error handler that I also call
; directly for my own personally defined errors.
;=============================================================================================================
:WBErrorHandler
   ; Convert the most recent error to human readable
   ErrCode = LastError()
   ErrText = IntControl(34, ErrCode, 0 , 0, 0)
   CriticalErrorHandler(ErrCode, ErrText, WBErrorHandlerLine, WBErrorHandlerOffset)
   IntControl(73, 2, 0, 0, 0)
   Return
:EndErrorHandler

;=============================================================================================================
; Handle critical errors.  This is called by CrashNBurn for internal errors in my UDFs, and by the critical
; error handler above.
;
; @param p_ErrCode      Numeric error code.  If non-blank, it's shown after the text error message.  If '',
;                       it's ignored.
;
; @param p_ErrString    Text Error description.  This is displayed to the user, along with the numeric code.
;
; @param p_ErrSource    Source line for the error as the line exactly as it appears in the script file.
;
; @param p_ErrOffset    Offset into the source for the errro.  NOTE!! This doesn't work right and isn't used
;                       in the current implementation until I write the brute-force code to handle it.
;
; @return               Critical error message is shown to the user, and they have a chance to exit or
;                       continue.  If they elect to continue, control returns and they can take their
;                       chances.
;=============================================================================================================
#DefineFunction CriticalErrorHandler(p_ErrCode, p_ErrString, p_ErrSource, p_ErrOffset)

   ; Read the error file.  Note that this is NOT reliable, but it's the best we have.  In particular, it's
   ; unreliable in UDFs.
   ErrFile = IntControl(1004, 0, 0, 0, 0)

   ; This unfinished code should just be deleted, but I'll finish it one day.  It takes the error offset,
   ; and calculates the line number from it.  Unfortunately, it doesn't handle #Includes, which makes it
   ; effectively useless.  If you feel like tackling it, email me the results when it works right.
;   ; Calculate the line number of the error using brute force.  Read the currently active source file into a
;   ; buffer, and count LFs until we get to the offset of our error.
;   ErrBuffer = BinaryAlloc(FileSize(ErrFile, 0) + 1)
;   BinaryReadEx(ErrBuffer, 0, ErrFile, 0, 2000)
;   ErrLine = 0
;   EolOffset = -1
;   While(@TRUE)
;      EolOffset = BinaryIndex(ErrBuffer, EolOffset + 1, @LF, 0)
;      CTrace(StrCat(EolOffset , ',' , ErrOffset))
;      If EolOffset == 0
;         ErrLine = "?"
;         Break
;      Endif
;      If EolOffset >= ErrOffset Then Break
;      ErrLine = ErrLine + 1
;   EndWhile
;
;   message("", BinaryPeekStr(ErrBuffer, 0, 200))
;   BinaryFree(ErrBuffer)

   ; Put the error source in the clipboard to help find the error
   ClipPut(p_ErrSource)

   ; Generate the basic error message, and then add optional
   ErrorMessage = StrCat("Error:", @Tab, @Tab, p_ErrString, @LF, "File:", @Tab, @Tab, ErrFile)
   If p_ErrSource != "" Then ErrorMessage = StrCat(ErrorMessage, @LF, "Source:", @Tab, @Tab, p_ErrSource)
   If p_ErrCode   != "" Then ErrorMessage = StrCat(ErrorMessage, " (", p_ErrCode, ")")

   ; I use the xGlobal extender to simulate global variables in UDFs.  One of those registers a test case,
   ; so if we're in an active test case show it.
;   If xGlobalGet("TestCase") != "" Then ErrorMessage = StrCat(ErrorMessage, @LF, "Test Case:", @Tab, xGlobalGet("TestCase"))

   ; Show the errors in an ordinary WIL dialog box
   CriticalErrorFormat=`WWWDLGED,6.1`

   CriticalErrorCaption=`WinBatch Critical Error`
   CriticalErrorX=700
   CriticalErrorY=000
   CriticalErrorWidth=300
   CriticalErrorHeight=074
   CriticalErrorNumControls=004
   CriticalErrorProcedure=`DEFAULT`
   CriticalErrorFont=`Microsoft Sans Serif|6656|40|34`
   CriticalErrorTextColor=`0|0|0`
   CriticalErrorBackground=`DEFAULT,DEFAULT`
   CriticalErrorConfig=0

   CriticalError001=`003,005,230,064,VARYTEXT,ErrorMessage,"",DEFAULT,3,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
   CriticalError002=`243,005,048,012,PUSHBUTTON,DEFAULT,"&Abort",0,1,32,DEFAULT,DEFAULT,DEFAULT`
   CriticalError003=`243,023,048,012,PUSHBUTTON,DEFAULT,"View &Source",1,2,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
   CriticalError004=`243,041,048,012,PUSHBUTTON,DEFAULT,"&Continue",2,4,DEFAULT,DEFAULT,DEFAULT,DEFAULT`

   ButtonPushed=Dialog("CriticalError")

   ; Dispatch the results.
   Switch ButtonPushed
   ; 0 will happend for accepting the default 'Abort' button, or pressing Esc.
   Case 0
      Exit

   ; View Source, which isn't necessarily reliable loads the source and tries to find the first instance.
   ; This particular routine probably isn't all that reliable since I wrote it in five minutes.  I normally
   ; use a different editor.
   Case 1
      Run('"WinBatch Studio" ', StrCat('"', ErrFile, '"'))
      SendKeysTo("WinBatch Studio", "^{Home}^f")
      Terminate(!WinWaitExist("Find", 5), "Error", "No Find Window")
      SendKeysTo("Find", StrCat(p_ErrSource, "~"))
      Exit

   ; If the user decides to contine, warn them that it may be bad karma, but then let them do it.
   Case 2
      If AskYesNo("Resuming After Error", "Caution!! Resuming after a critical error is dangerous.  Your macro may be in an unstable state.  Are you doubly sure you want to continue?")
         IntControl(73, 2, 0, 0, 0)
         Return
      Endif
   EndSwitch
   Exit
#EndFunction

Article ID:   W16182
File Created: 2004:03:30:15:43:10
Last Updated: 2004:03:30:15:43:10