You don’t really have to make XPCOM components if you prefer not to when you are developing a Firefox extension, but there are times when it’s the right way of doing things, and I just happen to be a guy who really love to do the things right. ;-)
Again, even though XPCOM is not necessary, and might be evil in some cases such as causing memory leaks if used without care, it does provide a lot of benefits, such as providing a clean way to store temporary data, sepating the development concerns between multiple developers by making a clear contract, also enabling developers to use different languages(C, C++, Java, Python, Javascript) to program the underlying implementations!
Since reading XPCOM document isn’t the easist thing for me, I am going to give you an even quicker and dirtier kick start:
- Go to http://developer.mozilla.org/en/docs/Gecko_SDK and download the right version of gecko sdk, for me, I am downloading the linux one on the bottom right side, since I am using ubuntu.
- Unzip it using “tar -xjf gecko-sdk-i686-pc-linux-gnu-1.8.0.4.tar.bz2”, and move it into your home directory “move gecko-sdk ~/”
- Go to your XOCOM component development dir and “touch HelloWorld.idl”
- Inside “HelloWorld.idl”, paste
#include "nsISupports.idl"
[scriptable, uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)]
interface nsIHelloWorld : nsISupports
{
string hello();
};
- Go to http://www.famkruithof.net/uuid/uuidgen, generate a bunch of UUID, and replace the xxx’s of “[scriptable, uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)]” with your favorite UUID that you want to use for your component.
- Compile the typelib interface
~/gecko-sdk/bin/xpidl -m typelib -w -v -I ~/gecko-sdk/idl -e nsIFireCruncher.xpt nsIFireCruncher.idl
- Paste the following code into “HelloWorld.js”.
/***********************************************************
constants
***********************************************************/
// reference to the interface defined in nsIHelloWorld.idl
const nsIHelloWorld = Components.interfaces.nsIHelloWorld;
// reference to the required base interface that all components must support
const nsISupports = Components.interfaces.nsISupports;
// UUID uniquely identifying our component
// You can get from: http://kruithof.xs4all.nl/uuid/uuidgen here
const CLASS_ID = Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx}");
// description
const CLASS_NAME = "My Hello World Javascript XPCOM Component";
// textual unique identifier
const CONTRACT_ID = "@hungryfools.com/helloworld;1";
/***********************************************************
class definition
***********************************************************/
//class constructor
function HelloWorld() {
};
// class definition
HelloWorld.prototype = {
// define the function we want to expose in our interface
hello: function() {
return "Hello World!";
},
QueryInterface: function(aIID)
{
if (!aIID.equals(nsIHelloWorld) &&
!aIID.equals(nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
/***********************************************************
class factory
This object is a member of the global-scope Components.classes.
It is keyed off of the contract ID. Eg:
myHelloWorld = Components.classes["@dietrich.ganx4.com/helloworld;1"].
createInstance(Components.interfaces.nsIHelloWorld);
***********************************************************/
var HelloWorldFactory = {
createInstance: function (aOuter, aIID)
{
if (aOuter != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return (new HelloWorld()).QueryInterface(aIID);
}
};
/***********************************************************
module definition (xpcom registration)
***********************************************************/
var HelloWorldModule = {
registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
{
aCompMgr = aCompMgr.
QueryInterface(Components.interfaces.nsIComponentRegistrar);
aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME,
CONTRACT_ID, aFileSpec, aLocation, aType);
},
unregisterSelf: function(aCompMgr, aLocation, aType)
{
aCompMgr = aCompMgr.
QueryInterface(Components.interfaces.nsIComponentRegistrar);
aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);
},
getClassObject: function(aCompMgr, aCID, aIID)
{
if (!aIID.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
if (aCID.equals(CLASS_ID))
return HelloWorldFactory;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
canUnload: function(aCompMgr) { return true; }
};
/***********************************************************
module initialization
When the application registers the component, this function
is called.
***********************************************************/
function NSGetModule(aCompMgr, aFileSpec) { return HelloWorldModule; }
- To install the Component that you’ve just created into your extension,
- Copy HelloWorld.js and HelloWorld.xpt to {extensiondir}/components/
- Delete compreg.dat and xpti.dat from your profile directory.
- Restart application
Original Reference: http://developer.mozilla.org/en/docs/How_to_Build_an_XPCOM_Component_in_Javascript