MM Developer's Guide
MM Interfaces | MM Methods | MM Types and Misc API
DR Interfaces | DR Methods | DR Types and Misc API

Director Xtra Development Kit: Multimedia Developer's Guide

Scripting Xtras

Introduction

Scripting Xtras provide new functions to call through the scripting interface of an application. In Director, Scripting Xtras extend the Lingo language and can also be called with Javascript syntax.

Scripting Xtra concepts

Application scripting models

In Director, the developer attaches scripts to various objects in a movie: sprites, frames, cast members, and the movie itself. An object's scripts provide behavior specific to that object. The Lingo language abstracts some general behaviors useful throughout the playback of a movie. For example, a Lingo script can access the properties of objects such as sprites and cast members, and use calculations in logical structures to control a movie based on user input.

Global, parent, and child functions

Scripting Xtras can add three types of functions: global, parent, and child.

In Director, a global Xtra function is like other Lingo global functions and commands. When a Scripting Xtra is available in Director, any script can call its global functions. Parent and child functions, like Director's parent scripts and child objects, let your Xtra define a type of object with specific properties and functions or handlers. A Lingo scripter can create instances of those objects in any script, with each instance containing its own version of its properties. Parent functions are like globals in that any script in a movie can call a Parent. To call a Child function, the scripter creates a new instance and assigns it to a variable. The script then invokes the child functions through the variable. The child is local to the script where it is created, and can be passed between scripts through handler calls.

Calling a Scripting Xtra

The way you call a scripting Xtra depend on the application you're scripting from. The following table shows the ways to invoke a Scripting Xtra.

Operation Director
Call global function Call the function in any Lingo script, fill in arguments
Call parent function functionName(xtra "xtraName" <, args*>)
Create child instance set myChild = new(xtra "xtraName" <, args*>)
Call child function functionName(myChild <, args*>)
Remove child set myChild = 0

Implementing a Scripting Xtra

A Scripting Xtra is defined by two classes: a registration class and a scripting class.

The registration class implements the IMoaRegister interface to inform an application of its capabilities. The IMoaRegister::Register() method describes an Xtra's capabilities through a message table, listing the name of the Xtra, and the names, types, and parameters of all the functions it provides.

The scripting class implements the IMoaMmXScripting interface to provide specific functions. This interface consists of a single method, Call(). When called, this method is passed a structure containing information from the function call, including the identity of the function called, the arguments to the function, and a slot for any return value or values. Your implementation of Call() should evaluate this structure and provide a way to handle each function you specify in your message table, along with a default return value for any calls you don't handle.

In addition to implementing IMoaMmXScripting, the Xtra class defines any instance variables required by global, parent, or child functions.

An application always creates an instance of the Scripting Xtra to support global and parent functions. This instance may not be created until the user first invokes a function. It's safe to assume this instance won't be created when the application fist starts. (If you need to initialize libraries or perform other startup actions, implement the IMoaInterrogator interface in your Xtra class.) Each time a script creates a new child instance, the application creates an additional instance of the Xtra class. In each case, your Xtra's MoaCreate... and MoaDestroy... functions are called, which means you may need to implement these functions carefully to perform the proper initialization for the global instance or child instances of your Xtra.

The registration class

To implement the registration class for a Scripting Xtra, you define a message table describing the Xtra and its functions. You also implement IMoaRegister to register the message table with the application.

The message table
The Scripting Xtra message table is an array of strings that describe the Xtra and its functions. The following example illustrates all of the conventions used in defining the message table:
static char msgTable[] = { \
        "xtra nameOfXtra \n" \
        "new object me <, args>* \n" \
        "forget object me <, args>* -- entirely optional-see text\n" \
        "-- Lingo style comment \n" \
        "* globalFunction <, args>* -- globalFunction description\n" \
        "+ parentFunction object xt <, args>* -- parentFunction description \n" \
        "childFunction object me <, args>* -- childFunction description\n" \
};

The first entry in the message table is the name of the Scripting Xtra. This name is used to invoke the Xtra's functions.

The remaining entries can be function definitions, comments (indicated by a Lingo-style "--" prefix), or a definition followed by a comment. Function definitions include the name and scope of the function, and the name and type of each argument.

Comments in the message table provide useful documentation, since the user can view the message list in the scripting interface -- through the mMessageList() command in Lingo.

Function definitions

A function definition follows a standard form:

<scope prefix> functionName <object objectName> <, argType argName>*

The <scope prefix> indicates the scope of a function. Global functions are indicated by an asterisk ("*") character, parent functions by a plus ("+") character, and child functions by no prefix. The functionName entry represents the name used to invoke the function.

The function name can be followed by a list of argument descriptions. Each argument description includes the type of the argument followed by an optional name. The <object objectName> argument description is used for parent and child functions. For child functions, objectName is the child whose function is being invoked. For parent functions, objectName is a reference to the Xtra itself. The type of these arguments is always object. The argType of other arguments can be of several types:

integer
float
string
symbol
object
any
*
For integer, float, string, symbol, and object arguments, the type of the argument supplied must always match that specified in the message table. The type any means the user can provide an argument of any type in the specified position. The asterisk (*) means the user can provide any number and any type of arguments.
Optional new and forget functions

Every Scripting Xtra may implement the optional child functions new and forget. These functions are pre-defined for specific purposes.

The new function is called when a child object is created. The first argument of the new function is the child object. Your Xtra may define additional arguments to enable the author to customize the child from Lingo. Your implementation of new should perform custom initialization for the child and respond to any arguments passed in by the author.

The forget function is called when a child object is about to be removed from memory. You should release any memory allocated in your new function.

Note that forget is a "hidden" function, never called directly from a script. Instead, Scripting Xtras are disposed of by reassigning a child's variable to 0 in Lingo. The forget function is called automatically when all references to the child are dropped. [This behavior has changed with Director MX 2004, see the following paragraph for details.]

Global References to Xtras
With the new JavaScript support in Director MX 2004, an xtra that is referenced by a global variable will NOT be disposed of by simply assigning the global object to 0. This is because global variables have an associated wrapper object so they can be accessed by JavaScript routines. Objects in JavaScript are cleaned up using a garbage collection approach rather than the reference counting approach used by lingo. It is important to note that this new behavior applies whether your movie is making use of JavaScript or not. You can use _system.gc() on JavaScript side to force objects stored in globals to really go away. A better way of dealing with this situation is to provide a separate, explicit close method with the xtra, so it does not depend on been freed to close down any system resources or connections that the xtra has made. Also, see Javascript and Memory Issues.
Implementing IMoaRegister

IMoaRegister is the standard MOA interface provided for registering Xtras with an application. In the case of Scripting Xtras, you implement this interface to pass your Xtra's message table to the application. Here's a typical implementation of IMoaRegister::Register():

STDMETHODIMP_(MoaError) XXPalette_IMoaRegister_Register(PIMoaCache pCache, PIMoaDict pXtraDict)
{
        X_ENTER
        MoaError err = kMoaErr_NoErr;
        PIMoaDict pRegDict;
        /* Register that we are a Scripting Xtra */
        err = pCache->AddRegistryEntry(pXtraDict, &CLSID_XXScripting, &IID_IMoaMmXScripting, &pRegDict);
        if ( err == kMoaErr_NoErr)
        {
                /* Register the message table */
                err = pRegDict->Put(kMoaMmDictType_MessageTable, msgTable, 0, kMoaMmDictKey_MessageTable);
        }
        X_STD_RETURN(err);
        X_EXIT
}
Knowing when to register
Scripting Xtras are designed to work across MOA applications, but a given Scripting Xtra need not be application-independent. To prevent compatibility problems, it's important to be sure your Xtra works with the application that's attempting to register it.

The IMoaAppInfo callback interface provides a way to check out the application registering your Xtra. Within the Register() method, use this interface to determine various attributes of the application to be sure.

Your Xtra's Register() method should also check for any callback interfaces or supporting Xtras it needs. Director defines application-specific service interfaces to access objects in their presentation models. Call QueryInterface() on the application object within your Xtra's Register() method to be sure callback interfaces are available.

Note for Windows Scripting Xtra developers
Microsoft Visual C has a limit of 2048 characters for a static string. If you reach this limit, you must store your msgTable in a resource. Your registration code must then load the resource, put its content into the registry, then release the resource. (Remember to use IMoaCallback::Begin/EndUsingResources() when accessing resources from your Xtra.)

The scripting class

The Scripting class provides the IMoaMmXScripting interface that implements the Xtra's functions. It provides instance variables for the properties of child objects; it can also provide specific instance variables for access through global and parent functions. It may provide the IMoaMmInterrogator and IMoaMmTerminator interfaces to perform initialization and cleanup for your Xtra.
Defining method symbols
Every implementaion of IMoaMmXScripting needs to include an enumeration consisting of symbols for each method that a Lingo Xtra implements. This enumeration is defined in the header file that declares the class and interface implementations. The members of this enumeration match the naming and ordering of the functions listed in the message table. By convention, for each function name in the message table, you create a corresponding enum with the prefix "m_", as follows:
enum { 
        m_new = 0, 
        m_globalFunction, 
        m_parentFunction, 
        m_childFunction
};
Values in this enumeration enable the script interpreter to convert function names listed in your message table to calls into your implementation. The order in this enumeration must match the order of function entries in the message table. Otherwise, the script interpreter will call the wrong function.
Creator and destructor functions
An earlier discussion mentions that one instance of the Scripting class is always created to respond to a Scripting Xtra's global and parent functions. This instance is usually created the first time a script in a presentation calls a global or parent function. A new instance of the Xtra class is also created each time a new child is created. This instance supports the child's unique properties through its instance variables. This means that the MoaCreate... and MoaDestroy... functions for the Xtra class should be designed carefully. For general allocations and initializations at startup, the Xtra class should probably implement the IMoaMmInterrogator interface. To allocate and initialize resources for a child instance, implement the new function in the IMoaMmXScripting::Call() method. The new function is called for each child created from your Scripting Xtra.
Implementing IMoaMmXScripting

To implement its functions, the Scripting Xtra implements the IMoaMmXScripting::Call() method. The Xtra should perform a switch selection based on the value of the methodSelector passed in the MoaMmCallInfo structure. This field contains the enumeration constant corresponding to the function being called. The same structure also provides values for any arguments to the function and a field for a return value.

Here's a complete sample implementation of the Call() method.

STDMETHODIMP CScriptingTemplate_IMoaMmXScripting_Call(PMoaMmCallInfo callPtr)
{
        X_ENTER
        PIMoaMmUtils pMmUtils = NULL; 
        MoaError err = kMoaErr_NoErr;
        err = This->pObj->pCallback->QueryInterface(&IID_IMoaMmUtils, &pMmUtils);
        if (err == kMoaErr_NoErr) 
		 {
                switch ( callPtr->methodSelector ) 
                {
                        case m_new:
                                /* Called when creating a new child.  
                                Setup instance vars for child.*/
                                break;
                        case m_globalFunction: /* a global function */
                                err = pMmUtils->PrintMessage("you've called the global function example\n");
                                break;
                        case m_parentFunction: /* a parent function */
                                err = pMmUtils->PrintMessage("You've called the parent function example\n");
                                break;
                        case m_childFunction: /* a child function */
                                err = pMmUtils->PrintMessage("you've called the child function example\n");
                                break;
                        default:
                                err = kMoaDrErr_FunctionNotDefined;
                                break;
                }
        }
        X_RETURN(MoaError, err);
        X_EXIT
}

Scripting Xtras in Director

Loading Scripting Xtras

When the user puts a Scripting Xtra into the standard Xtra directory, it is loaded automatically when Director starts.

To load a Scripting Xtra into Director from another directory, use the Lingo command openXLib. The openXLib takes a complete pathname for the Xtra. The pathname may be relative to the folder containing the movie or complete, including the source disk or volume. The pathname always includes the filename of the Xtra (not the internal name identifying the Xtra). For example:

openXLib "LocalDrive:MoreLingo:MyLingoXtra"

openXLib
is documented in the Lingo Dictionary.

Unloading Scripting Xtras

To remove a Scripting Xtra from memory, if it has been loaded with openXLib, you can call the closeXLib Lingo command. You must first set all previously defined child variable references to zero. Starting with Director MX 2004, this is not sufficient to ensure your Xtras "destroy" method is called. See Global References to Xtras for more information about this aspect of Xtras. For example:

myXtraChild = 0
closeXLib "MyLingoXtra"

closeXLib
is documented in the Lingo Dictionary.


Copyright © 1995-2008 Adobe Macromedia Software LLC, Inc.