• About the OSAX Mechanism AppleScript SDK January 22, 1999 AppleScript supports the notion of Scripting Additions, an extension mechanism whereby users can extend the global terminology of AppleScript outside of applications. Developers can write small extensions that perform tasks that are neither built in to AppleScript nor worth writing an entire scriptable application to perform. Don¹t Do This (without thinking about it first) The OSAX mechanism is far from perfect, and it will be changing both in the near term and the long term. Apple recommends that you use care when you decide to write a scripting addition, as there are severe limitations to what you can do in the context of a scripting addition, and the system costs of managing large numbers of scripting additions are high. OSAXen (as they are called) have the following limitations: € Global namespace. Every event handler, class definition, and even enumeration that is defined in the terminology resource of a scripting addition is global to AppleScript. If you use a term in your scripting addition (like ³search²), you effectively preëmpt its use in any scriptable application. Similarly, any system event handler you define in a scripting addition can potentially be overridden by an application event handler using the same four-character code. € Heap usage. Scripting additions do not have their own heaps; they must use memory out of the application heap (which is usually not expected by the host application¹s memory algorithms) or in the system heap or temporary memory. € No state. Scripting additions cannot store persistent state. € No object model. Most importantly, scripting additions cannot register object callbacks with the Object Support Library, so they cannot support real classes (only coerced AERecord classes) or object resolution. Ambitious projects end up supplying a large number of accessor events because they cannot use the standard ³get data² and ³set data² events with object specifiers, which contributes to the global namespace problem and makes for a poor scripting implementation. Scripting additions are best suited for a small number of unusual events, or setting or retrieving a small number of values. If your task involves a large number of events or values, you may consider creating a faceless background application to accomplish the same task. A faceless background application is lightweight, has its own segregated namespace and heap, can keep persistent state, and can resolve objects using the Object Support Library. Theory of Operation At startup time, the AppleScript extension installs two event handlers in the System heap: the Master Loader and the HandleGDUT handler. At the end of its initialization routine it calls the HandleGDUT handler directly (not through the AppleEvent manager). The HandleGDUT handler¹s job is to register all event and coercion handlers stored in scripting additions (and in the AppleScript extension itself) and collect the terminologies. It does this by first loading the terminology from the English Dialect, then installing all Œosax¹ resources in the AppleScript extension, and finally walking the Scripting Additions folder(s) and extracting the Œaete¹ resources and installing all the handlers in their Œosax¹ resources. Handlers are only installed if the modification date of the Scripting Addition folder has changed from the last HandleGDUT event. (If there are two Scripting Additions folder, one in the Extensions Folder and one in the System Folder, they are scanned individually, and only the scripting additions in the folder that changed are installed; this is a bug.) To install a handler, the HandleGDUT handler reads the resource name of its Œosax¹ resource. The name must be twelve characters, the first four of which are ³AEVT², ³CSPT², or ³CSDS². These characters determine the type of handler: an event handler, an AECoercePtr handler, or an AECoerceDesc handler. The following eight characters are the suite and event code (for ³AEVT² handlers), or the fromType and toType codes (for ³CSDS² and ³CSPT² handlers). For example, a resource with the name ³AEVTfoobbar ² would be registered as an event handler with suite code ³foob² and event code ³bar ². All handlers are installed in the system event table. But the HandleGDUT handler does not actually load the handler and install it; rather, it caches the file ID of the file in which the handler resides, uses that as the RefCon of the installed handler, and installs the address of the Master Loader as the entry point for that handler. So whenever a systemwide coercion or event handler is called, the Master Loader is the code that is actually dispatched. The Master Loader and HandleGDUT handler share a hash table, created at system startup, in which are stored the actual entry points of the handlers. At HandleGDUT time the handler code is retrieved from the resource fork with ResLoad set to false; that is, the resource is not actually loaded but an empty handle is allocated. It is this empty handle that is stored in the hash table, indexed by the suite and event codes (or fromType and toType). When a script issues an event (or invokes a coercion), the AppleEvent Manager dispatches it to the Master Loader (as it is the Master Loader's entry point that is registered for every pair). The Master Loader checks the handle and, if it is nil, it opens the resource file (using the file ID stored in the RefCon), loads the resource into the System heap, locks it, and calls it. When the handler is finished executing, control returns to the Master Loader. It marks the handler¹s block as unlocked and purgeable, so that it does not clog the System Heap. On the next invocation, if the block is still present and hasn't been purged, the Master Loader will simply lock the block and call it, rather than reload it from disk. This will continue as long as the System Heap has sufficient memory. At some point the handler will be purged; if it is invoked again, it will have an empty handle, and thus will be reloaded by the Master Loader. Several things should be noted from this: € You cannot use the refCon in your event handler. The AppleEvent Manager does not call your handler; the Master Loader does, and it always does so with a null RefCon. € If you deinstall and reinstall your own handler, you lose the services of the Master Loader, and will be present and locked in the system heap until the machine is rebooted. This can cause fragmentation in the System heap. € Handlers are never really deinstalled. If you remove a scripting addition from the Scripting Additions folder, its terminology will be unavailable (so no scripts using that terminology will compile), but executing scripts can still call the handler. If the handler is purged, it will still be reloaded from the scripting additions file, because its file ID does not change. The only time a handler becomes unavailable is when a) the handler has been purged from the system heap and b) the file from which the handler was drawn is physically unavailable, i.e. has been deleted. Mac OS 8.5 Native Scripting Additions The Standard Additions file in Mac OS 8.5 is a native CFM shared library with event handlers defined as entry points in the library. This mechanism is limited and will not be supported in future versions of the operating system; when a new mechanism is defined it will be documented in this SDK. ________________________________ © 1998 Apple Computer. Inc. All rights reserved. Apple, the Apple logo, LaserWriter, MacTCP, Power Macintosh, Mac, and Macintosh are trademarks of Apple Computer, Inc., registered in the U.S. and other countries. PowerPC is a trademark of International Business Machines Corporation, used under license therefrom. All other product names are trademarks or registered trademarks of their respective holders. Mention of non-Apple products is for information purposes and constitutes neither an endorsement nor a recommendation. Apple assumes no responsibility with regard to the selection, performance, or use of these products. Updated January 22, 1999 v 1.0