luciliacoelho
asked on
on error handling Visual Foxpro
I'm trying to setup an error handling routine.
I have tried to set up a simple "On Error do MyerrorHandler" at the begining of my main program. Then I create a simple error condition changing the name of a VFox table to get a run time error and activate the MyErrorHandler. Nevertheless the on error code doesn't execute.
If I follow the Try Catch approach how sould I proceed.
Kind regards
Lucilia C
I have tried to set up a simple "On Error do MyerrorHandler" at the begining of my main program. Then I create a simple error condition changing the name of a VFox table to get a run time error and activate the MyErrorHandler. Nevertheless the on error code doesn't execute.
If I follow the Try Catch approach how sould I proceed.
Kind regards
Lucilia C
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Oh, and another very simple way to test error handling is to call ERROR 1 or any other defined Error number.
Bye, Olaf.
Bye, Olaf.
I am using following setup and appropriate routine - it always saves the error info into a temporary file and also to the errorlog.dbf which is later posted to the development site (this part was removed):
ON ERROR DO PrgError WITH ERROR(), SYS(16), LINENO() && This must be at the beginning of the main program
The PrgError procedure must also be in the main program or in procedure file:
I am using TRY - CATCH for "local error handling" but to use this structure as the global error handler should also be possible.
ON ERROR setting cannot be ignored in your code, so if an error occurs it must pass the program flow into the error routine.
ON ERROR DO PrgError WITH ERROR(), SYS(16), LINENO() && This must be at the beginning of the main program
The PrgError procedure must also be in the main program or in procedure file:
PROCEDURE PrgError
LPARAMETERS nError, cMethod, nLine
LOCAL lcOutFile, lcErrtext, lcAppVers, lcAppName, ldAppDate, ;
laUsed[1], lnWarea, lnI, lnWAcount, loFormObject
lnWarea = SELECT(0)
lcOutFile = ADDBS(SYS(2023)) + SYS(2015) + '.ERR'
lcAppVers = IIF(TYPE("_screen.AppVersion")="C", _screen.AppVersion, "XXX")
lcAppName = IIF(TYPE("_screen.AppName")="C", _screen.AppName, "XXX")
ldAppDate = IIF(TYPE("_screen.AppDate")="D", _screen.AppDate, {//})
IF VARTYPE(m.gn_errCount) <> "N"
RELEASE gn_errCount
PUBLIC gn_errCount
gn_errCount = 0
ENDIF
gn_errCount = m.gn_errCount + 1
TEXT TO lcErrText TEXTMERGE NOSHOW
**********************************************************************************
<<"*"+PADC("Error log info from " + lcAppName + " v" + lcAppVers, 80)+"*">>
**********************************************************************************
ERROR trap in <<PROGRAM()>> <<SYS(0)>> <<DATETIME()>>
**********************************************************************************
Version: <<lcAppVers>> <<ldAppDate>>
ERROR <<nError>> in <<cMethod>>, Line: <<nLine>> (ErrCnt <<gn_errCount>>)
<<MESSAGE()>>
Settings:
SET DATE <<SET("DATE")>>
SET CENTURY <<SET("CENTURY")>>
SET STRICTDATE TO <<SET("STRICTDATE")>>
SET COLLATE TO <<SET("COLLATE")>>
Code Page: <<CPCURRENT()>>
SET EXACT <<SET("EXACT")>>
SET ANSI <<SET("ANSI")>>
SET DATASESSION TO <<SET("DATASESSION")>>
Configuration File: (<<IIF(FILE("@:\CONFIG.FPW"), "In EXE", "On disk")>>)
<<SYS(2019)>>
Resource File: (<<SET("RESOURCE")>>)
<<SYS(2005)>>
Temporary folder: (<<LTRIM(TRANSFORM(DISKSPACE(JUSTDRIVE(SYS(2023))),'999999999999999'))>> bytes free)
<<SYS(2023)>>
Home folder: (<<LTRIM(TRANSFORM(DISKSPACE(JUSTDRIVE(HOME())),'999999999999999'))>> bytes free)
<<HOME()>>
*Data folder: (<<LTRIM(TRANSFORM(DISKSPACE(JUSTDRIVE(AppDataFolder())),'999999999999999'))>> bytes free)
*<<AppDataFolder()>>
VFP Version: (Language <<VERSION(3)>>)
<<VERSION(1)>>
OS Version:
<<OS(1) + " " + OS(5) + " " + OS(7)>>
Topmost window: <<WONTOP()>>
Active form: <<IIF(TYPE("_screen.ActiveForm.Name")= "C", _screen.ActiveForm.Name, "")>>
ENDTEXT
lcErrText = lcErrText + CHR(13)+CHR(10) + "Form list:" + CHR(13)+CHR(10)
FOR lnI = 1 TO _screen.FormCount
loFormObject = _screen.Forms[lnI]
lcErrText = lcErrText + loFormObject.Class + " " + loFormObject.Name + " " + ;
IIF(TYPE("loFormObject.FormMode") = "C", loFormObject.FormMode, "") + " " + ;
IIF(TYPE("loFormObject.ActiveControl.Name") = "C", loFormObject.ActiveControl.Name, "") + CHR(13)+CHR(10)
NEXT
lcErrText = lcErrText + CHR(13)+CHR(10) + "Workarea list:" + CHR(13)+CHR(10)
lnWAcount = AUSED(laUsed)
FOR lnI = 1 TO m.lnWAcount
lcErrText = lcErrText + STR(laUsed[lnI, 2], 5) + " " + PADR(laUsed[lnI, 1], 40) + ;
TRANSFORM(RECNO(laUsed[lnI, 2])) + '/' + TRANSFORM(RECCOUNT(laUsed[lnI, 2])) + " " + ;
TRANSFORM(BOF(laUsed[lnI, 2])) + " " + TRANSFORM(EOF(laUsed[lnI, 2])) + CHR(13)+CHR(10)
NEXT
RELEASE laUsed
= STRTOFILE(lcErrText, lcOutFile)
LOCAL ARRAY laCallStack[1]
= ASTACKINFO(laCallStack)
LIST STATUS TO FILE (lcOutFile) ADDITIVE NOCONSOLE
LIST MEMORY TO FILE (lcOutFile) ADDITIVE NOCONSOLE
LIST OBJECTS TO FILE (lcOutFile) ADDITIVE NOCONSOLE
LOCAL lnErrId, loErrRec
*-- Save error info into a table if possible
IF VARTYPE(gc_site_code) = 'C' AND !EMPTY(m.gc_site_code)
TRY
IF USED("ERRORLOG") OR OpenTable("ERRORLOG", .F., .T., "ERRORLOG")
IF USED("COUNTERS") OR OpenTable("COUNTERS", .F., .T., "COUNTERS")
lnErrId = CreateNewPK("ERRORLOGID")
USE IN SELECT("COUNTERS")
IF m.lnErrId > 0
SELECT ERRORLOG
SCATTER MEMO NAME loErrRec BLANK
loErrRec.Id = m.lnErrId
loErrRec.LogInfo = FILETOSTR(lcOutFile)
UpdateSystemColumns(loErrRec, .T.)
IF FLOCK()
INSERT INTO ERRORLOG FROM NAME loErrRec
ENDIF
ENDIF
ENDIF
USE IN SELECT("ERRORLOG")
ENDIF
CATCH
USE IN SELECT("COUNTERS")
USE IN SELECT("ERRORLOG")
ENDTRY
SELECT (lnWarea)
ENDIF
WAIT WINDOW "ERROR INFORMATION WAS RECORDED IN " + lcOutFile TIMEOUT 1
IF m.gn_errCount > 20
ON ERROR CANCEL
CLEAR EVENTS
IF VERSION(2) = 0
QUIT
ELSE
SUSPEND
ENDIF
ENDIF
Disadvantage of this error procedure could be an automatic program continuation after the error occurence. It can cause unpredictable results sometimes but it ignores minor errors which do not affect program run in most of the cases. You may add some dialog to PrgError to let users decide if they want to continue or not. I am testing gn_errCount in regular code which allows to make this decision automatically.I am using TRY - CATCH for "local error handling" but to use this structure as the global error handler should also be possible.
ON ERROR setting cannot be ignored in your code, so if an error occurs it must pass the program flow into the error routine.
Try RETURN or RETRY from within a Catch Block. It's not supported.
With these last lines of your error handler, you can debug when an error occurred and return to the line of error:
If _vfp.startmode=0
set step on
return
Endif
This is not possible from CATCH, so TRY .. CATCH is bad for global error handling alone because of that.
Bye, Olaf.
With these last lines of your error handler, you can debug when an error occurred and return to the line of error:
If _vfp.startmode=0
set step on
return
Endif
This is not possible from CATCH, so TRY .. CATCH is bad for global error handling alone because of that.
Bye, Olaf.
ASKER
In fact when I tried to use directly the error message and send to the screen through a MessageBox, directly. The MyErrorHandling routine didn't work at all. The workaround I used was the following: The data gathered from an error is firstly writen in a errorlog table then I use this data to interact with the user.
It seems that the variables you were using are local to a certain procedure/function. It's best errors are logged in a database or text file. I also send them by email to the development team of course with the permission of the user.
The "MyerrorHandler" must either be a prg on it's own, you set procedure to, before on error, and that procedure must stay known throughout the lifetime of the application, it's really better to make a procudure in the main.prg file, as it's safe, it's always on the call stack.
If you ant to test your error handling simply add a line of total rubbish, like:
lcCode = "sdljfsjdgsfkghks"
&lcCode
This compiles but errors at runtime.
Or do
USE hjkshdfgkjsfhgkh
Bye, Olaf.