Mozilla browsers are opening up a world of opportunities with the ability to use Cross Platform Component Object Model (XPCOM) components. Mozilla browsers also introduced XPConnect technology, which allows components to be scripted in and developed with JavaScript.

XPCOM components work like Microsoft COM components in that communication between the client and the component is through interfaces. The basic interface for XPCOM is nsISupports. You use the QueryInterface method of nsISupports to retrieve the information regarding your specialised interface (these are the methods and properties that your interface supports).

In order to implement the nsISupports interface, a JavaScript XPCOM component must utilise the Interface Definition Language (IDL). IDL files are created and compiled into XPT type libraries. The component registrar uses the information in an XPT file to register the component with Mozilla. Once the component registers successfully, you can use the XPCOM component within your code.

In my example, I'll create a simple XPCOM component with JavaScript that exposes one method: reverseIt(). This method takes a string parameter and reverses the order of the characters in the string.

There are three layers of components: the XPCOM object layer, the nsIFactory layer, and the nsIModule layer. The XPCOM object layer is the guts of the system; this is where you'll put your business logic. The nsIFactory layer is the layer responsible for instantiating the XPCOM object. The nsIModule layer is responsible for registration and providing abstraction to the nsIFactory layer. These three layers are required, and each layer requires certain methods as you can see in Listing A.

Listing A
const MYCOMPONENT_CONTRACTID = '@mozilla.org/MyComponent;1';
const MYCOMPONENT_CID = Components.ID('{F443406C-961D-4ecc-BF39-
C0E9943C72AE}');
const MYCOMPONENT_IID = Components.interfaces.nsIMyComponent;
function nsMyComponent() { }
nsMyComponent.prototype = {
    reverseIt: function(s) {
        var a = s.split("");
        a = a.reverse();
        return a.join("");
    },
    QueryInterface: function(iid) {
        if (!iid.equals(Components.interfaces.nsISupports) &&
            !iid.equals(MYCOMPONENT_IID))
            throw Components.results.NS_ERROR_NO_INTERFACE;
        return this;
    }
};
var nsMyComponentModule = {
    registerSelf: function(compMgr, fileSpec, location, type) {
        compMgr =
compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
        compMgr.registerFactoryLocation(MYCOMPONENT_CID,
                                        "MyComponent test",
                                        MYCOMPONENT_CONTRACTID,
                                        fileSpec,
                                        location,
                                        type);
    },
    getClassObject: function(compMgr, cid, iid) {
        if (!cid.equals(MYCOMPONENT_CID))
            throw Components.results.NS_ERROR_NO_INTERFACE;
        if (!iid.equals(Components.interfaces.nsIFactory))
            throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
        return nsMyComponentFactory;   
    },
    canUnload: function(compMgr) { return true; }
};
var nsMyComponentFactory = {
    createInstance: function(outer, iid) {
        if (outer != null)
            throw Components.results.NS_ERROR_NO_AGGREGATION;
        if (!iid.equals(MYCOMPONENT_IID) &&
            !iid.equals(Components.interfaces.nsISupports))
            throw Components.results.NS_ERROR_INVALID_ARG;
        return new nsMyComponent();
    }
};
function NSGetModule(comMgr, fileSpec) { return nsMyComponentModule; }

The XPCOM component is registered under a friendly name. The Contract ID for XPCOM is like the ProgID for Microsoft COM components. In my example, this is '@mozilla.org/MyComponent;1'.

Contract IDs use the concept of namespaces to identify themselves, so it's important to precede your Contract ID with '@mozilla.org/'. A component's CID is a 128-bit UUID that uniquely identifies the component. The ID() on the Components object accepts a UUID string and returns an nsID object, which is used for registration and instantiation. (I created my UUID by using guidgen.exe on Windows.) Then, there's the component's Interface ID (IID), which is the name of the interface described in the XPT file. In this example, it's nsIMyComponent.

If you examine the code, you'll notice that the actual custom business logic is the reverseIt() method on the nsMyComponent class. The rest of the code is required to make the component work within XPCOM. If you were to create your own component from my example code, you would copy everything as it appears, but you would add your own methods and properties to the nsMyComponent class.

In order for the XPCOM system to acknowledge the nsIMyComponent interface and the exported method, you must provide an XPT type library. You'll do this by creating an IDL file and compiling it with xpidl.exe. Listing B contains the IDL for MyComponent.

Listing B
#include "nsISupports.idl"
[scriptable, uuid(F443406C-961D-4ecc-BF39-C0E9943C72AE)]
interface nsIMyComponent : nsISupports {
string reverseIt(in string s);
};

The IDL file includes the nsISupports.idl file in order to implement the nsISupports interface on the nsIMyComponent interface. The reverseIt() method is declared, specifying its return type and the parameter it accepts.

I couldn't find a generic download for xpidl.exe, so I created one from bits and pieces that I downloaded from Mozilla.org. I've successfully run this on Windows 2000 and XP. (My generic download is at http://www.geocities.com/phil_perkins_1/articles/XPIDL/xpidl.zip.) If you unpack this into a separate directory, you can use the -h on xpidl.exe to get information on its use.

To get this example working, you need to save the source code to the component under "nsMyComponent.js" in the "components" directory under Mozilla in your system. You then save the IDL file as "MyComponent.idl" under the directory where you unpacked the xpidl.zip file. From the command line, navigate to that directory and enter:

xpidl -m typelib -w -v -e [path to IDL file]
\MyComponent.xpt [path to IDL file]\MyComponent.idl

This should create a file called "MyComponent.xpt". Copy this file to the "components" directory under Mozilla.

From the command line, navigate to the Mozilla directory and look for "regxpcom.exe". Type in "regxpcom" and enter. This will register all your components for Mozilla. Then, you can look in the "compreg.dat" file to see if your component was registered successfully. Do not edit this file—this is a generated file. If you have Mozilla windows open, you should close all Mozilla windows before attempting to use new components. To test this component, save the HTML in Listing C to a file and open it within Mozilla.

Listing C
<html>
<head>
<script language="JavaScript">
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var oMyComponent = Components.classes['@mozilla.org/MyComponent;1'].
                        createInstance(Components.interfaces.nsIMyComponent);
function btnReverse_onclick() {
    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
    try {
        var s = oMyComponent.reverseIt(document.thisForm.txtString.value);
        document.thisForm.txtResult.value = s;
    } catch(e) {
        alert(e);
    }
}
</script>
</head>
<body>
This is a test.
<form name="thisForm" id="thisForm">
String: <input type="text" name="txtString" id="txtString" size="25"><br>
Result: <input type="text" name="txtResult" id="txtResult" size="25"><br>
<input type="button" value="Reverse" name="btnReverse" id="btnReverse"
    onclick="btnReverse_onclick()"> 
</form>
</body>
</html>

Look in the JavaScript console to check for errors. You can find the source code for this example at http://www.geocities.com/phil_perkins_1/articles/XPIDL/MyComponent.zip.

Advertisement

 Do you need help with JavaScript? Gain advice from Builder AU forums

  • Comments

1

praveen - 14/10/05

Simple and excellent tutorial. I've been looking for this kind of tutorial all over. Thanks

Praveen

» Report offensive content

2

oldboy - 18/01/06

typeerror ㅠㅠ

.js where?

» Report offensive content

3

Aadil Farid - 11/09/06

Very good, concise and excellent tutorial. Also thanks for the link to zpidl.exe executable. You efforts are much appreciated.

Thank U.

Aadil

» Report offensive content

4

Aadil Farid - 11/09/06

Very good, concise and excellent tutorial. Also thanks for the link to zpidl.exe executable. You efforts are much appreciated.

Thank U.

Aadil

» Report offensive content

5

Bassem - 13/01/07

thank you very much

» Report offensive content

6

Sam_A - 16/11/07

In my case I created XPCOM wapper (in C++) that called from the JS.
More then that I created in the same project a C++ Class that handle Stored Procedure (SQL Server DB) that I created with the wizard that supplied in the VS C++.

And now when I call the js to create the instance of my Class the action falied to load.

Do you know somthing about it?

» Report offensive content

  • Leave A Comment

(if you need to share some code)

You must read and type the 6 chars within 0..9 and A..F

* mandatory fields.

  • Latest comments

6

Sam_A - 16/11/07

In my case I created XPCOM wapper (in C++) that called from the JS. More then that I created in the same ... more

5

Bassem - 13/01/07

thank you very much ... more

4

Aadil Farid - 09/11/06

Very good, concise and excellent tutorial. Also thanks for the link to zpidl.exe executable. You efforts are much appreciated. Thank U. Aadil ... more

Log in


Sign up | Forgot your password?

  • Blogs

Brendon ChaseHow to manage a team of geniuses
Hiring a team of developers and techies that are smarter than you is inevitable. As a manager how do you cope with this and keep things on track? Read more »

-- posted by Brendon Chase

StaffXO to run XP
When Bill Gates says that everything in the world should be a computer, what he means is that everything in the world should be running Windows. Read more »

-- posted by Staff

StaffDrop in on Builder AU at Open CeBiT 2008
Got a question on open source you need answered? Need a way to help convince your boss that open source is the way to go? Or just curious to learn what all the fuss is about? Then drop in to the Builder AU Open Source Afternoon on Wednesday May 21. Read more »

-- posted by Staff

  • What's On?

Club Builder: Vapour-where? Club Builder: Vapour-where?
Applets are back from the dead, but do we want them? This week's Club Builder also looks at which pieces of software are utter vapour.

Understanding task and data parallelism
The difference between task and data parallelism, and how there is a way around the limits imposed by Amdahl's Law.