Marcus wrote a very good article about the TRY-CATCH structured error handling in VFP8 and later versions. One section in particular caught my eye because it directly relates to an issue I’ve hit recently:

[..] the result is opposite from the previous example. The Error()event takes precedence over the Try/Catch and handles the error inside the called object.

So what would happen if we added some structured error handling to the TestClass object?

DEFINE CLASS TestClass AS Custom
   FUNCTION Execute
      TRY
         xxxxxx
      CATCH
         MESSAGEBOX(“Exception 2!”)
      ENDTRY
   ENDFUNC

   FUNCTION Error(nError, cMethod, nLine)
      MESSAGEBOX(MESSAGE())
   ENDFUNC   
ENDDEFINE

In this example, the new Try/Catch will handle the error since it has been defined at a higher level of granularity.

Alas, this is not strictly true for every case. Consider the following code:

q = newobject("myTest")
q.Execute()


define class myTest as custom

procedure execute
   try 
      *-----------------------------------------	
      * This is handled nicely by the 
      * surrounding TRY_CATCH:
      *-----------------------------------------	
      y = newobject("invalidClass")

      *-----------------------------------------	
      * This one ignores the TRY-CATCH and 
      * triggers the .Error() event:
      *-----------------------------------------	
      THIS.NewObject( sys(2015), "invalidClass", "invalidLib.vcx" ) 

   catch
      =messagebox( "We successfully caught the error in the catch.",64  )
   endtry
endproc

procedure error( p1, p2, p3 )
   =messagebox("The object's error() event was triggered instead!",16)
endproc

enddefine

The structured error handling works as expected for the NEWOBJECT() function call, successfully trapping the “class not found” error. However, the method call THIS.NewObject() will force the objects .Error() event to fire, requiring a completely different set of handling code to suppress the error. This is not a bug, it’s the way objects work. Objects always defer to their own .Error() events to handle errors. Annoying, isn’t it?