Important: The information in this document is obsolete and should not be used for new development.
Handling High-Level Events
High-level events provide a means of communication between applications. Apple events are high-level events that follow the Apple Event Interprocess Messaging Protocol (AEIMP). In most cases, you should use Apple events rather than define your own high-level events if you wish to communicate with other applications. If you plan to use Apple events, see Inside Macintosh: Interapplication Communication for specific information on Apple events, and refer to this section for specific details about how the Event Manager reports high-level events.To receive high-level events, you must set the appropriate flags in your application's
'SIZE'
resource. You must set theisHighLevelEventAware
flag if your application
is to receive any high-level events. You must set thelocalAndRemoteHLEvents
flag for your application to receive high-level events sent from another computer on
the network. In addition, to receive high-level events from another computer, your application must be shared and Program Linking must be enabled. The user shares your application by selecting your application in the Finder and choosing Sharing from the File menu and enables Program Linking from the Sharing Setup control panel.If you set the
isHighLevelEventAware
flag in your application's'SIZE'
resource, your application receives the Finder information in the form of Apple events. The Finder information is the information your application can use to determine which files to open or print. Your application must respond to the required Apple events (Open Application, Open Documents, Print Documents, and Quit Application) that are sent by the Finder if your application sends or receives high-level events.The
what
field in the event record of a high-level event contains the kHighLevelEvent constant.To determine the type of high-level event received, your application needs to examine the
message
andwhere
fields of the event record. For high-level events, these two fields of the event record have special meanings.The
message
field and thewhere
field of the event record together define the specific type of high-level event received. Your application should interpret these fields as having the data typeOSType
, notLongInt
orPoint
.The
message
field contains the event class of the high-level event. For example, Apple events sent by the Edition Manager have the event class 'sect
'. You can define your own group of events that are specific to your application. If you have registered your application signature with Apple Computer, Inc., then you can use your signature to define the class of events that belong to your application. Note, however, that Apple reserves the use of all event classes whose names contain only lowercase letters and nonalphabetic characters.For high-level events, the
where
field in the event record contains a second message specifier, called the event ID. The event ID defines the particular type of event (or message) within the class of events defined by the event class. For example, the Section Read event sent by the Edition Manager has event class 'sect
' and event ID 'read
'. The Open Documents event sent by the Finder has event class 'aevt
' and event ID 'odoc
'. You can define your own set of event IDs corresponding to your own event class. For example, if themessage
field contains 'biff
' and thewhere
field contains 'cmd1
', then the high-level event indicates the type of event defined by 'cmd1
' within the class of events defined by the application with the signature 'biff
'.
Note that because the
- Note
- If your application supports Apple events, you can call the
AEProcessAppleEvent
function to determine the type of Apple event received, rather than examining themessage
andwhere
fields.where
field of an event record for a high-level event is used to select a specific kind of event (within the class determined by themessage
field), high-level event records do not contain the mouse location at the time of the event. You should not interpret thewhere
field before interpreting thewhat
field because different event classes can contain overlapping sets of event IDs.Unlike low-level events and operating-system events, high-level events may not be completely determined by the event record returned to your application when it calls
WaitNextEvent
. For example, you might still need to know which other application sent you the high-level event or what additional data that application wants to send you. Your application can obtain this further information about the high-level event by calling theAcceptHighLevelEvent
function. The additional information associated with a high-level event includes
To obtain this additional information, your application must call
- the identity of the sender of the event
- a unique number that identifies the request associated with the event or associates the particular event with a request from a previous event
- the address and length of a data buffer that can contain optional data
AcceptHighLevelEvent
before callingWaitNextEvent
again. By convention,
callingAcceptHighLevelEvent
indicates that your application intends to process
the high-level event.To accept an Apple event, call the
AEProcessAppleEvent
function instead of
theAcceptHighLevelEvent
function. The Apple Event Manager also extracts
any additional information associated with the Apple event at your application's request. This chapter discusses how to accept high-level events using theAcceptHighLevelEvent
function; for information on theAEProcessAppleEvent
function, see Inside Macintosh: Interapplication Communication.Responding to Events From Other Applications
You can identify high-level events by the value in thewhat
field of the event record. Themessage
andwhere
fields further classify the type of high-level event. Your application can choose to recognize as many events as are appropriate. Some high-level events may be fully specified by their event record only, while others may include additional information in an optional buffer. To get that additional information or to find the sender of the event, use theAcceptHighLevelEvent
function.
Listing 2-16 on the next page illustrates how to respond to a high-level event.
- Note
- To respond to an Apple event, use the Apple Event Manager, as described in Inside Macintosh: Interapplication Communication. u
The
DoHighLevelEvent
procedure in Listing 2-16 first determines the type of high- level event received by checking themessage
andwhere
fields of the event record. It then usesAcceptHighLevelEvent
to get any additional data associated with the event. This particular application recognizes only one type of high-level event. If the event is not of this type, the code assumes that the event is an Apple event and callsAEProcessAppleEvent
to handle the event.In general, you cannot know in advance how big the optional data buffer is, so you can allocate a zero-length buffer and then resize it if the call to
AcceptHighLevelEvent
returns thebufferIsSmall
result code.Listing 2-16 Accepting a high-level event
PROCEDURE DoHighLevelEvent (event: EventRecord); VAR myTarg: TargetID; {target ID record} myRefCon: LongInt; myBuff: Ptr; myLen: LongInt; myErr: OSErr; BEGIN IF (event.message = LongInt(kMySpecialHLEventClass)) AND (LongInt(event.where) = LongInt(kMySpecialHLEventID)) THEN BEGIN {it's a high-level event that doesn't use AEIMP} myLen := 0; {start with a 0-byte buffer} myBuff := NIL; myErr:=AcceptHighLevelEvent(myTarg,myRefCon, myBuff, myLen); IF myErr = bufferIsSmall THEN BEGIN myBuff := NewPtr(myLen);{allocate needed storage} myErr := AcceptHighLevelEvent(myTarg, myRefCon, myBuff, myLen); IF myErr = noErr THEN ; {perform any action requested by the event} END; IF myErr <> noErr THEN DoError(myErr);{perform the necessary error handling} END ELSE BEGIN {otherwise, assume that the event is an Apple event} myErr := AEProcessAppleEvent(event); IF myErr <> noErr THEN DoError(myErr);{perform the necessary error handling} END; END;TheAcceptHighLevelEvent
function returns additional information and data associated with the event. The ID of the sender of the event is returned in the first parameter, which is a target ID record. You can inspect the fields of that record to determine which application sent the event. The target ID record contains the session reference number that identifies the connection with the other application as well as the port name and location name of the sender. If the high-level event requires that you return information, you can use the information returned in the target ID record to
send an event back to the requesting application. See "Determining the Sender of a High-Level Event" on page 2-72 and "Sending High-Level Events" on page 2-73 for specific information on the target ID record.The second parameter to
AcceptHighLevelEvent
, the reference constant parameter, is a unique number that identifies the request associated with the event or identifies that the particular event is related to a request from a previous event. If you send a response to this event, you should use the same value for the reference constant so that the sender of the event can associate the reply with the original request.The third parameter points to any additional data associated with the event. Any data
in this additional buffer is defined by the particular high-level event. On input, the fourth parameter toAcceptHighLevelEvent
, the length parameter, contains the
size of the buffer. If no error occurs, on output the length parameter contains the size
of the message accepted. If theAcceptHighLevelEvent
function returns the result codebufferIsSmall
, the length parameter contains the size of the message yet to
be received.Searching for a Specific High-Level Event
Sometimes you do not want to accept the next available high-level event pending for your application. Instead, you might want to select one event from among all the high-level events in your application's high-level event queue. For example, you might want to look for a return receipt for a high-level event you previously posted before processing other high-level events.You can select a specific high-level event by calling the
GetSpecificHighLevelEvent
function. One of the parameters you pass to this function is a filter function that you provide. Your filter function should examine an event in your application's high-level event queue and determine whether it is the kind of event you wish to receive. If it is, your filter function returnsTRUE
. This indicates that your filter function does not want to inspect any more events. If the filter function finds an event of the desired type, it should callAcceptHighLevelEvent
to retrieve the event. When your function returnsTRUE
, theGetSpecificHighLevelEvent
function itself returnsTRUE
.If your filter function returns
FALSE
for an event in the high-level event queue, thenGetSpecificHighLevelEvent
looks at the next event in the high-level event queue and executes your filter function. If the filter function returnsFALSE
for all the high-
level events in the queue, thenGetSpecificHighLevelEvent
itself returnsFALSE
to your application.Here's how you declare the filter function whose address you pass to the
GetSpecificHighLevelEvent
function:
FUNCTION MyFilter (yourDataPtr: Ptr; msgBuff: HighLevelEventMsgPtr; sender: TargetID): Boolean;When your application callsGetSpecificHighLevelEvent
, you pass it a parameter that indicates the criteria your filter function should use to search for a specific event. TheGetSpecificHighLevelEvent
function passes this information to your filter function in theyourDataPtr
parameter. TheGetSpecificHighLevelEvent
function also provides your filter function with information about the event record of the high-level event in themsgBuff
parameter as well as information about the sender of the high-level event in thesender
parameter.The
msgBuff
parameter contains a pointer to a high-level event message record that has this structure:
TYPE HighLevelEventMsg = RECORD HighLevelEventMsgHeaderLength: Integer; version: Integer; reserved1: LongInt; theMsgEvent: EventRecord; userRefCon: LongInt; postingOptions: LongInt; msgLength: LongInt; END; HighLevelEventMsgPtr= ^HighLevelEventMsg;When you callGetSpecificHighLevelEvent
and it executes your filter function for a high-level event waiting in the high-level event queue, the fields of the high-level event message record are filled in by the Event Manager. You can then compare the fields of this record to the information in theyourDataPtr
parameter to determine whether that event suits your needs. For example, theyourDataPtr
parameter might contain the signature of a return receipt. You can test its value against the event class of the event record contained in thetheMsgEvent
field of the high-level event message record.Determining the Sender of a High-Level Event
When you receive a high-level event, part of the information returned byAcceptHighLevelEvent
is the identity of the sender of the event. You can use that information to respond selectively to requests made by other applications or to find which application to send any replies to. The information about the sender is provided in the form of a target ID record, defined as follows:
TYPE TargetID = RECORD sessionID: LongInt; {session reference number} name: PPCPortRec; {sender's port name} location: LocationNameRec; {sender's location name} recvrName: PPCPortRec; {reserved} END;ThesessionID
field corresponds to the session reference number created by the PPC Toolbox. This is a 32-bit number that uniquely identifies a PPC Toolbox session (or connection) with another application. Thename
andlocation
fields contain the sender's port name and location name. If the sending application is on the same computer as the receiving application, you can determine the sending application's process serial number by calling theGetProcessSerialNumberFromPortName
function.Sending High-Level Events
You use thePostHighLevelEvent
function to send a high-level event to another application. When doing so, you need to provide six pieces of information:
- an event record with the event class and event ID assigned appropriately
- the identity of the recipient of the event
- a unique number that identifies the communication associated with this
particular event- a data buffer that can contain optional data
- the length of the data buffer
- options determining how the event is posted
When you post a high-level event to an application on the same computer, you can specify its recipient in one of four ways:
- Note
- To send an Apple event, use the Apple Event Manager function
AESend
. The Apple Event Manager uses the Event Manager to post Apple events. For information on posting Apple events, see Inside Macintosh: Interapplication Communication. u
To specify the recipient of a high-level event sent across a network, you can use only
- by port name and location name (specified in a target ID record)
- by a session reference number
- by the application's creator signature
- by a process serial number
the receiving application's port name and location name or its session reference number. You can use any of the four ways when sending high-level events to applications on the local computer.You specify the recipient of a high-level event in the
receiverID
parameter when you use thePostHighLevelEvent
function. To specify a port name and location name, provide the address of a target ID record in thereceiverID
parameter. To specify a process serial number, provide its address in thereceiverID
parameter. To specify a session reference number, or signature, provide the data in thereceiverID
parameter.When you are replying to a high-level event, it is easy to identify the recipient because you can use the target ID record that you receive from
AcceptHighLevelEvent
, the session reference number contained in that target ID record, or the process serial number (if the receiving process is local). Note that replying by session reference number is always the fastest way to respond to a high-level event.When you are not replying to a previous event, you need to determine the identity of
the target application yourself. You can use one of several methods to do this. If the target application is on the local computer, you can search for that application's creator signature or its process serial number by calling theGetProcessInformation
function. See the chapter "Process Manager" in Inside Macintosh: Processes for a detailed explanation of theGetProcessInformation
function and for examples of how to use it to generate a list of process serial numbers of all open processes on the local computer.If the application to which you want to send a high-level event is located on a remote computer, you need to identify it either by its session reference number or by its port name and location name. You can call the
PPCBrowser
function to let the user browse for a specific port. You can call theIPCListPorts
function to obtain a list of all ports registered with the target PPC Toolbox. See the chapter "Program-to-Program Communications Toolbox" in Inside Macintosh: Interapplication Communication for an explanation of both of these functions.As just described, you can identify the recipient of the high-level event in one of four ways. Listing 2-17 illustrates how to send a high-level event to an application on the local computer using the application's creator signature. In this example, an application is sending a high-level event to the application with the creator signature of
'boff'
. The specific high-level event being sent is identified by the event class'boff'
and the event ID'cmd1'
.Listing 2-17 Posting a high-level event by application signature
PROCEDURE MyPostTest; VAR myEvent: EventRecord; {an event record} myRecvID: OSType; {receiver ID} myOpts: LongInt; {posting options} myErr: OSErr; BEGIN myEvent.what := kHighLevelEvent; myEvent.message := LongInt('boff'); {event class} myEvent.where := Point(LongInt('cmd1')); {event ID} {the receiver is identified by its signature and } { a return receipt is requested} myOpts := receiverIDisSignature + nReturnReceipt; myRecvID := 'boff'; {receiver's signature} myErr := PostHighLevelEvent(myEvent, Ptr(myRecvID), 0, NIL, 0, myOpts); IF myErr <> noErr THEN DoError(myErr); END;In this example of using the PostHighLevelEvent function, there is no additional data to transmit, so the sending application providesNIL
as the pointer to the data buffer and sets the buffer length to 0. ThemyOpts
variable specifies posting options.Posting options are of two types: delivery options and options associated with the
receiverID
parameter. You can specify one or more delivery options to indicate if you want the other application to receive the event at the next opportunity and to indicate if you want acknowledgment that the other application received the event. You use the options associated with thereceiverID
parameter to indicate how you are specifying the recipient of the event. To set the various posting options, use these constants:
CONST nAttnMsg = $00000001;{give this message priority} nReturnReceipt = $00000200;{return receipt requested} receiverIDisTargetID = $00005000;{ID is port name and location name} receiverIDisSessionID = $00006000;{ID is PPC session ref number} receiverIDisSignature = $00007000;{ID is creator signature} receiverIDisPSN = $00008000;{ID is process serial number}When you specify the receiving application in thereceiverID
parameter, you can use these constants to specify the receiver of the event by port name and location name, session reference number, process serial number, or signature. Any of these specifications allows you to send an event to another application on the local computer. For example, in Listing 2-17 themyOpts
variable indicates that the receiver is identified by its creator signature, and themyRecvID
variable contains the receiver's creator signature. To send events to an application on a remote computer, you can specify the recipient only by the session reference number or by the port name and location name.When you specify the receiver of the event by port name and location name, use the
receiverIDisTargetID
constant in the posting options parameter and specify the address of a target ID record in thereceiverID
parameter.
TYPE TargetID = RECORD sessionID: LongInt; {unused for posting} name: PPCPortRec; {recipient's port name} location: LocationNameRec;{recipient's port loc} recvrName: PPCPortRec; {unused for posting} END;When you pass a target ID record, you need to specify only thename
andlocation
fields. You can use theIPCListPorts
function to list all of the existing port names along with information on whether the port will accept authenticated service on the computer specified by the location name. For information on how to use theIPCListPorts
function, see the chapter "Program-to-Program Communications Toolbox" in Inside Macintosh: Interapplication Communication.You can also use the
PPCBrowser
function to fill in a target ID record. Listing 2-18 on the next page illustrates how to use thePPCBrowser
function to post a high-level event. In this example, the sending application wants to locate a dictionary application and have the dictionary return the definition of a word to it.Listing 2-18 Using the
PPCBrowser
function to post a high-level event
FUNCTION MyPostWithPPCBrowser (aTextPtr: Ptr; textlength: LongInt): OSErr; VAR myHLEvent: EventRecord; myErr: OSErr; myNumTries: Integer; myPortInfo: PortInfoRec; myTarget: TargetID; BEGIN {use PPCBrowser to get the target} myErr := PPCBrowser('Select an Application', 'Application', FALSE, myTarget.location, myPortInfo, NIL, ''); IF myErr = NoErr THEN BEGIN {copy port name into myTarget.name} myTarget.name := myPortInfo.name; myHLEvent.what := kHighLevelEvent; myHLEvent.message := LongInt('Dict'); myHLEvent.where := Point(LongInt('Defn')); {if a connection is broken, then sessClosedErr is returned to } { PostHighLevelEvent; to reestablish the connection, just post } { the event one more time} myNumTries := 0; REPEAT myErr := PostHighLevelEvent(myHLEvent, @myTarget, 0, aTextPtr, textlength, receiverIDisTargetID); myNumTries := myNumTries + 1; UNTIL (myErr <> sessClosedErr) OR (myNumTries > 1); END; MyPostWithPPCBrowser := myErr; {return any error} END;The application-defined function in Listing 2-18 uses thePPCBrowser
function to display a dialog box asking the user to select a dictionary. (For additional information
on thePPCBrowser
function, see Inside Macintosh: Interapplication Communication.) If
the user selects a dictionary, this code posts a high-level event to that dictionary application asking for the definition of the selected text. Note that the sending application and the receiving application must both agree that definition queries are to be of event class 'Dict
' and event ID 'Defn
'. It is necessary to define a private protocol only in cases in which no suitable Apple event exists.
If a high-level event is posted successfully,
- Note
- You should avoid passing handles to the receiving application in an attempt to share a block of data. It is better to put the relevant data into a buffer (as illustrated in Listing 2-18) and pass the address of the buffer. If you absolutely must share data by passing a handle, make sure that the block of data is located in the system heap. u
PostHighLevelEvent
returns the result codenoErr
, which indicates only that the event was successfully passed to the PPC Toolbox. Your application needs to call another Event Manager routine (EventAvail
,GetNextEvent
, orWaitNextEvent
) to give the other application an opportunity to receive the event.The event you send might require the other application to return some information to your application by sending a high-level event back to your application. You can scan for the response by using
GetSpecificHighLevelEvent
. If your application must wait for this event, you might want to display a wristwatch cursor or take other action as appropriate to your application. You also might want to implement a timeout mechanism in case your application never receives a response to the event.Requesting Return Receipts
When you post a high-level event, you can request a return receipt by including thenReturnReceipt
constant as one of the posting options. This requests that the Event Manager send your application a high-level event that tells you whether the other application accepted your event. Note that this does not necessarily mean that the other application performed any action you might have requested from it.A return receipt is a high-level event having an event class and an event ID indicated by these two constants:
CONST HighLevelEventMsgClass = 'jaym'; rtrnReceiptMsgID = 'rtrn';Return receipts are posted by the Event Manager on the computer of the receiving application (and not by the receiving application itself). No data buffer is associated with a return receipt. However, the posting Event Manager sets themodifiers
field of the high-level event record to one of the following values:
CONST msgWasNotAccepted = 0; msgWasFullyAccepted = 1; msgWasPartiallyAccepted = 2;ThemsgWasNotAccepted
constant indicates that your event was not accepted by
the receiving application. This means that the receiving application was notified
of the arrival of your event (throughWaitNextEvent
) but did not callAcceptHighLevelEvent
to accept the event. ThemsgWasFullyAccepted
constant indicates that the receiving application did callAcceptHighLevelEvent
and retrieved all the data in the optional data buffer. ThemsgWasPartiallyAccepted
constant indicates that the receiving application calledAcceptHighLevelEvent
, but the application's data buffer was too small to hold the data sent with your application, and the receiving application calledWaitNextEvent
before retrieving the rest of the buffer.Note that a return receipt does not indicate the identity of the receiving application. To determine on whose behalf the Event Manager has sent you a particular return receipt, you need to call
AcceptHighLevelEvent
. WhenAcceptHighLevelEvent
returns successfully, thesender
parameter contains a target ID record with the fields filled in for the receiving application. With return receipts, themsgLen
parameter is 0, themsgBuff
parameter isNIL
, and themsgRefCon
parameter contains the unique number of therefCon
parameter of the original high-level event sender (that is, your application).Handling Apple Events
If your application uses high-level events, your application must respond to the
required Apple events sent by the Finder. The four required Apple events are Open Application, Open Documents, Print Documents, and Quit Application. See Inside Macintosh: Interapplication Communication for information on how to handle the required Apple events.When your application receives a high-level event (as indicated by the
kHighLevelEvent
constant in thewhat
field of the event record), and if your application supports Apple events, call theAEProcessAppleEvent
function. TheAEProcessAppleEvent
function provides an easy way for your application to identify the event class and event ID of the Apple event and to direct the Apple Event Manager to call the code in your program that handles the Apple event.To send Apple events to other applications, use the
AESend
function.To ensure compatibility and smooth interaction with other Macintosh applications, you should use the Apple event protocol for high-level events whenever possible. By implementing the capabilities to send Apple events to and receive Apple events from other applications, you allow other applications to interact with your application and provide enhanced capabilities to your users.
See Inside Macintosh: Interapplication Communication for complete information on how to send and receive Apple events.