You are currently viewing a snapshot of taken on April 21, 2008. Most of this content is highly out of date (some pages haven't been updated since the project began in 1998) and exists for historical purposes only. If there are any pages on this archive site that you think should be added back to, please file a bug.

Scripting Plugins in Mozilla

Andrei Volkov <>

October 30, 2001
This article applies to Mozilla versions 0.9.2 and higher and Netscape versions 6.1 and higher. It does not cover Netscape 6 and 6.01

New in Mozilla code
New in plugin code
JavaScript code
Building and installing the plugin
What else to read


Plugins that used to take advantage of being scriptable via LiveConnect in 4.x Netscape browsers lost this possibility in the new world. The main reason for this is that there is no guarantee of Java compatibility on a binary level due to the jri/jni switch. The new Mozilla XPCOM architecture allows XPCOM components be scriptable via a different mechanism called XPConnect. We leverage some of these ideas to help you make your Netscape Communicator 4.x plugins exposed to JavaScript in Mozilla based browsers.

In order to make it still possible to script plugins, some changes have been made to the Mozilla code. The changes allow to make existing 4.x plugins scriptable with only minor modifications in their code. The present document describes the steps of what should be done to the plugin code to turn it scriptable again.

What's in the Mozilla code?

A couple of lines have been added to the DOM code asking a plugin to return a scriptable iid and a pointer to a scriptable instance object. The old Plugin API call NPP_GetValue is used to retrieve this information from the plugin. So the plugin project should be aware of two new additions to NPPVariable enumeration type which are now defined in npapi.h as

NPPVpluginScriptableInstance = 10,
NPPVpluginScriptableIID      = 11

and two analogous additions to nsPluginInstanceVariable type in nsplugindefs.h as

nsPluginInstanceVariable_ScriptableInstance = 10,
nsPluginInstanceVariable_ScriptableIID      = 11

What's in the plugin code?

  1. A unique interface id should be obtained. Windows command uuidgen should be sufficient.
  2. An Interface Definition (.idl) file describing the plugin scriptable interface should be added to the project (see example 1).
  3. A Scriptable instance object should be implemented in the plugin. This class will contain native methods callable from JavaScript. This class should also inherit from nsIClassInfo and implement its methods to be able to request all necessary privileges from the Mozilla security manager (see example 2).
  4. Two new cases for the above mentioned new variables should be added to the plugin implementation of NPP_GetValue (see example 3).

How to call plugin native methods

The following HTML code will do the job:

<embed type="application/plugin-mimetype">
<script language="javascript">
var embed = document.embeds[0];

How to build and install

Having the built Mozilla tree is probably not necessary, but building the plugin with a scriptable instance interface will require Mozilla headers and the XPCOM compatible idl compiler -- xpidl.exe. MS DevStudio MIDL must not be used. (Let's assume 'TestPlugin' as a plugin name-place holder.)

  1. Compile nsITestPlugin.idl with the idl compiler. This will generate nsITestPlugin.h and nsITestPlugin.xpt files.
  2. Put nsITestPlugin.xpt to the Components folder.
  3. Build nptestplugin.dll with nsITestPlugin.h included for compiling scriptable instance class implementaion.
  4. Put nptestplugin.dll to the Plugins folder.

Related sources

Example 1. Sample .idl file
(this code is for illustration purposes, for full samples please refer to Related sources section)

#include "nsISupports.idl"

[scriptable, uuid(bedb0778-2ee0-11d5-9cf8-0060b0fbd8ac)]
interface nsITestPlugin : nsISupports {
      void nativeMethod();

Example 2. Scriptable instance class
(this code is for illustration purposes, for full samples please refer to Related sources section)

#include "nsITestPlugin.h"
#include "nsIClassInfo.h"

// We must implement nsIClassInfo because it signals the
// Mozilla Security Manager to allow calls from JavaScript.

// helper class to implement all necessary nsIClassInfo method stubs
// and to set flags used by the security system
class nsClassInfoMixin : public nsIClassInfo
  // These flags are used by the DOM and security systems to signal that 
  // JavaScript callers are allowed to call this object's scritable methods.
  NS_IMETHOD GetFlags(PRUint32 *aFlags)
    {*aFlags = nsIClassInfo::PLUGIN_OBJECT | nsIClassInfo::DOM_OBJECT;
     return NS_OK;}
  NS_IMETHOD GetImplementationLanguage(PRUint32 *aImplementationLanguage)
    {*aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
     return NS_OK;}

  // The rest of the methods can safely return error codes...
  NS_IMETHOD GetInterfaces(PRUint32 *count, nsIID * **array)
  NS_IMETHOD GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
  NS_IMETHOD GetContractID(char * *aContractID)
  NS_IMETHOD GetClassDescription(char * *aClassDescription)
  NS_IMETHOD GetClassID(nsCID * *aClassID)
  NS_IMETHOD GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)

class nsScriptablePeer : public nsITestPlugin,
                         public nsClassInfoMixin




// Notice that we expose our claim to implement nsIClassInfo.
NS_IMPL_ISUPPORTS2(nsScriptablePeer, nsITestPlugin, nsIClassInfo)
// the following method will be callable from JavaScript
    return NS_OK;

Example 3. NPP_GetValue implementation and possible scenario of scriptable object life cycle
(this code is for illustration purposes, for full samples please refer to Related sources section)

#include "nsITestPlugin.h"

NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode,
                int16 argc, char* argn[], char* argv[], NPSavedData* saved)
    if(instance == NULL)

    // just prime instance->pdata with null for the purpose of this example
    // it will be assigned to the scriptable interface later to keep its
    // association with the specific plugin instance
    instance->pdata = NULL;
    return rv;

NPP_GetValue(NPP instance, NPPVariable variable, void *value)
    if(instance == NULL)

    NPError rv = NPERR_NO_ERROR;
    static nsIID scriptableIID = NS_ITESTPLUGIN_IID;

    if (variable == NPPVpluginScriptableInstance) {

        // nsITestPlugin interface object should be associated with the plugin
        // instance itself. For the purpose of this example to keep things simple
        // we just assign it to instance->pdata after we create it.

        nsITestPlugin *scriptablePeer = (nsITestPlugin *)instance->pdata;

        // see if this is the first time and we haven't created it yet
        if (!scriptablePeer) {
            scriptablePeer = new nsScriptablePeer();
            if (scriptablePeer)
                NS_ADDREF(scriptablePeer); // addref for ourself, 
                                           // don't forget to release on 
                                           // shutdown to trigger its destruction
        // add reference for the caller requesting the object
        *(nsISupports **)value = scriptablePeer;
    else if (variable == NPPVpluginScriptableIID) {
        nsIID* ptr = (nsIID *)NPN_MemAlloc(sizeof(nsIID));
        *ptr = scriptableIID;
        *(nsIID **)value = ptr;
    return rv;

NPError NPP_Destroy (NPP instance, NPSavedData** save)
    if(instance == NULL)

    // release the scriptable object 
    // Note that even though we release it here it does not necesserely
    // mean that its refcount will go to zero and it will be deleted.
    // XPCOM code in the browser may still hold more outstanding 
    // references to this object and even execute calls to it at some
    // later time, when other plugin objects no longer exist. So in real 
    // implementations some measures of precaution must be taken here to 
    // prevent crash such as notifying the scriptable object that there
    // may be some dangling pointers and it is not safe to use them any more