nsComponentManager
nsServiceManager
No restrictions. You can call any function from the static classes nsComponentManager and nsServiceManager. XPCOM will do the right thing to initialize itself at both places.Autoregistration() can happen only after Init_XPCOM() is called since the registy might be required by SelfRegister() functions of the dlls and it is only in Init_XPCOM() do we create register the RegistryFactory() with the ComponentManager.
Init_XPCOM()Now the hard problem is when to trigger Init_XPCOM() There are two static objects nsComponentManager and nsServiceManager. Any function in either of them can be called first. Today nsServiceManager::GetService() is the first one that gets called. All the members of the static nsServiceManager use the NS_GetGlobalServiceManager() to get to the global service manager. All members of the static nsComponentManager use the NS_GetGlobalComponentManager() to get to the global component manager. Hence if we trigger Init_XPCOM() from both NS_GetGlobalComponentManager() and NS_GetGlobalServiceManager() we will be safe.create the global service manager create the global component manager and register as service with the global service manager RegisterFactory(...RegistryFactory...) Register the RegistryFactory with the component manager so that new registry objects can be created.
No. The nsIRegistry is designed to be lightweight access to the registry. Consumers who need to access the registry should use the component manager to create the their own registry access object. This is required because the open() call is supported by the nsIRegistry() and if we maintain a global registry arbitrating which registry file is opened is going to be a major headach.The ProgID for the registry will be component://netscape/registry
ComponentManager is the only way for component creation. ComponentManager always uses the component's factory to create the component instance. Clients (code that calls CreateInstance() to create and use a component) call the ComponentManager to create instances. Components (the code that implemented NSRegisterSelf()) calls the ComponentManager to register itself and gets called when a Client wants to instantiate a component.ServiceManager is a convinience for getting singleton components, components for which only one instance stays alive for the entire application e.g Netlib. It enforces only one of a kind of a component to exist. Hence the notion of getting a service not creating one. (as opposed to the notion of Creating instances with the componentManager). ServiceManager is a convenience because components can technically force singletonism by making their factory return the same instance if one was created already. The other big use of ServiceManager is the (still unimplemented) notion of Shutting down a service.
Client
Component
- When does a client use the service manager vs component manager
When a client knows that the component that they are trying to instantiate is a singleton, they need to call service manager instead of component manager. Clients dont have to worry about calling the ComponentManager at all in this case. The ServiceManager will take care of creating the instance if the first one doesn't exist already.
- When does a client use the Component Manager as opposed to Service Manager
When a client wants a private instance of a component, they call the Component Manager. From the Clients point of view, a new xpcom object creation happens everytime they call CreateInstance() Anything else is an implementation detail that the Client need not worry about.
- How does a Client know that they have to instantiate a singleton
For now, the Client just has to know. There is no way of telling which component is a Service and which isn't. In fact, in todays xpcom (Mar 1999) any component can be accessed as a Service. Use your judgement until there is a proper method or service manager is eliminated. There is nothing even in the code that detects Services from Instances.Need a solution for this. Email suggestion to warren@netscape.com, dp@netscape.com
- Can a component enforce use only as a Service
No. The notion of the ServiceManager is available only to Clients.Note that at some points when a component wants another component, it actually behaves as a client and hence follows the rules of the Client above to either CreateInstance() or GetService() the needed component.
Workaround: If however a component wants only one of its instances to exist and cannot ensure that Clients understand well enough only to use the Service Manager to get it, it can implement singletonism in its factory. Basically the factory on first instance creation should hang on to the instance. On subsequence instance creations, addref the instance it is holding to and return that instead creating a new one.
E.g preferences does this. Code sample at nsPref.cpp nsPrefFactory::CreateInstance() and nsPref.cpp nsPref::GetInstance() With this implementation, whether Clients get to it by calling nsIServiceManager::GetService() or nsIComponentManager::CreateInstance(), the same object will be returned hence guaranteeing singletonism.- Should a component do anything at creation to become a Service
No. Again, the notion of a ServiceManager is available only to Clients.
- Can a component advertise that it is a service so clients can use it as one
No. There isn't a way other than a comment in the interface of the header file.
ClassID or CLSID is the unique indentification of a component. It is a structure of huge numbers generated by using uuidgen on a windows box. It is represented as a string in documentation as {108d75a0-bab5-11d2-96c4-0060b0fb9956}ProgID is the string identification of an implementation of a component the client is looking for. The representation takes a URI syntax. Eg. component://netscape/network/protocol?name=http;description=Http%20Protocol%20Handler
Some simplify this to, ProgID is a more readable string form of a CLSID. That is acceptable on the periphery. The ProgID is a Client thing. Components register with component manager to claim that they are the implementation for a ProgID. A component can register to be the implementation for multiple ProgIDs (not implemented yet).Client
Component
- Should CreateInstance() calls use ProgID or CLSID
ProgID is what Clients should use to CreateInstances. Clients should not even know about the CLSID unless they are hell bent on creating a particular implementation of a component.
- Should Components register with both a CID and ProgID
Absolutely.
XPCOM provides log output. To enable the logging:setenv NSPR_LOG_MODULES nsComponentManager:5Start your application after setting the above environment variables. Debug log from xpcom would be in the file xpcom.log
setenv NSPR_LOG_FILE xpcom.logSince components are dynamically loaded only on demand, debugging them could be a hard. Here are some tips to debugging components.
Windows: VC5.0 VC6.0
Include your component library in the Project->Settings, Additional Dll. drop down. After that breakpoints can be enabled.
Unix: gdbLet the program run until you are sure that your component is loaded. Type Control-C. Now all symbols from your component will be available in gdb. Put your breakpoints and restart the app. Gdb will complain that it cannot set the breakpoint, and that it is temporarily disabling it, but when the *.so is loaded, the breakpoint is enabled automatically. - <Eric Van Der Poel>Mac: CodewarriorI think typing "dir components" (assuming you're in dist/bin) will also allow you to see the symbols in your stack the first time. - <Alec Flett>
Just open the appropriate .xSYM file in the debugger; the debugger will target the library when the application is run. - <Simon Fraser>