11 Replies Latest reply on Sep 14, 2007 7:21 AM by JamesAZaun

    Calling functions / setting variables in loaded SWF

    ScottEOsborn
      You know how you can create a Movieclip object, add a function or variable to it, then call that function or change that variable from within the SWF that includes it? I wanna be able to do that, only with SWFs that are loaded at run time.

      My "main" SWF is simply a menu-type thing. The user clicks a button in my MAIN.SWF, and the MAIN.SWF then loads the SWF that's associated with that button, using the AS 3.0 prescribed Loader()-URLRequest()-addChild() method that everyone always asks about.

      This works great. But now I've got some custom objects and such (ie., not just strings) within my MAIN.SWF that I'd like to be able to share with the loaded SWFs. Preferably, I'd like to use an accessor-type function (ie., LoadedSWF.GiveMeTheCoolObject(MyCoolObject);), though at this point I'm willing to hack into the object itself (ie., LoadedSWF.CoolObject.CoolField = MyCoolObject.CoolField;) if that's what it takes.

      I've tried just calling the functions and setting the fields, but the AS 3.0 compiler doesn't care for that sort of nonsense on it's generically-defined objects. Notice also that, at run time, a call to LoadedSWF.hasOwnObject("GiveMeTheCoolObject") returns true.

      So my big-brained colleagues, what's the magic?

      In advance, thanks for the help!
      Scott
        • 1. Re: Calling functions / setting variables in loaded SWF
          kglad Adobe Community Professional & MVP
          cast your loader's content property as a movieclip and you should be able to access the loaded swf's variables and functions like in as2, IF your loaded swf is also as3. if the loaded swf is as2 you'll need to use localconnection to communicate between as3 and as2 swf.
          • 2. Re: Calling functions / setting variables in loaded SWF
            ScottEOsborn Level 1
            Kglad,

            First, thanks for the help!

            Secondly:

            > cast your loader's content property as a movieclip
            So... like this?

            //Not that familiar with casting in AS3: Is this line correct?
            var LoadedSWF:MovieClip = LoadedSWFObj.content as MovieClip;

            //Won't the compiler compain about this? The LoadedSWF is within a different FLA file,
            //though both the loader and loadee have access to the source for MyCoolObject (within a .AS file).
            LoadedSWF.GiveMeTheCoolObject(MyCoolObject);)

            (Not within Flash CS3 at the moment, hence the questions within the comments above.)

            Thanks again,
            Scott
            • 3. Re: Calling functions / setting variables in loaded SWF
              kglad Adobe Community Professional & MVP
              that's one way to do it.
              • 4. Re: Calling functions / setting variables in loaded SWF
                ScottEOsborn Level 1
                quote:

                Originally posted by: kglad
                that's one way to do it.



                Thanks for the response. But if you could clarify:

                1) You didn't address this snippet:
                var LoadedSWF:MovieClip = LoadedSWFObj.content as MovieClip;
                LoadedSWF.GiveMeTheCoolObject(MyCoolObject);)

                When you said:
                > cast your loader's content property as a movieclip
                Does this code snippet represent what you're suggesting?

                2) You say "that's one way". Is there another way?

                Again, thanks for the help.
                • 6. Re: Calling functions / setting variables in loaded SWF
                  ScottEOsborn Level 1
                  Kglad,

                  Thanks, that compiles and runs, so we're getting somewheres!

                  Now, at the point when it calls the function (LoadedSWF.GiveMeTheCoolObject(MyCoolObject);), Flash throws an exception:

                  Error #1034: Type Coercion failed: cannot convert MyCoolObject@3441ac1 to MyCoolObject.

                  Hmmm. Sounds like a I'm missing out on some sort of linkage. Can I trouble you for hints on what to look for?

                  Again, thanks for the help, I'm much further after a few exchanges with you than all the hours I've spent pouring through the LiveDocs...

                  Scott
                  • 7. Re: Calling functions / setting variables in loaded SWF
                    kglad Adobe Community Professional & MVP
                    from that error message it appears your function is expecting a member of the MyCoolObject class, correct?

                    and MyCoolObject is not an instance of that class. so, you need to fix that. ie, create a member of that class and use that class member as the function parameter.
                    • 8. Re: Calling functions / setting variables in loaded SWF
                      ScottEOsborn Level 1
                      Kglad,
                      quote:

                      Originally posted by: kglad
                      from that error message it appears your function is expecting a member of the MyCoolObject class, correct?
                      and MyCoolObject is not an instance of that class. so, you need to fix that. ie, create a member of that class and use that class member as the function parameter.

                      Heh, that's what the error message says all right. But the object actually IS a MyCoolObject class object. I stared at this thing for hours, and MyCoolObject IS an instance of that class. I tried various casting combinations (including casting it to an Object and passing that) but had no luck whatsoever.

                      So I googled this particular runtime error message ("Error #1034: Type Coercion failed: cannot convert ") and found a ton of links to other people having a similar issue. Typically, the problem was just as you said, someone passing a button as a string, that kinda thing. But one guy had a problem with an object he derived from the Event class. After hours spent trying to get it to work, he tried overriding the base class' clone() method and got it to work:

                      http://www.asserttrue.com/articles/2006/10/14/custom-events-in-actionscript-3-0

                      As for my project, I took a long hard look at the overall architecture of my project and decided that it was best if all the "real work" took place in the MAIN.SWF file. This approach would solve a couple of other problems, and it just makes sense in a "separate the display from the data" mentality.

                      So (and this is the interesting part) I changed the API for the LOADED.SWF to accept String pairs (ie., LoadedSWF.AddToDisplay(Name:String, Data:String) ) instead of accepting MyCoolObj. Ran it, and Viola, now we're working without any run time exceptions. After that glorious moment, I created a couple of other APIs that just accepted base classes (one an int type, the other a function type) and was happily on my way.

                      From this, I gather that passing non-base class (ie, derived class) objects to loaded MovieClips via custom function APIs is... maybe not as straightforward as we'd expect. In the grand scheme of things though, not a big deal: As far as I'm concerned AS3 rocks.

                      Again Kglad, thanks for all the help: Your input on how to do this was the big push that I needed to get over the last technical hurdle of this project.

                      To those who are reading this topic for the "how do I call functions and/or set variables in a loaded SWF?"

                      The short answer is to cast the loaded SWF's content object as a MovieClip and then call the function or alter the variable:

                      //Load the SWF (you've seen this code a million times)
                      var LoadedSWFObj:Loader = new Loader();
                      var MyURL:URLRequest = new URLRequest("LoadThisSWF.SWF");
                      LoadedSWFObj.load(MyURL);

                      //This is within your Event.COMPLETE handler:

                      //Cast it as a MovieClip object and work with that.
                      var LoadedSWF:MovieClip = LoadedSWFObj.content as MovieClip;

                      // or another way to cast it is:
                      var LoadedSWF:MovieClip = MovieClip(LoadedSWFObj.content);

                      //Call yer function:
                      LoadedSWF.CallMe();
                      • 9. Re: Calling functions / setting variables in loaded SWF
                        kglad Adobe Community Professional & MVP
                        how can you have an object or instance with the same name as a class name? that's a problem.

                        you may have changed too many things to go back and test with a "proper" instance name, but if you haven't, i'm interested in learning if there's a problem passing a legit instance name.
                        • 10. Re: Calling functions / setting variables in loaded SWF
                          ScottEOsborn Level 1
                          > how can you have an object or instance with the same name as a class name? that's a problem.
                          You are right: In my posted code, the object instance was the name of my class. But those posts were pseudo code, not the actual code itself: I'm not always physically in a position where I can copy/paste from my FLA file.

                          > you may have changed too many things to go back and test with a "proper" instance name
                          > but if you haven't, i'm interested in learning if there's a problem passing a legit instance name.
                          I assure you, once I was in a position where I could, I checked and rechecked and rechecked the instance type and name. I am pretty confident I was not passing a class name or wrong type of object.

                          Still, coulda done something wrong, it's pretty common to pass the wrong label. After I get this out, I may go back and create a dummy project just to test this out. I'll post my findings here...
                          • 11. Re: Calling functions / setting variables in loaded SWF
                            JamesAZaun
                            This was helpful, but I'm having a similar issue sort of in reverse. I have two SWFs Plugin_A and Plugin_B where B loads A. The Document Classes for both SWFs are defined in a similar way:

                            package fc.plugins.A
                            {
                            import fc.plugins.IPlugin;
                            import fc.pluginFW.IPluginAdapter;
                            public class Plugin_A extends MovieClip implements IPlugin
                            {
                            public function set adapter(arg: IPluginAdapter): void { adapter = arg; }
                            }
                            }

                            package fc.plugins.B
                            {
                            import fc.plugins.IPlugin;
                            import fc.pluginFW.IPluginAdapter;
                            public class Plugin_B extends MovieClip implements IPlugin
                            {
                            public function set adapter(arg: IPluginAdapter): void { adapter = arg; }
                            }
                            }

                            Plugin_B loads Plugin_A via an adapter class (via a call in B not shown above). The adapter is define like this:

                            public class TwoPhasePluginAdapter extends EventDispatcher implements IPluginAdapter { ... }

                            Just before the adapter loads A into B, it requests that A be loaded into the same ApplicationDomain as B, like this:

                            var ldrContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);

                            After Plugin_A.swf is successfully loaded into Plugin_B.swf (on an Event.INIT), The adapter instance in B attempts to do two type coercions that both fail. And, I don't see why. First, I attempted to type cast the loaded "Plugin_A" SWF document class to IPlugin using a class reference:

                            var loaderInfo: LoaderInfo = LoaderInfo(evt.target); // works
                            var docClassRef: Class = loaderInfo.applicationDomain.getDefinition("fc.plugins.A.Plugin_A") as Class; // works
                            var plugin: IPlugin = new docClassRef() as IPlugin; // fails

                            getDefinition() succeeds but casting as IPlugin fails (i.e. var plugin is null). Why?

                            Second, I also attempt to pass the adapter, this, created in B to a setter defined in A. That is, I'm attempting to pass a reference in the B SWF back into the just loaded A SWF:

                            content = MovieClip(loaderInfo.content); // works
                            content.adapter = IPluginAdapter(this); // fails

                            This generates the runtime error: TypeError: Error #1034: Type Coercion failed: cannot convert fc.pluginFW.impl::TwoPhasePluginAdapter@103bd01 to fc.pluginFW.IPluginAdapter.

                            The thing is that TwoPhasePluginAdapter does implement IPluginAdapter, so why is this illegal? It seems like A is being treated as if it is in a separate ApplicationDomain even though I told the loader to share the same domain.

                            What is even weirder, is that the above code works just fine if I test within the Flash CS3 IDE, but fails when running the SWFs directly (by clicking on the SWFs directly). And stranger still, is that other plug-ins identically defined using the same framework code work no matter what but these specific two plug-ins always fail when run outside the IDE. This is very odd. I also tried to distill the essential code into a small testcase and the as bad luck would have it, it always works. I think my problem is somewhere else (maybe outside the code) but I have no idea where to look. Any suggestions?