TRY...CATCH...FINALLY Command

Provides a structure to handle errors and exceptions that can occur while running a block of code. For general information about structured error handling, see Structured Error Handling.

TRY
     [ tryCommands ] 
[ CATCH [ TO VarName ] [ WHEN lExpression ] 
     [ catchCommands ] ]
[ THROW [ eUserExpression ] ]
[ EXIT ]
[ FINALLY 
     [ finallyCommands ] ] 
ENDTRY

Parameters

  • TRY
    Indicates the beginning of the TRY...CATCH...FINALLY structure.

  • tryCommands
    Specifies statements where an error might occur.

    If an error occurs, Visual FoxPro stores a reference to an Exception object specified by the VarName memory variable in the TOVarName clause. Program execution then proceeds directly to the CATCH statements. If no error occurs, program execution proceeds to the FINALLY statements.

  • CATCH
    Indicates the beginning of a CATCH block, which handles the appropriate error. You can specify a CATCH statement without arguments, which evaluates to CATCH WHEN .T. (True).

    A CATCH statement is called only when an error occurs in the TRY block for that method, and the code in the method causes the exception. If another method called from within the TRY block causes an error, the Error event for that method handles the error. This behavior occurs because the other method could have been either called directly or from a different method that does not contain a TRY...CATCH...FINALLY structure. The following example illustrates this behavior:

    x=NEWOBJECT("myClass")
    x.myMethod()
    
    DEFINE CLASS myClass AS Session OLEPUBLIC
       PROCEDURE myMethod
          myMethod3()         && Error event handles errors.
          TRY
             THIS.myMethod2()
             myMethod3()      && CATCH handles this error.
          CATCH TO oErr
             ? "Catch:",oErr.ErrorNo
          FINALLY
          ENDTRY
       ENDPROC
    
       PROCEDURE myMethod2
          x=y   && The y variable does not exist. Error event
                && handles this error.
       ENDPROC
    
       PROCEDURE Error(nError, cMethod, nLine)
          ? "Error:",nError
       ENDPROC
    ENDDEFINE
    
    PROCEDURE myMethod3
       x = y
    ENDPROC
    
  • TO VarName
    Specifies an optional memory variable that stores a reference to an Exception object, which is automatically created if an error occurs in the TRY block. VarName can only be a simple memory variable, not an object property reference.

    You can explicitly set VarName to any value in the TRY...CATCH...FINALLY structure. The value does not change as long as another CATCH statement does not run, which resets VarName to NULL.

    VarName can have local, public, or private scope, which depends on how the variable was previously declared. If VarName has not been previously declared, it has private scope. The Exception object created has the same scope as VarName. When VarName goes out of scope, is released, or is reset, the Exception object is also released.

    When a CATCH TOVarName clause executes, Visual FoxPro always sets the VarName to a new Exception object regardless of its previous setting, though VarName retains its scope. Therefore, the contents of VarName are always overwritten regardless of what it previously referenced.

    If a WHEN clause exists, and it evaluates to False (.F.), Visual FoxPro releases the Exception object and resets the VarName to NULL. You can test whether VarName is set to a type or to NULL by using the VARTYPE() function.

  • WHEN lExpression
    Specifies an optional expression that is evaluated when the program encounters the CATCH statement. The expression must evaluate to True (.T.) for the corresponding catchCommands to run.

    The lExpression parameter can contain a reference to the VarNameException object so that you can query the resulting error and handle it accordingly.

  • catchCommands
    Specifies statements to run when the program encounters the corresponding CATCH statement.

  • THROW [ eUserExpression ]
    Creates a new Exception object to be caught by a CATCH statement. The eUserExpression parameter specifies an expression of any type and sets the UserValue property for the Exception object. Usually, you use a THROW clause in a CATCH block to escalate an error or exception to a higher-level error handler. You can pass an object of any type because ExceptionUserValue stores only the object reference.

    When you use the THROW clause with eUserExpression, Visual FoxPro sets the Exception object's ErrorNo property value to 2071, which corresponds to the error, User Thrown Error (Error 2071). If you omit eUserExpression, Visual FoxPro escalates the original Exception object, if it exists. If the Exception object does not exist, Visual FoxPro throws a new Exception object with an ErrorNo property value of 2071.

    Note   You should pass a value for eUserExpression, which sets the UserValue property for the Exception object, because it allows you to chain multiple Exception objects. For more information about chaining Exception objects, see the Example section.

    If you do not include eUserExpression, and the THROW clause escalates the Exception object to an outer TRY...CATCH block, the same Exception object is caught by the outer TRY...CATCH block. Values returned by the ERROR(), MESSAGE( ), and AERROR( ) functions might not always be reliable when used in a structured exception handler, so, instead, you should use the Exception object.

    You can call THROW from any code block in a TRY...CATCH...FINALLY structure. However, you can use THROW anywhere in code where an error handler exists to catch the exception. You cannot call THROW from the Command window.

    Caution   Calling the THROW command outside the TRY...CATCH...FINALLY structure and without an appropriate error handler causes your program to quit.

    If an outer TRY...CATCH statement is in effect when THROW is called from a CATCH or FINALLY block, Visual FoxPro assigns VarName in the CATCH TO clause to the object reference for the Exception object generated by the thrown exception. If no outer TRY...CATCH statement is in effect, Visual FoxPro escalates the exception to an ON ERROR or Error event, if one exists; otherwise, Visual FoxPro calls its system error handler.

    Note   Runtime applications should properly wrap a THROW statement with an outer TRY...CATCH...FINALLY structure.

    If you wish to rethrow the original exception that was caught by the CATCH TOVarName clause, you can call THROWVarName to rethrow the exception.

    Note   Rethrowing the original exception produces another new Exception object, at the outer CATCH statement, that has a UserValue property containing an object reference to the original exception.

    Visual FoxPro disregards any THROW statements appearing in a CATCHWHENeExpression clause.

    If THROW encounters an error when evaluating an expression, Visual FoxPro escalates the error in the usual way.

  • EXIT
    Include in a TRY, CATCH, or FINALLY block to immediately break out of a code block.

    If EXIT appears in the TRY or CATCH block, the program resumes execution at the FINALLY statement, if one exists. If EXIT appears in the FINALLY block or if FINALLY does not exist, the program resumes execution immediately following the ENDTRY statement.

  • FINALLY
    Indicates the beginning of the FINALLY block, which you use to clean up any resources allocated by the TRY block and always runs except when the CANCEL and QUIT commands are used.

    For more information about commands you can use in the TRY...CATCH...FINALLY structure, see Structured Error Handling.

  • finallyCommands
    Specifies statements to run in the FINALLY block after either finding no errors in the TRY block or running statements in a CATCH block.

  • ENDTRY
    Indicates the end of the TRY...CATCH...FINALLY structure. Each TRY...CATCH...FINALLY structure must end with an ENDTRY keyword. As with other Visual FoxPro control statements, you can add comments prefaced by double ampersand (&&) characters after this ENDTRY.

    If you do not include the ENDTRY statement at the end of the TRY...CATCH...FINALLY structure, Visual FoxPro generates an error when you compile your code. Although you can still execute code with compile errors, you should not do so in this scenario because it causes Visual FoxPro to stop responding.

Remarks

Like other error handling in Visual FoxPro, exceptions that occur in TRY...CATCH...FINALLY exception handlers set the SET CONSOLE command to ON. For more information, see SET CONSOLE Command.

You cannot explicitly transfer program execution to a CATCH or FINALLY code block.

Visual FoxPro determines scope for variables on a procedural, not block, basis. That is, variables declared in a TRY block are visible from a FINALLY block within the same TRY...CATCH...FINALLY structure. However, in a nested structure, variables that are declared in a TRY, CATCH, or FINALLY block have local scope.

You should not initialize variables or set up critical code inside the TRY block because the code is not guaranteed to run. If an error occurs at a particular line of code in the TRY block, all subsequent lines in the TRY block do not run.

Any errors that occur in an object's Error event must be handled by the object and are not escalated to an ON ERROR routine or TRY...CATCH...FINALLY handler. However, you can use a TRY...CATCH...FINALLY structure in the Error event to catch errors from an Error event. For more information, see Error Event.

Using the COMRETURNERROR() function in a CATCH block ends all further processing and returns control of the program directly to the Component Object Model (COM) client. Therefore, if you have a FINALLY block, it does not run. For more information, see COMRETURNERROR( ) Function.

Avoid using the SET TEXTMERGETOMEMVAR command within a TRY...CATCH...FINALLY structure because the memory variable will be lost if an error occurs in the statement.

You can use the SYS(2410) - Error Handler function in your TRY...CATCH...FINALLY code to determine a course of action, for example, by using a DO CASE structure, depending on the type of handler that handles the exception. For more information, see SYS(2410) - Error Handler.

You can use TRY...CATCH...FINALLY to handle errors that occur in menu and timer events and with commands such as ON KEY LABEL if the structure is properly wrapped. The following example illustrates how the READ EVENTS command retains control of the program within the TRY...CATCH...FINALLY structure so that you trap menu events. Error trapping is controlled by the position of TRY...CATCH...FINALLY on the call stack.

TRY
   DO myMenu.mpr
   DO FORM myForm
   myForm.AddObject("tm1","mytimer")
   READ EVENTS
CATCH TO oException
   IF oException.ErrorNo = 1
ENDIF
FINALLY
   CLEAR EVENTS
ENDTRY

For more information, see READ EVENTS Command and ON KEY LABEL Command.

Visual FoxPro supports Set Next Statement debugging functionality only within a single code block. For example, when executing code in a TRY block, you can use Set Next Statement only to another line within the TRY block. You cannot jump to another line of code in a CATCH or FINALLY block. For more information, see Debugger Keyboard Shortcuts and Menus.

Visual FoxPro generates the appropriate messages under the following conditions:

  • A mismatch or error occurs with the TRY...CATCH...FINALLY structure.
  • An unhandled exception occurs.
  • A command that is not permitted for a specific block appears in a TRY, CATCH, or FINALLY block. For more information, see Structured Error Handling.
  • A user-thrown error occurs.

Example

The following example illustrates how to nest TRY...CATCH statements, use the THROW clause, and handle Exception objects.

LOCAL x AS Integer, y AS Integer, result AS Integer
LOCAL oErr AS Exception, oErr1 AS Exception 
TRY
   x = 1
   TRY 
      USE nothing
      GO TOP
      y = nothing.col1
   CATCH TO oErr 
      oErr.UserValue = "Nested CATCH message: Unable to handle"
      ?[: Nested Catch! (Unhandled: Throw oErr Object Up) ]  
      ?[  Inner Exception Object: ]
      ?[  Error: ] + STR(oErr.ErrorNo) 
      ?[  LineNo: ] + STR(oErr.LineNo) 
      ?[  Message: ] + oErr.Message 
      ?[  Procedure: ] + oErr.Procedure 
      ?[  Details: ] + oErr.Details 
      ?[  StackLevel: ] + STR(oErr.StackLevel) 
      ?[  LineContents: ] + oErr.LineContents
      ?[  UserValue: ] + oErr.UserValue 
      THROW oErr 
   FINALLY
      ?[: Nested FINALLY executed ] 
      IF USED("nothing")   
         USE IN nothing
      ENDIF      
   ENDTRY   
   result = x-y
CATCH TO oErr1
   ?[: Outer CATCH! ]
      ?[  Outer Exception Object: ] 
      ?[  Error: ] + STR(oErr1.ErrorNo)
      ?[  LineNo: ] + STR(oErr1.LineNo) 
      ?[  Message: ] + oErr1.Message 
      ?[  Procedure: ] + oErr1.Procedure 
      ?[  Details: ] + oErr1.Details 
      ?[  StackLevel: ] + STR(oErr1.StackLevel) 
      ?[  LineContents: ] + oErr1.LineContents 
      ?[  ->UserValue becomes inner exception THROWn from nested TRY/CATCH ]
      ?[     Error: ] + STR(oErr1.UserValue.ErrorNo)
      ?[     Message: ] + oErr1.UserValue.Message 
      ?[     Procedure: ] + oErr1.UserValue.Procedure 
      ?[     Details: ] + oErr1.UserValue.Details 
      ?[     StackLevel: ] + STR(oErr1.UserValue.StackLevel) 
      ?[     LineContents: ] + oErr1.UserValue.LineContents 
      ?[     UserValue: ] + oErr1.UserValue.UserValue 
   result = 0   
FINALLY
   ?[: FINALLY statement executed ] 
ENDTRY
RETURN result

The following example shows how you might want to chain Exception objects:

TRY
   TRY
      x=y      && The y variable does not exist and causes an error.
   CATCH TO oException2
      THROW CREATEOBJECT("myException")
   ENDTRY
CATCH TO oException1
ENDTRY

? 2, oException2.ErrorNo, oException2.UserValue
? 1, oException1.ErrorNo, oException1.UserValue.UserValue

DEFINE CLASS myException AS Exception
UserValue = "My custom error handler"
PROCEDURE Init
   STRTOFILE("An error occurred at: " + TRANSFORM(DATETIME());
 + CHR(13),"c:\errs.log",.T.)
ENDPROC
ENDDEFINE

See Also

Commands | Exception Class | UserValue Property | VARTYPE( ) Function | ErrorNo Property | ERROR( ) Function | MESSAGE( ) Function | AERROR( ) Function | SYS(2018) - Error Message Parameter