|
This Technote describes the API that allow developers to create AppleScript scripting additions for Mac OS X. It is directed at application developers who are interested in creating scripting additions. What are Scripting Additions?Scripting additions provide a mechanism for delivery of additional functionality that can be used in AppleScripts. A scripting addition can provide Apple event handling and Apple event data coercion handling. The Apple event handlers and Apple event data coercion handlers installed by a scripting addition are written in basically the same way that handlers used inside an application are written. What differs between scripting additions and applications is the packaging of the code and the mechanisms by which the scripting addition is installed in the system. These differences are discussed in the sections that follow. Packaging Scripting AdditionsScripting additions are packaged as bundles with a name ending with the extension Note: Single-file CFM binaries linked with Mac OS X v10.6 (Snow Leopard) and later: Info.plistMac OS X v10.6 (Snow Leopard) uses a data-driven scheme for installing the handlers in a scripting addition. The older methods described below are still supported, but the 10.6-style Info.plist is recommended for performance reasons. The 10.6 format is not backward-compatible; an addition that uses it will only work on Mac OS X v10.6 and later. The
The value in each case is a dictionary whose keys are the eight-character event code (event class and event id) or the "from" and "to" <key>OSAXHandlers</key> <dict> <key>Events</key> <dict> <key>sysodlog</key> <dict> <key>Handler</key> <string>DisplayDialogEventHandler</string> <key>ThreadSafe</key> <false/> <key>Context</key> <string>Process</string> </dict> </dict> <key>DescCoercions</key> <dict> <key>STXTutxt</key> <dict> <key>Handler</key> <string>CoerceStyledTextToUnicodeText</string> </dict> </dict> <key>PtrCoercions</key> <dict> <key>TEXTutxt</key> <dict> <key>Handler</key> <string>CoercePlainTextToUnicodeText</string> </dict> </dict> </dict> For each handler, the dictionary contains the name of the handler function, and for event handlers, its thread-safety and context requirements, using the keys and values described here: Table 1 : Handler dictionary keys
HandlerThis is the handler function name. The function must be exported as an entry point into the executable. ThreadSafeOSA and AppleScript in Mac OS X v10.6 are thread-safe. If a script is executed on a background thread and invokes an event handler that is not thread-safe, it will be called on the main thread, which is slower than directly invoking it on the calling thread and may reduce application responsiveness to user input. Ideally, all handlers should be thread-safe. Some inherently cannot be; for example, almost anything that displays UI must be executed on the main thread. You are encouraged to either verify that your event handlers are thread-safe or update them to make them thread-safe. If the value of this key is true, then the handler may be executed on a non-main thread and it may be executed concurrently from multiple threads. If false, it will only be executed on the main thread. This key is required for event handlers, and must not be present for coercion handlers, which are required to be thread-safe. If a coercion handler cannot be made safe to run on background threads, the handler must arrange to execute the coercion on the main thread, such as using by using libdispatch and the main dispatch queue. ContextFor security reasons, Mac OS X v10.6 will only execute scripting additions in other processes if it is necessary, and in some cases may ask for authorization before doing so. Exactly how a scripting addition is handled depends on the value of the "Context" key, which describes what execution context the handler depends on in order to function correctly. In the script, a scripting addition command may be inside a Table 2 : Context values
Any value of This key is required for event handlers, and must not be present for coercion handlers, which are always executed in the same process as the script. Mac OS X v10.5 (Leopard): Info.plistMac OS X v10.5 (Leopard) uses an Info.plist identical to the one described above, except that the value for a handler entry is simply a string specifying the name of the handler function, not a dictionary. For example, Listing 2 shows the 10.5-style declaration of <key>OSAXHandlers</key> <dict> <key>Events</key> <dict> <key>sysodlog</key> <string>DisplayDialogEventHandler</string> </dict> </dict> Scripting addition event handlers using this format on 10.6 are assumed to be thread-unsafe and have a context of "Machine". Mac OS X v10.4 (Tiger) and earlier: Required FunctionsIf your scripting addition will only run on Mac OS X v10.5 or later versions, then this Info.plist entry is all you need. If you want it to run on older versions of Mac OS X, then you must supply three additional functions to install, terminate, and reference-count your scripting addition. Note: These functions are not supported in 64-bit mode. 64-bit scripting additions must use one of the Info.plist formats above. Note: When running in 10.5 and later, the initialization function will only be called if you do not provide the Info.plist data described above. The reference-count function will never be called, since Leopard will never attempt to unload a scripting addition from a process once it is loaded. The termination functions will also never be called. If your addition needs to do work at process termination time, such as releasing resources, use InitializationYour scripting addition's initialization routine is responsible for installing your scripting addition's handler routines. To implement it, the scripting addition must export a routine named OSErr SAInitialize(CFBundleRef additionBundle) { OSErr err; Boolean isSysHandler = true; err = AEInstallEventHandler(theAEEventClass, theAEEventID, eventHandlerUPP, refcon, isSysHandler); err = AEInstallCoercionHandler(fromType, toType, coercionHandlerUPP, refcon, fromIsDesc, isSysHandler); return err; } All scripting addition handlers must be installed in the system dispatch table, as shown above. IMPORTANT: If your initialization routine returns any result other than Your scripting addition should always install all of its handlers, even if functionality they require is not present in the system. That way, you have an opportunity to provide a meaningful error message when your addition is invoked, rather than the generic "doesn't understand" or "can't coerce" message. Your initialization function may perform additional setup operations, such as allocating memory or finding files, but this is not recommended: it creates additional startup cost, and may not even be necessary, since your scripting addition may never be invoked. Initialization should be deferred until your addition is actually invoked. The Information about bundle references and the bundle format can be found in the References section at the end of this article. TerminationYour scripting addition's termination routine is responsible for removing your scripting addition's handler routines. To implement it, a scripting addition must export a routine named void SATerminate(void) { AERemoveEventHandler(theAEEventClass, theAEEventID, gTheHandler, true); DisposeAEEventHandlerUPP(gTheHandler); ...other cleanup operations... } The termination routine may perform other cleanup operations, such as releasing resources. However, the termination function will never be called in Leopard. If your addition needs to do work at process termination time, such as releasing resources, use Reference CountingThis routine exists for historical reasons: in classic Mac OS, it was possible to crash the system by removing a scripting addition while it was still running. Therefore, scripting additions exported a function named Boolean SAIsBusy(void) { return false; } Helpful TipsRuntime ConsiderationsYour scripting addition may be loaded into any application's process, and should therefore take care to not disturb the global state outside of the addition handler itself, such as the Resource Manager resource chain, effective user id, and so on. Scripting additions are loaded separately into each application process that uses them. As a result, you should design your scripting addition keeping in mind that there may be many instances of your scripting addition open in many different applications at the same time. Some scripting additions may require additional code if they use a single shared resource such as a printer or a serial port. Locating Your Scripting Addition's Bundle ResourcesScripting additions may need to access resources and files located inside of their bundle. To do this, get a Information about bundle references and the bundle format can be found in the References section at the end of this article. Local and Remote RequestsIf executing your scripting addition command on a remote machine is not meaningful or would constitute a security risk, your command handler should detect and reject events from remote machines. A handler can determine the source of an event by examining the DescType sourceAttr; err = AEGetAttributePtr(eventPtr, keyEventSourceAttr, typeType, NULL, &sourceAttr, sizeof(sourceAttr), NULL); if (err != noErr || sourceAttr == kAERemoteProcess) { return errAELocalOnly; } ReferencesDownloadables
Document Revision History
|