Example: Using the external API with an ActiveX container



This example demonstrates using the external API to communicate between ActionScript and a desktop application that uses the ActiveX control. The example reuses the Introvert IM application, including the ActionScript code and even the same SWF file, and therefore does not describe the use of the external API in ActionScript. Familiarity with the preceding example will be helpful in understanding this one.

The desktop application in this example is written in C# using Microsoft Visual Studio .NET. The focus of the discussion is the specific techniques for working with the external API using the ActiveX control. This example demonstrates the following:

  • Calling ActionScript functions from a desktop application hosting the Flash Player ActiveX control

  • Receiving function calls from ActionScript and processing them in an ActiveX container

  • Using a proxy class to hide the details of the serialized XML format that Flash Player uses for messages sent to an ActiveX container

To get the application files for this sample, see www.adobe.com/go/learn_programmingAS3samples_flash. The Introvert IM C# files can be found in the Samples/IntrovertIM_CSharp folder. The application consists of the following files:

File

Description

AppForm.cs

The main application file with the C# Windows Forms interface.

bin/Debug/IntrovertIMApp.swf

The SWF file loaded by the application.

ExternalInterfaceProxy/ExternalInterfaceProxy.cs

The class that serves as a wrapper around the ActiveX control for External Interface communication. It provides mechanisms for calling and receiving calls from ActionScript.

ExternalInterfaceProxy/ExternalInterfaceSerializer.cs

The class that performs the task of converting Flash Player’s XML format messages to .NET objects.

ExternalInterfaceProxy/ExternalInterfaceEventArgs.cs

This file defines two C# types (classes): a custom delegate, and an event arguments class, which are used by the ExternalInterfaceProxy class to notify a listener of a function call from ActionScript.

ExternalInterfaceProxy/ExternalInterfaceCall.cs

This class is a value object representing a function call from ActionScript to the ActiveX container, with properties for the function name and parameters.

bin/Debug/IntrovertIMApp.swf

The SWF file loaded by the application.

obj/AxInterop.ShockwaveFlashObjects.dll,

obj/Interop.ShockwaveFlashObjects.dll

Wrapper assemblies created by Visual Studio .NET that are required to access the Flash Player (Adobe Shockwave® Flash) ActiveX control from managed code.

Overview of the Introvert IM C# Application

This sample application represents two instant-messaging client programs (one within a SWF file and another built with Windows Forms) that communicate with each other. The user interface includes an instance of the Shockwave Flash ActiveX control, within which the SWF file containing the ActionScript IM client is loaded. The interface also includes several text fields that make up the Windows Forms IM client: a field for entering messages (MessageText), another that displays the transcript of the messages sent between the clients (Transcript), and a third (Status) that displays the availability status as set in the SWF IM client.

Including the Shockwave Flash ActiveX control

To include the Shockwave Flash ActiveX control in your own Windows Forms application, you must first add it to the Microsoft Visual Studio Toolbox.

To add the control to the toolbox:

  1. Open the Visual Studio Toolbox.

  2. Right-click the Windows Forms section in Visual Studio 2003 or any section in Visual Studio 2005. From the context menu select Add/Remove Items in Visual Studio 2003 (Choose Items... in Visual Studio 2005).

    This opens the Customize Toolbox (2003)/Choose Toolbox Items (2005) dialog box.

  3. Select the COM Components tab, which lists all of the available COM components on your computer, including the Flash Player ActiveX control.

  4. Scroll to Shockwave Flash Object and select it.

    If this item is not listed, make sure that the Flash Player ActiveX control is installed on your system.

Understanding ActionScript to ActiveX container communication

Communication using the external API with an ActiveX container application works like communication with a web browser, with one important difference. As described earlier, when ActionScript communicates with a web browser, as far as the developer is concerned, the functions are called directly; the details of how the function calls and responses are formatted to pass them between the player and browser are hidden. However, when the external API is used to communicate with an ActiveX container application, Flash Player sends messages (function calls and return values) to the application in a specific XML format, and it expects function calls and return values from the container application to use the same XML format. The developer of the ActiveX container application must write code that understands and can create function calls and responses in the appropriate format.

The Introvert IM C# example includes a set of classes that allow you to avoid formatting messages; instead, you can work with standard data types when calling ActionScript functions and receiving function calls from ActionScript. The ExternalInterfaceProxy class, together with other helper classes, provides this functionality, and can be reused in any .NET project to facilitate external API communication.

The following sections of code, excerpted from the main application form (AppForm.cs), demonstrate the simplified interaction that is achieved by using the ExternalInterfaceProxy class:

public class AppForm : System.Windows.Forms.Form 
{ 
    ... 
    private ExternalInterfaceProxy proxy; 
    ... 
    public AppForm() 
    { 
        ... 
        // Register this app to receive notification when the proxy receives 
        // a call from ActionScript. 
        proxy = new ExternalInterfaceProxy(IntrovertIMApp); 
        proxy.ExternalInterfaceCall += new ExternalInterfaceCallEventHandler(proxy_ExternalInterfaceCall); 
        ... 
    } 
    ...

The application declares and creates an ExternalInterfaceProxy instance named proxy, passing in a reference to the Shockwave Flash ActiveX control that is in the user interface (IntrovertIMApp). Next, the code registers the proxy_ExternalInterfaceCall() method to receive the proxy’s ExternalInterfaceCall event. This event is dispatched by the ExternalInterfaceProxy class when a function call comes from Flash Player. Subscribing to this event is the way the C# code receives and responds to function calls from ActionScript.

When a function call comes from ActionScript, the ExternalInterfaceProxy instance (proxy) receives the call, converts it from XML format, and notifies the objects that are listeners for the proxy’s ExternalInterfaceCall event. In the case of the AppForm class, the proxy_ExternalInterfaceCall() method handles that event, as follows:

    /// <summary> 
    /// Called by the proxy when an ActionScript ExternalInterface call 
    /// is made by the SWF 
    /// </summary> 
    private object proxy_ExternalInterfaceCall(object sender, ExternalInterfaceCallEventArgs e) 
    { 
        switch (e.FunctionCall.FunctionName) 
        { 
            case "isReady": 
                return isReady(); 
            case "setSWFIsReady": 
                setSWFIsReady(); 
                return null; 
            case "newMessage": 
                newMessage((string)e.FunctionCall.Arguments[0]); 
                return null; 
            case "statusChange": 
                statusChange(); 
                return null; 
            default: 
                return null; 
        } 
    } 
    ...

The method gets passed an ExternalInterfaceCallEventArgs instance, named e in this example. That object, in turn, has a FunctionCall property that is an instance of the ExternalInterfaceCall class.

An ExternalInterfaceCall instance is a simple value object with two properties. The FunctionName property contains the function name specified in the ActionScript ExternalInterface.Call() statement. If any parameters are added in ActionScript, those parameters are included in the ExternalInterfaceCall object’s Arguments property. In this case, the method that handles the event is simply a switch statement that acts like a traffic manager. The value of the FunctionName property (e.FunctionCall.FunctionName) determines which method of the AppForm class is called.

The branches of the switch statement in the previous code listing demonstrate common method call scenarios. For instance, any method must return a value to ActionScript (for example, the isReady() method call) or else should return null (as seen in the other method calls). Accessing parameters passed from ActionScript is demonstrated in the newMessage() method call (which passes along a parameter e.FunctionCall.Arguments[0], the first element of the Arguments array).

Calling an ActionScript function from C# using the ExternalInterfaceProxy class is even more straightforward than receiving a function call from ActionScript. To call an ActionScript function, you use the ExternalInterfaceProxy instance’s Call() method, as follows:

    /// <summary> 
    /// Called when the "Send" button is pressed; the value in the 
    /// MessageText text field is passed in as a parameter. 
    /// </summary> 
    /// <param name="message">The message to send.</param> 
    private void sendMessage(string message) 
    { 
        if (swfReady) 
        { 
            ... 
            // Call the newMessage function in ActionScript. 
            proxy.Call("newMessage", message); 
        } 
    } 
    ... 
    /// <summary> 
    /// Call the ActionScript function to get the current "availability" 
    /// status and write it into the text field. 
    /// </summary> 
    private void updateStatus() 
    { 
        Status.Text = (string)proxy.Call("getStatus"); 
    } 
    ... 
}

As this example shows, the ExternalInterfaceProxy class’s Call() method is very similar to its ActionScript counterpart, ExternalInterface.Call(). The first parameter is a string, the name of the function to call. Any additional parameters (not shown here) are passed along to the ActionScript function. If the ActionScript function returns a value, that value is returned by the Call() method (as seen in the previous example).

Inside the ExternalInterfaceProxy class

Using a proxy wrapper around the ActiveX control may not always be practical, or you may wish to write your own proxy class (for instance, in a different programming language or targeting a different platform). Although not all the details of creating a proxy will be explained here, it is instructive to understand the inner workings of the proxy class in this example.

You use the Shockwave Flash ActiveX control’s CallFunction() method to call an ActionScript function from the ActiveX container using the external API. This is shown in this extract from the ExternalInterfaceProxy class’s Call() method:

// Call an ActionScript function on the SWF in "_flashControl", 
// which is a Shockwave Flash ActiveX control. 
string response = _flashControl.CallFunction(request);

In this code excerpt, _flashControl is the Shockwave Flash ActiveX control. ActionScript function calls are made using the CallFunction() method. That method takes one parameter (request in the example), which is a string containing XML-formatted instructions including the name of the ActionScript function to call and any parameters. Any value returned from ActionScript is encoded as an XML-formatted string and sent back as the return value of the CallFunction() call. In this example, that XML string is stored in the response variable.

Receiving a function call from ActionScript is a multistep process. Function calls from ActionScript cause the Shockwave Flash ActiveX control to dispatch its FlashCall event, so a class (such as the ExternalInterfaceProxy class) that intends to receive calls from a SWF file needs to define a handler for that event. In the ExternalInterfaceProxy class, the event handler function is named _flashControl_FlashCall(), and it is registered to listen for the event in the class constructor, as follows:

private AxShockwaveFlash _flashControl; 
 
public ExternalInterfaceProxy(AxShockwaveFlash flashControl) 
{ 
    _flashControl = flashControl; 
    _flashControl.FlashCall += new _IShockwaveFlashEvents_FlashCallEventHandler(_flashControl_FlashCall); 
} 
... 
private void _flashControl_FlashCall(object sender, _IShockwaveFlashEvents_FlashCallEvent e) 
{ 
    // Use the event object's request property ("e.request") 
    // to execute some action. 
    ... 
    // Return a value to ActionScript; 
    // the returned value must first be encoded as an XML-formatted string. 
    _flashControl.SetReturnValue(encodedResponse); 
}

The event object (e) has a request property (e.request) that is a string containing information about the function call, such as the function name and parameters, in XML format. This information can be used by the container to determine what code to execute. In the ExternalInterfaceProxy class, the request is converted from XML format to an ExternalInterfaceCall object, which provides the same information in a more accessible form. The ActiveX control’s SetReturnValue() method is used to return a function result to the ActionScript caller; once again, the result parameter must be encoded in the XML format used by the external API.

Communication between ActionScript and an application hosting the Shockwave Flash ActiveX control uses a specific XML format to encode function calls and values. In the Introvert IM C# example, the ExternalInterfaceProxy class makes it possible for the code in the application form to operate directly on values sent to or received from ActionScript, and ignore the details of the XML format used by Flash Player. In order to accomplish this, the ExternalInterfaceProxy class uses the methods of the ExternalInterfaceSerializer class to actually translate the XML messages into .NET objects. The ExternalInterfaceSerializer class has four public methods:

  • EncodeInvoke(): Encodes a function name and a C# ArrayList of arguments into the appropriate XML format.

  • EncodeResult(): Encodes a result value into the appropriate XML format.

  • DecodeInvoke(): Decodes a function call from ActionScript. The FlashCall event object’s request property is passed to the DecodeInvoke() method, and it translates the call into an ExternalInterfaceCall object.

  • DecodeResult(): Decodes the XML received as the result of calling an ActionScript function.

These methods encode C# values into the external API’s XML format and decode the XML into C# objects. For details on the XML format used by Flash Player, see The external API’s XML format.