зеркало из https://github.com/mozilla/pjs.git
412 строки
17 KiB
HTML
412 строки
17 KiB
HTML
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
<meta name="Author" content="Suresh Duddi">
|
|
<meta name="GENERATOR" content="Mozilla/4.51 [en] (WinNT; U) [Netscape]">
|
|
<title>XPCOM Dynamic Component Registration</title>
|
|
</head>
|
|
<body>
|
|
|
|
<center>
|
|
<h2>
|
|
XPCOM Dynamic Component Registration</h2></center>
|
|
|
|
<center>Suresh Duddi <<a href="mailto:dp@netscape.com">dp@netscape.com</a>>
|
|
<hr WIDTH="100%"></center>
|
|
|
|
<p>Dynamic object registration in XPCOM is achieved by interaction of the
|
|
following components:
|
|
<ul>
|
|
<li>
|
|
The Registry</li>
|
|
|
|
<li>
|
|
The Repository</li>
|
|
|
|
<li>
|
|
The Service Manager</li>
|
|
|
|
<li>
|
|
Component dll implementing <tt>NSRegisterSelf()</tt></li>
|
|
</ul>
|
|
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 <b>autodetection</b> by the Repository
|
|
Manager at runtime.
|
|
<br>
|
|
<h3>
|
|
<a NAME="The Registry: XPCOM Hierarchy"></a>The Registry: XPCOM Hierarchy</h3>
|
|
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.
|
|
<p>XPCOM will use the following registry hierarchy:
|
|
<blockquote><tt>ROOTKEY_COMMON</tt>
|
|
<br><tt> Common</tt>
|
|
<br><tt> Classes</tt>
|
|
<br><tt>
|
|
CLSID</tt>
|
|
<br><tt>
|
|
|
|
<b><font color="#CC0000">{108d75a0-bab5-11d2-96c4-0060b0fb9956}</font></b></tt>
|
|
<br><tt><nobr>
|
|
InprocServer (S) = <font color="#CC0000">/home/dp/dist/bin/components/libnfs-protocol.so</font></nobr></tt>
|
|
<br><tt><nobr>
|
|
ProgID (S) = <b><font color="#CC0000">component://netscape/network-protocol&type=nfs</font></b></nobr></tt>
|
|
<br><tt><nobr>
|
|
ClassName (S) = <b><font color="#CC0000">NFS Protocol
|
|
Handler</font></b></nobr></tt>
|
|
<p><tt>
|
|
<font color="#CC0000">component://netscape/network-protocol&type=nfs</font></tt>
|
|
<br><tt><nobr>
|
|
CLSID (S) = <font color="#CC0000">{108d75a0-bab5-11d2-96c4-0060b0fb9956}</font></nobr></tt>
|
|
<p><tt><i> </i>Software</tt>
|
|
<br><tt> Netscape</tt>
|
|
<br><tt>
|
|
XPCOM</tt>
|
|
<br><tt>
|
|
VersionString (S)
|
|
= <font color="#CC0000">alpha0.20</font></tt>
|
|
<p><tt>
|
|
|
|
<font color="#CC0000">/home/dp/dist/bin/components/libnfs-protocol.so</font></tt>
|
|
<br><tt>
|
|
ComponentsCount (Int) = <font color="#CC0000">1</font></tt>
|
|
<br><tt>
|
|
FileSize (Int)
|
|
= <font color="#CC0000">78965</font></tt>
|
|
<br><tt>
|
|
LastModTimeStamp (S) = <font color="#CC0000">Wed
|
|
Feb 24 11:24:06 PST 1999</font></tt>
|
|
<p><tt><font color="#CC0000">
|
|
|
|
</font><font color="#000000">Events</font></tt>
|
|
<br><tt><font color="#000000">
|
|
Startup</font></tt>
|
|
<br><tt><font color="#000000">
|
|
|
|
</font><font color="#CC0000">{108d75a0-bab5-11d2-96c4-0060b0fb9956}</font></tt>
|
|
<br><tt><font color="#CC0000">
|
|
{17894983-ab78-8d75-a0bb-511d296c4006}</font></tt>
|
|
<p><tt><font color="#000000">
|
|
Shutdown</font></tt>
|
|
<br><tt><font color="#000000">
|
|
|
|
</font><font color="#CC0000">{748958ea-abab-511d-296c-40060b0fb995}</font></tt>
|
|
<br><tt><font color="#CC0000">
|
|
{45617894-983a-b788-d75a-0bab11d296c4}</font></tt>
|
|
<br> </blockquote>
|
|
|
|
<h3>
|
|
<a NAME="The Repository: Object instance creation"></a>The Repository:
|
|
Object instance creation</h3>
|
|
All object creation happens via The Repository. <tt>nsIRepository::CreateInstance()</tt>
|
|
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:
|
|
<ol>
|
|
<li>
|
|
The CLSID of the component that would need to create the object instance
|
|
is identified.</li>
|
|
|
|
<ol>Callers use <tt>nsIRepository::ProgIDToCLSID()</tt> to convert the
|
|
ProgID string to the CLSID.</ol>
|
|
|
|
<li>
|
|
Load the dll associated with the CLSID after consulting the Registry</li>
|
|
|
|
<li>
|
|
Instantiate the class factory by calling a globally exported dll function
|
|
<tt>NSGetFactory()</tt>.
|
|
This returns an instance of the class factory that implements the <tt>nsIFactory</tt>
|
|
interface.</li>
|
|
|
|
<li>
|
|
The actual object creation is delegated to this <tt>nsIFactory</tt> instance
|
|
with a call to <tt>nsIFactory::CreateInstance()</tt>.</li>
|
|
</ol>
|
|
|
|
<h3>
|
|
<a NAME="The Service Manager"></a>The Service Manager</h3>
|
|
All globally created system services are available via the <tt>nsIServiceManager</tt>,
|
|
including the <tt>nsIRepository</tt> and <tt>nsIRegistry</tt>. Although
|
|
the <tt>nsIServiceManager</tt> uses the Registry and Repository in the
|
|
creation and maintenance of other services, the circular dependency is
|
|
broken by not letting the <tt>nsIServiceManager</tt> create the <tt>nsIRepository</tt>
|
|
and <tt>nsIRegistry</tt> instance and registering them specially with the
|
|
<tt>nsIServiceManager</tt>.
|
|
The nsIServiceManager is passed into NSGetFactory() for assisting the DLL
|
|
in the Factory creation process.
|
|
<h3>
|
|
<a NAME="Component Registration"></a>Component Registration</h3>
|
|
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 <tt>navigator.repository.autodetect()</tt>. The steps in component
|
|
registration would be:
|
|
<ol>
|
|
<li>
|
|
The dll is loaded</li>
|
|
|
|
<li>
|
|
The component is allowed to self register by a call to a globally exported
|
|
dll function <tt>NSRegisterSelf()</tt>. The <tt>nsIServiceManager</tt>
|
|
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 <a href="#The Registry: XPCOM Hierarchy">XPCOM
|
|
hierarchy</a> in the registry. <tt>nsIRepository</tt>, which can be queried
|
|
from the <tt>nsIServiceManager</tt>, has useful registration functions
|
|
that would easen the process.</li>
|
|
|
|
<li>
|
|
The dll is unloaded</li>
|
|
</ol>
|
|
|
|
<h3>
|
|
<a NAME="Autodetection of Components"></a>Autodetection of Components</h3>
|
|
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 <tt>nsIRepository</tt> has no list of them. The <tt>NSCanUnload()</tt>
|
|
will be called with input parameter <i>force</i> set to <tt>true</tt>.
|
|
The dll has to prepare for getting unloaded. After this call returns, the
|
|
dll <b>will</b> be unloaded if the return value is <tt>true</tt>. If the
|
|
dll detects that it cannot properly prepare for unloading, then it can
|
|
return <tt>false</tt>. 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.
|
|
<h3>
|
|
<a NAME="ProgID Spec"></a>ProgID Spec</h3>
|
|
The general format of ProgIDs is <i><b><font color="#990000">component://</font></b>netscape<b><font color="#990000">/</font></b>compname<b><font color="#990000">?</font></b>var<b><font color="#990000">=</font></b>value<b><font color="#990000">;</font></b>var<b><font color="#990000">=</font></b>value<b><font color="#990000">;</font></b>var<b><font color="#990000">=</font></b>value...</i>
|
|
<p>Let us consider some more examples:
|
|
<ol>
|
|
<li>
|
|
A pluggable protocol that implementes the nfs protocol</li>
|
|
|
|
<li>
|
|
A converter that can handle application/x-zip</li>
|
|
|
|
<li>
|
|
A plugin that can handle image/gif</li>
|
|
|
|
<li>
|
|
A widget that can do a toolbar</li>
|
|
|
|
<li>
|
|
A datasource that can handle mail</li>
|
|
|
|
<li>
|
|
A helperapp that deals with application/postscript</li>
|
|
</ol>
|
|
All the above have what type they are and one or more arguments on what
|
|
they particularly do.
|
|
<p>The ProgID for these would look like
|
|
<ol>
|
|
<li>
|
|
<tt>component://netscape/network-protocol?type=nfs</tt></li>
|
|
|
|
<li>
|
|
<tt>component://netscape/data-converter?type=application/x-zip</tt></li>
|
|
|
|
<li>
|
|
<tt>component://netscape/plugin?type=image/gif;name=ImageMedia%20Gif%20Image%20Plugin;Description=Renders%20GIF%20Images....</tt></li>
|
|
|
|
<li>
|
|
<tt>component://netscape/widget?type=toolbar</tt></li>
|
|
|
|
<li>
|
|
<tt>component://netscape/rdf/datsource?type=mail</tt></li>
|
|
|
|
<li>
|
|
<tt>component://netscape/helperapp?type=application/postscript</tt></li>
|
|
</ol>
|
|
{Assume proper escaping of all above URI}
|
|
<p>The above semantics would let ProgID be an extensible mechanism that
|
|
could be searched on multiple ways. And
|
|
<br>query on a progid should match only whatever was passed in. So a query
|
|
for
|
|
<br>component://netscape/plugin?type=image/gif should pass for the progid
|
|
specified above. We could extend this
|
|
<br>mechanism with wildcards, but I dont want to go there yet... :-)
|
|
<br>
|
|
<h3>
|
|
<a NAME="Startup Components"></a>Components created on events</h3>
|
|
Some dlls have components that want to be created on certain events namely
|
|
Startup, Shutdown (for now). Example is xpinstall.
|
|
<blockquote>RegisterComponentForEvent(..., RegisterationTime when, ...)
|
|
<br>RegisterFactoryForEvent(..., RegistrationTime when,...)</blockquote>
|
|
exists for this purpose. When an application wants to Fire the particular
|
|
event, it calls
|
|
<blockquote>nsComponentManager::FireEvent(RegistrationTime when)</blockquote>
|
|
ComponentManager will look for components that are registered to be created
|
|
on these events and do the following for each of the components:
|
|
<ol>
|
|
<li>
|
|
CreateInstance(...,CID, knsIStartupComponentIID, &obj);</li>
|
|
|
|
<br>For a shutdown event, knsIShutdownComponentIID would be used.
|
|
<br>
|
|
<li>
|
|
obj->Release();</li>
|
|
|
|
<br>The component needs to take adequate measures to keep itself alive
|
|
and figure out how it would delete the object, since a Release() happens
|
|
immediately after a CreateInstace()</ol>
|
|
<b><i>Warning: </i></b>Order of creation of multiple components registered
|
|
on the same event is not defined. Component dependencies aren't thought
|
|
of yet.
|
|
<br>
|
|
<h3>
|
|
<a NAME="How will all this help me"></a>How will all this help me</h3>
|
|
For Component Developers:
|
|
<ul>
|
|
<li>
|
|
Component dlls developed could be dropped into a directory, a JS function
|
|
called after which your component is in business without even a restart
|
|
of the browser. Of course, there needs to be someone accessing it.</li>
|
|
|
|
<li>
|
|
No need to export you CLSID or run around finding where to advertise your
|
|
CLSID</li>
|
|
</ul>
|
|
For Component Users:
|
|
<blockquote>
|
|
<li>
|
|
No more hacking in calls to <tt>nsIRepository::RegisterFactory()</tt></li>
|
|
|
|
<li>
|
|
No need to know the CLSID of components that you want to instantiate. Component
|
|
creation can happen like this</li>
|
|
|
|
<br><tt>nsIRepository::CreateInstance(<b>"<font color="#CC0000">component://netscape/network-protocol&type=nfs</font>"</b>,
|
|
NULL, kProtocolIID, &result);</tt>
|
|
<br>instead of
|
|
<br><strike>nsIRepository::CreateInstance(NFS_PROTOCOL_CID, NULL, domIID,
|
|
&result);</strike></blockquote>
|
|
|
|
<h3>
|
|
<a NAME="What has happened so far"></a>What has happened so far</h3>
|
|
|
|
<ul>
|
|
<li>
|
|
Autoregistration implemented to grovel for components from the current
|
|
directory</li>
|
|
|
|
<li>
|
|
nsRepository is a global object. Not nsIRepository exists.</li>
|
|
|
|
<li>
|
|
nsRepository::ProgIDToCLSID() implemented</li>
|
|
</ul>
|
|
|
|
<h3>
|
|
<a NAME="Changes to XPCOM happening"></a>Changes to XPCOM happening</h3>
|
|
|
|
<ul>
|
|
<li>
|
|
API changes to get ProgID in entire registration process for factories
|
|
and components</li>
|
|
|
|
<li>
|
|
ProgID cache to improve performance of ProgID queries</li>
|
|
|
|
<li>
|
|
Notion of Component dlls living in a <b>Components directory </b>and autoregistration
|
|
will load/manage only these components. Other components that are linked
|
|
in to the app need to call <tt>nsRepository::RegisterFactory()</tt> from
|
|
the app. <b>To make this happen we need a list of these.</b></li>
|
|
|
|
<li>
|
|
<b>nsRegistry:</b> Enabling the new nsRegistry developed by Bill Law <law@netscape.com></li>
|
|
|
|
<li>
|
|
Service Manager and Repository: Merge them</li>
|
|
|
|
<li>
|
|
Convenience function to createIntance(progid)</li>
|
|
|
|
<li>
|
|
Base ProgID in the interface ID header file</li>
|
|
</ul>
|
|
|
|
<h3>
|
|
<a NAME="What should I do"></a>What should I do</h3>
|
|
|
|
<ul><b><font color="#CC0000">Component Developers</font></b>
|
|
<ul>
|
|
<li>
|
|
<font color="#000000">Implement <tt>NSRegisterSelf()</tt> for your component
|
|
dlls. Sample implementation that perf</font> <a href="http://cvs-mirror.mozilla.org/webtools/lxr/source/modules/libpref/src/nsPref.cpp#608">http://cvs-mirror.mozilla.org/webtools/lxr/source/modules/libpref/src/nsPref.cpp#608</a></li>
|
|
|
|
<li>
|
|
Use <tt>nsRepository::RegisterComponent()</tt> instead of <tt>nsRepository::RegisterFactory()</tt>
|
|
if your component lives in a DLL</li>
|
|
|
|
<li>
|
|
<b>Dont use static constructors in loadable components</b></li>
|
|
</ul>
|
|
|
|
<p><br><b><font color="#CC0000">Component Users</font></b>
|
|
<ul>
|
|
<li>
|
|
Create all your components using ProgID rather than CID</li>
|
|
|
|
<li>
|
|
If you were thinking of managing creation of components yourself, think
|
|
again. The repository may be already doing that.</li>
|
|
</ul>
|
|
</ul>
|
|
|
|
<h3>
|
|
<a NAME="Issues"></a>Issues</h3>
|
|
|
|
<ul>
|
|
<li>
|
|
Need support for questions like:</li>
|
|
|
|
<ol>
|
|
<li>
|
|
Enumerate all CLSIDs that implement a particular interface.</li>
|
|
|
|
<li>
|
|
Let a particular CLSID be the preferable implementation for an interface.</li>
|
|
|
|
<br>I dont know how this a XPCOM component user could use it unless there
|
|
could be a call like:
|
|
<br><tt>nsIRepository::CreateInstance(<b>NULL</b>, NULL, nsWidgetIID, &result);</tt>
|
|
<li>
|
|
Enumerate all interfaces supported by a CLSID</li>
|
|
</ol>
|
|
|
|
<li>
|
|
Resolving naming conflicts between ProgID</li>
|
|
|
|
<li>
|
|
Store component specific name-values under <tt>ROOTKEY_COMMON\\<i>component.class.version\\</i></tt></li>
|
|
|
|
<li>
|
|
Add a registry entry under <tt>ROOTKEY_COMMON\\<i>component.class.version\\</i></tt>to
|
|
indicate the willingness for a CLSID to behave as a Service.</li>
|
|
|
|
<li>
|
|
Add quick registration support functions in <tt>nsIRepository</tt> for
|
|
components to use.</li>
|
|
|
|
<li>
|
|
Is the hierarchy <tt>ROOTKEY_COMMON\\<b>Classes</b>\\CLSID </tt>acceptable.</li>
|
|
|
|
<li>
|
|
Should we have a nsIRepository. JS needs it so that they can reflect it
|
|
in javascript. Remove &'s in the API.</li>
|
|
</ul>
|
|
|
|
<hr WIDTH="100%">
|
|
<br><i><font size=-1>Last Modified: 28 Jan 1998</font></i>
|
|
<br><font size=-1><i>Feedback to: </i><a href="news:netscape.public.mozilla.xpcom">netscape.public.mozilla.xpcom</a></font>
|
|
</body>
|
|
</html>
|