Apple
Events 101
UserLand Software, Inc.
©
copyright 1993-1994, UserLand Software, Inc.
UserLand
Software is the developer of the UserLand Frontier scripting system. The
company is located at 555 Bryant #237, Palo Alto, CA 94301. 415-326-7791,
415-326-7793 (fax). UserLand, Frontier, Frontier Runtime and Frontier Extras
are trademarks of UserLand Software, Inc. Other product names may be trademarks
or registered trademarks of their owners.
Email:
userland.dts@applelink.apple.com. If youÕre an AppleLink user, check out the
UserLand Discussion Board under the Third Parties icon. CompuServe users enter
GO USERLAND at any ! prompt. On America On-Line, enter the keyword USERLAND.
Comments,
questions and suggestions are welcome!
Synopsis
Basic
introduction to Apple Events programming using THINK C. Two sample programs in
source code: Client and Server. Client sends a series of Apple Events to
Server. They are minimal programs, makes it easy to see how the Apple Events
work. Requires THINK C 5.0 or greater. Readme in Word 4.0 format. Packed with
StuffIt 3.0. Does not require Frontier or Frontier Runtime.
Requires System 7.0,
Universal Headers, MacsBug/TMON
The
Apple Event Manager, which this sample code builds on, first appeared in System
7.0. These programs will not run on earlier versions of the Macintosh operating
system.
The
source code samples were written using Think C 7.0 and Metrowerks Code Warrior
1.0, but they donÕt rely on features that are only present in these versions.
You can build this code with any compiler compatible with AppleÕs Universal
Headers.
Error
reporting is done via DebugStr calls. So you should have MacsBug or TMON loaded
to report errors without crashing your system.
A pair of sample programs
There
are two programs in this package: Client and Server. They illustrate the basic
techniques of Macintosh interapplication communication using the Apple Event
Manager.
Server
has a standard Apple menu. Its File menu contains a single command, Quit. It
installs handlers for the four required Apple Events and a handler for a custom
event thatÕs called by the Client app.
Client
is even simpler than Server. It has no menus and no windows. It initializes the
Macintosh managers and then drops into a loop. Each time thru the loop it sends
an Apple Event asking Server to display a number between 1 and 100. It checks
errors, reporting them via DebugStr.
These
programs are minimal in every way. That makes it easy to find the Apple Event
code.
You
may copy the source code from these applications into any other program without
any royalty or license fee. You may redistribute this package exactly as-is.
You may not distribute a modified version of this package.
A pair of experiments
Experiment #1: Be
sure the programs work on your machine.
1. Be
sure MacsBug or TMON is loaded.
2. Launch
Server.
3. Launch
Client.
You should see a count from 1 to 100 in the Server window.
Then Client quits. Server doesnÕt quit.
Experiment
#2: See how errors are reported
1. Be
sure MacsBug or TMON is loaded.
2. Launch
Server.
3. Launch
Client.
4. Quickly
bring Server to the front.
5. Quit.
Client should halt with an error code of -609, an Event
Manager error which according to Think Reference means Òinvalid connectionÓ.
Certainly you have more luxurious error reporting in your
program. ;-)
Touring the source code
1. Open server.¹, the project file
for the Server app. Open server.c. Server sits in its main event loop, like all
Macintosh applications, waiting for an interactive event, such as a mouse click
or keystroke. Also, in its main event loop, it watches for incoming Apple
Events and uses AEProcessAppleEvent to dispatch to its Apple Event handler
routines.
2. Search for handleEvent. All the
code above this routine deals with the usual things that Macintosh programs
have to deal with.
3. Look at the switch statement in
handleEvent. ThereÕs a branch for kHighLevelEvent, and in that branch is a call
to AEProcessAppleEvent. If your program is going to handle incoming Apple
Events, you must call AEProcessAppleEvent on receipt of a HighLevelEvent.
4. AEReturnError returns an error
to the caller. You may want to copy it directly into your program to make it
easy to report errors on processing incoming Apple Events.
5. openDocEvent and printEvent
donÕt do anything since this program doesnÕt open files or print them.
6. How setMessageEvent works
The setMessageEvent Apple Event handler expects a
single parameter whose key is '----', and type is 'TEXT', containing a handle
to the text to be displayed in its window.
If the handle contains more than 255 characters, only
the first 255 characters are copied.
If the '----' parameter isnÕt present,
setMessageEvent returns an error to the caller, following the error reporting
conventions supported by Frontier and AppleScript.
If everything goes well, it copies the text into the
windowmessage string and invalidates the window.
To illustrate how returned values work,
setMessageEvent converts the string to a number, and adds it to the Apple Event
reply. The Client app checks for this reply.
7. quitEvent sets the
flexitmainloop boolean true, which causes the program to exit from its main
event loop. ItÕs essential that the quit handler return normally to the Apple
Event Manager to avoid hanging the system.
8. How installHandlers works
installHandlers attempts to install five Apple Event
handlers.
Each handler is installed with a four-character class
and an identifier. In the first call to AEInstallEventHandler, we associate the
class 'SERV' and id 'DISP' with the setMessageEvent routine. The last
parameter, false, says this is not a system event handler, the second-to-last
parameter, 0, indicates that this handler doesn't have a refcon.
When an Apple Event whose class is 'SERV' and id is
'DISP' arrives for this application, AEProcessAppleEvent will call setMessageEvent.
The AppleEvents.h include file contains #defines for
the standard classes and ids used in the subsequent AEInstallEventHandler
calls.
9. Check out the SIZE resource
Choose the Set Project Type command in Think CÕs
Project menu. The SIZE setting is 58E0, indicating that the following flags are
on:
Multifinder-aware
Background
null events
Suspend
& resume events
32-bit
compatible
HighLevelEvent-aware
Accept
remote HighLevelEvents
The major one, clearly, is HighLevelEvent-aware,
although we think the others generally follow -- if youÕre scriptable, you
should be scriptable over the network, and you very likely need background null
events and suspend and resume events.
10. Close server.¹ and open
client.¹. Open client.c.
11. Starting at the top,
initMacintosh initializes the usual Macintosh managers.
12. Jump to the end of the file and
look at the main function. It loops 100 times,
sending an Apple Event to Server each time through the loop.
13. How sendMessageToServer works
It creates an Apple Event, converts the number to a
string, sends the event to Server, waits for a reply, and checks the reply to
be sure everything worked.
ItÕs a complicated routine, so we broke it up into
four sections. The following comments apply to each of the sections:
1. Creates
an address descriptor using ServerÕs creator id. We use that address to create
an Apple Event by calling AECreateAppleEvent.
2. Converts
the number to a string using NumToString, and then adds it onto the Apple
Event.
3. Sends
the message and waits for a reply using AESend.
4. Finally,
we look at the reply, and check to see that itÕs a long, containing the number
we started with.
If any errors occur, we use DebugStr to report them.
If you see no crashes running this program, you know that all is well!
Finally, we dispose of the address descriptor, the
event we create and the reply. Note that all are initialized to {typeNull, nil}
at the beginning of the routine, so that the calls to AEDisposeDesc will work
even if an error causes the event not to be created or sent.
14. Set Project Type
As with the Server app, check the Set Project Type
command. WeÕve set the SIZE resource to 58E0, the same as Server.
15. Client could be a script
The Client app is playing the role thatÕs usually
played by a Frontier or AppleScript script.
HereÕs what the Frontier script would look like:
local (i)
for i = 1 to 100
appleEvent ('AESV', 'SERV', 'DISP',
'----', string (i))
The details of the appleEvent call could be hidden in
a subroutine:
on display (num)
return (appleEvent ('AESV', 'SERV',
'DISP', '----', string (num)))
local (i)
for i = 1 to 100
display (i)
WeÕve included a copy of this script in
clientAsScript in the Client folder. You can run it with Frontier or Frontier
Runtime 2.0.
Apple Events 102 and beyond
That
wraps it up for Apple Events 101. With this sample source code, you should be
able to add a set of Apple Event handlers to any main-event-loop based
Macintosh program.
We
have ideas for what would make a good AE 102 upload. For example, weÕre working
on a minimal document-based application that implements a set of Apple Events
that open and close windows, save documents, let scripts move data into the
application and get data from the application. Again, the goal will be to be
supply an absolutely minimal application, to make it easy for you to borrow
code to include in your software.
What
would you like to see in future Apple Events sample code?
Please
get in touch thru Section/Library 16 at GO USERLAND on CompuServe. Or thru our
AppleLink and America On-Line forums. Look for more sample C source code,
documentation and sample scripts in these places.