Of course, these patterns can be combined as well: A single extension could use one extension for a block of simple functions, and another on a per-object basis, and so on.
In C, each context is initialized (and finalized) via a function registered in the extension initialization call. The context initializer must return a set of functions registered by name, and can optionally perform additional work.
It can determine which set of functions to return by looking at its second parameter (
the example above.).
In Java, a similar pattern is achieved via the FREContext abstract class. Extensions must create a derived class that implements the
and then return an instance of that class from
(Note, however, that the derived class can't use other FREContext helper methods until after
and context initialization has been completed.)
ActionScript access from native code
With initialization and registration complete, ActionScript code can begin calling native code via
ActionScript objects of any type can be passed to such calls. Native code accesses these arguments using a native API exported by the runtime itself.
Access to ActionScript from native code is centered on the FREObject type. (This is an opaque handle in C, and a class in Java.) Given a FREObject, native code can:
Determine its type, via FREGetObjectType or dynamically casting to a derived class.
Convert to an integer, floating point, Boolean, or string value.
If the object is not a primitive type like int, then native code can:
Set and get properties of the object.
Call methods on the object.
In order to create values for setting properties, arguments for calling methods, and return values from native functions, native code can also:
Construct new objects from integer, floating point, Boolean, and string values.
Construct new objects by invoking class constructors.
Taken together, these capabilities allow fairly complete access to ActionScript from native code.
Nonetheless, accessing ActionScript from native code can be tedious due to the need to handle error conditions, explicitly construct argument arrays, and so on. If you have to access a significant amount of ActionScript from native
code—accessing properties, invoking methods, and so on—consider creating a helper method in ActionScript, and invoking that from native code instead.
Finally, note that FREObjects have a limited lifetime: They are only valid while a call into the extension, via
remains on the stack. They cannot be held in native code across calls; you'll receive an error if you attempt to use them in this way. If you need to store an ActionScript reference across calls, save it in the ActionScriptData parameter on the relevant
context. (If you need to store multiple references, put an Object in ActionScriptData, and hang references off of it as properties.)
Specialized native APIs
The runtime API made available to native code is augmented with special-case accessors for ByteArrays, Arrays, Vectors, and BitmapData objects. These specialized APIs are designed to provide the fastest possible performance for
types frequently used to manipulate or transfer large amounts of data.
In C, these APIs take the form of functions that require FREObjects of corresponding types. In Java, they're accessed via classes derived from FREObject, which add additional, type-appropriate methods.
The special-case accessors for Arrays and Vectors are the most straightforward, adding four calls to get and set the length, and get and set individual items. These APIs avoid the inconvenience and overhead of, for example, converting
each index from integers to FREObjects and back.
The ByteArray and BitmapData APIs are a bit more complex, and in turn allow direct access to the memory backing the array or image. This allows ActionScript code and native code to share access to memory segments and images without
requiring intermediate copies.
ByteArray and BitmapData access involves a three-step process:
Acquire the object. This locks the underlying memory buffer in place, thus permitting access from native code without the risk of the garbage collector releasing or moving the memory.
Access the object, reading or modifying as desired. During this time, other ActionScript methods cannot be accessed; they're locked out while the memory buffer is locked.
Release the object. This invalidates references to the memory obtained in Step 1, and re-enables access to the rest of the API.
For BitmapData only, note that you should also use the invalidate call to inform the runtime as to which portion of the image is updated; this in turn is used to correctly refresh that portion of the image when it's next rendered.
In the C API, the acquire methods return structs which contain a raw pointer to the underlying memory, plus associated necessary information, like the width and height of the image. In Java, this information is exposed as object
properties, and access to the memory is provided using an instance of java.nio.ByteBuffer.
Note also that these APIs are subject to the same lifetime rules as any other FREObject. Even if a ByteArray or BitmapData object is locked, references to it cannot be successfully held after the outermost call to an extension returns.
Native code is permitted to use any available platform threading facilities. This means that extensions can be used, among other things, to improve application responsiveness by moving long-running tasks off of the ActionScript
execution thread. However, access to the runtime extension API is allowed, with one exception, only from the same thread on which the runtime invokes the extension. (Note that the runtime doesn't make any guarantees about which thread it will use to invoke
If you do use an extension to move work to a background thread, there's a straightforward pattern you can use to work with this restriction:
Upon invocation from ActionScript, gather all the data that's needed and save copies in native data structures.
Spin up or acquire a thread to perform the work, and hand it the copied data.
Upon completion, store the results to a native data structure, and notify ActionScript (see below).
When ActionScript receives the completion notification, call into the extension a second time to retrieve the results, which are copied out of the result data structure.
The signaling mentioned in Step 3 is accomplished by calling FREDispatchStatusEventAsync (C) or FREContext.dispatchStatusEventAsync (Java). This call is the one exception mentioned above; it can be called from any thread at any
time after the corresponding context is fully initialized.
When this signaling API is called, it causes a StatusEvent, with the specified code and level, to be queued for dispatch in ActionScript at the next opportunity. Typically, this means the event will be dispatched within one frame.
The event is dispatched by the corresponding ExtensionContext object. At this point, since execution is by definition back on the ActionScript thread, it's safe (although optional) to call back into native code.
Extensions that allocate resources (memory, threads, file handles, and so on) in native code should take care to release those resources when they're no longer required. The runtime provides a pair of notification APIs that help
manage resources associated with the lifetime of the context or the extension itself.
When a context is released from ActionScript, native code is notified by a call to the registered context
(C) or the
(Java). In ActionScript, this can be triggered either explicitly from
implicitly when the ExtensionContext object is garbage-collected. Use of the
is recommended, as there can be substantial delays between when an object is available to the garbage collector and when it is ultimately collected.
When an extension itself is shut down, native code is notified by a call to the registered extension
(C) or the
(Java). Note that the runtime doesn't guarantee that these methods are called. On most platforms, the extension remains loaded as along as the application is running, and so the extension itself is never shut down.