gecko-dev/xpcom/doc/nsIClassInfo-overview.html
shaver%mozilla.org fcf7cd0d9f 67699: all your nsIClassInfo is belong to us
- teach nsGenericFactory about nsIClassInfo, and nsIClassInfo.idl to the
  builds
- add a heaping serving of macro love for classes that want to support it
- convert many modules to use nsGenericModule the new way
- handful of warning and modeline fixes
- nsSample and some XPConnect test classes now have nsIClassInfo support for
  testing
2001-03-12 20:43:02 +00:00

263 lines
12 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<title>nsIClassInfo Overview</title>
<meta name="author" content="Mike Shaver">
<meta name="description" content="General Overview of nsIClassInfo infrastructure">
<style type="text/css">
a:link, a:visited { text-decoration: none; }
</style>
</head>
<body bgcolor="#ffffff" link="#0000ee" vlink="#551a8b" alink="#0000ee">
<h2><code>nsIClassInfo</code> Overview</h2>
Mike Shaver &lt;<a href="mailto:shaver@mozilla.org">shaver@mozilla.org</a>
&gt;<br>
&nbsp;&nbsp; &nbsp; Last Modified: March 12, 2001<br>
<hr align="Left" width="100%" size="2">
<h3>Table of Contents</h3>
<ul>
<li><a href="#What_is_nsIClassInfo">What is <code>nsIClassInfo</code>?</a></li>
<li><a href="#How_do_I_use_it">How do I use it?</a><a href="#What_is_nsIClassInfo"></a></li>
<li><a href="#Doesnt_that_break_the_COM">Doesn't that break the COM <code>
QueryInterface</code> rules?</a><a href="#Doesnt_that_break_the_COM"></a></li>
<li><a href="#What_are_the_language_helpers_for">What are the "language
helpers" for?</a><br>
</li>
<li><a href="#That_sounds_useful_How_do_I_make_it">That sounds useful.
How do I make that work with my code?</a></li>
<ul>
<li>I'm writing C++ code, and</li>
<ul>
<li><a href="#Im_writing_C_code_and_I_use_the">I use the generic factory
and <code>nsModuleComponentInfo</code></a></li>
<li><a href="#Im_writing_C_code_and_I_use_a_custom">I use a custom factory
or a singleton service object</a><br>
</li>
</ul>
</ul>
<ul>
<li><a href="#Im_writing_JS_code">I'm writing JS code.</a></li>
</ul>
<li><a href="#Whats_interface_flattening">What's "interface flattening"?</a><br>
</li>
</ul>
<hr align="Left" width="100%" size="2">
<h4><a name="What_is_nsIClassInfo"></a>What is <code>nsIClassInfo</code>?</h4>
<p><a href="http://lxr.mozilla.org/mozilla/source/xpcom/components/nsIClassInfo.idl#38"><code>
nsIClassInfo</code></a> is an interface that provides information
about a specific implementation class, to wit:</p>
<ul>
<li> a contract ID and class ID through which it may be instantiated;</li>
<li>the language of implementation (C++, JavaScript, etc.);</li>
<li> a list of the interfaces implemented by the class;</li>
<li>flags indicating whether or not the class is threadsafe or a singleton;
and</li>
<li>helper objects in support of various language bindings.</li>
</ul>
<h4><a name="How_do_I_use_it"></a>How do I use it?</h4>
<p> To get the <code>nsIClassInfo</code> object for the implementation behind
a given interface, simply <code>QueryInterface</code> for the nsIClassInfo
interface:</p>
<blockquote>C++:<br>
<code>nsCOMPtr&lt;nsIClassInfo&gt; info = do_QueryInterface(ifacePtr);</code><br>
<br>
JavaScript:<br>
<code>var info = ifacePtr.QueryInterface(Components.interfaces.nsIClassInfo);</code></blockquote>
<p>It's important to note that this will usually return a <i>singleton</i>
object: there often exists only one nsIClassInfo implementation for
all implementations of a given class. This is very important, because it
means that you can't <code>QueryInterface</code> back to the original object,
no matter how hard you try.</p>
<h4><a name="Doesnt_that_break_the_COM"></a>Doesn't that break the COM
<code>QueryInterface</code> rules?</h4>
<p>Quite. As discussed in <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=67699">
bug 67699</a>, though, it's a reasonable concession to make in order
to avoid an additional vtbl entry on every class that wants to export <code>
nsIClassInfo</code> data.<br>
</p>
<h4><a name="What_are_the_language_helpers_for"></a>What are the "language
helpers" for?</h4>
<p>The language helpers are basically hooks for alternate language bindings
to use for providing language-specific wrapping and manipulation behaviour,
without adding code to every wrapped object.&nbsp; In <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=67699">
bug 67669</a>, jband tells us what XPConnect does with the language helpers:</p>
<blockquote>
<p>When wrapping an object xpconnect QIs the object for its classinfo
(say 'foo'). If it has seen that foo classinfo pointer before then it knows
that this object is a foo and it can reuse all the info is knows about foo
objects. If it has never seen foo it will gather info (such as the JS helper)
and remember that for future wrappings of foo objects.</p>
<p> Assuming that the foo helper tells xpconnect to not bother QI'ing
each foo instance for a per instance helper (or if the instances don't respond
to QI for the helper) then the same foo helper is used on all calls from
JS relating to the foo instances. </p>
<p>What you may be missing is that methods on the helper (nsIXPCScriptable
in the xpconnect case) *all* receive a pointer to the instance wrapper when
called. I.e. the helper methods have an explicit 'self' param. This allows
the helper to customize its response for each method call without requiring
a helper per instance.</p>
</blockquote>
See <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=67699">bug 67699</a>
for more interesting discussion about pluggable language helpers and decoupling
them from specific wrapped classes.
<p></p>
<h4><a name="That_sounds_useful_How_do_I_make_it"></a>That sounds useful.
How do I make it work with my code?</h4>
<p>Why, yes, it <i>is</i> useful. To provide <code>nsIClassInfo</code>
data for your class, you need to ensure that it returns an <code>nsIClassInfo</code>
-implementing object when it is <code>QueryInterface</code>d for <code>
nsIClassInfo</code> . Simple enough, but it can be even simpler through
the use of a handful of helper macros/functions. Choose your own adventure:</p>
<h4><a name="Im_writing_C_code_and_I_use_the"></a>I'm writing C++ code,
and I use the generic factory and <code>nsModuleComponentInfo</code>.</h4>
<p>First, make sure that your class has the <code>nsIClassInfo</code>
helpers, by changing the <code>NS_IMPL_ISUPPORTS</code> line:</p>
<blockquote><code>NS_IMPL_ISUPPORTS2(nsSampleImpl, nsISample, nsIOther)</code><br>
</blockquote>
<p>becomes</p>
<blockquote><code>NS_IMPL_ISUPPORTS2_CI(nsSampleImpl, nsISample, nsIOther)</code><br>
</blockquote>
<p>This will provide an implementation of a helper function, named
<code>nsSampleImpl_GetInterfacesHelper</code>, which handles the processing
of <code>nsIClassInfo::getInterfaces</code>.</p>
<p>Next, in your module code, use <code>NS_DECL_CLASSINFO</code> to
provide the rest of the per-class infrastructure (a global pointer into
which to stash the <code>nsIClassInfo</code> object, and an extern declaration
of the interfaces-helper, in case it's defined in another file):</p>
<blockquote><code>NS_DECL_CLASSINFO(nsSampleImpl)</code><br>
</blockquote>
<p>You'll need one of these lines for each <code>nsIClassInfo</code>
-supporting class represented in your <code>nsModuleComponentInfo</code>
array.</p>
<p>Lastly, fill in the appropriate members of <code>nsModuleComponentInfo</code>
to wire everything up:</p>
<blockquote><code>static nsModuleComponentInfo components[] =</code><br>
<code>{</code><br>
<code> &nbsp; {<br>
&nbsp; &nbsp; "Sample Component", NS_SAMPLE_CID, NS_SAMPLE_CONTRACTID,
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br>
&nbsp; &nbsp; nsSampleImplConstructor,</code><br>
<code> &nbsp; &nbsp; nsSampleRegistrationProc,</code><br>
<code> &nbsp; &nbsp; nsSampleUnregistrationProc,</code><br>
<code> &nbsp; &nbsp; nsnull /* no factory destructor */,</code><br>
<code><font color="#ff0000"> &nbsp; &nbsp; NS_CI_INTERFACE_GETTER_NAME(nsSampleImpl),&nbsp;
/* interface getter */</font></code><br>
<code> &nbsp; &nbsp; nsnull /* no language helper */,</code><br>
<code><font color="#ff0000"> &nbsp; &nbsp; &amp;NS_CLASSINFO_NAME(nsSampleImpl),&nbsp;
/* global class-info pointer */</font></code><br>
<code> &nbsp; &nbsp; 0 /* no class flags */<br>
&nbsp; }</code><br>
<code>};</code><br>
</blockquote>
<p>If you want to add a callback which provides language-helper
objects, replace the last <code>nsnull</code> with your callback. See the
<a href="http://lxr.mozilla.org/mozilla/source/xpcom/components/nsIClassInfo.idl"><code>
nsIClassInfo</code> IDL file</a> for details on language helpers and
other esoterica.</p>
<p><b><i>Note</i></b>: the details of these macros may change
slightly over the next week or so, as we refine a system for using table-driven
QI and sharing data between QI and the class-info calls.<br>
</p>
<h4><a name="Im_writing_C_code_and_I_use_a_custom"></a>I'm writing
C++ code, and I use a custom factory or a singleton service object.</h4>
<p>You need some utility macros, don't ya?&nbsp; We're working
on it.&nbsp; (You should really use the generic factory and module, though.&nbsp;
See <a href="http://lxr.mozilla.org/seamonkey/source/intl/uconv/src/nsUConvModule.cpp">
nsUConvModule.cpp</a> for an example of how to use <code>nsModuleComponentInfo</code>
and the generic modules even when you have highly-custom registration
requirements.)</p>
<h4><a name="Im_writing_JS_code"></a>I'm writing JS code.</h4>
You poor thing. You suffer without even a GenericModule helper. We're
<a href="http://bugzilla.mozilla.org/show_bug.cgi?id=71689">working on
that</a>, too.
<h4><a name="Whats_interface_flattening"></a>What's "interface
flattening"?</h4>
<p></p>
<p> Interface flattening is a way to present multiple interfaces
of the same object to a language binding, without requiring explicit <code>
QueryInterface</code> calls.&nbsp; Consider the following interfaces and
an object <code>obj</code> that implements both of them:</p>
<blockquote>
<p><code>interface nsIFoo : nsISupports {<br>
&nbsp; &nbsp; void fooMeth(in string message);<br>
};</code></p>
<p><code>interface nsIBar : nsISupports {<br>
&nbsp; &nbsp; void barMeth(in PRUint32 meaning);<br>
};</code></p>
</blockquote>
<p>You could use the following code to call both fooMeth and
barMeth without any QueryInterface:<br>
</p>
<blockquote><code>obj.fooMeth("welcome to foo");<br>
obj.barMeth(42);</code></blockquote>
<p>Pretty, no?&nbsp; Pretty, yes. </p>
<p>There are also intricacies related to conflicting method
names and the difference between interface sets that are part of a contract's
promise and those which are simply artifacts of the implementation, but they're
beyond the scope of this overview.<br>
<br>
</p>
</body>
</html>