Posts Tagged: Firefox


26
Jun 07

Detecting plugins in Internet Explorer (and a few hints for all the others)

There’s a lot of bad information out there about detecting plugins in Internet Explorer. I know; I spent days crawling through it all in order to create a plugin detection tool for a client. It’s not that the code you’ll find in the crevices of those forgotten pages doesn’t work. It does. The problem is that virtually all of it is grossly inefficient and almost immediately outdated because it’s version-based and has to be updated with each new plugin release. On top of that, some of it still uses VBScript, or even worse, JavaScript that writes VBScript. Since plugin detection itself continues to be necessary in some unique situations, I was determined to find a way to do it that didn’t require constant maintenance.

The problem is that no one quite knows what to look for when dealing with Internet Explorer’s plugins. Plugins in IE are ActiveX-based, so there’s no single API for them all—each has its own method of returning, for example, version information. What this basically means is that while Firefox and other browsers are putting all of their plugin information in one handy place, Internet Explorer is jealously guarding its plugin-related secrets. It’s like the Dick Cheney of browsers. And we are, um, the Information Security Oversight Office in that analogy.

Er… let’s just jump right in with some working detection code.

Adobe Reader

Detecting Adobe Reader (formerly Acrobat Reader) is pretty straightforward, except for the hitch that the ActiveX control was renamed in version 7. The key for version detection here is GetVersions(). Unfortunately, no version information is available for Adobe Reader 8 and later for non-IE browsers.

var isInstalled = false;
var version = null;
if (window.ActiveXObject) {
  var control = null;
  try {
    // AcroPDF.PDF is used by version 7 and later
    control = new ActiveXObject('AcroPDF.PDF');
  } catch (e) {
    // Do nothing
  }
  if (!control) {
    try {
      // PDF.PdfCtrl is used by version 6 and earlier
      control = new ActiveXObject('PDF.PdfCtrl');
    } catch (e) {
      return;
    }
  }
  if (control) {
    isInstalled = true;
    version = control.GetVersions().split(',');
    version = version[0].split('=');
    version = parseFloat(version[1]);
  }
} else {
  // Check navigator.plugins for "Adobe Acrobat" or "Adobe PDF Plug-in"*
}

* Nicole Lucas adds that “Adobe Acrobat” won’t work with Adobe Reader 8 because Adobe changed the name to “Adobe PDF Plug-In for Firefox and Netscape”. Thanks, Nicole.

Flash Player

Flash is even easier. The version method in this case is GetVariable('$version').

var isInstalled = false;
var version = null;
if (window.ActiveXObject) {
  var control = null;
  try {
    control = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
  } catch (e) {
    return;
  }
  if (control) {
    isInstalled = true;
    version = control.GetVariable('$version').substring(4);
    version = version.split(',');
    version = parseFloat(version[0] + '.' + version[1]);
  }
} else {
  // Check navigator.plugins for "Shockwave Flash"
}

Java Runtime Environment

The JRE (formerly Java Virtual Machine, or JVM) is actually more difficult to handle than you would think. Determining if Java is installed is easy—a quick call to navigator.javaEnabled() returns a simple Boolean.* The problem is detecting the version and provider (Microsoft or Sun).

I never found a satisfactory solution to this. The gist is this: to get this information, you must load a Java applet. To load the Java applet, you must do it externally. But when an applet is loaded externally, it doesn’t load right away, so any programmatic calls to the exposed class methods must be delayed. And dealing with this with setTimeout() is awkward.

Nevertheless, here’s what I ended up with:

var isInstalled = navigator.javaEnabled();
if (!isInstalled) {
  return;
}

// Get version
var version = null;
if (/*@cc_on ! @*/ false) { // This JRE check does not depend on ActiveX, only IE
  // IE requires the 'classid' attribute upon object creation.
  var element = '<object classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93">';
  var applet  = document.createElement(element);
  applet.id = 'applet';

  // IE requires that objects be displayed in order to interact with them
  applet.style.width  = '1px';
  applet.style.height = '1px';

  // Create and append the object's 'code' parameter
  var param = document.createElement('param');
  param.name  = 'code';
  param.value = 'JavaDetector.class';
  applet.appendChild(param);

  // Append the applet to <body>
  document.body.appendChild(applet);

  // Attempt to get the version
  var window.java = new Object();

  // Synchronous calls to getVendor(), etc. result in an exception, but despite
  // the timeout of 0 this call will not execute immediately
  setTimeout(function() {
    try {
      var applet = document.getElementById('applet');
      window.java.vendor  = applet.getVendor();
      window.java.version = parseFloat(applet.getVersion());
    } catch (e) {
      // Do nothing
    }
  }, 0);
} else {
  if (typeof java != 'undefined') {
    version = java.lang.System.getProperty('java.version');
  } else {
    // Look for "Java Plug-in", "Java (version) Plug-in", and "Java Plug-in for Cocoa"
  }
  version = parseFloat(version);
}

And your Java class looks something like this:

public class JavaDetector extends java.applet.Applet {
    public static String getVendor() {
        String vendor = null;
        try {
            vendor = System.getProperty("java.vendor");
        } catch (Exception e) {
            vendor = "Microsoft Corp.";
        }
        return vendor;
    }

    public static String getVersion() {
        return System.getProperty("java.version");
    }
}

* Eric Gerds adds that “navigator.javaEnabled() does not reveal whether Java is installed or not in IE.” Apparently disabling Java in IE merely disables the applet tag. Applets can still be loaded with the object tag despite javaEnabled() returning false. As such, you may want to modify this code. See his complete comment below.

QuickTime Player

QuickTime is another one that poses difficulty for IE. Detecting it is simple enough: just check for QuickTime.QuickTime. But detecting the version poses other problems. The ActiveX control that returns version information for QuickTime must be enabled manually in Internet Explorer 7. When called, the user is prompted. Although it saves that information for all future visits to that page, the code that follows will typically return null for the version number the first time around. Unfortunately, I’ve found no good way to reliably detect the version through ActiveX alone.

The version number that you do receive isn’t immediately useful. The QuickTimeVersion property is in hexadecimal (for whatever reason), so you’ll need to convert it by calling QuickTimeVersion.toString(16) and then manually assembling the number.

var isInstalled = false;
var version = null;
if (window.ActiveXObject) {
  var control = null;
  try {
    control = new ActiveXObject('QuickTime.QuickTime');
  } catch (e) {
    // Do nothing
  }
  if (control) {
    // In case QuickTimeCheckObject.QuickTimeCheck does not exist
    isInstalled = true;
  }

  try {
    // This generates a user prompt in Internet Explorer 7
    control = new ActiveXObject('QuickTimeCheckObject.QuickTimeCheck');
  } catch (e) {
    return;
  }
  if (control) {
    // In case QuickTime.QuickTime does not exist
    isInstalled = true;

    // Get version
    version = control.QuickTimeVersion.toString(16); // Convert to hex
    version = version.substring(0, 1) + '.' + version.substring(1, 3);
    version = parseFloat(version);
  }
} else {
  // Check navigator.plugins for "QuickTime Plug-in"
}

RealPlayer

Because it’s had so many names (five, that I can count), RealPlayer is still one of the more inefficient plugins to check for. Thankfully, they’ve kept the API the same, however, so checking for the version is still just GetVersionInfo().

var isInstalled = false;
var version = null;
if (window.ActiveXObject) {
  var definedControls = [
    'rmocx.RealPlayer G2 Control',
    'rmocx.RealPlayer G2 Control.1',
    'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)',
    'RealVideo.RealVideo(tm) ActiveX Control (32-bit)',
    'RealPlayer'
  ];

  var control = null;
  for (var i = 0; i < definedControls.length; i++) {
    try {
      control = new ActiveXObject(definedControls[i]);
    } catch (e) {
      continue;
    }
    if (control) {
      break;
    }
  }
  if (control) {
    isInstalled = true;
    version = control.GetVersionInfo();
    version = parseFloat(version);
  }
} else {
  // Check navigator.plugins for "RealPlayer" and "RealPlayer Version"
}

Shockwave Player

Thankfully, Macromedia always made an effort to remain consistent with their naming. Thus, one simple call can detect any version of Shockwave. The version check here is ShockwaveVersion('')—yes, you must pass it an empty string.

var isInstalled = false;
var version = null;
if (window.ActiveXObject) {
  var control = null;
  try {
    control = new ActiveXObject('SWCtl.SWCtl');
  } catch (e) {
    return;
  }
  if (control) {
    isInstalled = true;
    version = control.ShockwaveVersion('').split('r');
    version = parseFloat(version[0]);
  }
} else {
  // Check navigator.plugins for "Shockwave for Director"
}

Windows Media Player

Windows Media Player is probably the easiest one to detect of them all, but also the most unreliable on non-Internet Explorer browsers. Firefox users will typically be missed here unless they’ve installed the WMP for Firefox plugin. The relevant version property is versionInfo.

var isInstalled = false;
var version = null;
if (window.ActiveXObject) {
  var control = null;
  try {
    control = new ActiveXObject('WMPlayer.OCX');
  } catch (e) {
    return;
  }
  if (control) {
    isInstalled = true;
    version = parseFloat(control.versionInfo);
  }
} else {
  // Check navigator.plugins for "Windows Media"--this also detects the Flip4Mac plugin
}

Phew! That’s that. I can’t guarantee these are the best methods of detecting plugins in Internet Explorer, but they’re the best I came up with. If you’re aware of easier solutions, let me know and I’ll update this post.

Incidentally, if you need a comprehensive solution, I recommend putting these into a class structure—for my project, I used an abstract base class that each plugin class extended, and an overall plugin detection class that called each class’s self-detection method. Extensible, self-contained, and unobtrusive.

Like this post? You might also like Coalmine, my centralized error tracking service for your apps. Coalmine captures errors and all kinds of helpful debugging information, notifies you, and makes it all searchable. Check it out!

18
Apr 07

Microsoft releases Windows Media Player 11 plugin for Firefox

Now Firefox users can use Windows Media Player within Firefox in a plugin designed by the WMP team. According to Hank Janssen, who posted the plugin on Microsoft’s open-source website, Port 25, it is “designed to support” all varieties of Windows XP and Vista. However, he also mentions that it’s backwards-compatible with WMP versions as far back as 6.4, which seems to imply that it might also work on Windows systems as old as Windows 95. That’s just speculation, though.

In any event, you can download the files from Port 25′s website. You can also find this link from the Firefox Add-ons page.

Like this post? You might also like Coalmine, my centralized error tracking service for your apps. Coalmine captures errors and all kinds of helpful debugging information, notifies you, and makes it all searchable. Check it out!

7
Nov 06

Faster JavaScript in Firefox 3, thanks to Adobe

You might have seen the press release from Mozilla in the news today.

SAN FRANCISCO November 7, 2006 Adobe Systems Incorporated (Nasdaq:ADBE) and the Mozilla Foundation, a public-benefit organization dedicated to promoting choice and innovation on the Internet, today announced that Adobe has contributed source code for the ActionScript™ Virtual Machine, the powerful standards-based scripting language engine in Adobe® Flash® Player, to the Mozilla Foundation. Mozilla will host a new open source project, called Tamarin, to accelerate the development of this standards-based approach for creating rich and engaging Web applications.

This is great news for developers and users alike. Essentially, Adobe has given away their JIT compiler for ActionScript to Mozilla, and Mozilla has named this “Tamarin” (à la SpiderMonkey). This isn’t Flash—just the component of Flash that compiles ActionScript within Flash.

Because both ActionScript and JavaScript are based on the ECMAScript specification, this means that Mozilla will be able to use this compiler to significantly speed up JavaScript functionality in Firefox 3. Since that includes XMLHttpRequest, the functionality driving so-called Web 2.0 applications, it means that developers can get more and more daring with their use of JavaScript-heavy websites, allowing users to do more and do it more quickly, with fewer page refreshes. It also means Firefox plugins will be faster. Firefox 3 is expected to be released in early- to mid-2007.

This may not sound like a big deal, but consider this: Adobe is contributing around 135,000 lines of code to Mozilla. That’s the single largest contribution to the Mozilla Foundation since Netscape originally made Mozilla open source in the first place.

Frank Hecker (executive director of Mozilla) has a great write-up on his website explaining today’s events in more detail, so if you want to know more, I encourage you to take a look.

Like this post? You might also like Coalmine, my centralized error tracking service for your apps. Coalmine captures errors and all kinds of helpful debugging information, notifies you, and makes it all searchable. Check it out!