The interface information used by xpconnect is not discovered
from your JS code. That information is gathered at startup by
reading the .xpt files in the components directory. Your
interface needs to be expressed in idl, declared as 'scriptable',
and have a unique iid. The .xpt file generated by the xpidl
compiler from your idl file needs to be in the components
directory. In a debug build the new or changed .xpt file will be
found automatically at startup. In a release build (where it is
expected that developers will not be making frequent code
changes) you need to force the system to notice the new file by
either deleting the xpti.dat file (which is an index of
discovered interface information used by the xpcom internals) or
by running regxpcom.
Please post again if this does not solve your problem.
John.
Martin Karlsson wrote:
>
> I'm having some trouble registering a simple JS component. The component
> is basically a copy of nsSample.js, but with more debug output. The file
> nsMyComponent.js below is copied to Mozilla's dist/bin directory, and
> test.js below is a simple test file (within my chrome) for verifying its
> functionality.
>
> At Mozilla startup the component gets registred. Debug output:
>
> -> NSGetModule()
> <- NSGetModule()
> -> myComponentModule.registerSelf()
> <- myComponentModule.registerSelf()
>
> This means that the component is registred (additional output in
> nsComponentManager.cpp tells me that the component registred
> successfully). Then, when the chrome is loaded the component gets
> tested. The function calls in test.js are very straight forward
> (privilegdes are granted because test.js is loaded within the chrome).
> Debug output:
>
> -> myComponentTest()
> -> NSGetModule()
> <- NSGetModule()
> -> myComponentModule.getClassObject()
> myComponentModule.getClassObject() : cid = nsIMyComponent
> myComponentModule.getClassObject() : iid = nsIFactory
> <- myComponentModule.getClassObject()
> -> myComponentFactory.createInstance()
> myComponentFactory.createInstance() : iid = nsISupports
> <- myComponentFactory.createInstance()
> -> nsMyComponent.QueryInterface()
> nsMyComponent.QueryInterface() : iid = nsISupports
> <- nsMyComponent.QueryInterface()
> -> nsMyComponent.QueryInterface()
> nsMyComponent.QueryInterface() : iid = nsISupports
> <- nsMyComponent.QueryInterface()
> -> nsMyComponent.QueryInterface()
> nsMyComponent.QueryInterface() : iid = nsIScriptObjectOwner
> <- nsMyComponent.QueryInterface() : Throwing NS_ERROR_NO_INTERFACE
> -> nsMyComponent.QueryInterface()
> nsMyComponent.QueryInterface() : iid = nsIXPCScriptable
> <- nsMyComponent.QueryInterface() : Throwing NS_ERROR_NO_INTERFACE
> [Exception... "Could not convert JavaScript argument (NULL value can not
> be used for a C++ reference type) arg 0 [nsISupports.QueryInterface]"
> nsresult: "0x8057000b (NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF)" location:
> "JS frame :: chrome://mychrome/content/js/test.js :: MyComponentTest ::
> line 7" data: no]
> <- myComponentTest()
>
> The things that are printed out here are the function calls together
> with their arguments. So, in order to execute the instruction
>
> var comp =
> Components.classes["@mozilla.org/mycomponent;1"].createInstance();
>
> four different QueryInterface are run. The first two are nsISupports,
> and the other ones are nsIScriptObjectOwner and nsIXPCScriptable. The
> two last QI both fail and therefore NS_ERROR_NO_INTERFACE is thrown
> twice. Afterwards the instruction
>
> comp = comp.QueryInterface(Components.interfaces.nsIMyComponent);
>
> is tried, but because Components.interfaces.nsIMyComponent is undefined
> it doesn't work, so it throws the NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF
> exception on me.
>
> Any ideas why this happens?? Is this because the component registration
> didn't really work, or is the QueryInterface function incorrect? My
> guess would be that the component didn't register correctly, but
> printouts from the component manager ensures me that it is...
>
> /martin
>
> test.js
> =====
>
> dump("-> myComponentTest()\n");
>
> try {
> // create object instance, doesn't work
> var comp =
> Components.classes["@mozilla.org/mycomponent;1"].createInstance();
>
> // query interface, "Components.interfaces.nsIMyComponent" is
> undefined => exception thrown
> comp = comp.QueryInterface(Components.interfaces.nsIMyComponent);
>
> // method call, never gets here...
> comp.myTest();
> }
> catch (ex) {
> dump(ex + "\n");
> }
>
> dump("<- myComponentTest()\n");
>
> nsMyComponent.js
> ===============
>
> const MYCOMPONENT_CONTRACTID = "@mozilla.org/mycomponent;1";
> const MYCOMPONENT_CID =
> Components.ID("{0284a776-edee-4d40-9e59-ebc057bfe98c}");
> const nsISupports = Components.interfaces.nsISupports;
> const nsIFactory = Components.interfaces.nsIFactory;
> const nsIMyComponent =
> Components.interfaces.nsIMyComponent;
> const nsIXPCScriptable =
> Components.interfaces.nsIXPCScriptable;
> const nsIScriptObjectOwner =
> Components.interfaces.nsIScriptObjectOwner;
> const nsISecurityCheckedComponent =
> Components.interfaces.nsISecurityCheckedComponent;
>
> function nsMyComponent() {}
>
> nsMyComponent.prototype.myTest =
> function () {
> dump("-> nsMyComponent.myTest()\n");
>
> dump("<- nsMyComponent.myTest()\n");
> }
>
> nsMyComponent.prototype.QueryInterface =
> function (iid) {
> dump("-> nsMyComponent.QueryInterface()\n");
> dump(" nsMyComponent.QueryInterface() : iid");
>
> if (iid.equals(nsIMyComponent)) {
> dump(" = nsIMyComponent\n");
> }
> else if (iid.equals(nsIFactory)) {
> dump(" = nsIFactory\n");
> }
> else if (iid.equals(nsISupports)) {
> dump(" = nsISupports\n");
> }
> else if (iid == "{8a9c85f0-ba3a-11d2-982d-006008962422}") {
> dump(" = nsIXPCScriptable\n");
> }
> else if (iid == "{8f6bca7e-ce42-11d1-b724-00600891d8c9}") {
> dump(" = nsIScriptObjectOwner\n");
> }
> else if (iid.equals(nsISecurityCheckedComponent)) {
> dump(" = nsISecurityCheckedComponent\n");
> }
> else {
> dump(" = unknown\n");
> }
>
> if (!iid.equals(nsIMyComponent) &&
> !iid.equals(nsISecurityCheckedComponent) && !iid.equals(nsISupports)) {
> dump("<- nsMyComponent.QueryInterface() : Throwing
> NS_ERROR_NO_INTERFACE\n");
> throw Components.results.NS_ERROR_NO_INTERFACE;
> }
>
> dump("<- nsMyComponent.QueryInterface()\n");
> return this;
> }
>
> var myComponentModule = new Object();
>
> myComponentModule.registerSelf =
> function (compMgr, fileSpec, location, type)
> {
> dump("-> myComponentModule.registerSelf()\n");
>
> compMgr.registerComponentWithType(MYCOMPONENT_CID, "MyComponent JS
> Component",
> MYCOMPONENT_CONTRACTID, fileSpec,
> location,
> true, true, type);
>
> dump("<- myComponentModule.registerSelf()\n");
> }
>
> myComponentModule.getClassObject =
> function (compMgr, cid, iid) {
> dump("-> myComponentModule.getClassObject()\n");
> dump(" myComponentModule.getClassObject() : cid");
>
> if (cid.equals(MYCOMPONENT_CID)) {
> dump(" = nsIMyComponent\n");
> }
> else {
> dump(" = unknown\n");
> }
>
> dump(" myComponentModule.getClassObject() : iid");
>
> if (iid.equals(nsIMyComponent)) {
> dump(" = nsIMyComponent\n");
> }
> else if (iid.equals(nsIFactory)) {
> dump(" = nsIFactory\n");
> }
> else if (iid.equals(nsISupports)) {
> dump(" = nsISupports\n");
> }
> else if (iid == "{8a9c85f0-ba3a-11d2-982d-006008962422}") {
> dump(" = nsIXPCScriptable\n");
> }
> else if (iid == "{8f6bca7e-ce42-11d1-b724-00600891d8c9}") {
> dump(" = nsIScriptObjectOwner\n");
> }
> else if (iid.equals(nsISecurityCheckedComponent)) {
> dump(" = nsISecurityCheckedComponent\n");
> }
> else {
> dump(" = unknown\n");
> }
>
> if (!cid.equals(MYCOMPONENT_CID)) {
> dump("<- myComponentModule.getClassObject() : Throwing
> NS_ERROR_NO_INTERFACE\n");
> throw Components.results.NS_ERROR_NO_INTERFACE;
> }
>
> if (!iid.equals(nsIFactory)) {
> dump("<- myComponentModule.getClassObject() : Throwing
> NS_ERROR_NOT_IMPLEMENTED\n");
> throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
> }
>
> dump("<- myComponentModule.getClassObject()\n");
> return myComponentFactory;
> }
>
> myComponentModule.canUnload =
> function(compMgr) {
> return true;
> }
>
> myComponentFactory = new Object();
>
> myComponentFactory.createInstance =
> function (outer, iid) {
> dump("-> myComponentFactory.createInstance()\n");
> dump(" myComponentFactory.createInstance() : iid");
>
> if (iid.equals(nsIMyComponent)) {
> dump(" = nsIMyComponent\n");
> }
> else if (iid.equals(nsIFactory)) {
> dump(" = nsIFactory\n");
> }
> else if (iid.equals(nsISupports)) {
> dump(" = nsISupports\n");
> }
> else if (iid == "{8a9c85f0-ba3a-11d2-982d-006008962422}") {
> dump(" = nsIXPCScriptable\n");
> }
> else if (iid == "{8f6bca7e-ce42-11d1-b724-00600891d8c9}") {
> dump(" = nsIScriptObjectOwner\n");
> }
> else if (iid.equals(nsISecurityCheckedComponent)) {
> dump(" = nsISecurityCheckedComponent\n");
> }
> else {
> dump(" = unknown\n");
> }
>
> if (outer != null) {
> dump("<- myComponentFactory.createInstance() : Throwing
> NS_ERROR_NO_AGGREGATION\n");
> throw Components.results.NS_ERROR_NO_AGGREGATION;
> }
>
> dump("<- myComponentFactory.createInstance()\n");
> return (new nsMyComponent()).QueryInterface(iid);
> }
>
> function NSGetModule(compMgr, fileSpec) {
> dump("-> NSGetModule()\n");
> dump("<- NSGetModule()\n");
> return myComponentModule;
> }