Wiki Home

App Shut Down


Namespace: Wiki
I often have situations where error handlers go into endless loops, such as Can't Release Object, Do you want to Continue Yes/No, xxx is not an object, Can't release Object, Do you want to Continue Yes/No etc. etc.
Consider Manual Garbage Collection ?
I figure in situations like these it would be good to give the user another option, CANCEL and it would just execute some code that will bail out FOR SURE. I tried QUIT and CLEAR ALL, QUIT etc. or releasing the main application object, but they just continue with endless error loops.

There are other conditions that will prevent closure: pending transactions, dirty buffers, etc. Let's accumulate all of our shutdown code into one big prg.
ACTIVATE WINDOW COMMAND
SET SYSMENU TO DEFAULT
FOR each oFrm in _SCREEN.Forms
  oFrm.Release()
NEXT
on error
on shutdown
close all
clear all
CANCEL


There were some errors in this code that the ON ERROR plError = .T. line made go unnoticed. Now it actually works. -- Mike Feltman
*==============================================================================
* Procedure:
* RESET.PRG
*
* Purpose:
* Reset VFP back to normal - may need to be run twice
* sometimes.  First time does not always catch things that
* can't be removed fully until all applications have stopped.
* You can avoid this problem many times by using the reset
* hotkey recommendations in the session notes from
* Error Handling and Debugging in VFE.
*
* Authors:
* Fletcher Johnson, Patrick Murphy, DVT, Toni M. Feltman, David Tansey
*
*==============================================================================
LOCAL lnTransaction

ON SHUTDOWN
ON ERROR
ON ESCAPE
SET ESCAPE ON

FOR lnTransaction = 1 TO TXNLEVEL()
  ROLLBACK
ENDFOR

CLEAR ALL
CLOSE ALL
CLEAR PROGRAM
CLEAR MEMORY
CLEAR
RELEASE ALL EXTENDED

MODIFY WINDOW SCREEN
* ZOOM WINDOW SCREEN MAX

SET TALK ON
SET STATUS BAR ON
SET RESOURCE ON
SET DEVELOPMENT ON

* SET SYSMENU NOSAVE
* SET SYSMENU TO DEFAULT
SET SYSMENU ON

* SET SYSMENU TO DEFAULT

CANCEL

*==============================================================================
*!*  PROCEDURE CloseDataAll
*
* Purpose:
* This will close and revert all the open tables in all
* the data sessions
*
* Special thanks again to Fletcher Johnson for this portion
* of the reset code which was the winner of the $100 poker
* chip contest from the Error Handling and Debugging session.
*
* Authors:
* David Tansey
* Fletcher Johnson - CIS 72647,1447
*
********************************************************
#define MAX_SESSIONS 200

LOCAL lnCurrentDataSession, ;
  lnCurrentWorkArea, ;
  lcErrorCode, ;
  laFiles[1]

PRIVATE plError

plError = .F.
lcErrorCode = ON( "error")
ON ERROR plError = .T.

FOR lnCurrentDataSession = 1 TO MAX_SESSIONS
  SET DATASESSION TO ( lnCurrentDataSession )
  IF plError
    *-- An error occured, must not have
    *-- any data in this datasession
    plError = .f.
  ELSE
    *-- Ok, we have data here
    FOR lnCurrentWorkArea = 1 to AUSED( laFiles )
      SELECT (laFiles[lnCurrentWorkArea])
      IF CURSORGETPROP("BUFFERING") > 1
        TABLEREVERT( .T.)
      ENDIF
      USE && close the table
      plError = .F.
    ENDFOR
  ENDIF
ENDFOR
FLUSH

*-- Now reset the error handling code
IF NOT EMPTY( lcErrorCode )
  ON ERROR &lcErrorCode
ELSE
  ON ERROR
ENDIF

This is the version that I use that I have adapted from many sources including the above. It has been updated for VFP8 and multiple data sessions. I assume that data should be tableupdated if possible.
Procedure closeall
  * Procedure CLOSEALL
  * Closes, Clears and Resets most everything after an error or suspend
  * I usually assign this routine to a function key using on key label
  *
  * Written in VFP8 by Ben Creighton 9/1/2005
  * 1st:  Clean up ON routines
  On Error
  On Shutdown
  On Escape
  Set Escape On
  On Key
  Clear Typeahead

  * 2nd: Trash and reset the menus
  * These are done early in case any variables/fields are used in SKIP FOR
  Deactivate Menu All
  Clear Menus
  Clear Popups
  Set Sysmenu To Default
  Set Sysmenu On

  * Go through each session, rollback transactions,
  * and tableupdate unless there is an error in which case revert
  For xx=1 To Asessions(sessionList)
    Set DataSession To sessionList[m.xx]
    Do While Txnlevel() > 0
      Rollback
    Enddo
    For yy=1 To Aused(usedA)
      Select (usedA[m.yy,1])
      If CursorGetProp("Buffering") > 1
        If !Tableupdate(2, .T.)
          Tablerevert(.T.)
        Endif
      Endif
    Endfor
  Endfor

  * Clear out memory first, close data later
  Clear All
  Clear Program
  Clear Resources
  Close All

  * Miscellaneous stuff
  Set Printer To
  Set Printer Off
  Set Talk Off
  Set Help To
  Set Help On
  Clear
  If Version(2)>0
    * Development Environment Specific Stuff
    * POP KEY
  Endif
  Cancel
  Return

A much easier way to do this is just kill the application process. I tried many solution to this problem, included Garbage Collection techniques and code like the one above, but killing the process turned to be the only reliable solution that works in ANY situation.

So now I have a function called Abend(), that I call when the user press the Cancel button in an error dialog:
FUNCTION Abend
  ON ERROR foo=1
  CLOSE ALL
  SET PROCEDURE TO WPLIB
  WPKillCurrentProcess()
ENDFUNC


Library WPLIB.PRG can be downloaded from here: http://www.victorespina.com/hs/files/vfp/dwn/wp2.zip. -- Victor Espina
Victor: A problem with your Abend routine is that it doesn't take care of pending table updates or transactions before attempting to CLOSE ALL. Also, I don't want to Kill the process when I am doing development since that would shutdown FoxPro. Finally, your web site address is not working. -- Ben Creighton

Ben: Thanks for reporting the broken link; its fixed. The idea behind Abend() is to be able to finish the current program smoothly, regardless any problem that may rise during the shutdown process. When you try to close a running program in VFP, closing any opened files or finish pending updates isn't a real problem: the problem is to terminate the program AFTER this tasks are done.. and here is when an abend() funcion become handy. Of course, you are right about that wouldn't be nice to terminate your VFP session when you are testing your program... all you have to do is don't call abend() funcion if you are in development mode (wich can be determinated in runtime using the Start Mode property of _VFP object). -- Victor Espina
See also: Clean Up Code
Contributors: Carl Karsten, Hermann Strijewski, DavidTansey, Mike Feltman, Ben Creighton, Victor Espina
Category Code Samples Category Application Design
( Topic last updated: 2008.08.03 12:48:42 PM )