How to call dynamically created flash external interface in IE from javascript

domflashinternet explorer

What I have:

  1. A swf exports a function via ExternalInterface
  2. Javascript creates new embed object and adds it to the document
  3. Calling flash functions works fine in other browsers
  4. Calling flash functions will fail in IE 8

Example of exporting functions in swf:

flash.external.ExternalInterface.addCallback("isActive", ...

Example of creating the embed object:

var b = document.createElement('embed');

    b.type = 'application\u002fx-shockwave-flash';
    b.setAttribute('allowFullScreen', 'true');
    b.setAttribute('allowNetworking', 'all');
    b.setAttribute('allowScriptAccess', 'always');
    b.width = 500;
    b.height = 400;
    b.src = 'assets\u002fUltra4.UltraApplication\u002fUltra4.UltraApplication+UltraSprite.swf';

Example of calling flash external interface in javascript:

   try
    {
      e = b.isActive();
    }
    catch (__exc){ }

In IE it will catch with message "Object doesn't support this property or method"

How to fix it?

  1. Related: http://bojolais.livejournal.com/251383.html
  2. Related: ExternalInterface not working in IE
  3. Related: http://swfupload.org/forum/generaldiscussion/985
  4. Related: http://code.google.com/p/doctype/wiki/ArticleFixingFlashExternalInterface
  5. Related: http://www.dangerouslyawesome.com/2006/10/20/another-swfobject-problem-deproblemed/
  6. Related: http://www.airtightinteractive.com/news/?p=71

In script debugger I can see a third party script which is supposed to be the bridge:

function __flash__arrayToXML(obj) {
    var s = "<array>";
    for (var i=0; i<obj.length; i++) {
        s += "<property id=\"" + i + "\">" + __flash__toXML(obj[i]) + "</property>";
    }
    return s+"</array>";
}
function __flash__argumentsToXML(obj,index) {
    var s = "<arguments>";
    for (var i=index; i<obj.length; i++) {
        s += __flash__toXML(obj[i]);
    }
    return s+"</arguments>";
}
function __flash__objectToXML(obj) {
    var s = "<object>";
    for (var prop in obj) {
        s += "<property id=\"" + prop + "\">" + __flash__toXML(obj[prop]) + "</property>";
    }
    return s+"</object>";
}
function __flash__escapeXML(s) {
    return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
}
function __flash__toXML(value) {
   var type = typeof(value);
    if (type == "string") {
        return "<string>" + __flash__escapeXML(value) + "</string>";
    } else if (type == "undefined") {
        return "<undefined/>";
    } else if (type == "number") {
        return "<number>" + value + "</number>";
    } else if (value == null) {
        return "<null/>";
    } else if (type == "boolean") {
        return value ? "<true/>" : "<false/>";
    } else if (value instanceof Date) {
        return "<date>" + value.getTime() + "</date>";
   } else if (value instanceof Array) {
       return __flash__arrayToXML(value);
   } else if (type == "object") {
       return __flash__objectToXML(value);
   } else {
        return "<null/>"; //???
    }
}
function __flash__addCallback(instance, name) {
  instance[name] = function () { 
    return eval(instance.CallFunction("<invoke name=\""+name+"\" returntype=\"javascript\">" + __flash__argumentsToXML(arguments,0) + "</invoke>"));
  }
}
function __flash__removeCallback(instance, name) {
  instance[name] = null;
}

Best Answer

I'm not sure if I understand your question correctly. But I think you are missing a couple of things:

1) Your embed tag needs a name attribute. Let's name it "NewFlashMovie" for the subsequent code:

b.name = "NewFlashMovie";

2) You need to call the "isActive" function differently using an external function. First add this function

 function thisMovie(movieName) {
     if (navigator.appName.indexOf("Microsoft") != -1) {
         return window[movieName];
     } else {
         return document[movieName];
     }
 }

Then you can call the function like this

thisMovie("NewFlashMovie").isActive();

From my experience, this "thisMovie" is essential to bridge the IE-Flash calls. This is also documented in the ExternalInterface documentation

3) I also recommend using swfobject instead of creating your own "embed" object.

Hope these helps.