Handling the Required Apple Events
This section describes the required Apple events--the Apple events your application must support to be compatible with System 7 and later versions of system software--and the descriptor types for all parameters of the required Apple events. It also describes how to write the handlers for these events, and it provides sample code.To support the required Apple events, you must set the necessary flags in the
'SIZE'
resource of your application, install entries in your application's Apple event dispatch table, add code to the event loop of your application to recognize high-level events, and call theAEProcessAppleEvent
function, as described in "Accepting an Apple Event," which begins on page 4-5, and "Installing Entries in the Apple Event Dispatch Tables," which begins on page 4-7. You must also write handlers for each Apple event; this section describes how to write these handlers.Required Apple Events
When a user opens or prints a file from the Finder, the Finder sets up the information your application uses to determine which files to open or print. In System 7 and later versions, if your application supports high-level events, the Finder communicates this information to your application through the required Apple events.The Finder sends these required Apple events to your application to request the corresponding actions:
Apple event Requested action Open Application Perform tasks your application normally performs when a user opens your application without opening or printing any documents Open Documents Open the specified documents Print Documents Print the specified documents Quit Application Perform tasks--such as releasing memory, requesting the user to save documents, and so on--associated with quitting before the Finder terminates your application In System 7 and later versions, the Finder uses these events as part of the mechanisms for launching and terminating applications. When the Finder launches your application, the application receives the Open Application, Open Documents, or Print Documents event. When the Finder terminates your application, the application receives the Quit Application event. This method of communicating Finder information to your application replaces the mechanisms used in earlier versions of system software.
Applications that do not support high-level events can still use the
CountAppFiles
,GetAppFiles
, andClrAppFiles
procedures (or theGetAppParms
procedure) to get the Finder information. See the chapter "Introduction to File Management" in Inside Macintosh: Files for information on these routines. To make your application compatible with System 7 and with earlier and later versions, you must support both the old and new mechanisms.Use the
Gestalt
function to determine whether the Apple Event Manager is present. If it is and theisHighLevelEventAware
flag is set in your application's'SIZE'
resource, your application receives the Finder information through the required Apple events.If your application accepts high-level events, it must be able to process the four required Apple events. Your application receives the required Apple events from the Finder in these situations:
Upon receiving any of the required Apple events, your application should perform the action requested by the event. Here is a summary of the contents of the required events and the actions they request applications to perform:
- If your application is not open and the user opens your application from the Finder without opening or printing any documents, the Finder launches your application and sends it the Open Application event.
- If your application is not open and the user opens one of your application's documents from the Finder, the Finder launches your application and sends it the Open Documents event.
- If your application is not open and the user prints one of your application's documents from the Finder, the Finder launches your application and sends it the Print Documents event. Your application should print the selected documents and remain open until it receives a Quit Application event from the Finder.
- If your application is open and the user opens or prints any of your application's documents from the Finder, the Finder sends your application the Open Documents or Print Documents event.
- If your application is open and the user chooses Restart or Shut Down from the Finder's Special menu, the Finder sends your application the Quit Application event.
Your application needs to recognize only two descriptor types to handle the required Apple events: descriptor lists and alias records. The Open Documents event and Print Documents event use descriptor lists to store a list of documents to open. Each document is specified as an alias record in the descriptor list.
You can retrieve the data that specifies the document to open as an alias record, or you can request that the Apple Event Manager coerce the alias record to a file system specification (
FSSpec
) record. The file system specification record provides a standard method of identifying files in System 7 and later versions. See Inside Macintosh: Files for a complete description of how to specify files using file system specification records.Handling the Open Application Event
When the user opens your application, the Finder uses the Process Manager to launch your application. On startup, your application typically performs any needed initialization, and then begins to process events. If your application supports high-level events, and if the user opens your application without selecting any documents to open or print, your application receives the Open Application event.To handle the Open Application event, your application should do just what the user expects it to do when it is opened. For example, your application might open a new untitled window in response to an Open Application event.
Listing 4-5 shows a handler that processes the Open Application event. This handler first calls an application-defined function called
MyGotRequiredParams
, which checks whether the Apple event contains any required parameters. If so, the handler returns an error, because by definition, the Open Application event should not contain any required parameters. Otherwise, the handler opens a new document window.Listing 4-5 A handler for the Open Application event
FUNCTION MyHandleOApp (theAppleEvent, reply: AppleEvent; handlerRefcon: LongInt): OSErr; VAR myErr: OSErr; BEGIN myErr := MyGotRequiredParams(theAppleEvent); IF myErr = noErr THEN DoNew; MyHandleOApp := myErr; END;For a description of theMyGotRequiredParams
function, see Listing 4-11 on page 4-35. For information about thereply
andhandlerRefcon
parameters for an Apple event handler, see "Writing Apple Event Handlers" on page 4-33.Handling the Open Documents Event
To handle the Open Documents event, your application should open the documents that the Open Documents event specifies in its direct parameter. Your application extracts this information and then opens the specified documents. Listing 4-6 shows a handler for the Open Documents event.Listing 4-6 A handler for the Open Documents event
FUNCTION MyHandleODoc (theAppleEvent, reply: AppleEvent; handlerRefcon: LongInt): OSErr; VAR myFSS: FSSpec; docList: AEDescList; myErr, ignoreErr: OSErr; index, itemsInList: LongInt; actualSize: Size; keywd: AEKeyword; returnedType: DescType; BEGIN {get the direct parameter--a descriptor list--and put it } { into docList} myErr := AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, docList); IF myErr = noErr THEN BEGIN {check for missing required parameters} myErr := MyGotRequiredParams(theAppleEvent); IF myErr = noErr THEN BEGIN {count the number of descriptor records in the list} myErr := AECountItems (docList, itemsInList); IF myErr = noErr THEN {now get each descriptor record from the list, } { coerce the returned data to an FSSpec record, and } { open the associated file} FOR index := 1 TO itemsInList DO BEGIN myErr := AEGetNthPtr(docList, index, typeFSS, keywd, returnedType, @myFSS, Sizeof(myFSS),actualSize); IF myErr = noErr THEN BEGIN myErr := MyOpenFile(@myFSS); IF myErr <> noErr THEN ; {handle error from MyOpenFile} END ELSE ; {handle error from AEGetNthPtr} END; {of For index Do} END ELSE ; {handle error from MyGotRequiredParams} ignoreErr := AEDisposeDesc(docList); END ELSE ; {failed to get direct parameter, handle error} MyHandleODoc := myErr; END;The handler in Listing 4-6 first uses theAEGetParamDesc
function to get the direct parameter (specified by thekeyDirectObject
keyword) out of the Apple event. The handler requests thatAEGetParamDesc
return a descriptor list in thedocList
variable. The handler then checks that it has retrieved all of the required parameters by calling theMyGotRequiredParams
function. (See Listing 4-11 on page 4-35 for a description of this function.)Once the handler has retrieved the descriptor list from the Apple event, it uses
AECountItems
to count the number of descriptors in the list. Using the returned number as an index, the handler can get the data of each descriptor record in the list. This handler requests that theAEGetNthPtr
function coerce the data in the descriptor record to a file system specification record. The handler can then use the file system specification record as a parameter to its own routine for opening files.For more information on the
AEGetParamDesc
function, see page 4-70. For more information on theAEGetNthPtr
andAECountItems
functions, see "Getting Data Out of a Descriptor List" on page 4-31.After extracting the file system specification record that describes the document to open, your application can use this record to open the file. For example, in Listing 4-6, the code passes the file system specification record to its routine for opening files, the
MyOpenFile
function.The
MyOpenFile
function should be designed so that it can be called in response to both the Open Documents event and to events generated by the user. For example, when the user chooses Open from the File menu, the code that handles the mouse-down event uses theStandardGetFile
procedure to let the user choose a file; it then callsMyOpenFile
, passing the file system specification record returned byStandardGetFile
. By isolating code that performs a requested action from code that interacts with the user, you can easily adapt your application to handle Apple events that request the same action.Note the use of the
AEDisposeDesc
function to dispose of the descriptor list when your handler no longer requires the data in it. Your handler should also return a result code.Handling the Print Documents Event
To handle the Print Documents event, your application should extract information about the documents to be printed from the direct parameter, then print the specified documents.If your application can interact with the user, it should open windows for the documents, display a Print dialog box for the first document, and use the settings entered by the user for the first document to print all the documents. If user interaction is not allowed, your application may either return the error
errAENoUserInteraction
or print the documents using default settings. See "Interacting With the User," which begins on page 4-47, for information about using theAEInteractWithUser
function to interact with the user.Note that your application can remain open after processing the Print Documents event; when appropriate, the Finder sends your application a Quit Application event immediately after sending it a Print Documents event.
The handler for the Print Documents event shown in Listing 4-7 is similar to the handler for the Open Documents event, except that it prints the documents referred to in the direct parameter.
Listing 4-7 A handler for the Print Documents event
FUNCTION MyHandlePDoc (theAppleEvent, reply: AppleEvent; handlerRefcon: LongInt): OSErr; VAR myFSS: FSSpec; docList: AEDescList; myErr, ignoreErr: OSErr; index, itemsInList: LongInt; actualSize: Size; keywd: AEKeyword; returnedType: DescType; BEGIN {get the direct parameter--a descriptor list--and put it } { into docList} myErr := AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, docList); IF myErr = noErr THEN BEGIN {check for missing required parameters} myErr := MyGotRequiredParams(theAppleEvent); IF myErr = noErr THEN BEGIN {count the number of descriptor records in the list} myErr := AECountItems (docList, itemsInList); IF myErr = noErr THEN {now get each descriptor record from the list, } { coerce the returned data to an FSSpec record, and } { print the associated file} FOR index := 1 TO itemsInList DO BEGIN myErr := AEGetNthPtr(docList, index, typeFSS, keywd, returnedType, @myFSS, Sizeof(myFSS), actualSize); IF myErr = noErr THEN BEGIN myErr := MyPrintFile(@myFSS); IF myErr <> noErr THEN ; {handle error from MyOpenFile} END ELSE ; {handle error from AEGetNthPtr} END; {of For index Do} END ELSE ; {handle error from MyGotRequiredParams} ignoreErr := AEDisposeDesc(docList); END ELSE ; {failed to get direct parameter, handle error} MyHandlePDoc := myErr; END;Handling the Quit Application Event
To handle the Quit Application event, your application should take any actions that are necessary before it is terminated (such as saving any open documents). Listing 4-8 shows an example of a handler for the Quit Application event.When appropriate, the Finder sends your application a Quit Application event immediately after a Print Documents event. The Finder also sends your application a Quit Application event if the user chooses Restart or Shut Down from the Finder's Special menu.
Listing 4-8 A handler for the Quit Application event
FUNCTION MyHandleQuit (theAppleEvent, reply: AppleEvent; handlerRefcon: LongInt): OSErr; VAR myErr: OSErr; userCanceled: Boolean; BEGIN {check for missing required parameters} myErr := MyGotRequiredParams(theAppleEvent); IF myErr = noErr THEN BEGIN userCanceled := MyPrepareToTerminate; IF userCanceled THEN MyHandleQuit := kUserCanceled ELSE MyHandleQuit := noErr; END ELSE MyHandleQuit := myErr; END;The handler in Listing 4-8 calls another function supplied by the application, theMyPrepareToTerminate
function. This function saves the documents for any open windows and returns a Boolean value that indicates whether the user canceled the Quit operation. This is another example of isolating code for interacting with the user from the code that performs the requested action. By structuring your application in this way, you can use the same routine to respond to a user action (such as choosing the Quit command from the File menu) or to the corresponding Apple event. (For a description of theMyGotRequiredParams
function, see "Writing Apple Event Handlers" on page 4-33.)
- IMPORTANT
- When your application is ready to quit, it should call the
ExitToShell
procedure from the main event loop, not from your handler for the Quit Application event. Your application should quit only after the handler returnsnoErr
as its function result.