Comunicación entre películas de Flash

9 de octubre de 2005

Buenas…ya son las 8.
Ayer nos quedamos con el esquema de comunicación de las distintas partes de nuestra aplicación. Nos quedaba por aclarar la comunicación entre películas, que pasaremos a describir ahora.
En condiciones normales solo tendríamos que usar el objeto LocalConnect de Flash para establecer una comunicación entre dos películas, en la documentación de Flash hay un ejemplo donde viene todo explicado con claridad.
Como me gusta complicarme la vida, estoy usando NeoSwiff para programar. En los espacios de nombres de NeoSwiff encontramos dos objetos System.Net.LocalSender y System.Net.LocalReceiver que parecen cumplir las funciones de LocalConnect. Desgraciadamente el NeoSwiff esta aún en desarrollo, la documentacion del SDK es practicamente nula y no he conseguido echar a andar la comunicación entre dos películas utilizándolos. Pero como el NeoSwiff tiene sus cosas útiles me he resistido a abandonarlo, he investigado un poco y he encontrado la manera de superar este escollo.

Para establecer la comunicación entre dos películas sin utilizar los objetos LocalSender ni LocalReceiver lo que haremos será embeber una película Flash en nuestro código de NeoSwiff (ver ejemplo “interop” del NeoSwiff). En esta película pondremos la función de recibir mensajes creando un LocalConnection, y haremos que llamé a un método de nuestro código en C#.

Receiver.fla (código en el primer fotograma):


stop();
var lcReceiver= new LocalConnection();
var datos:Array= new Array(3);
lcReceiver.Receive= function(dato1, dato2,dato3)
{
trace(“Mensaje recibido ” + dato1 +”,” + dato2);
datos[1]=dato1;
datos[2]=dato2;
datos[3]=dato3;
_root.Receiver_OnReceived();
}
function Connect(canal:String)
{
lcReceiver.connect(canal);
}

frmReceiver.ccs:


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Net;
using System.Native;
using System.Diagnostics;

namespace LCReceiver
{
public class frmPpal : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;

private bool escuchandoReceiver=false;
static private AsyncMovieBox movie= new AsyncMovieBox();

public frmPpal()
{
InitializeComponent();

}

private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(50, 50);
this.button1.Name=”button1″;
this.button1.Text = “Escucha”;
this.button1.Click +=new System.EventHandler(this.button1_Click);

//
// frmPpal
//
this.Controls.Add(this.button1);
this.Text =”frmPpal”;
this.ResumeLayout(false);

}

static void Main()
{
//
// TODO: Add application logic here
//
Application.Run( new frmPpal() );
}
private void button1_Click(object sender, System.EventArgs e)
{
//Cargamos la película de recepción
movie.Location= new Point(20,50);
this.Controls.Add(movie);
movie.MovieLocation=”../../fla/Receiver.swf”;
movie.LoadStateChanged += new EventHandler(on_load);
this.button1.Enabled=false;

}
private void on_load(object sender, EventArgs e)
{
movie= (AsyncMovieBox) sender;
Debug.WriteLine(“LoadState:”+movie.LoadState);
if( movie.LoadState == LoadState.Error )
{
Debug.WriteLine(“Falló al cargar la película externa.”);
return;
}

if( movie.LoadState != LoadState.Completed )
return;

object native_obj=movie.NativeMovie;
NativeAccess.Invoke( native_obj, “Connect”, “canalTest”);
this.button1.Text=”Escuchando”;

}
// Método de evento para la recepción de mensajes
// Este método es invocado por la película hija, cargada en la
// variable movie
static __export void Receiver_OnReceived()
{
object native_obj=movie.NativeMovie;
object array=NativeAccess.GetProperty(native_obj,”datos”);
Debug.WriteLine(“Mensaje Recibido”);
Debug.WriteLine(“Native Array length:”+((int)NativeAccess.GetProperty(array,”length”)) );
Debug.WriteLine(“Native Array [1]: ‘”+((string)NativeAccess.GetElement(array,1))+”‘” );
Debug.WriteLine(“Native Array [2]: ‘”+((string)NativeAccess.GetElement(array,2))+”‘” );
Debug.WriteLine(“Native Array [3]: ‘”+((string)NativeAccess.GetElement(array,3))+”‘” );
}

}
}

En este ejemplo podemos ver dos elementos importantes.
En el código de la Receiver.fla tenemos el objeto LocalConnection, una matriz donde se almacenan los datos recibidos, y la llamada a la función Receiver_OnReceived. Esto llamará la función de lectura de datos en nuestra película padre.
En el código de frmReceiver la cosa es un poco más compleja.Al pulsar el botón cargamos la película en la propiedad static movie, y enlazamos el evento LoadStateChanged con nuestro método on_load. Cada vez que se produzca un cambio de estado en la carga de la película verificamos si ha terminado, y si es así llamamos a su método Connect pasandole el nombre que queremos que tenga el canal de comunicación.
Cuando Receiver.fla reciba un mensaje llamará al método Receiver_OnReceived, que nos mostrará en la ventana de depuración los resultados.

Para probarlo todo junto solo nos falta el emisor:

Sender.fla:

stop();
var lcSender:LocalConnection = new LocalConnection();
lcSender.send("canalTest","Receive","1","2","3");

Este código va en el primer fotograma de la película. Crea la conexión con el Receiver.fla, y llama a su método Receiver con los datos.

Para verlo todo junto compilamos frmReceiver.ccs con el NeoSwiff y lo ejecutamos. Pulsamos su botón de Escucha, y empezará a cargar la película Receiver.fla. Cuando termine ejecutamos Sender.fla y veremos los datos ir de una película a otra.

Mañana otro pasito más, y decisivo: La carga del fichero al servidor.

  • qrcode link