XPCOM Dynamic Component Registration

Suresh Duddi <dp@netscape.com>

Dynamic object registration in XPCOM is achieved by interaction of the following components:

The registration mechanism for XPCOM components is similar in many ways to that of COM. The XPCOM component dlls will have the opportunity to register themselves with the registry. The exact time of installation would be either at install time or as a result of autodetection by the Repository Manager at runtime.
 

The Registry: XPCOM Hierarchy

XPCOM uses the nsRegistry to store mappings between CLSIDs and their implementations. The Registry provides persistent storage of hierarchical keys and name-value pairs associated with each key. Each key also keeps a default value.

XPCOM will use the following registry hierarchy:

ROOTKEY_COMMON
    Common - Classes - CLSID
        {108d75a0-bab5-11d2-96c4-0060b0fb9956}
            InprocServer (S)  = libnfs-protocol.so
            ProgID       (S)  = component://netscape/network-protocol&type=nfs
            ClassName    (S)  = NFS Protocol Handler

        component://netscape/network-protocol&type=nfs
            CLSID        (S)  = {108d75a0-bab5-11d2-96c4-0060b0fb9956}

    Software - Netscape - XPCOM
        VersionString          (S)  = alpha0.20

        libnfs-protocol.so
            ComponentsCount    (S)  = 1
            FileSize           (S)  = 78965
            LastModTimeStamp   (S)  = Wed Feb 24 11:24:06 PST 1999

The Repository: Object instance creation

All object creation happens via The Repository.  nsIRepository::CreateInstance() will be the primary way of creation of object instances. The steps in instantiation of an object that implements the IID interface and of class CLSID is as follows:
  1. The CLSID of the component that would need to create the object instance is identified.
    1. Callers use nsIRepository::ProgIDToCLSID() to convert the ProgID string to the CLSID.
  2. Load the dll associated with the CLSID after consulting the Registry
  3. Instantiate the class factory by calling a globally exported dll function NSGetFactory(). This returns an instance of the class factory that implements the nsIFactory interface.
  4. The actual object creation is delegated to this nsIFactory instance with a call to nsIFactory::CreateInstance().

The Service Manager

All globally created system services are available via the nsIServiceManager, including the nsIRepository and nsIRegistry. Although the nsIServiceManager uses the Registry and Repository in the creation and maintenance of other services, the circular dependency is broken by not letting the nsIServiceManager create the nsIRepository and nsIRegistry instance and registering them specially with the nsIServiceManager. The nsIServiceManager is passed into NSGetFactory() for assisting the DLL in the Factory creation process.

Component Registration

Either at installation time of the Component or at times when the XPCOM library autodetect new/changed dlls, component registration is activated. The autodetection happens at startup time of the navigator or via a javascript trigger navigator.repository.autodetect(). The steps in component registration would be:
  1. The dll is loaded
  2. The component is allowed to self register by a call to a globally exported dll function NSRegisterSelf(). The nsIServiceManager and the fullpath of the dll are passed in to assist in the registration process. The dll is expected to create/modify its entries in the Registry according to the guidelines of the XPCOM hierarchy in the registry. nsIRepository, which can be queried from the nsIServiceManager, has useful registration functions that would easen the process.
  3. The dll is unloaded

Autodetection of Components

Autodetection of changed dlls happened by storing the dll's last modified time and its size in the Registry automatically. If either the last modified time stamp or the filesize differs from that stored in the Registry for the dll, re-registration takes place. Before re-registration, the existing instances of the objects created by the classes in the dll are not freed because the nsIRepository has no list of them. The NSCanUnload() will be called with input parameter force set to true. The dll has to prepare for getting unloaded. After this call returns, the dll will be unloaded if the return value is true. If the dll detects that it cannot properly prepare for unloading, then it can return false. XPCOM will not let the re-registration of the modified dll proceed in this case. There is nothing much that XPCOM library can do to salvage this situation other than warning the user of possible instability and advice a restart upon which the re-registration will happen.

ProgID Spec

Let us consider some more examples:
  1. A pluggable protocol that implementes the nfs protocol
  2. A converter that can handle application/x-zip
  3. A plugin that can handle image/gif
  4. A widget that can do a toolbar
  5. A datasource that can handle mail
  6. A helperapp that deals with application/postscript
All the above have what type they are and one or more arguments on what they particularly do.

The ProgID for these would look like

  1. component://netscape/network-protocol&type=nfs
  2. component://netscape/data-converter&type=application/x-zip
  3. component://netscape/plugin&type=image/gif&name=ImageMedia's Gif Image Plugin&Description=Reders GIF Images....
  4. component://netscape/widget&type=toolbar
  5. component://netscape/rdf/datsource&type=mail
  6. component://netscape/helperapp&type=application/postscript
{Assume proper escaping of all above URI}

The above semantics would let ProgID be an extensible mechanism that could be searched on multiple ways. And
query on a progid should match only whatever was passed in. So a query for
component://netscape/plugin&type=image/gif should pass for the progid specified above. We could extend this
mechanism with wildcards, but I dont want to go there yet... :-)
 

How will all this help me

For Component Developers: For Component Users:
  • No more hacking in calls to nsIRepository::RegisterFactory()
  • No need to know the CLSID of components that you want to instantiate. Component creation can happen like this

  • nsIRepository::CreateInstance("component://netscape/network-protocol&type=nfs", NULL, kProtocolIID, &result);
    instead of
    nsIRepository::CreateInstance(NFS_PROTOCOL_CID, NULL, domIID, &result);

    What has happened so far

    Changes to XPCOM happening

    What should I do

    Issues



    Last Modified: 28 Jan 1998
    Feedback to: netscape.public.mozilla.xpcom