Previous Book Contents Book Index Next

Inside Macintosh: Interapplication Communication /
Chapter 4 - Responding to Apple Events / Handling Apple Events


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 the AEProcessAppleEvent 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 eventRequested action
Open ApplicationPerform tasks your application normally performs when a user opens your application without opening or printing any documents
Open DocumentsOpen the specified documents
Print DocumentsPrint the specified documents
Quit ApplicationPerform 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, and ClrAppFiles procedures (or the GetAppParms 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 the isHighLevelEventAware 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:
Open Application--perform tasks associated with opening an application
Event classkCoreEventClass
Event IDkAEOpenApplication
ParametersNone
Requested actionPerform any tasks--such as opening an untitled document window--that you would normally perform when a user opens your application without opening or printing any documents.
Open Documents--open the specified documents
Event classkCoreEventClass
Event IDkAEOpenDocuments
Required parameter 
 Keyword:keyDirectObject
 Descriptor type:typeAEList
 Data:A list of alias records for the documents to be opened
Requested actionOpen the documents specified in the keyDirectObject parameter.
Print Documents--print the specified documents
Event classkCoreEventClass
Event IDkAEPrintDocuments
Required parameter 
 Keyword:keyDirectObject
 Descriptor type:typeAEList
 Data:A list of alias records for the documents to be printed
Requested actionPrint the documents specified in the keyDirectObject parameter without opening windows for the documents.
Quit Application--perform tasks associated with quitting
Event classkCoreEventClass
Event IDkAEQuitApplication
ParametersNone
Requested actionPerform any tasks that your application would normally perform when the user chooses Quit. Such tasks typically include asking the user whether to save documents that have been changed. When appropriate, the Finder sends this event to an application immediately after sending it a Print Documents event (unless the application was already open) or if the user chooses Restart or Shut Down from the Finder's Special menu.

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 the MyGotRequiredParams function, see Listing 4-11 on page 4-35. For information about the reply and handlerRefcon 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 the AEGetParamDesc function to get the direct parameter (specified by the keyDirectObject keyword) out of the Apple event. The handler requests that AEGetParamDesc return a descriptor list in the docList variable. The handler then checks that it has retrieved all of the required parameters by calling the MyGotRequiredParams 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 the AEGetNthPtr 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 the AEGetNthPtr and AECountItems 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 the StandardGetFile procedure to let the user choose a file; it then calls MyOpenFile, passing the file system specification record returned by StandardGetFile. 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 the AEInteractWithUser 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, the MyPrepareToTerminate 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 the MyGotRequiredParams 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 returns noErr as its function result.

Previous Book Contents Book Index Next

© Apple Computer, Inc.
7 JUL 1996