Detecting plugins in Internet Explorer (and a few hints for all the others)
Posted on June 26th, 2007 in Code, Firefox, Internet Explorer, JavaScript, Safari |
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
- Flash Player
- Java Runtime Environment
- QuickTime Player
- RealPlayer
- Shockwave Player
- Windows Media Player
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
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.
21 Responses
navigator.javaEnabled() does not reveal whether Java is installed or not in IE. It merely tells you if the applet tag is enabled or disabled.
You can disable the applet tag in the IE security settings … Tools -> Internet Options -> Security -> Custom Level -> Java Permissions -> Disable Java
This will cause javaEnabled() to be false, yet Java is still installed. For that matter, it isn’t disabled either. Only the applet tag is disabled.
You can still display a Java applet using the object tag (with a classid/ActiveX) while javaEnabled() is false.
Great resource, saved my day.
Check navigator.plugins for “Adobe Acrobat” won’t work with Adobe Reader 8 as it’s name changed to “Adobe PDF Plug-in for Firefox and Netscape” instead of it’s previous name “Adobe Acrobat…”
I found ur flash detection script very usefull…Thx for the stuff
this is great! it’s so nice to find a script that simply does what you need without all the bloat. thank you.
Instead of “Adobe PDF Plug-in for Firefox and Netscape” should be “Adobe PDF Plug-In for Firefox and Netscape”
the detectQuickTime() function returns a number like 7.3.1 for Firefox, but 7.31 for IE. I think I see why you can’t get the correct version number of 7.3.1. It makes it incorrect though. 7.10.1 would become 7.10 which would also be equal to 7.1.0
So, there is know way to know what version they have installed without making assumptions. And you know what assumptions make… and ass out of u and me. Arrgggh. Thanks for the resource and providing the best available solution.
In case someone needs it. I think this will solve the problem of how IE returns the version in QuickTime. Replace these two lines
version = version.substring(0, 1) + '.' + version.substring(1, 3); version = parseFloat(version);with these two
version = parseInt(version.substring(0, 1),16) + '.' + parseInt(version.substring(1, 2),16) + "." + parseInt(version.substring(2, 3),16); version = version;Thanks for the info. The Adobe PDF stuff works like a charm, and I’m definitely bookmarking this for the Flash rollout. I don’t suppose there’s a way I can figure out the properties and methods of Adobe’s SVG viewer? I’ve combed the Adobe developer center with no luck so far.
Again, thanks for sharing the awesome info!
- cubiclegrrl
Just found the answer here (http://wiki.svg.org/Interface_Definition_For_ASV) after a little more digging and a lot more dumb luck. So I thought I’d pass it on for anyone else who might have the same issue/question.
Thanks again!
[...] Caso você precise adicionar funcionalidades em suas aplicações, é necessário verificar antes se o usuário possui o complemento instalado em seu micro, pois caso contrário você pode alertá-lo disso e não ter problemas com suas aplicações. Isso pode ocorrer quando você está fazendo o uso do window.ActiveXObject(). Abaixo você vê uma recompilação dos detectores de plugins para Internet Explorer: [...]
[...] Olá olá, seus ‘nerds’?! Achei um super link de como detectar pluguins no IE, segue o link: http://www.builtfromsource.com/2007/06/26/detecting-plugins-in-internet-explorer-and-a-few-hints-fo... [...]
Thanks for this blog - unfortunately I found it after much digging myself into this and sorting out something similar. I’m still left with a problem which is this: although detecting whether something is installed is a great way towards solving my problem, how can I find out whether a plug-in is enabled in IE. In Netscape-based browsers you can use navigator.mimeTypes['video/quicktime'].enabledPlugins. Is there anything for IE?
@Steve
Sorry, I don’t think there’s a way to check that in IE. If you find a way, please post it!
[...] * 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. [...]
Thanks for the tutorial.
Any idea if it’s possible to install a plugin using JAVASCRIPT ?
Great text, thank you.
Loved the remark about Dick Cheney and IE.
I have an error, when I start the code in IE I get “‘return’ statement outside of function.”.
Interesting work. How you find the name of the activeX plugin? Specifically, I’m trying to find what the GoogleEarth plugin is named. Is it in the registry somewhere? Or is there someplace obvious in IE?
Thanks.
This is definitely one of the best tutorial i ever came across with. Nice tip, thanks for shaing with us.
@Carl
Research on Google. Some of the harder-to-find ones I found on mailing list archives.
Are the try-catches necessary? Will the compiler stop if ActiveX is disabled?