Now that I've been able to do some more thorough testing and clean-up, I 
will post the solution I have used to register components for JS, so others 
may benefit.  This should be easier than looking at the XMLHttpRequest 
example, because it is the least amount of things you need to do, and it 
will compile with MOZILLA_STRICT_API.  I still have not figured out how to 
prevent JS attributes from being GC on the XPCOM component yet.

Use the following macro for defining entries in your nsComponentModuleInfo, 
in the following way.

#define XPCOM_REGISTER_WITH_JAVASCRIPT( componentName, contractId ) \
  static NS_METHOD \
  Register##componentName(nsIComponentManager *aCompMgr, \
                          nsIFile *aPath, \
                          const char *registryLocation, \
                          const char *componentType, \
                          const nsModuleComponentInfo *info) \
  { \
    nsCOMPtr< nsIServiceManager > serviceManager; \
    nsresult result = NS_GetServiceManager( getter_AddRefs( 
serviceManager ) ); \
    NS_ENSURE_SUCCESS( result, result ); \
    \
    nsCOMPtr< nsICategoryManager > catman; \
   result = serviceManager->GetServiceByContractID( 
"@mozilla.org/categorymanager;1", \
                                                    NS_GET_IID( 
nsICategoryManager ), \
                                                    getter_AddRefs( 
catman ) ); \
    NS_ENSURE_SUCCESS( result, result ); \
    \
    nsEmbedCString previous; \
    return catman->AddCategoryEntry(JAVASCRIPT_DOM_CLASS, \
                                    #componentName, \
                                    contractId, \
                                    PR_TRUE, PR_TRUE, 
getter_Copies(previous)); \
  }

XPCOM_REGISTER_WITH_JAVASCRIPT( Foo, FOO_CONTRACTID );

static const nsModuleComponentInfo components[] =
{
  { "Foo",
    FOO_CID,
    FOO_CONTRACTID,
    FooConstructor,
    RegisterFoo,
    nsnull,
    nsnull,
    NS_CI_INTERFACE_GETTER_NAME(Foo),
    nsnull,
    &NS_CLASSINFO_NAME(Foo),
    nsIClassInfo::DOM_OBJECT // Pretend to be part of the DOM, so component 
has same-origin access.
  }
}

In the component, make sure to use the NS_IMPL_ISUPPORTS3_CI family of 
macros to declare a class interface.

For each foo, you should initialize before running any JS, with a call to 
the following. (One gotcha is that keepAliveFooName must be kept alive as 
long as the DOM needs it, so I suggest putting it in a static variable.)

    domSOFactory->RegisterDOMClassInfo( keepAliveFooName.get(),
                                        &GetClassInfoFor,
                                        NULL,
                                        interfaces,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS,
                                        PR_TRUE,
                                        &fooCID );

Where GetClassInfoFor returns the nsIClassInfo object.  If you have many 
objects to register, then you can use one GetClassInfoFor function that 
looks up the proper CID in a map.  In any event, a call to the following is 
the key part of the module I called GetClassInfoFor.  (Another gotcha is 
that although GetClassInfoFor may seem like a getter, it is not 
XPCOM-compliant, so you should not AddRef, unless you want a memory leak. 
This means calling Release on classInfo, after calling GetClassObject and 
before returning.)

  componentManager->GetClassObject( fooCID,
                                    NS_GET_IID( nsIClassInfo ),
                                    reinterpret_cast< void** >( 
&classInfo ) ); 


_______________________________________________
dev-tech-xpcom mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-tech-xpcom

Reply via email to