When using UDF ErrorHandler, lose ability to do ErrorMode(@off)

Started by galaara98, July 30, 2014, 04:44:41 PM

Previous topic - Next topic

galaara98

I have a large and fairly sophisticated Winbatch program (> 5000 Lines) which I just recently decided I should start giving my users a "better crash screen" :)
However the moment I implemented a custom Error Handler via: IntControl(73,3,0,"ErrorHandler",0) ; SET Error Handler
every place where I take advantage of the concept of:

   ErrorMode(@off)
     A line of Code that may fail, but it important to this program that I try
     Err = LastError()
   ErrorMode (@Cancel)
   if Err then
      Things didn't go right... make live decisions/changes accordingly
   end if

- which is over 50 different spots in my code


began sending ALL Errors to my Handler (regardless of the ErrorMode) ...
     which of course then had NO idea what the "make changes accordingly" concept should be for the exact circumstance of a certain acceptable error

and just exploded 


if I ask for the ErrorMode to be Off I don't want it to send errors to the default handler OR my Handler...

As soon as I removed any IntControl(73,x,x,x,x)  everything went right back to normal

The only solution I see is to switch the default handler just before I use ErrorMode(@off), but

1) To me it just seems like a bug and I hate "accommodating bugs", AND
2) My code is extremely optimize to not waste CPU cycles (if possible) and I just can't bear to set ErrorHandlers back and forth so frivolously

Anyone have any idea what I may have done wrong, am I crazy, or is this really an "unexpected result" / bug in Winbatch

Aaron


galaara98

=====
7/31/14
well I ran some tests and another solution (which I don't like) would be to flag the ErrorMode(@off) in my own way... like ErrMode = @off and then have my custom handler check for this flag and do nothing specific, set LstError = LastError()

something like


Gosub UDFS

IntControl(73,3,0,"ErrorHandler",0)

;Known Good Statements

; ErrorMode(@off)
ErrMode = @off
   Command That May Fail, but this Program needs to Try
;ErrorMode(@Cancel)
ErrMode = @Cancel

;if LastError() then
if LstError then
  ; There was trouble, make live decisions/changes as appropriate
End if

Exit

:UDFS

#DefineSubroutine ErrorHandler(wberrorarray)
       LstError = wberrorarray[0]
       if isDefined(ErrMode) then
            if ErrMode == @OFF then Return  1 ; do nothing
       end if
       ; Do Anything needed before End User Interaction

        ErrorRecipient = "axxlbxxith@bxxxhxxx.com"
        ErrorSubject = "My Program Error Report"

   MyExe = IntControl(1004, 0, 0, 0, 0)         ; Get fully qualified name of the current WB program
   MyVersion = Strreplace(FileVerInfo(MyExe, "", "#FileVersion" ),",",".")

   ;This is a our universal Error Handler
   ; We want to ask User if we can send an email
   ; We want to ask user if they want to restart PS

   MyDialogFormat=`WWWDLGED,6.2`

   MyDialogCaption=`MyProgram - v<MyVersion>  CRITICAL ERROR`
   MyDialogX=073
   MyDialogY=080
   MyDialogWidth=170
   MyDialogHeight=094
   MyDialogNumControls=006
   MyDialogProcedure=`DEFAULT`
   MyDialogFont=`Calibri|6656|40|34`
   MyDialogTextColor=`DEFAULT`
   MyDialogBackground=`DEFAULT,219|219|219`
   MyDialogConfig=0
   
   MyDialog001=`001,077,066,012,PUSHBUTTON,"BtnYesRestart",DEFAULT,"Yes, and then Restart",1,10,32,DEFAULT,DEFAULT,DEFAULT`
   MyDialog002=`073,077,048,012,PUSHBUTTON,"BtnNoRestart",DEFAULT,"No, but Restart",2,20,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
   MyDialog003=`001,001,164,034,PICTURE,"Picture_2",DEFAULT,"Picture 2",DEFAULT,30,DEFAULT,DEFAULT,DEFAULT,"BannerLite_ERROR.bmp"`
   MyDialog004=`015,035,136,020,STATICTEXT,"ErrorInstructions1",DEFAULT,"Wooops!  This Program, well... Crashed, Choked, FAILED, you know... ""Critical Error"".",DEFAULT,40,512,DEFAULT,DEFAULT,DEFAULT`
   MyDialog005=`001,055,166,020,STATICTEXT,"ErrorInstructions2",DEFAULT,"Would it be OK if This Program used your Email client to send a Bug Report (you will be able to review before send)",DEFAULT,40,512,DEFAULT,DEFAULT,DEFAULT`
   MyDialog006=`127,077,038,012,PUSHBUTTON,"BtnNoClose",DEFAULT,"No, and Exit",3,30,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
   
   ;ButtonPushed=Dialog("MyDialog")

   MyDialogCaption = StrReplace(MyDialogCaption,"<MyVersion>",MyVersion)
   ButtonPushed=Dialog("MyDialog")

   if ButtonPushed == 3 then
                ; User just wants us to quit
      ErrorMode(@off)
                ; do cleanup tasks
      Exit
   elseif ButtonPushed == 2 then
                ; User Wants us to Restart
      ErrorMode(@off)
                ; Do Cleanup Tasks
           
      Run(IntControl(1004, 0, 0, 0, 0),"")
      Exit
   else
                ;User Wants us to help file a bug report
      ErrorMode(@off)
               
                ;KNOWN WBERRORARRAY LABELS AS OF 7/31/14
      NumberofErrorFields = ArrInfo( wberrorarray, 1 )
      ErrorLabels = ArrDimension( NumberofErrorFields )
      ArrInitialize( ErrorLabels, "UnDefined Label" ) ; ANY NEW INFORMATION Winbatch adds to weberrorarray in the future will get this label
      ErrorLabels[0] = "LastError()"
      ErrorLabels[1] = "wberrorhandlerline"
      ErrorLabels[2] = "wberrorhandleroffset"
      ErrorLabels[3] = "wberrorhandlerassignment"
      ErrorLabels[4] = "wberrorhandlerfile"
      ErrorLabels[5] = "wberrortextstring"
      ErrorLabels[6] = "wberroradditionalinfo"
      ErrorLabels[7] = "wberrorinsegment"
      ErrorLabels[8] = "wberrorhandlerlinenumber"
      ErrorLabels[9] = "line number in the UDF where the error occurred or 0."
      ErrorLabels[10] = "a positive number if reported line numbers are accurate, zero (0) if possibly inaccurate or -1 if run from WinBatch Studio, in which case both `wberrorhandlerlinenumber` and `line number in the UDF where the error occurred or 0.` will contain the line number of the error in the UDF."
      ErrorLabels[11] = "Used only with error handler UDF method to set return value of the function the error occurred on."


      ErrorText = ""
                For I = 0 to (NumberofErrorFields - 1)
                       ErrorText = ItemInsert(ErrorLabels : ":  " : wberrorarray,-1,ErrorText,@TAB)
                Next I
      ErrorText = "MyEXE:  " : MyExe : @TAB : "MyVersion:  " : MyVersion : @TAB : @TAB : ErrorText

      ErrorText = StrReplace(ErrorText," ","%%20")
      ErrorText = StrReplace(ErrorText,@TAB,"%%0A")
      MailToLink = "Mailto:" : ErrorRecipient : "?subject=" : ErrorSubject : "&body=" : ErrorText
      ShellExecute(MailToLink,"","",0,"Open") ; call the current mailto: handler...
                ; DO Cleanup tasks
      Run(IntControl(1004, 0, 0, 0, 0),"")
      Exit
   end if
   Exit
#EndSubroutine

return




If I take this approach I have to update my code making it unable to function with the default handler. 
Maybe I am envisioning this wrong, but I would like to operate just like the default handler, but with my own GUI and user choices.

Aaron



JTaylor

This is probably a variation of what you are considering but maybe a bit cleaner...Perhaps just set a flag above the code you are trying and reset after so you know at what point the error occurred.  This keeps all your error handling in one place.

Jim

IntControl(73....)
error_flag = 0                 ;'Generic'
....
...
error_flag = 1                  ;'Act1'
  command that fails occasionally
error_flag = 0                 ;'Generic'
....
error_flag = 2                  ;'Act2'
  command that fails occasionally
error_flag = 0                 ;'Generic'
....
error_flag = 3                 ;'Act3'
  command that fails occasionally
error_flag = 0                 ;'Generic'
....

#DefineSubroutine ErrorHandler(wberrorarray)

  Switch(error_flag)
     Case 0;    Generic
          Do whatever fall all other errors
          Break
     Case 1; Act1
          Do for Act1
          Break
     Case 2; Act3
          Do for Act1
          Break
      Case 3;  Act 3
          Do for Act3
          Break
      Case error_flag;
          Do whatever fall all other errors or figure out why error_flag isn't accounted for here.
          Break
  EndSwitch

#EndSubRoutine

stanl

Jim's suggestion is valid, but a program with 50 possible 'crashes' doesn't sound that stable. You might also consider breaking down the lasterr() into recoverable/non-recoverable options.

Deana

This is expected behavior. There are two major methods to trap errors. The more powerful method is to use IntControl 73 to set an error handler to capture all types of errors. Where as, the older ErrorMode can only be used to capture minor errors.

If you really want to handle errors for the entire script, we recommend using the IntControl 73 function. If you only want to minor capture errors for a single function use ErrorMode only, to wrap that function call. For a list of the various error numbers, see the Window Interface Language help file or manual. 

Reference: http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/nftechsupt.web+Tutorials+Trap~Errors.txt
Deana F.
Technical Support
Wilson WindowWare Inc.