I'm a lurker / first-time poster to this list but this is an advanced
issue. I think may be a bug in the Player or Flash libraries but maybe
I'm missing something.

I have an AIR application which needs to load multiple SWFs from the
filesystem. Once the SWFs are loaded, the AIR application needs to (1)
call a single method on the document base class of the SWF, then (2)
play the SWF such that the timeline displays correctly and the frame
scripts execute correctly.

The SWFs are authored in Flash CS3 and have a document base class,
which they all share. The base class implements an interface. The AIR
application knows about the interface. So it casts the MovieClip to
the interface to call the method.

If the AIR application loads the SWF file directly from the filesystem
(i.e. by passing the file path or a file:// URL into SWFLoader) then I
can't find a way to make the interface cast work. I get a "Security
sandbox violation" error. That seems to be consistent with the
documentation which says "Content in the air application security
sandbox cannot load content from other sandboxes into its
SecurityDomain." (In general, I find the security sandbox
documentation to be very confusing, but my interpretation is that this
is not expected to work.)

The workaround is to load the SWF myself into a ByteArray, then use
allowCodeBytesExecution to permit me to call methods, etc.

I have a SWFLoader that looks like this:

  <mx:SWFLoader id="mySWFLoader" autoLoad="false"
    visible="true" scaleContent="false" trustContent="true"
    complete="onSWFLoaderComplete(event);"/>

First my AIR application sets up the LoaderContext for the SWFLoader:

    var newDomain:ApplicationDomain = new ApplicationDomain();
    var myDomain:ApplicationDomain = ApplicationDomain.currentDomain;
    var childDomain:ApplicationDomain = ApplicationDomain(childDomain);
    var loaderContext:LoaderContext = 
        new LoaderContext(false, childDomain);
    loaderContext.allowLoadBytesCodeExecution = true;
    this.mySWFLoader.loaderContext = loaderContext;

Then I just load the SWF using AIR's FileStream class:

    var file:File = new File(path);
    var fileStream:FileStream = new FileStream();
    fileStream.open(file, FileMode.READ);
    var byteArray:ByteArray = new ByteArray();
    fileStream.readBytes(byteArray);
    fileStream.close();

Then I poke the content into the SWFLoader:

    this.mySWFLoader.load(byteArray);

And, once loading is complete, I execute the cast:

  private function onSWFLoaderComplete(event:Event):void {
    try {
      var myChild:ITestInterface =
          ITestInterface(this.mySWFLoader.content);
      myChild.someMethod();
      trace('Coersion to ITestInterface SUCCESSFUL');
    } catch (e:Error) {
      trace('Coersion to ITestInterface UNSUCCESSFUL');
    }
  }

This WORKS. Both of the things I amy trying to accomplish are
successful. (1) I am able to call the method someMethod() which is
defined in the interface and implemented in the document base class of
the SWF; and (2) when the SWF plays (which happens automatically once
it's loaded) it appears correctly on the stage, and the frame scripts
in the SWF execute correctly (I can verify in trace output).

HOWEVER, the NEXT time I load a SWF, something very strange happens.
The cast works, the method is called, the SWF is loaded and plays
correctly. __But it uses the frame scripts from the previous script,
not its own__.

So here's the sequence:
  (1) Load SWF A
  (2) SWF A is displayed correctly on the stage
  (3) I am able to call someMethod on SWF A
  (4) SWF A's frame scripts execute correctly
  (5) Load SWF B
  (6) SWF B is displayed correctly on the stage
  (7) I am able to call someMethod on SWF B
  (8) SWF A's frame scripts execute, but usually break because
      they are looking for symbols, etc. which aren't there.
      The frame scripts defined on SWF A are trying to execute
      in the context of SWF B.

Note that this does NOT appear to be a garbage collection issue
related to sharing the SWFLoader. Even if I use an entirely different
SWFLoader, the problem persists.

Furthermore, it ONLY persists if the SWFs share *Document Base Classes
of the same name*. If the Document Base Classes have different names
(but are identical code, implementing the same interface) then it
works fine.

I have read that frame scripts are actually handled as methods on the
MovieClip itself -- which makes sense. And what I am imagining
happening is that, when a loaded SWF has a document base class, those
methods are being applied to the base class *and all successive SWFs
loaded that use a document base class of the same name*. This seems
completely wrong. The SWFs are, in a sense *instances* of the base
class which could quite sensibly have different frame scripts. So I
*think* what's happening is that Flash Player is keeping some registry
of classes; when it loads a SWF it also loads the definition of the
class; it's adding the methods for the frame scripts to the definition
of the class; and when it loads another SWF with a base class of the
same name, it sees that it already "has" the definition and doesn't
bother looking at the frame scripts in the newly loaded SWF.

I keep thinking I'm way off base, and that there must be some simple
solution, but I really can't find it. 

Does *anyone* have any experience that might help?

Cheers,

Francis

Reply via email to