Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC

< Previous PageNext Page > Hide TOC

Writing an Apple Event Handler

Your Apple event handler typically performs the following operations:

In this section:

Extracting Information From the Apple Event
Performing the Requested Action
Adding Information to a Reply Apple Event
Returning a Result Code
Returning Error Information
A Handler for the Open Documents Apple Event


Extracting Information From the Apple Event

For nearly all standard Apple events, your handler extracts data from the event to help determine how to process the event. The following are some kinds of information you are likely to extract:

“Working With the Data in an Apple Event” provides additional information and examples of how you extract data from an Apple event.

Performing the Requested Action

When your application responds to an Apple event, it should perform the standard action requested by that event. For example, your application should respond to the print documents event by printing the specified documents.

Many Apple events can ask your application to return data. For instance, if your application is a spelling checker, the client application might expect your application to return data in the form of a list of misspelled words.

Adding Information to a Reply Apple Event

If the application that sent the Apple event requested a reply, the Apple Event Manager passes a default reply Apple event to your handler. The reply event has event class kCoreEventClass and event ID kAEAnswer. If the client application does not request a reply, the Apple Event Manager passes a null descriptor instead—that is, a descriptor of type typeNull whose data handle has the value NULL.

The default reply Apple event has no parameters, but your handler can add parameters or attributes to it. If your application is a spelling checker, for example, you can return a list of misspelled words in a parameter. However, your handler should check whether the reply Apple event exists before attempting to add to it. Attempting to add to a null descriptor generates an error.

Your handler may need to add error information to the reply event, as described in subsequent sections.

Returning a Result Code

When your handler finishes processing an Apple event, it should dispose of any Apple event descriptors or other data it has acquired. It should then return a result code to the Apple Event Manager. Your handler should return noErr if it successfully handles the Apple event or a nonzero result code if an error occurs.

If an error occurs because your application cannot understand the event, it should return errAEEventNotHandled. This allows the Apple Event Manager to look for a handler in the system dispatch table that might be able to handle the event. If the error occurs because the event is impossible to handle as specified, return the result code returned by whatever function caused the failure, or whatever other result code is appropriate.

For example, suppose your application receives a get data event requesting the name of the current printer, but it cannot handle such an event. In this situation, you can return errAEEventNotHandled in case another available handler can handle the get data event. However, this strategy is only useful if your application has installed such a system handler, or the event is one of the few for which a system handler may be installed automatically. (For information on handlers that are installed automatically, see “Handling Apple Events Sent by the Mac OS.”)

However, if your application cannot handle a get data event that requests the fifth paragraph in a document because the document contains only four paragraphs, you should return some other nonzero error, because further attempts to handle the event are pointless.

In addition to returning a result code, your handler can also return an error string by adding a keyErrorString parameter to the reply Apple event. The client can use this string in an error message to the user. For more information, see “Returning Error Information.”

For scriptable applications, the client is often the Script Editor, or some other application, executing a script. When you return an error code that the Apple Event Manager understands, the Script Editor automatically displays an appropriate error message to the user. You can find tables of error codes documented in Apple Event Manager Reference and Open Scripting Architecture Reference.

Returning Error Information

If your handler returns a nonzero result code, the Apple Event Manager adds a keyErrorNumber parameter to the reply Apple event (unless you have already added a keyErrorNumber parameter). This parameter contains the result code that your handler returns. This can be useful because it associates the error number directly with the return event, which the client application may pass around without the result code.

Rather than just returning an error code, your handler itself can add error information to the reply Apple event. It can add both an error number and an error string. As noted previously, in many cases returning an Apple Event Manager error code will result in an appropriate error message. You should only add your own error text in cases where you can provide information the Apple Event Manager cannot, such as information specific to the operation of your application.

Note: Handlers can return several additional types of error information. For details, see the OSAScriptError function and the constant section “OSAScriptError Selectors” in Open Scripting Architecture Reference.

To directly add an error number parameter to a reply Apple event, your handler can call a function like the one in Listing 5-2.

Listing 5-2  A function to add an error number to a reply Apple event

static void AddErrNumberToEvent(OSStatus err, AppleEvent* reply)// 1
{
    OSStatus returnVal = errAEEventFailed;// 2
 
    if (reply->descriptorType != typeNull)// 3
    {
        returnVal = AESizeOfParam(reply, keyErrorNumber, NULL, NULL);
        if (returnVal != noErr))// 4
        {
            AEPutParamPtr(reply, keyErrorNumber,
                        typeSInt32, &err, sizeof(err));// 5
        }
    }
    return returnVal;
}

Here’s a description of how this function works:

  1. It receives an error number and a pointer to the reply Apple event to modify.

  2. It declares a variable for the return value and sets it to the Apple Event Manager error constant for “Apple event handler failed.” If the function is successful, this value is changed.

  3. It checks the descriptor type of the reply Apple event to make sure it is not a null event.

  4. It verifies that the event doesn’t already contain an error number parameter (AESizeOfParam returns an error if it doesn’t find the parameter).

  5. It calls AEPutParamPtr to add an error number parameter to the reply event:

    • keyErrorNumber specifies the keyword for the added parameter.

    • typeSInt32 specifies the descriptor type for the added parameter.

    • err specifies the error number to store in the added parameter.

In addition to returning a result code, your handler can return an error string in the keyErrorString parameter of the reply Apple event. Your handler should provide meaningful text in the keyErrorString parameter, so that the client can display this string to the user if desired.

Listing 5-3 shows a function that adds a parameter, from a string reference that refers to Unicode text, to a passed descriptor. You pass the desired keyword to identify the parameter to add. The AEPutParamString function calls AEPutParamPtr, which adds a parameter to an Apple event record or an Apple event, so those are the types of descriptors you should pass to it. (“Descriptors, Descriptor Lists, and Apple Events” describes the inheritance relationship between common Apple event data types.)

Listing 5-3  A function that adds a string parameter to a descriptor

OSErr AEPutParamString(AppleEvent *event,
                    AEKeyword keyword, CFStringRef stringRef)// 1
{
    UInt8 *textBuf;
    CFIndex length, maxBytes, actualBytes;
 
    length = CFStringGetLength(stringRef);// 2
 
    maxBytes = CFStringGetMaximumSizeForEncoding(length,
                                    kCFStringEncodingUTF8);// 3
    textBuf = malloc(maxBytes);// 4
    if (textBuf)
    {
        CFStringGetBytes(stringRef, CFRangeMake(0, length),
                kCFStringEncodingUTF8, 0, true,
                (UInt8 *) textBuf, maxBytes, &actualBytes);// 5
 
        OSErr err = AEPutParamPtr(event, keyword,
                typeUTF8Text, textBuf, actualBytes);// 6
 
        free(textBuf);// 7
        return err;
    }
    else
        return memFullErr;
}

Here’s a description of how this function works:

  1. It receives a pointer to a descriptor to add a parameter to, a key word to identify the parameter, and a string reference from which to obtain the text for the parameter.

  2. It gets the length of the string from the passed reference.

  3. It determines the maximum number of bytes needed to store the text, based on its encoding.

  4. It allocates a buffer of that size.

  5. It gets the text from the string reference.

  6. It adds the text as a parameter to the passed descriptor. (If called with the keyword keyErrorString, for example, it adds an error string parameter.)

  7. It frees its local buffer.

Listing 5-4 shows how you could call AEPutParamString to add an error string to a reply Apple event.

Listing 5-4  Adding an error string to an Apple event with AEPutParamString

CFStringRef errStringRef = getLocalizedErrMsgForErrNumber(err);
OSErr anErr = AEPutParamString(reply, keyErrorString, errStringRef);

Here’s a description of how this code snippet works:

  1. It calls an application-defined function to obtain a localized error message as a string reference, based on a passed error number. (For information on localized strings, see Working With Localized Strings in Bundle Programming Guide.)

  2. It calls AEPutParamString, passing the event (obtained previously) to add the error text to, the error string keyword, and the string reference for the error message text.

A Handler for the Open Documents Apple Event

Listing 5-5 shows a handler that responds to the open documents Apple event.

Listing 5-5  An Apple event handler for the open documents event

static pascal OSErrOpenDocumentsAE(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon)
{
    AEDescList  docList;
    FSRef       theFSRef;
    long        index;
    long        count = 0;
    OSErr       err = AEGetParamDesc(theAppleEvent,
                            keyDirectObject, typeAEList, &docList);// 1
    require_noerr(err, CantGetDocList);// 2
 
    err = AECountItems(&docList, &count);// 3
    require_noerr(err, CantGetCount);
 
    for(index = 1; index <= count; index++)// 4
    {
        err = AEGetNthPtr(&docList, index, typeFSRef,
                        NULL, NULL, &theFSRef, sizeof(FSRef), NULL);// 5
        require_noerr(err, CantGetDocDescPtr);
 
        err = OpenDocument(&theFSRef);// 6
    }
    AEDisposeDesc(&docList);// 7
 
CantGetDocList:
CantGetCount:
CantGetDocDescPtr:
    if (err != noErr)// 8
    {
        // For handlers that expect a reply, add error information here.
    }
    return(err);// 9
}

Here’s a description of how this open documents handler works:

  1. It calls an Apple Event Manager function (AEGetParamDesc) to obtain a descriptor list from the direct object of the received Apple event. This is a list of file aliases, one for each document to open.

  2. It uses the require_noerr macro (defined in AssertMacros.h) to jump to a labeled location as a simple form of error handling.

  3. It calls an Apple Event Manager function (AECountItems) to obtain the number of items in the descriptor list.

  4. It sets up a loop over the items in the descriptor list.

  5. It calls an Apple Event Manager function (AEGetNthPtr) to get an item from the list, by index, asking for a type of typeFSRef. This causes the function to coerce the retrieved item (a file alias) to the requested type.

  6. It calls a function you have written (OpenDocument) to open the current document from the list.

    A print documents event handler would be very similar to this one, but in this step could call your PrintDocument function.

  7. It disposes of the document list descriptor.

  8. The open documents event sent by the Mac OS doesn’t expect a reply, so the reply parameter is a null event. For event handlers that expect a reply, this is where you can use the techniques described earlier in this chapter to add an error number or an error string. Some examples of events that expect a reply (and thus supply a non-null reply event) include get data events and quit events.

  9. It returns an error code (noErr if no error has occurred).

As an alternative to code shown in this handler, you might use an approach that extracts the document list in the event handler, then passes it to a separate function, OpenDocuments, to iterate over the items in the list. This has the advantage that you can also call the OpenDocuments function with the document list obtained from NavDialogGetReply when you are working with Navigation Services. The selection field of the returned NavReplyRecord is a descriptor list like the one described above.



< Previous PageNext Page > Hide TOC


Last updated: 2007-10-31




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2007 Apple Inc.
All rights reserved. | Terms of use | Privacy Notice