pjs/xpcom/doc/xpcom-brownbag-1.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 &lt;<a href="mailto:dp@netscape.com">dp@netscape.com</a>>
<br>August 17, 1999&nbsp;
<hr WIDTH="100%"></center>
<h3>
Terminology</h3>
&nbsp;
<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&nbsp; {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>&nbsp;
<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>&nbsp;
<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>&nbsp;
- 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>&nbsp;</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>&nbsp;
<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>&nbsp;
- 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>&nbsp;</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 **)&amp;imgdec);</tt>
<br>&nbsp;
<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>&nbsp;
<ul><tt>nsCOMPtr &lt;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,
&lt;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 &amp;&amp; marked for unload)</li>
<ul>
<li>
Unload()</li>
</ul>
<li>
if (unloadable &amp;&amp; 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 &lt;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>&nbsp;<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&amp;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>&nbsp;
</body>
</html>