Home Tutorials Forums Articles Blogs Movies Library Employment Press
Old 02-09-2010, 05:17 AM   #1
web developer
Senior Member
 
Join Date: Sep 2008
Posts: 147
Default Access method from an embedded SWF

Hi,

It is possible to access a method in an embedded SWF? For example, here's the SWF that I want to embed:
Code:
package 
{
  import flash.display.Sprite;
  import flash.events.Event;
  
  /**
   * ...
   * @author 
   */
  public class Main2 extends Sprite 
  {
    
    public function Main2():void 
    {
      if (stage) init();
      else addEventListener(Event.ADDED_TO_STAGE, init);
    }
    
    private function init(e:Event = null):void 
    {
      removeEventListener(Event.ADDED_TO_STAGE, init);
      // entry point
    }
    
    public function load(str:String):void
    {
      trace(str);
    }
    
  }
}
And here's the parent SWF:
Code:
package 
{
  import flash.display.Sprite;
  import flash.events.Event;
  
  /**
   * ...
   * @author 
   */
  public class Main extends Sprite 
  {
    [Embed(source="../../ChildSWF/bin/ChildSWF.swf")]
    public var SWF:Class;
    
    public function Main():void 
    {
      if (stage) init();
      else addEventListener(Event.ADDED_TO_STAGE, init);
    }
    
    private function init(e:Event = null):void 
    {
      removeEventListener(Event.ADDED_TO_STAGE, init);
      
      var swf:Object = new SWF();
      swf.load("hello");
    }
  }
  
}
When I run this, I get the following exception:
ReferenceError: Error #1069: Property load not found on Main_SWF and there is no default value.

Is what I'm trying to do possible?
web developer is offline   Reply With Quote
Old 02-09-2010, 06:20 AM   #2
ASWC
Super Moderator
 
ASWC's Avatar
 
Join Date: Dec 2007
Location: Greenville, SC
Posts: 6,528
Default

it's possible and there's basically a dirty way which most people use and a clean way which I use (I'm not the only one of course).
Dirty way: Cast to MovieClip and take advantage of the dynamic property of MovieClip by calling a non existing method:
ActionScript Code:
var swf:movieClip = new SWF() as MovieClip;       swf.load("hello");//compiler can't tell you wrong so you succeed
Clean way: Make your swf a datatype and make sure the loading swf knows the type:

ActionScript Code:
//theorical  var swf:Main2 = new SWF() as Main2;       swf.load("hello");//compiler knows what's a Main2 and the call succeed
But more to the point that's where Interface can get into play:
ActionScript Code:
//theorical  var swf:Iloaded = new SWF() as Iloaded;       swf.load("hello");//compiler knows what's a Iloaded and the call succeed
__________________
aswebcreations
Super Duper!
ASWC is offline   Reply With Quote
Old 02-09-2010, 06:30 AM   #3
web developer
Senior Member
 
Join Date: Sep 2008
Posts: 147
Default

Thanks, I'll try out the "clean way."
However, I don't understand the difference between your last two examples.
web developer is offline   Reply With Quote
Old 02-09-2010, 06:34 AM   #4
ASWC
Super Moderator
 
ASWC's Avatar
 
Join Date: Dec 2007
Location: Greenville, SC
Posts: 6,528
Default

Quote:
Originally Posted by web developer View Post
I don't understand the difference between your last two examples.
An Interface is basically an empty class just enumerating the method signatures while a class like Main2 does enumerate the methods but provides also the implementation. So the difference between them is the file size that they generate. When you load an external swf you probably don't wnat to import in the loading swf the class that you already use in the loaded swf since that would mean having twice the same class and file size added. The Interface does not provide implementation and therefore is light weight.
__________________
aswebcreations
Super Duper!
ASWC is offline   Reply With Quote
Old 02-09-2010, 06:43 AM   #5
web developer
Senior Member
 
Join Date: Sep 2008
Posts: 147
Default

So have an interface that Main2 implements and cast to that instead of the Main2 class? This is a good idea but the interface class could become not generic if I want to have complex arguments passed to the method.
web developer is offline   Reply With Quote
Old 02-09-2010, 08:22 AM   #6
krayzeebean
Senior Member
 
Join Date: Feb 2006
Posts: 682
Default

The problem you're having is because when you embed a swf, it's not embedded as a MovieClip or Sprite, it's a MovieClipLoaderAsset. In your parent swf, change swf.load("hello") to swf.content.load("hello"). You may have to cast the content to an Object to access the load() method: Object(swf.content).load("hello");
krayzeebean is offline   Reply With Quote
Old 02-09-2010, 10:19 AM   #7
henke37
Senior Member
 
henke37's Avatar
 
Join Date: Mar 2009
Location: Sweden
Posts: 11,024
Send a message via Skype™ to henke37
Default

The Object class is already dynamic, the issue is not a compiler error. The error is due to the embed tag corrupting the embeded swf file by replacing the main timeline class. You can not use it like this. You need to embed it as a bytearray so that the compiler stops corrupting your data.
__________________
Signature: I wrote a pair of articles about the timeline.
henke37 is offline   Reply With Quote
Old 02-09-2010, 06:19 PM   #8
krayzeebean
Senior Member
 
Join Date: Feb 2006
Posts: 682
Default

Quote:
Originally Posted by henke37 View Post
The Object class is already dynamic, the issue is not a compiler error. The error is due to the embed tag corrupting the embeded swf file by replacing the main timeline class. You can not use it like this. You need to embed it as a bytearray so that the compiler stops corrupting your data.
You do not need to embed it as a byte array. What I said above is true; when you embed a swf the way he did it is not corrupt, it is a MovieClipLoaderAsset, which is a Loader added to a MovieClip: http://livedocs.adobe.com/flex/3/lan...aderAsset.html The Loader contains your embedded swf.

I did make a mistake in my code though, the first child is the loader, so in the example above you would use Loader(swf.getChildAt(0)).content.load("hello"); Before you access the content you also need to have an event listener that either listens for the COMPLETE event, or use an ENTER_FRAME event to wait a couple frames. When you embed swf's this way I have found the ENTER_FRAME to be more reliable. There was a discussion about this a couple weeks ago, embedding as a byte array will always work correctly with a COMPLETE, but a MovieClipLoaderAsset doesn't, at least not in my experience...that's why I use ENTER_FRAME.

Here is a simple example of how to get at the content of your embedded swfs: http://www.bit-101.com/blog/?p=1435

Last edited by krayzeebean; 02-09-2010 at 09:39 PM. Reason: clarification
krayzeebean is offline   Reply With Quote
Old 02-10-2010, 04:41 AM   #9
web developer
Senior Member
 
Join Date: Sep 2008
Posts: 147
Default

What ASWC suggested did not work for me.

I am also not able to get krayzeebean's suggestion to work:
ActionScript Code:
package {   import adobe.utils.CustomActions;   import flash.display.Loader;   import flash.display.MovieClip;   import flash.display.Sprite;   import flash.display.SWFVersion;   import flash.events.Event;   import flash.events.IOErrorEvent;   import flash.net.URLRequest;   import local.ChildSWF;     /**    * ...    * @author    */   public class Main extends Sprite   {     [Embed(source="../../ChildSWF/bin/ChildSWF.swf")]     public var SWF:Class;     public static const NUM_FRAMES:int = 5;     public var m_numFrames:int;         public function Main():void     {       m_numFrames = 0;       if (stage) init();       else addEventListener(Event.ADDED_TO_STAGE, init);     }         private function init(e:Event = null):void     {       removeEventListener(Event.ADDED_TO_STAGE, init);             addEventListener(Event.ENTER_FRAME, enterFrame);     }         public function enterFrame(e:Event):void     {       m_numFrames++;             if (m_numFrames == NUM_FRAMES)       {         removeEventListener(Event.ENTER_FRAME, enterFrame);               var swf:Sprite = new SWF();         //Object(swf.getChildAt(0)).print("hello");         //Loader(swf.getChildAt(0)).content.print("hello");       }     }   }   }

If I uncomment out Object(swf.getChildAt(0)).print("hello");, I get the following runtime error:
ReferenceError: Error #1069: Property print not found on flash.display.Loader and there is no default value.

If I uncomment out Loader(swf.getChildAt(0)).content.print("hello"); I get a compilation error saying that the "print" method is not defined.
web developer is offline   Reply With Quote
Old 02-10-2010, 06:50 AM   #10
krayzeebean
Senior Member
 
Join Date: Feb 2006
Posts: 682
Default

You need to cast the content as Object. It is a DisplayObject, which of course doesnt' have your print() function so Flash is giving you a compile error. You also need to instantiate the SWF class in your init function. The enter frame event is to give it enough time to initialize. Getting to your print() function can be done in fewer lines, but I've broken it up to (hopefully) make it a little clearer.

ActionScript Code:
package {   import adobe.utils.CustomActions;   import flash.display.Loader;   import flash.display.MovieClip;   import flash.display.Sprite;   import flash.display.SWFVersion;   import flash.events.Event;   import flash.events.IOErrorEvent;   import flash.net.URLRequest;   import local.ChildSWF;     /**    * ...    * @author    */   public class Main extends Sprite   {     [Embed(source="../../ChildSWF/bin/ChildSWF.swf")]     public var SWF:Class;     public static const NUM_FRAMES:int = 5;     public var m_numFrames:int;     private var swf:Sprite;     private var embeddedContent:Sprite;         public function Main():void     {       m_numFrames = 0;       if (stage) init();       else addEventListener(Event.ADDED_TO_STAGE, init);     }         private function init(e:Event = null):void     {       removeEventListener(Event.ADDED_TO_STAGE, init);       swf = new SWF();       addEventListener(Event.ENTER_FRAME, enterFrame);     }         public function enterFrame(e:Event):void     {       m_numFrames++;             if (m_numFrames == NUM_FRAMES)       {         removeEventListener(Event.ENTER_FRAME, enterFrame);         var loader:Loader = swf.getChildAt(0) as Loader;         embeddedContent = loader.content as Sprite;         addChild(embeddedContent);         Object(embeddedContent).print("hello");       }     }   }   }
krayzeebean is offline   Reply With Quote
Reply


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 07:01 AM.

///
Follow actionscriptorg on Twitter

 


Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Ad Management plugin by RedTyger
Copyright 2000-2013 ActionScript.org. All Rights Reserved.
Your use of this site is subject to our Privacy Policy and Terms of Use.