FSCommand and getURL Bug in Flash Player 9
 Posted on Tue Sep 11 2007 in Flash by Tim

There is a problem in the heart of the Flash 9 player. It eats unsuspecting FSCommands and getURL calls. This isn't a problem with any single call, this is a potential problem with every FSCommand or getURL call you make and if you don't know what to look for it can strike at any time. The problem exists in the Flash 9 standalone player, the Flash 9 ActiveX player (for IE) and the Flash 9 plugin (for Firefox).

You may be wondering why you haven't heard about this if it's such a big problem. Well, you probably have. You may have even run into it yourself, come up with a workaround and chalked it up to random weirdness in your project, like I almost did. Symptoms of this bug have been reported in all the major Flash/Flex discussion lists and forums. This bug is subtle, insidious, not simple to explain, but very easy to reproduce.

The Basic Problem

If you make two or more getURL (AS2) or navigateToURL (AS3) calls in the same frame, only one of the getURL calls will work, the others seem to be swallowed up by the Flash player, never to be seen again. Don't believe it? Try this simple example. In previous versions of the Flash player this would have opened two browser windows. In Flash 9, only one browser window appears and it's the one for the last getURL call to display northcode.com.

getURL("http://www.adobe.com", "_blank");
getURL("http://www.northcode.com", "_blank");

If you're targeting AS3 then you would use navigateToURL instead of getURL but the results are exactly the same.

navigateToURL(new URLRequest("http://www.adobe.com"), "_blank");
navigateToURL(new URLRequest("http://www.northcode.com"), "_blank");

How often have you added something like the following to the beginning of a CD project? If you create a projector in Flash CS3 using just the code below you might be surprised at the results. The movie will scale with the window as you resize it, but it will not be in fullscreen mode.

fscommand("fullscreen", "true");
fscommand("allowscale", "true");

The fullscreen command appears to have failed, but in reality the Flash player did not even execute the fullscreen command! That's a serious departure from how previous versions of the Flash player worked.

Although it's not easy to explain (yet) those are all symptoms of the exact same problem in the Flash 9 player. It looks like we've stumbled across some strange black hole that eats FSCommand and getURL calls!

A Black Hole?

Suppose you want to call some JavaScript functions from your SWF and you want to call them asynchronously. According to the documentation for FSCommand you can just do it like this.

fscommand("this", "");
fscommand("then", "");
fscommand("that", "");

Now if we add the code below to the web page that contains the SWF file, when an FSCommand call is triggered in Flash the command and parameter strings are passed to the myDocument_DoFSCommand. In this example the function just displays the command in a JavaScript alert box.

function myDocument_DoFSCommand(command, args)
{
alert(command);
}

If you put this example together and try it, the only alert box you will see will display that. Now you've probably had an a-ha! moment and figured out that only the last FSCommand in a frame is getting called. Life is never that simple.

Some Calls Escape!

Here's a final example to confound and amaze you. Let's make a slight modification to the previous example and add a parameter to one of the FSCommand calls and see what happens.

fscommand("this", "");
fscommand("then", "hello");
fscommand("that", "");

This example will produce two alert boxes, the first one will display that and the second one will display then! That's backward from the order they were called and the alert box for "this" is still missing!

The exact same behavior can be seen with getURL and navigateToURL. It doesn't matter what URL you use in your call, it's the other arguments that determine what happens. In the example below two browser windows will be opened "flashkit.com" and "northcode.com".

getURL("http://www.adobe.com", "_blank");
getURL("http://www.flashkit.com", "myWindow");
getURL("http://www.northcode.com", "_blank");

When I first saw this I thought the good folks that wrote the Flash player had completely lost their minds, but this was actually the key to understanding everything. I haven't seen the source for the Flash player so the best I can do is use the results of these tests to provide an educated guess that explains all of the symptoms we've seen.

It's Not a Black Hole... it's a Map!?

To kick-start the explanation you should first understand why this problem seems to affect FSCommand and getURL/navigateToURL in exactly the same way. The secret is that FSCommand is actually implemented (at the bytcode level) as a call to getURL. In AS3 the navigateToURL will also ultimately generate the same bytecode and thus suffer from the same problem. These calls all do exactly the same thing.

FSCommand("fullscreen", "true");
getURL("FSCommand:fullscreen", "true"); // as2
navigateToURL(new URLRequest("fscommand:fullscreen"), "true"); // as3

It doesn't matter whether you target AS2 or AS3, the black hole will exist if you target the Flash 9 player when creating your SWF from Flash CS3 or Flex. If you choose one of the older Flash player versions then your FSCommand and getURL calls will work just like they did before.

All the FSCommand and getURL/navigateToURL calls made during a given frame are passed to the Flash player for execution. At the end of the frame, after all other ActionScript on that frame has run, the Flash player processes the FSCommand and getURL calls it encountered. So far this is exactly the same as previous Flash player versions. However, in Flash 9 some of the calls are being excluded. This is how it appears to be happening.

Each call is added to an associative array (also called a map) based on the value of its argument (not the command name or the URL). If the argument does't exist in the map it's added to the end, which preserves the order of execution. So far no problem, until we encounter two commands with the exact same argument string. In this case, the call already in the map is replaced by the new one being added instead of just being added to the end of the map. The order of execution has now been changed and one calls has been blown away. The more calls you make, the more confusing the results will seem.

Workarounds

When crafting your own FSCommands you can get around this problem by making sure that the argument strings to your commands are always different. A very easy way to do this is to append some kind of unique id to each argument string.

If you're calling built-in commands (exec, fullscreen, ALLOWSCALE, etc.) the only thing you can do unless Adobe fixes this problem is make sure you never call two FSCommands with the same argument in the same frame. That's an ugly fix for something that used to work just fine.

With getURL and navigateToURL the problem is a bit more difficult because the only parameter you can change that will make a difference is the target window, which you normally want set to "_blank". If you use different values for the target window, all of your getURL/navigateToURL calls will execute but they may not behave exactly as you intended.

Ironically, using FSCommand may provide the best workaround for this problem if you're working in a browser (this won't work in a standalone payer). Instead of calling getURL/navigateToURL directly you would call a JavsScript FSCommand handler to open the new windows for you. As long as the argument to every FSCommand call is different, the black hole won't swallow any of your calls.

FSCommand("openURL", "http:/www.northcode.com");

function myDocument_DoFSCommand(command, args)
{
if (command == "openURL")
{
window.open(args);
}
}

Comments

nasty stuff. fortunately (?) I still don't have a copy of CS3 so can't publish to Flash Player 9 and so can't get this bug! However, it's a pretty nasty one given that it differs so massively from previous behaviour.

What about ExternalInterface? Does that have similar issues? If not, could that not be used as a workaround - both for running commands and for launching URLs?
Posted by MattL on 12 Sep 2007 at 5:37am
ExternalInterface doesn't suffer from the same problem but it's not a replacement for FSCommand because all calls to ExternalInterface are synchronous where FSCommand calls are asynchronous. If you don't want to block on every call then you need something like FSCommand (or getURL). One place where this can have an impact is when you want to send tracking data to a server, definitely not a good place to use a synchronous call.
Posted by Tim on 12 Sep 2007 at 10:26am
One workaround for the fscommand with built-in commands (fullscreen, trapallkeys, etc) is to use different caps on the arguments. The following works perfectly:
fscommand("trapallkeys","true");
fscommand("fullscreen","TRUE");
Posted by Thiago Montoya on 13 Sep 2007 at 8:09pm
I didn't think to try mixing up the case of the arguments but it makes sense that it would work since the command names are case insensitive.

It also tells us that the comparison they're using to add commands to the map is case sensitive (i.e. case matters) or your trick would not work.

Some people don't realize that the arguments to FSCommands are strings and I see people use booleans all the time. Booleans have to be all lower case so anyone using booleans will just have to convert their code to use strings instead.

Thanks for the tip!
Posted by Tim on 14 Sep 2007 at 5:00am
I use fscommand("exec","filename.bat") to open PDFs in a flash menu and it worked like a dream until player 8. Now, I make it again and the bat file does not work. Too bad this upgrade becomes a downgrade.
Posted by Aristarco on 9 Nov 2007 at 8:21pm
Aristarco, everything should work fine unless you have multiple calls to EXEC in a single frame. I think you might be running into another problem I found that happens just with the EXE command: FSCommand EXEC is Broken in Flash CS3. That blog post also contains a solution for calling EXEC with BAT files in CS3.
Posted by Tim on 10 Nov 2007 at 11:03pm
This turns out to be tha cause of a problem that has been driving me crazy, thanks for taking the time to write it and explain it, the workarounds worked great. This is a major issue.
Posted by shawn on 16 Nov 2007 at 11:07pm
If you call getURL or navigateToURL and set the target to "_blank" a new browser window will not open consistently. It might open sometimes, however.

It WORKS if you are running a swf app alone, but if you embed it in an html page you get unexpected results.

This is a HUGE problem b/c you cannot have hyperlinks in your webpage in flash. I hope they fix this.
Posted by chris on 1 Dec 2007 at 5:08pm
Wow, thank you so much for pointing this out. I thought the problem was that Flash CS3 wasn't supporting all the fscommands. I guess it's one of those things that didn't get caught in beta.
Posted by tunghoy on 21 Feb 2008 at 11:34am
Not sure if there has been any updates on a "fix" from Adobe --- but what I have found to work for me when exporting to Flash 9 is to place the first "getURL" on frame 1 and the next "getURL" on something like frame 5 -- works every time for me with two separate windows. This is using the exact same scripting -- but different urls.

Blessings

jwr
Posted by James (jwr) on 30 Mar 2008 at 9:34pm
That will definitely work James, IF you know that this is what's causing your problem! The insidious part of this problem is that the behavior was unintentionally changed between versions. That means some applications just fail after a recompile with Flash 9.
Posted by Tim on 30 Mar 2008 at 10:22pm
Thanks for pointing this out. I’ve been using Flash 9 compilation for a video player project that uses fullscreen mode and have run into similar issues. Now, unless there’s design work or library management to do, I’m using FlashDevelop 3 Beta 4
Posted by kral oyun on 21 Apr 2008 at 8:57am
Hi Tim,
Thanks for the post buddy. saved a lot of time. :)
Posted by Arvind Kumar on 27 May 2008 at 1:19am
Leave a Comment

Add a comment by filling out the form below. All comments will be reviewed before they appear.

name:

email:

website:

comment:


← Back
 

copyright © 2000-2007 Northcode Inc  ·  all rights reserved  ·  contact us  ·  report piracy  ·  privacy policy