Here goes. Hope it's correct and working.
Code: Select all
function MyComponent() {
// you can do |this.wrappedJSObject = this;| for the first version of the component
// (in case you don't want to write IDL yet.)
}
MyComponent.prototype = {
classID: Components.ID("{xxxxxxxx-be3a-2b41-7a76-12533ba32166}"), // xxx generate guid
contractID: "@mozilla.doslash.org/test/component;1", // XXX generated contractid too
classDescription: "Test component",
QueryInterface: function(aIID) {
if(!aIID.equals(CI.nsISupports) && !aIID.equals(CI.nsIObserver) && !aIID.equals(CI.nsISupportsWeakReference)) // you can claim you implement more interfaces here
throw CR.NS_ERROR_NO_INTERFACE;
return this;
},
// you can implement other interfaces here..
// nsIObserver implementation
observe: function(aSubject, aTopic, aData) {
switch(aTopic) {
case "xpcom-startup":
dump("xpcom-startup");
// this is run very early, right after XPCOM is initialized, but before
// user profile information is applied. Register ourselves as an observer
// for 'profile-after-change' and 'quit-application'.
var obsSvc = CC["@mozilla.org/observer-service;1"].getService(CI.nsIObserverService);
obsSvc.addObserver(this, "profile-after-change", true);
obsSvc.addObserver(this, "quit-application", true);
break;
case "profile-after-change":
// This happens after profile has been loaded and user preferences have been read.
// startup code here
break;
case "quit-application":
dump("quit");
// shutdown code here
break;
default:
throw Components.Exception("Unknown topic: " + aTopic);
}
}
};
// constructors for objects we want to XPCOMify
var objects = [MyComponent];
/*
* Registration code.
*
*/
const CI = Components.interfaces, CC = Components.classes, CR = Components.results;
const MY_OBSERVER_NAME = "My Observer";
function FactoryHolder(aObj) {
this.CID = aObj.prototype.classID;
this.contractID = aObj.prototype.contractID;
this.className = aObj.prototype.classDescription;
this.factory = {
createInstance: function(aOuter, aIID) {
if(aOuter)
throw CR.NS_ERROR_NO_AGGREGATION;
return (new this.constructor).QueryInterface(aIID);
}
};
this.factory.constructor = aObj;
}
var gModule = {
registerSelf: function (aComponentManager, aFileSpec, aLocation, aType)
{
aComponentManager.QueryInterface(CI.nsIComponentRegistrar);
for (var key in this._objects) {
var obj = this._objects[key];
aComponentManager.registerFactoryLocation(obj.CID, obj.className,
obj.contractID, aFileSpec, aLocation, aType);
}
// this can be deleted if you don't need to init on startup
var catman = CC["@mozilla.org/categorymanager;1"].getService(CI.nsICategoryManager);
catman.addCategoryEntry("xpcom-startup", MY_OBSERVER_NAME,
MyComponent.prototype.contractID, true, true);
catman.addCategoryEntry("xpcom-shutdown", MY_OBSERVER_NAME,
MyComponent.prototype.contractID, true, true);
},
unregisterSelf: function(aCompMgr, aFileSpec, aLocation) {
// this must be deleted if you delete the above code dealing with |catman|
var catman = CC["@mozilla.org/categorymanager;1"].getService(CI.nsICategoryManager);
catman.deleteCategoryEntry("xpcom-startup", MY_OBSERVER_NAME, true);
// end of deleteable code
aComponentManager.QueryInterface(CI.nsIComponentRegistrar);
for (var key in this._objects) {
var obj = this._objects[key];
aComponentManager.unregisterFactoryLocation(obj.CID, aFileSpec);
}
},
getClassObject: function(aComponentManager, aCID, aIID) {
if (!aIID.equals(CI.nsIFactory)) throw CR.NS_ERROR_NOT_IMPLEMENTED;
for (var key in this._objects) {
if (aCID.equals(this._objects[key].CID))
return this._objects[key].factory;
}
throw CR.NS_ERROR_NO_INTERFACE;
},
canUnload: function(aComponentManager) {
return true;
},
_objects: {} //FactoryHolder
};
function NSGetModule(compMgr, fileSpec)
{
for(var i in objects)
gModule._objects[i] = new FactoryHolder(objects[i]);
return gModule;
}
useful links:
http://developer.mozilla.org/en/docs/Cr ... ng_WebLock - explains notifications, in particular startup notifications, in detail
http://developer.mozilla.org/en/docs/Ho ... Javascript
http://kb.mozillazine.org/Implementing_ ... JavaScript
[edit] marked the part of registration code many people won't need as optional
[edit 3/3/2006] registering as a weak observer