mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-30 05:35:31 +00:00
fcf7cd0d9f
- 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
263 lines
12 KiB
HTML
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 <<a href="mailto:shaver@mozilla.org">shaver@mozilla.org</a>
|
|
><br>
|
|
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<nsIClassInfo> 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. 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> {<br>
|
|
"Sample Component", NS_SAMPLE_CID, NS_SAMPLE_CONTRACTID,
|
|
<br>
|
|
nsSampleImplConstructor,</code><br>
|
|
<code> nsSampleRegistrationProc,</code><br>
|
|
<code> nsSampleUnregistrationProc,</code><br>
|
|
<code> nsnull /* no factory destructor */,</code><br>
|
|
<code><font color="#ff0000"> NS_CI_INTERFACE_GETTER_NAME(nsSampleImpl),
|
|
/* interface getter */</font></code><br>
|
|
<code> nsnull /* no language helper */,</code><br>
|
|
<code><font color="#ff0000"> &NS_CLASSINFO_NAME(nsSampleImpl),
|
|
/* global class-info pointer */</font></code><br>
|
|
<code> 0 /* no class flags */<br>
|
|
}</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? We're working
|
|
on it. (You should really use the generic factory and module, though.
|
|
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. Consider the following interfaces and
|
|
an object <code>obj</code> that implements both of them:</p>
|
|
<blockquote>
|
|
<p><code>interface nsIFoo : nsISupports {<br>
|
|
void fooMeth(in string message);<br>
|
|
};</code></p>
|
|
<p><code>interface nsIBar : nsISupports {<br>
|
|
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? 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>
|