Important: The information in this document is obsolete and should not be used for new development.
Installing an Exception Procedure
The Collection Manager allows you to specify an exception procedure for each collection object. When you attempt to manipulate a collection object using a Collection Manager function and the function results in an error, the Collection Manager calls the exception procedure for the collection object and sends it two parameters: a reference to the collection object that caused the error and the error code that was generated.In an exception procedure, you can handle the error and then change the error code to
noErr, a process which indicates that the Collection Manager can return control to the place in your application that generated the error as if no error had occurred. You can also change the error from one error code to another. A third alternative is to use the ANSI C functionssetjmpandlongjmpto jump out of the exception handler and into code to handle the error. Listing 5-27 shows a sample exception procedure.Listing 5-27 A sample exception procedure
jmp_buf cpuState; /* global machine state */ pascal OSErr MyExceptionHandler(Collection errorCollection, OSErr status) { /* ignore collectionItemLockedErr errors */ if (status == collectionItemLockedErr) return noErr; /* all other errors must be handled by caller's setjmp block */ /* jump back to callers setjmp block and return status */ longjmp(cpuState, status); } void ExceptionTest(Collection anyCollection) { OSErr result; SetCollectionExceptionProc(anyCollection, MyExceptionHandler); if (!(result = setjmp(cpuState))) { AddCollectionItem(anyCollection, 'tag1', 1, 4, "data"); AddCollectionItem(anyCollection, 'tag1', 2, 9, "more data"); AddCollectionItem(anyCollection, 'tag1', 3, 9, "last data"); /* cause an error . . . */ RemoveCollectionItem(anyCollection, 'tag1', 4); } else { . . . /* handle errors other than collectionItemLockedErr */ /* use result local variable to determine which error */ . . . } }In Listing 5-27, theExceptionTestsample function takes a single parameter: a reference to a collection object. The sample function first calls theSetCollectionExceptionProcfunction to install an exception handler for this collection object. In this example, the call toSetCollectionExceptionProcinstalls theMyExceptionHandlerfunction as the exception handler.The next line of the
ExceptionTestsample function calls thesetjmpfunction. This function stores the current machine state, including the current position in the sample code, into thecpuStateglobal variable. It also returns a value of 0 as its function result, and this value is assigned to the local variableresult. This value is negated (by the!operator), an operation that produces a Boolean value oftrue. Therefore, the block of code in theifclause begins to execute.Imagine that the first call to the
AddCollectionItemfunction completes successfully, but that the second call toAddCollectionItemgenerates acollectionItemLockedErrerror. During the second call toAddCollectionItem, the Collection Manager responds to the error by calling theMyExceptionHandlerfunction. The first parameter passed to this function indicates the collection that generated the error, and the second parameter passed to this function indicates the error that was generated. This sample exception handler determines whether the error is thecollectionItemLockedErrerror (which it is in this example) and then returns with thenoErrerror as the function result. The Collection Manager notices this change in error and returns control to the sample function as if no error had occurred. (Just as you can use this mechanism to ignore certain errors, you can also use this mechanism to change errors of one type into errors of another type.) Since effectively no error has now occurred, theExceptionTestsample function continues by executing the third call to theAddCollectionItemfunction.The subsequent line of the
ExceptionTestsample function attempts to remove an item that is not in the collection, resulting in acollectionItemNotFoundErrerror. Again, the Collection Manager responds by calling the exception handler. In this case, however, the error is not thecollectionItemLockedErrerror, so the exception handler executes this line of code:longjmp(cpuState, status);
When you call the
longjmpfunction,
Therefore, this call to the
- control is passed to the location of the corresponding call to the
setjmpfunction- the value passed as the second parameter to the
longjmpfunction becomes the function result of thesetjmpfunction
longjmpfunction passes control back to the location in theExceptionTestsample function wheresetjmp(cpuState)was called earlier. This time, however, the function result returned by thesetjmpfunction is not 0, as it was before, but instead is the value ofstatus, the second parameter in the call to thelongjmpfunction. Therefore, the function result of thesetjmpfunction is set to be thecollectionItemNotFoundErrerror.Once again, the
ExceptionTestsample function assigns this function result to theresultlocal variable, and negates it with the!operator. This time the negation produces a Boolean value offalse, and therefore the block of code in theelseclause begins to execute. In this block of code, you can handle errors not handled in the exception handler, using theresultlocal variable to determine which error occurred.You can find more information about the
SetCollectionExceptionProcfunction on page 5-59. You can find more information about exception procedures on page 5-101.