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.
Do you need help with JavaScript? 



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