Ejemplo de API externa: Comunicación entre ActionScript y una aplicación de escritorio que utiliza el control ActiveX

Flash Player 9 y posterior

En este ejemplo se muestra el uso de la API externa para establecer una comunicación entre ActionScript y una aplicación de escritorio que usa el control ActiveX. Para el ejemplo se reutiliza la aplicación Introvert IM, incluido el código ActionScript e incluso el mismo archivo SWF y, por lo tanto, no se describe el uso de la API externa en ActionScript. Para entender este ejemplo, resultará de utilidad estar familiarizado con el anterior.

La aplicación de escritorio de este ejemplo se ha escrito en C# con Microsoft Visual Studio .NET. El análisis se centra en las técnicas específicas para trabajar con la API externa usando el control ActiveX. En este ejemplo se muestran los siguientes procedimientos:

  • Llamar a funciones ActionScript desde una aplicación de escritorio que aloja el control ActiveX de Flash Player.

  • Recibir llamadas a funciones desde ActionScript y procesarlas en un contenedor ActiveX.

  • Utilizar una clase proxy para ocultar los detalles del formato XML serializado que utiliza Flash Player para los mensajes enviados a un contenedor ActiveX.

Para obtener los archivos de la aplicación de este ejemplo, consulte www.adobe.com/go/learn_programmingAS3samples_flash_es. Los archivos C# de Introvert IM se encuentran en la carpeta Samples/IntrovertIM_CSharp. La aplicación consta de los siguientes archivos:

Archivo

Descripción

AppForm.cs

El archivo de aplicación principal con la interfaz Windows Forms en C#.

bin/Debug/IntrovertIMApp.swf

El archivo SWF que carga la aplicación.

ExternalInterfaceProxy/ExternalInterfaceProxy.cs

La clase que actúa como envolvente del control ActiveX para la comunicación con la interfaz externa. Proporciona mecanismos para llamar y recibir llamadas desde ActionScript.

ExternalInterfaceProxy/ExternalInterfaceSerializer.cs

La clase que realiza la tarea de convertir los mensajes en formato XML de Flash Player en objetos .NET.

ExternalInterfaceProxy/ExternalInterfaceEventArgs.cs

Este archivo define dos tipos C# (clases): una clase de delegado personalizada y una clase de argumentos de evento, ambas utilizadas por la clase ExternalInterfaceProxy para notificar a un detector la existencia de una llamada a función desde ActionScript.

ExternalInterfaceProxy/ExternalInterfaceCall.cs

Esta clase es un valor de objeto que representa una llamada a una función desde ActionScript al contenedor ActiveX, con propiedades para el nombre de función y los parámetros.

bin/Debug/IntrovertIMApp.swf

El archivo SWF que carga la aplicación.

obj/AxInterop.ShockwaveFlashObjects.dll,

obj/Interop.ShockwaveFlashObjects.dll

Ensamblados de envolventes creados por Visual Studio .NET que son necesarios para acceder al control ActiveX de Flash Player (Adobe Shockwave® Flash) desde el código administrado.

Información general de la aplicación Introvert IM escrita en C#

Esta aplicación de ejemplo representa dos programas cliente de mensajería instantánea (uno dentro de un archivo SWF y otro creado con Windows Forms) que se comunican entre sí. La interfaz de usuario incluye una instancia del control ActiveX de Shockwave Flash, dentro del cual se carga el archivo SWF que contiene el cliente de mensajería instantánea de ActionScript. La interfaz también incluye varios campos de texto que conforman el cliente de mensajería instantánea de Windows Forms: un campo para introducir mensajes (MessageText), otro que muestra la transcripción de los mensajes enviados entre clientes (Transcript) y un tercero (Status) que indica el estado de disponibilidad tal y como se establece en el cliente de mensajería instantánea del archivo SWF.

Inclusión del control ActiveX de Shockwave Flash

Para incluir el control ActiveX de Shockwave Flash en una aplicación de Windows Forms, en primer lugar es necesario añadirlo al cuadro de herramientas de Microsoft Visual Studio.

Para añadir el control al cuadro de herramientas:

  1. Abra el cuadro de herramientas de Visual Studio.

  2. Haga clic con el botón derecho en la sección Windows Forms en Visual Studio 2003 o en cualquier sección en Visual Studio 2005. En el menú contextual, seleccione Agregar o quitar elementos en Visual Studio 2003 (Elegir elementos... en Visual Studio 2005).

    Se abrirá el cuadro de diálogo Personalizar cuadro de herramientas (2003)/Elegir elementos del cuadro de herramientas (2005).

  3. Seleccione la ficha Componentes COM, en la que aparecen todos los componentes COM disponibles en el equipo, incluido el control ActiveX de Flash Player.

  4. Desplácese hasta el objeto Shockwave Flash y selecciónelo.

    Si este elemento no aparece en la lista, compruebe que el control ActiveX de Flash Player está instalado en el equipo.

Aspectos básicos de la comunicación entre ActionScript y el contenedor ActiveX

El funcionamiento de la comunicación a través de la API externa con una aplicación contenedora ActiveX es igual que el del la comunicación con un navegador web, con una diferencia importante. Según se expuso anteriormente, cuando ActionScript se comunica con un navegador web, por lo que respecta al desarrollador, las funciones se llaman directamente; los detalles sobre el modo en que se da formato a las llamadas a funciones y a las respuestas para pasarlas entre el reproductor y el navegador quedan ocultas. No obstante, cuando se utiliza la API externa para comunicarse con una aplicación contenedora ActiveX, Flash Player envía mensajes (llamadas a funciones y valores devueltos) a la aplicación en un formato XML específico y espera que las llamadas a funciones y valores devueltos por la aplicación contenedora tengan el mismo formato XML. El desarrollador de la aplicación contenedora ActiveX debe escribir código que entienda y pueda crear llamadas a funciones y respuestas con el formato adecuado.

El ejemplo de Introvert IM en C# incluye un conjunto de clases que permiten evitar la tarea de dar formato a los mensajes; en vez de eso, es posible trabajar con tipos de datos estándar al llamar a funciones ActionScript y recibir llamadas a funciones desde ActionScript. La clase ExternalInterfaceProxy, junto con otras clases auxiliares, proporcionan esta funcionalidad y se pueden reutilizar en cualquier proyecto .NET para facilitar la comunicación con la API externa.

Las siguientes secciones de código son extractos del formulario de aplicación principal (AppForm.cs) que muestran la interacción simplificada que se logra utilizando la clase ExternalInterfaceProxy:

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); 
        ... 
    } 
    ...

La aplicación declara y crea una instancia de ExternalInterfaceProxy llamada proxy, que pasa una referencia al control ActiveX de Shockwave Flash que se encuentra en la interfaz de usuario (IntrovertIMApp). A continuación, el código registra el método proxy_ExternalInterfaceCall() para recibir el evento ExternalInterfaceCall del proxy. La clase ExternalInterfaceProxy distribuye este evento cuando llega una llamada a una función desde Flash Player. Al suscribirse a este evento, el código C# puede recibir llamadas a funciones (y responderlas) desde ActionScript.

Cuando llega una llamada a una función desde ActionScript, la instancia de ExternalInterfaceProxy (proxy) recibe la llamada, convierte el formato XML y notifica a los objetos que son detectores del evento ExternalInterfaceCall de proxy. En el caso de la clase AppForm, el método proxy_ExternalInterfaceCall() gestiona ese evento del modo siguiente:

    /// <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; 
        } 
    } 
    ...

El método pasa una instancia de ExternalInterfaceCallEventArgs llamada e en este ejemplo. Ese objeto, a su vez, tiene una propiedad FunctionCall que es una instancia de la clase ExternalInterfaceCall.

Una instancia de ExternalInterfaceCall es un valor de objeto sencillo con dos propiedades. La propiedad FunctionName contiene el nombre de la función especificado en la sentencia ExternalInterface.Call() de ActionScript. Si se añaden más parámetros en ActionScript, éstos se incluirán en la propiedad Arguments del objeto ExternalInterfaceCall. En este caso, el método que gestiona el evento es simplemente una sentencia switch que actúa como un controlador de tráfico. El valor de la propiedad FunctionName (e.FunctionCall.FunctionName) determina el método de la clase AppForm al que se llamará.

Las ramas de la sentencia switch del listado de código anterior muestran situaciones comunes de llamadas a métodos. Por ejemplo, todo método debe devolver un valor a ActionScript (por ejemplo, la llamada al método isReady()) o bien devolver null (según se muestra en las demás llamadas a métodos). En la llamada al método newMessage() (que pasa un parámetro e.FunctionCall.Arguments[0], es decir, el primer elemento del conjunto Arguments) se muestra el acceso a los parámetros pasados desde ActionScript.

Llamar a una función de ActionScript desde C# utilizando la clase ExternalInterfaceProxy es aún más sencillo que recibir una llamada a una función desde ActionScript. Para llamar a una función de ActionScript se utiliza el método Call() de la instancia de ExternalInterfaceProxy de la siguiente forma:

    /// <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"); 
    } 
    ... 
}

Como muestra este ejemplo, el método Call() de la clase ExternalInterfaceProxy es muy similar a su homólogo de ActionScript, ExternalInterface.Call(). El primer parámetro es una cadena, el nombre de la función que se va a llamar. Los parámetros adiciones (que no se muestran aquí) se pasan también a la función de ActionScript. Si la función de ActionScript devuelve un valor, éste se devuelve mediante el método Call() (como puede verse en el ejemplo anterior).

Dentro de la clase ExternalInterfaceProxy

Puede que no siempre sea práctico utilizar un envolvente de proxy en torno al control ActiveX o bien el desarrollador puede desear escribir su propia clase proxy (por ejemplo, en un lenguaje de programación diferente u orientado a una plataforma distinta). Si bien aquí no se explican todos los detalles sobre la creación de una clase proxy, resulta útil comprender el funcionamiento interno de la clase proxy en este ejemplo.

Se usa el método CallFunction() del control ActiveX de Shockwave Flash para llamar a una función de ActionScript desde el contenedor ActiveX utilizando la API externa. Esto se muestra en el siguiente extracto del método Call() de la clase ExternalInterfaceProxy:

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

En este fragmento de código, _flashControl es el control ActiveX de Shockwave Flash. Para realzar las llamadas a funciones ActionScript se utiliza el método CallFunction(). Este método acepta un parámetro (request en el ejemplo), que es una cadena que contiene instrucciones en formato XML entre las que se incluye el nombre de la función de ActionScript que se llamará y los correspondientes parámetros. Todos los valores devueltos desde ActionScript se codifican como una cadena con formato XML y se envían como el valor devuelto de la llamada a CallFunction(). En este ejemplo, la cadena XML se almacena en la variable response.

Recibir una llamada a una función desde ActionScript es un proceso compuesto de varios pasos. Las llamadas a funciones desde ActionScript hacen que el control ActiveX de Shockwave Flash distribuya su evento FlashCall, de modo que una clase (como la clase ExternalInterfaceProxy) diseñada para recibir llamadas desde un archivo SWF tiene que definir un controlador para ese evento. En la clase ExternalInterfaceProxy, la función de controlador de eventos se llama _flashControl_FlashCall() y está registrada para detectar el evento en el constructor de la clase del siguiente modo:

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); 
}

El objeto de evento (e) tiene una propiedad request (e.request) que es una cadena que contiene información en formato XML acerca de la llamada a la función, como el nombre de la función y los parámetros. El contenedor puede utilizar esta información para determinar qué código se debe ejecutar. En la clase ExternalInterfaceProxy, request se convierte del formato XML a un objeto ExternalInterfaceCall, que proporciona la misma información con un formato más accesible. El método SetReturnValue() del control ActiveX se utiliza para devolver el resultado de una función al elemento que origina la llamada en ActionScript; de nuevo, el parámetro del resultado debe estar codificado en el formato XML utilizado por la API externa.

En la comunicación entre ActionScript y la aplicación que aloja el control ActiveX de Shockwave Flash se utiliza un formato XML específico para codificar las llamadas a las funciones y los valores. En el ejemplo en C# de Introvert IM, la clase ExternalInterfaceProxy posibilita que el código del formulario de la aplicación opere directamente sobre los valores enviados o recibidos desde ActionScript e ignore los detalles del formato XML utilizado por Flash Player. Para lograrlo, la clase ExternalInterfaceProxy usa los métodos de la clase ExternalInterfaceSerializer para convertir los mensajes XML en objetos .NET. La clase ExternalInterfaceSerializer tiene cuatro métodos públicos:

  • EncodeInvoke(): codifica el nombre de una función y una lista de argumentos ArrayList de C# con el formato XML adecuado.

  • EncodeResult(): codifica un valor de resultado con el formato XML apropiado.

  • DecodeInvoke(): descodifica una llamada de función desde ActionScript. La propiedad request del objeto de evento FlashCall se pasa al método DecodeInvoke(), que convierte la llamada en un objeto ExternalInterfaceCall.

  • DecodeResult(): descodifica los datos XML recibidos como resultado de llamar a una función de ActionScript.

Estos métodos codifican valores de C# en el formato XML de la API externa y descodifica el XML para transformarlo en objetos de C#. Para obtener información sobre el formato XML utilizado por Flash Player, consulte Formato XML de la API externa.