зеркало из https://github.com/mozilla/pjs.git
488 строки
14 KiB
HTML
488 строки
14 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="GENERATOR" content="Mozilla/4.61 [en] (X11; U; Linux 2.2.5-15 i686) [Netscape]">
|
||
|
<title>xpcom-review</title>
|
||
|
</head>
|
||
|
<body>
|
||
|
|
||
|
<center>
|
||
|
<h1>
|
||
|
XPCOM Brown Bag I</h1></center>
|
||
|
|
||
|
<center>Suresh Duddi <<a href="mailto:dp@netscape.com">dp@netscape.com</a>>
|
||
|
<br>August 17, 1999
|
||
|
<hr WIDTH="100%"></center>
|
||
|
|
||
|
<h3>
|
||
|
Terminology</h3>
|
||
|
|
||
|
<table BORDER WIDTH="100%" NOSAVE >
|
||
|
<tr NOSAVE>
|
||
|
<td NOSAVE>Interface</td>
|
||
|
|
||
|
<td>Contract betwen the implementation and usage. A pure virtual abstract
|
||
|
base class with no data members. eg. nsIZip</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>IID</td>
|
||
|
|
||
|
<td>Interface ID {xxxxx-xxx-xxx-xxxxxx} a unique number that identifies
|
||
|
the Interface being talked about</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>nsISupports</td>
|
||
|
|
||
|
<td>The mother of all interfaces. All interfaces ultimately inherit from
|
||
|
this. Provides refcounting. The IID and definition has been carefully choosen
|
||
|
so as to be binary compatible with COM.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>Component</td>
|
||
|
|
||
|
<td>An implementation of a set of interfaces identified by a CLSID</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>Object</td>
|
||
|
|
||
|
<td>An instance of a Component</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>CLSID</td>
|
||
|
|
||
|
<td>Component ID {xxxxx-xxx-xxx-xxxxxx} a unique number that identifies
|
||
|
a component</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>Module</td>
|
||
|
|
||
|
<td>A packaging of a set of Components (ie) a DLL</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>Factory</td>
|
||
|
|
||
|
<td>An object whose sole purpose is creation of objects of a particular
|
||
|
component. There exists only one factory for every Component (CLSID). The
|
||
|
IID and definition has been carefully choosen so as to be binary compatible
|
||
|
with COM. nsIFactory</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>ClassObject</td>
|
||
|
|
||
|
<td>Same object as factory.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>ProgID</td>
|
||
|
|
||
|
<td>A String name for a Component.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>ComponentManager</td>
|
||
|
|
||
|
<td>Central Object of XPCOM that provides API for object creation and management.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>ServiceManager</td>
|
||
|
|
||
|
<td>A singleton manager. Holds and manages singleton references to objects
|
||
|
for application. Going to be merged with the componentmanager.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>Service</td>
|
||
|
|
||
|
<td>A singleton object within an application.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>Registry</td>
|
||
|
|
||
|
<td>A hierarchical attribute-value pair storage.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>XPIDL</td>
|
||
|
|
||
|
<td>Cross Platform Interface Definition Language. Language for expressing
|
||
|
interfaces.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>Typelib</td>
|
||
|
|
||
|
<td>A storage for meta information about interfaces. Interfaces expressed
|
||
|
in IDL have their meta information maintained in Typelib automatically.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>XPConnect</td>
|
||
|
|
||
|
<td>Ability to call c++ implementations of interfaces expressed in IDL
|
||
|
from javascript and viceversa.</td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
|
||
|
<h3>
|
||
|
An Interface</h3>
|
||
|
|
||
|
<ul>
|
||
|
<li>
|
||
|
E.g Image Decoder <a href="http://lxr.mozilla.org/seamonkey/source/modules/libimg/public_com/nsIImgDecoder.h">nsIImgDecoder</a></li>
|
||
|
|
||
|
<br>
|
||
|
<li>
|
||
|
Dont put data members</li>
|
||
|
|
||
|
<li>
|
||
|
Return value of member function should always be <tt>nsresult using the
|
||
|
NS_IMETHOD macro.</tt></li>
|
||
|
|
||
|
<li>
|
||
|
Use XPIDL for interface header files</li>
|
||
|
|
||
|
<li>
|
||
|
Useful Macros if not using XPIDL</li>
|
||
|
|
||
|
<ul>
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_DEFINE_STATIC_IID_ACCESSOR">NS_DEFINE_STATIC_IID_ACCESSOR</a>
|
||
|
- Defines static GetIID() method for an interface</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_IMETHOD">NS_IMETHOD</a>
|
||
|
- Prototypes return value of interface function declaration</li>
|
||
|
</ul>
|
||
|
</ul>
|
||
|
|
||
|
<h3>
|
||
|
The Component</h3>
|
||
|
|
||
|
<ul>
|
||
|
<li>
|
||
|
E.g GIF Image Decoder nsGIFDecoder <a href="http://lxr.mozilla.org/seamonkey/source/modules/libimg/gifcom/nsGIFDecoder.h">nsGIFDecoder.h</a>,
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/source/modules/libimg/gifcom/nsGIFDecoder.cpp">nsGIFDecoder.cpp</a></li>
|
||
|
|
||
|
<br>
|
||
|
<li>
|
||
|
Useful Macros</li>
|
||
|
|
||
|
<ul>
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_DECL_ISUPPORTS">NS_DECL_ISUPPORTS</a>
|
||
|
- Declares all methods of nsISupports. Used in implementation declaration
|
||
|
header file.</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_INIT_ISUPPORTS">NS_INIT_ISUPPORTS</a>
|
||
|
- nitilize the base class ISupports. Used in constructor of implementation.</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_IMPL_ISUPPORTS">NS_IMPL_ISUPPORTS</a>
|
||
|
- Implement the nsISupports functions. Used in implementation file.</li>
|
||
|
|
||
|
<ul>
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_IMPL_ADDREF">NS_IMPL_ADDREF</a>
|
||
|
- Implementation of nsISupports::Release()</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_IMPL_RELEASE">NS_IMPL_RELEASE</a>
|
||
|
- Implementation of nsISupports::AddRef()</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_IMPL_QUERY_INTERFACE">NS_IMPL_QUERY_INTERFACE</a>
|
||
|
- Implementation of nsISupports::QueryInterface() for one IID</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_IMPL_ISUPPORTS2">NS_IMPL_ISUPPORTS2</a>
|
||
|
- Implements the nsISupports function with QueryInterface for two IIDs</li>
|
||
|
|
||
|
<br> </ul>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_DEFINE_IID">NS_DEFINE_IID</a>
|
||
|
- Define a variable of type nsIID initialized with a struct representatio
|
||
|
of an IID</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_GET_IID">NS_GET_IID</a>
|
||
|
- Use this instead of nsIFoo::GetIID() or NS_DEFINE_IID()...</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_DEFINE_CID">NS_DEFINE_CID</a>
|
||
|
- Define a variable of type nsCID intialized with a struct representation
|
||
|
of the CLSID</li>
|
||
|
|
||
|
<br>
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_IMETHODIMP">NS_IMETHODIMP</a>
|
||
|
- Prototypes return value for interface functions implementation. Used
|
||
|
in implementation file.</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_ADDREF">NS_ADDREF</a>,
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_IF_ADDREF">NS_IF_ADDREF</a>
|
||
|
- Addref an object by client</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_ADDREF_THIS">NS_ADDREF_THIS</a>
|
||
|
- Addref used in object implementation. Dont need this if using NS_IMPL_ADDREF</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_RELEASE">NS_RELEASE</a>,
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_IF_RELEASE">NS_IF_RELEASE</a>
|
||
|
- Release an object by client</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_RELEASE_THIS">NS_RELEASE_THIS</a>
|
||
|
- Released used in object implementation. Dont need this if using NS_IMPL_RELEASE</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_RELEASE2">NS_RELEASE2</a>
|
||
|
- Release and get the refcount. Useful to check if refcount hit Zero.</li>
|
||
|
|
||
|
<br> </ul>
|
||
|
|
||
|
<li>
|
||
|
Generic Factory - A generic factory implementation with callback ability
|
||
|
for object creation. Simplies factory implementation.</li>
|
||
|
</ul>
|
||
|
|
||
|
<h3>
|
||
|
Object Creation</h3>
|
||
|
|
||
|
<ul><tt>rv = compMgr->CreateInstance(imgProgID, NULL, <a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_GET_IID">NS_GET_IID</a>(nsIImgDecoder),
|
||
|
(void **)&imgdec);</tt>
|
||
|
<br>
|
||
|
<li>
|
||
|
It is preferable to use the NS_GET_IID() version of getting iid instead
|
||
|
of the old way</li>
|
||
|
|
||
|
<ul>
|
||
|
<li>
|
||
|
NS_DEFINE_IID(kImgDecodeIID, NS_IIMGDECODER_IID);</li>
|
||
|
|
||
|
<br>and then using kImgDecoderIID for the IID
|
||
|
<li>
|
||
|
<b>DO NOT USE nsIImgDecoder::GetIID()</b></li>
|
||
|
</ul>
|
||
|
|
||
|
<li>
|
||
|
The component manager does this on a CreateInstance()</li>
|
||
|
|
||
|
<ul>
|
||
|
<li>
|
||
|
map ProgID to CLSID</li>
|
||
|
|
||
|
<li>
|
||
|
Get module object for dll which implements component CLSID</li>
|
||
|
|
||
|
<li>
|
||
|
nsISupports classObject = module->GetClassObject()</li>
|
||
|
|
||
|
<li>
|
||
|
nsIFactory factory = classObject->QueryInterface(NS_GET_IID(nsIFactory));</li>
|
||
|
|
||
|
<li>
|
||
|
return factory->CreateInstance(IID);</li>
|
||
|
</ul>
|
||
|
|
||
|
<li>
|
||
|
<b>[hint]</b> Use nsCOMPtr</li>
|
||
|
|
||
|
<br>
|
||
|
<ul><tt>nsCOMPtr <nsIImgDecoder> imgdec;</tt>
|
||
|
<br><tt>rv = compMgr->CreateInstance(imgProgID, NULL, <a href="http://lxr.mozilla.org/seamonkey/ident?i=NS_GET_IID">NS_GET_IID</a>(nsIImgDecoder),
|
||
|
<font color="#990000">getter_AddRefs(imgdec)</font>);</tt></ul>
|
||
|
</ul>
|
||
|
|
||
|
<h3>
|
||
|
Object Release</h3>
|
||
|
|
||
|
<blockquote><tt>NS_IF_RELEASE(obj);</tt>
|
||
|
<p>It should be noted that release and addref are directly talking to the
|
||
|
object with no intermediaries. The macro NS_*_RELEASE() set the object
|
||
|
to NULL.</blockquote>
|
||
|
|
||
|
<h3>
|
||
|
Component Registration Process</h3>
|
||
|
|
||
|
<ul>
|
||
|
<li>
|
||
|
<a href="http://lxr.mozilla.org/seamonkey/source/xpcom/components/nsIModule.idl">nsIModule.idl</a></li>
|
||
|
</ul>
|
||
|
|
||
|
<ul>At startup of apprunner, a call to <tt>nsIComponentManager::AutoRegister(<i>Startup,
|
||
|
<exedir>/Components</i>)</tt> This will descend recursively looking
|
||
|
for loadable files (files with a certain externsion and on Mac of certain
|
||
|
type) If the file had changed since the last time the file was visited
|
||
|
(ModifiedDate check) registration is initiated on the file.
|
||
|
<p>Registration involves:
|
||
|
<ul>
|
||
|
<li>
|
||
|
Load the dll</li>
|
||
|
|
||
|
<li>
|
||
|
nsIModule module = "NSGetModule"() - Create the module object</li>
|
||
|
|
||
|
<li>
|
||
|
module->RegisterSelf(<i>location</i>)</li>
|
||
|
</ul>
|
||
|
|
||
|
<p><br>The module registers with the componentmanager every {CLSID, ProgID}
|
||
|
it implements with a call to <tt>nsIComponentManager::RegisterComponentSpec()</tt>
|
||
|
These registrations are stored in the registry. Hence the next time around,
|
||
|
the module is loaded not at startup but only when the first object that
|
||
|
is implemented by a component in the module is created.
|
||
|
<p>e.g Registration of GIF Decoder <a href="http://lxr.mozilla.org/seamonkey/source/modules/libimg/gifcom/nsGIFModule.cpp">nsGIFModule.cpp</a>
|
||
|
<p><b>DO NOT CONVERT YOUR COMPONENT TO nsIModule yet. We are working on
|
||
|
the sample code which will make the conversion process even simpler.</b></ul>
|
||
|
|
||
|
<h3>
|
||
|
Module Unloading</h3>
|
||
|
|
||
|
<blockquote>Every module implements a CanUnload() function that returns
|
||
|
a boolean of whether the module can be unloaded. This implies that the
|
||
|
module needs to be counting all outstanding object and return PR_TRUE only
|
||
|
if there are no outstanding objects served from within the module.
|
||
|
<p>Unloading happens either on a Timer or on an explicit call to nsComponentManager::<a href="http://lxr.mozilla.org/seamonkey/ident?i=FreeLibraries">FreeLibraries()</a>.
|
||
|
The general logic is:
|
||
|
<ul>
|
||
|
<li>
|
||
|
PRBool unloadable = module->CanUnload()</li>
|
||
|
|
||
|
<li>
|
||
|
if (unloadable && marked for unload)</li>
|
||
|
|
||
|
<ul>
|
||
|
<li>
|
||
|
Unload()</li>
|
||
|
</ul>
|
||
|
|
||
|
<li>
|
||
|
if (unloadable && not mark for unload)</li>
|
||
|
|
||
|
<ul>
|
||
|
<li>
|
||
|
mark for unload</li>
|
||
|
</ul>
|
||
|
</ul>
|
||
|
No assumptions can be made that the module will be unloaded if nsIModule::CanUnload()
|
||
|
returns PR_TRUE. It is guaranteed that if nsIModule::CanUnload() returns
|
||
|
PR_FALSE, the module <b>will not</b> be unloaded.</blockquote>
|
||
|
|
||
|
<h3>
|
||
|
The Component Registry</h3>
|
||
|
|
||
|
<blockquote>Nothing but a persistent hiearchical store of attribute value
|
||
|
pairs. It is the use of the registry by XPCOM that is very interesting.
|
||
|
Physical location of the registry is in the <exedir>/component.reg
|
||
|
<p>The xpcom hierarchy of the registry is considered to be opaque to components.
|
||
|
Use the nsIComponentManager Api to register as opposed to meddling with
|
||
|
the xpcom hierarchy in the registry directly.
|
||
|
<p>mozregistry.dat is NOT the component registry. It is the application
|
||
|
(apprunner) registry.</blockquote>
|
||
|
|
||
|
<h3>
|
||
|
Old Method for Module definition</h3>
|
||
|
|
||
|
<blockquote>Previously module definition was scattered across many exported
|
||
|
functions from a dll.
|
||
|
<br> <a href="http://lxr.mozilla.org/seamonkey/ident?i=NSGetFactory">NSGetFactory(
|
||
|
)</a>, <a href="http://lxr.mozilla.org/seamonkey/ident?i=NSCanUnload">NSCanUnload(
|
||
|
)</a>, <a href="http://lxr.mozilla.org/seamonkey/ident?i=NSRegisterSelf">NSRegisterSelf(
|
||
|
)</a>, <a href="http://lxr.mozilla.org/seamonkey/ident?i=NSUnregisterSelf">NSUnregisterSelf(
|
||
|
)</a>
|
||
|
<br>Now these are combined into a <a href="http://lxr.mozilla.org/seamonkey/source/xpcom/components/nsIModule.idl">nsIModule</a>
|
||
|
<p><b>Please continue to use the old method until sample code using nsIModule
|
||
|
is available.</b></blockquote>
|
||
|
|
||
|
<h3>
|
||
|
ComponentManager vs ServiceManager</h3>
|
||
|
|
||
|
<blockquote>ServiceManager is a an object that holds instances to objects
|
||
|
in a cache and manages them. It uses the ComponentManager to create an
|
||
|
instance the first time an object is queried for. Lifetime of the instance
|
||
|
is currently the lifetime of the app. We are working on what is required
|
||
|
here and how to control the lifetime. Possbily merging ServiceManager with
|
||
|
the ComponentManager.
|
||
|
<p>From the components perspective there is nothing it does special to
|
||
|
behave as a service. The application controls the creation of services
|
||
|
by its usage or call to <tt>nsServiceManager::GetService()</tt> .Some components
|
||
|
that want to enforce being a service return cached instances on <tt>nsComponentManager::CreateInstance()
|
||
|
</tt>.
|
||
|
We are working on a more elegant syntax and semantics for this. Post suggestions
|
||
|
to newsgroup netscape.public.mozilla.xpcom (or Email <a href="mailto:mozilla-xpcom@mozilla.org">mozilla-xpcom@mozilla.org</a>)
|
||
|
with suggestions.</blockquote>
|
||
|
|
||
|
<h3>
|
||
|
ProgID vs CLSID</h3>
|
||
|
|
||
|
<blockquote>CLSID is a number identifying a specific implementation.
|
||
|
<p>ProgID is a like a pointer to a CLSID. It is an opaque string to xpcom.It
|
||
|
is used for two purposes.
|
||
|
<ol>
|
||
|
<li>
|
||
|
Implementation independence for clients: <tt>component://netscape/registry</tt></li>
|
||
|
|
||
|
<br>The CLSID associating itself to a ProgID can be changed. Hence if a
|
||
|
new implementation with a new CLSID superceeds an older implementation,
|
||
|
the client wont be tied to the older implementation if it uses the ProgID.
|
||
|
<li>
|
||
|
CLSID switching: <tt>component://netscape/image/decoder&type=image/gif</tt></li>
|
||
|
|
||
|
<br>A client wants to create different objects based on a switch (the mimetype
|
||
|
for the case of imagedecoders). A Progid is formed with a concatenation
|
||
|
of a BASE_PROGID and the switch (mimetype) and an instance of that created.
|
||
|
Components, when registering, associate their CLSID to specific progids.</ol>
|
||
|
NOTE: Only Clients that are adamant about the use of a specific implementation
|
||
|
need to create instances using CLSID.
|
||
|
<p>We encourage use of ProgID. This works well in the scriptable world
|
||
|
too.
|
||
|
<p><b>We are working on a ProgID syntax.</b></blockquote>
|
||
|
|
||
|
<h3>
|
||
|
Steps for XPCOM Review</h3>
|
||
|
|
||
|
<ol>
|
||
|
<li>
|
||
|
Know your interfaces and objects.</li>
|
||
|
|
||
|
<br>List the objects your component is serving. List the interfaces that
|
||
|
it implements.
|
||
|
<li>
|
||
|
List the objects that your component uses.</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://www.mozilla.org/scriptable/interface-rules-we-break.html">http://www.mozilla.org/scriptable/interface-rules-we-break.html</a></li>
|
||
|
|
||
|
<li>
|
||
|
Do not switch over to using nsIModule yet. We will publish sample code
|
||
|
in a week with guidelines.</li>
|
||
|
|
||
|
<li>
|
||
|
Use the above stated macros.</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="http://www.mozilla.org/projects/xpcom/">http://www.mozilla.org/projects/xpcom/</a>
|
||
|
- <b>Watch for more documents here</b></li>
|
||
|
</ol>
|
||
|
|
||
|
<p><br>
|
||
|
<hr WIDTH="100%">
|
||
|
<br>
|
||
|
</body>
|
||
|
</html>
|