Important: The information in this document is obsolete and should not be used for new development.
Failure-Handling Overview
MacApp provides a failure-handling mechanism that allows your application to clean up after errors. This mechanism is described in detail in "Failure Handling," beginning on page 54. Your application can install failure handlers at multiple points. MacApp links the failure handlers together in a linked list, shown in Figure 3-2. You install a failure handler in the list with theTry
macro, as shown in the following code fragment:
// Declare a failure handler. FailInfo fi; // Link the failure handler to the global list. Try(fi) { // Code that may cause a failure. . . . // If no failure occurs, remove the failure handler from the list. fi.Success(); } else { // Code to recover if an error occurs. . . . // In this case, pass error on to next handler. fi.ReSignal(); }TheTry
block of code is executed first.Try
is implemented as a macro rather than as a method of theFailInfo
class, because the failure-handling code must be inline to properly save the current machine state. TheTry
macro links the failure handler to the list of failure handlers and callssetjmp
to save the current machine state in the failure handler's buffer.
Note that the call to
- If an error occurs, the failure handler is invoked and causes execution to continue with the
else
block of code--otherwise, theelse
block is never executed. Optionally, the failure handler may call a specific cleanup routine.- If no error occurs, the call to
Success
removes the failure handler from the list.
ReSignal
, which invokes the next failure handler in the list, is not always necessary--the error code from the first handler may handle the error condition completely.ReSignal
is a convenience routine that just callsFailure
, passing the same message and error number values from the previous call. TheFailure
routine is described beginning on page 563.Figure 24-2 shows the classes, methods, and routines used by MacApp and your application to handle failures and display error messages.
Figure 24-2 Failure-handling and error-message classes, methods, and routines
MacApp Error-Checking Routines
MacApp supplies the following global routines to check for common error conditions:
You can read more about these error-checking routines in the MacApp Class and Method Reference. The temporary and low-space reserves are described in "Dynamic Memory Allocation," beginning on page 62.
FailMemError
- The
FailMemError
routine calls the Toolbox routineMemError
to check whether the last memory operation caused an error. You callFailMemError
after making a Toolbox call that affects memory, such asSetPtrSize
orSetHandleSize
.FailNIL
- The
FailNIL
routine tests whether the passedvoid *
value isNULL
. The most common value passed toFailNIL
is a newly created object reference, pointer, or handle.FailNIL
fails withmemFullErr
as the error message. This results in an error message of "Unable to <x> because there is not enough memory." <x> is a string that describes the current operation, such as "open a new document".FailNILResource
- The
FailNILResource
routine checks whether the handle returned by a Resource Manager call isNULL
. You passFailNILResource
the handle returned by a Resource Manager call such asGetResource
.FailNonObject
- The
FailNonObject
routine attempts to determine whether the passed pointer references an object, and generates a failure if it doesn't. The checking is more robust when the application is built with MacApp's debugging support.- You use
FailNonObject
to check whether an object pointer is valid when you really expect it to be valid. If the value passed isNULL
or does not point to something that looks like an object,FailNonObject
fails withminErr
as the error message: "Unable to <x> because there is not enough memory."FailNoReserve
- The
FailNoReserve
routine checks whether the application's temporary reserve is low. CallingFailNoReserve
causes MacApp to rebuild its memory reserves, so use it sparingly, such as when you must be sure that some reserve space is available.FailOSErr
- The
FailOSErr
routine tests whether the passedOSErr
value is not equal tonoErr
. The most common value passed toFailOSErr
is the result of a Toolbox call, such asFSWrite
.FailResError
- The
FailResError
routine calls the Toolbox routineResError
to check whether there was an error caused by the last resource operation. You callFailResError
after making a Resource Manager call that does not return a handle to the resource.FailSpaceIsLow
- The
FailSpaceIsLow
routine checks whether the low-space reserve is missing.FailSpaceIsLow
causes MacApp to rebuild its memory reserves, so it should not be called indiscriminately.You call an error-checking routine with code like the following:
fDataHandle = (Handle)GetPixPat(fRsrcID); FailNILResource(fDataHandle);This code calls the Toolbox routine GetPixPat to get a'ppat'
resource. It then calls FailNILResource to determine whether the call succeeded and to generate a failure and display an error message if it did not.The Failure Routine
When an error-checking routine is called but no error occurs, it simply returns. When an error does occur, the error-checking routine calls MacApp'sFailure
routine to process the error. The interface toFailure
is defined as follows:
void Failure(OSErr error, long message)The parameters toFailure
are discussed in the following section. TheFailure
routine starts the process of handling an error by retrieving the most recent failure handler from the linked list and restoring the machine state stored by the handler. Routines called after the handler was initialized are skipped, and execution continues in the failure handler's error-recovery code branch. The error-recovery code performs its cleanup, then optionally callsReSignal
to invoke the next failure handler to continue the process.The next section describes MacApp's mechanism for displaying failure-related errors.
How Error Messages Are Displayed
If each failure handler calls ReSignal to invoke the next failure handler in the list, the handler installed by the application object'sPollEvent
method is eventually reached. Its error-recovery code calls the application'sShowError
method, passing the same error and message parameters that were passed to theFailure
routine.ShowError
passes these parameters on to theErrorAlert
routine to display an alert box.MacApp supplies several
'ALRT'
resources to display error message strings to the user. These resources each have placeholders, denoted as ^0, ^1, and ^2. The MacApp constants for these alert resources, and the message strings they contain, are as follows:
The placeholder ^2 is called the operation (the command or operation that caused the error), ^0 is called the reason (why the operation could not be completed), and ^1 is called the recovery (what the user can do to recover from the error).
phGenError
- Could not ^2, because ^0. ^1.
phCommandError
- Could not complete the ^2 command because ^0. ^1.
phUnknownErr
- Could not complete your request because ^0. ^1.
The
ErrorAlert
routine chooses an alert resource and fills in the placeholders based on theerror
andmessage
values passed to it.ErrorAlert
uses the Toolbox routineParamText
to set the alert text. The placeholders are filled in as follows:
- ^0:
ErrorAlert
uses theerror
parameter passed toFailure
to look up a string that describes the kind of error that occurred.- ^1: Depending on the
error
parameter passed toFailure
, it may or may not be appropriate to use the ^1 placeholder. When appropriate,ErrorAlert
uses theerror
parameter to specify a string that suggests a recovery strategy.- ^2:
ErrorAlert
treats themessage
parameter, a long integer, as a pair of numbers. The high word ofmessage
determines how the low word is interpreted. There are five possibilities:
- high word =
messageCommandError
The low word is the command number.ErrorAlert
translates that command number into a command name and substitutes it for ^2. ThephCommandError
alert is used.- high word =
messageAlert
The low word is an alert number (that is, a resource number). This is generally an alert that you have defined. That alert is displayed. In this case,ErrorAlert
does not callParamText
, and does nothing to set replacement text for the placeholders.- high word =
messageLookup
The low word is a positive integer index into a message table in the resource file.ErrorAlert
retrieves a string to replace ^2 that describes the operation.- high word = none of above
The high word is a resource ID for a string list, and the low word is an index into that list.ErrorAlert
substitutes the specified string for ^2.ErrorAlert
uses thephGenError
alert.- message = 0
ErrorAlert
uses thephUnknownErr
alert.
- Note
- Placeholders are convenient for English language applications, but it is easier to internationalize (or localize) applications that use only complete error strings.
Setting the Error Message in a Failure Handler
After you have dealt with an error in your failure-handling code, you can either return normally by doing nothing or propagate the error by callingReSignal
. TheFailInfo::ReSigna
l method just callsFailure
to execute the next failure handler in the list, passing the sameerror
andmessage
values that were passed to your failure handler.If the message parameter was already set to a nonzero value, you don't usually want to change it in your failure handler. A failure handler should generally assume that the routine that called
Failure
has more specific knowledge about the error, so the values it supplied forerror
andmessage
are the most appropriate values.To set the
message
value only if it hasn't been set already, you can call theFailNewMessage
global routine instead of callingReSignal
. TheFailNewMessage
routine has three parameters:error
,oldMessage
, andnewMessage
. You pass theerror
value, the previousmessage
value, and anewMessage
value to use if the previous value is 0.FailNewMessage
callsFailure
, passing the old message if it isn't 0, and otherwise the new message.Calling the Failure Routine Directly
Instead of calling one of the error-checking routines supplied by MacApp, your application can check for errors itself, then call MacApp'sFailure
routine if it detects an error. When you callFailure
directly, you supply error and message parameters as described in "How Error Messages Are Displayed," beginning on page 564. You can either passerror
andmessage
values that are defined by MacApp, or you can define your own special messages. The following example shows how to fail with a program error instead of an out-of-memory error:
fDataHandle = YourGetDataHandleRoutine(); // Returns a data handle. if (fDataHandle == NULL) Failure(minErr, 0);In this code fragment, you expect to get the YourGetDataHandleRoutine routine to return a handle. If you callFailNIL
on the returned value and the value is NULL, the error message would be "Unable to <x> because there is not enough memory." By callingFailure
directly and passingminErr
as the error value, the error message becomes "Unable to <x> because of a program error."
- Note
- When you call
Failure
directly, you can effectively create a "silent failure" (no message is displayed) with a call like the following:Failure(noErr, 0);// Silent failure. uYou can also override theShowError
method in your application class to change the way error alerts are displayed.