File:  [mozdev] / books / www / chapters / ch08.html
Revision 1.40: download - view: text, annotated - select for diffs - revision graph
Fri Apr 4 16:27:40 2003 UTC (16 years, 7 months ago) by cdn
Branches: MAIN
CVS tags: HEAD
ahem

    1:     <link rel="prev" href="http://books.mozdev.org/chapters/ch07.html" />
    2:     <link rel="next" href="http://books.mozdev.org/chapters/ch09.html" />
    3: 
    4:     <h2>Chapter 8</h2>
    5:     <h1><a name="77048"></a> XPCOM</h1>
    6:     <p>This chapter provides a high-level
    7:     introduction to XPCOM component technology. XPCOM can be
    8:     difficult to master, but after reading this chapter, you should
    9:     have a good sense of what it is and the important part it plays
   10:     as Mozilla's core technology. You should be able to find and
   11:     use existing scriptable components in your own applications and
   12:     create a simple XPCOM component by using JavaScript or C++.</p>
   13:     <p>XPCOM permits a reusable code module to be globally
   14:     accessible to a Mozilla-based application. You do not need to
   15:     worry about including external source files in your application
   16:     distribution and you can distribute components by using
   17:     XPInstall. This type of architecture makes the development of
   18:     core application services flexible and entirely modular.</p>
   19:     <p>The section <a href="#77065">"Creating a JavaScript XPCOM
   20:     Component</a>" lets you create an interface from start to
   21:     finish-writing the implementation for that interface, compiling
   22:     it into a type library, registering it with Mozilla, and then
   23:     testing the new component. One advantage of using XPCOM is that
   24:     you can create multiple implementations for a single interface;
   25:     following the JavaScript component section, we will take the
   26:     same <tt>nsISimple</tt> interface and implement it in C++ as
   27:     well.</p>
   28:     <p>The section <a href="#77079">"C++ Implementation of
   29:     nsISimple</a>" includes some techniques and programming tasks
   30:     that are particular to C++ components, such as handling return
   31:     values and generating header files and useful macros. The
   32:     section <a href="#77086">"Other Languages for XPCOM</a>"
   33:     introduces the XPCOM bindings 
   34:     for the
   35:     Python language (pyXPCOM). First, it provides an overview of
   36:     XPCOM and how it relates to other technologies used in
   37:     Mozilla.</p>
   38:     <h2><a name="77049"></a> What Is XPCOM?</h2>
   39:     <p>XPCOM is Mozilla's cross-platform component object model.
   40:     Although it is similar to Microsoft's COM technology, this
   41:     chapter points out some important differences.</p>
   42:     <p>Essentially, when you program in a component-based
   43:     environment, you do one of three things: you create a new
   44:     component using existing components, write a component that
   45:     implements other components, and establish interdependencies
   46:     and a service network.</p>
   47:     <h3><a name="77050"></a> What Is a Component?</h3>
   48:     <p>You've already seen components used in this 
   49:     book. In some
   50:     cases, you may have used the services of Mozilla components
   51:     without knowing it-for example, when you created a XUL tree
   52:     widget in the section <a href="ch03.html#77101">"High
   53:     Performance Trees</a>" in <a href="ch03.html#32764">Chapter
   54:     3</a>, and used its built-in layout and view capabilities. Some
   55:     of this functionality is defined in an interface called
   56:     <i>nsITreeView</i>, which provides specific methods and
   57:     properties for a XUL tree, persisting its state, row, cell, and
   58:     column properties, navigation, and other object metadata used
   59:     in a tree object. Behind the scenes, you'll find an
   60:     XPCOM-instantiated tree view object where methods and
   61:     properties associated with the XUL element are accessed via DOM
   62:     > JavaScript > XPConnect > XPCOM layers.</p>
   63:     <p>A component is a reusable or modular piece of code that
   64:     implements a clearly defined interface. In Mozilla, this code
   65:     can exist as a singleton service or an object instance. A
   66:     singleton service is an object instance that is created only
   67:     once and then used by other code (usually called "callers,"
   68:     "clients," or "consumers"). An object instance is an object
   69:     that is instantiated once or many times. Components are written
   70:     as classes that typically have member variables and methods.
   71:     The basic purpose of a component is to implement a clearly
   72:     defined set of APIs that exist in a public interface. The
   73:     interface exists separately so that the implementation is
   74:     abstracted away, and it can be changed without affecting the
   75:     interface or breaking binary compatibility. When interfaces are
   76:     deployed in a production environment, they are frozen, which
   77:     means they are held in an immutable state-theoretically for as
   78:     long as the application exists. While MSCOM provides a
   79:     component-based programming model on Microsoft platforms, XPCOM
   80:     provides it on all platforms where Mozilla is available.</p>
   81:     <p><a href="#77008">Example 8-1</a> shows how simple 
   82:     using XPCOM components can be. In two lines, an
   83:     XPConnect<i>-</i>wrapped <tt>nsIBookmarksService</tt> object is
   84:     instantiated, and one of its methods is called, providing easy
   85:     access to this XPCOM component from JavaScript.</p>
   86:     <p><i>Example 8-1: <a name="77008"></a></i> <i>Using an XPCOM
   87:     object in script</i></p>
   88: <pre>
   89:  // create a bookmark service object in JS
   90:  var bmks =
   91:    Components.classes</td>["@mozilla.org/browser/bookmarks-service;1"].
   92:        getService(Components.interfaces.nsIBookmarksService);
   93:  // call one of the object's methods:
   94:  // flush the bookmarks to disk if they've been touched.
   95:  bmks.Flush( );
   96: </pre>
   97:     <p>As you can see, the assignment of an XPCOM object to the
   98:     variable <i>bmks</i> takes only a single line. Once you are
   99:     comfortable using XPCOM from JavaScript, you can use any of
  100:     Mozilla's scriptable interfaces in your application. Once an
  101:     object like <tt>bmks</tt> is created, as in <a href=
  102:     "#77008">Example 8-1</a>, it can be used to call any method in
  103:     the <i>nsIBookmarksService</i> interface, of which <tt>Flush(
  104:     )</tt> is an example.</p>
  105:     <h3><a name="77051"></a> XPConnect and the Component
  106:     Object</h3>
  107:     <p>As shown the previous example, 
  108:     the XPCOM object is called and instantiated from script. For an
  109:     interpreted language like JavaScript to call and instantiate
  110:     it, a bridge must bind JavaScript types to XPCOM types. These
  111:     type bindings are part of a technology called XPConnect.</p>
  112:     <p>In XPConnect, XPCOM interfaces, <tt>classIDs</tt>, and
  113:     <tt>progIDs</tt> are stored as global Java-Script objects and
  114:     properties that can be manipulated directly through a top-level
  115:     object called <tt>Components</tt>. This object accesses any 
  116:     component that is declared "scriptable" in an XPCOM IDL
  117:     interface. Through the <tt>Components</tt> object, you can
  118:     access and use the services that these interfaces provide. The
  119:     <tt>Component</tt> object's top-level properties and methods
  120:     include:</p>
  121:     <dl>
  122:       <dt>QueryInterface</dt>
  123:       <dd>A method used to match an 
  124:       interface with a desired implementation. The implementation
  125:       can be in C, C++, JavaScript, Python, and other languages for
  126:       which appropriate bindings are created. You can have multiple
  127:       implementations for an interface. Through
  128:       <tt>QueryInterface</tt>, you can ask for and assign the
  129:       desired interface to its implementation. Each XPCOM object
  130:       needs to implement <tt>QueryInterface</tt> in order to return
  131:       an instance of that object's class:</dd>
  132:     </dl>
  133: <pre>
  134: js> var clz  = Components.classes['@mozilla.org/file/local;1'];
  135: js> var inst = clz.getService( );
  136: js> inst.QueryInterface(C.interfaces.nsILocalFile);
  137: [xpconnect wrapped nsILocalFile @ 0x81b7040]
  138: </pre>
  139: <dl><dt>interfaces
  140: <dd>A read-only object array  
  141: containing all the interfaces declared scriptable in the IDL file. The object name has the same name as the interface it represents.<br/>
  142: </dl>
  143: Components.interfaces.nsILocalFile
  144: <dl><dd>The source file for this particular interface, for example, is <i>nsILocalFile.idl</i>. This XPIDL compiler compiles this file to produce a cross-platform binary type library, <i>nsILocalFile.xpt</i>, which contains tokenized IDL in an efficiently parsed form.<br/>
  145: <dt>classes
  146: <dd>A read-only array of all  
  147: the XPCOM component classes indexed by the <tt>ProgID</tt> (or human-readable name) of the component class. The <tt>classes</tt> object has these properties associated with it:<br/>
  148: </dl>
  149: <xmp>
  150:         toString       Returns the string progID.
  151:         QueryInterface Used to QI this interface.
  152:         name           Returns the string progid name.
  153:         number         Returns the string components uuid
  154:                        number.
  155:         valid          Boolean verifies if the instance is
  156:                        valid.
  157:         equals         The Boolean used to match identical
  158:                        instances.
  159:         initialize     I don't know what this does.
  160:         createInstance Will create an instance of the
  161:                        component; you can have many
  162:                        instances.
  163:         getService     Will instantiate the component as a
  164:                        service; you can have only one
  165:                        instance of a service.
  166: </xmp>
  167: <dl><dt>classesByID
  168: <dd>The same as classes, except  
  169: this time the array is indexed by the "canonical" or "well-established" form of their CLSID:<br/>
  170: </dl>
  171: Components.classesByID['{dea98e50-1dd1-11b2-9344-8902b4805a2e}'];
  172: <dl><dd>The <tt>classesByID</tt> object has the same properties object associated with it as the <tt>class</tt> object. The properties are also used in the same way:<br/>
  173: </dl>
  174: toString
  175: QueryInterface
  176: name
  177: number
  178: valid
  179: equals
  180: initialize
  181: createInstance
  182: getService
  183: <dl><dt>stack
  184: <dd>A read-only property that represents  
  185: a snapshot of the current JavaScript call stack. JavaScript handles each code interpretation one call at a time and then places that code onto a call stack. This property can be used for recondite diagnostic purposes:<br/>
  186: </dl>
  187: <xmp>
  188: js> var C=Components;
  189: js> C.stack;
  190: JS frame :: typein :: <TOP_LEVEL> :: line 2
  191: js>  C.stack;
  192: JS frame :: typein :: <TOP_LEVEL> :: line 3
  193: </xmp>
  194: <dl><dt>results
  195: <dd>An object array of <tt>
  196: nserror</tt> results:<br/>
  197: </dl>
  198:  Components.results.NS_ERROR_FILE_ACCESS_DENIED;
  199:   2152857621
  200: <dl><dt>manager
  201: <dd>A reflection of the XPCOM global native component manager service. Using the component manager
  202: is the only way for a component to actually be created. It uses the components factory to create an instance of the <tt>class</tt> object.<br/>
  203: <dt>ID
  204: <dd>A constructor used  
  205: for a component written in JavaScript This component needs to register itself with the component manager by using its own <tt>nsID</tt> (an ID that is not already registered and thus does not appear in <i>Components.classes</i>).<br/>
  206: <dt>Exception
  207: <dd>A JavaScript constructor  
  208: used to create exception objects. When implementing XPCOM interfaces in JavaScript, these exception objects are the preferred types of exceptions. When an XPCOM exception is thrown in your JS code, it takes the form of an <tt>Exception</tt> object that has properties associated with this object. Exceptions are usually caught in a "catch" block.<br/>
  209: <dt>Constructor
  210: <dd>A JavaScript constructor  
  211: object that constructs new instances of XPCOM components:<br/>
  212: </dl>
  213: <xmp>
  214: js> var File=new Components.Constructor(
  215:   "@mozilla.org/file/local;1", "nsILocalFile", "initWithPath");
  216: </xmp>
  217: <dl><dd>The interface <i>nsILocalFile</i> and the method <tt>initWithPath</tt> are optional. This example creates and initializes the <i>nsILocalFile</i> component.<br/>
  218: <dt>isSucessCode
  219: <dd>A function that determines if the results code argument is successful. It takes an argument of <tt>nsresult</tt> and returns the Boolean values true or false:<br/>
  220: </dl>
  221: <xmp>
  222: js> Components.isSuccessCode(Components.results.NS_OK);
  223:   true
  224: js> Components.isSuccessCode(Components.results.NS_ERROR_FAILURE);
  225:   false
  226: </xmp>
  227: <br/>
  228: The methods and properties of the <tt>Components</tt> object listed above provide the only means to instantiate and access XPCOM objects from JavaScript. They are found often in the Mozilla codebase. In the sections that follow, they will be used frequently.
  229: <h3><a name= "77052"></a> XPCOM Interfaces and the IDL</h3>
  230: <br/>
  231: All XPCOM interfaces are defined  
  232: with the Interface Definition Language (IDL). IDL provides a language-neutral way to describe the public methods and properties of a component. Mozilla actually uses a modified, cross-platform version of IDL called XPIDL to compile interface source files.
  233: <br/>
  234: The separation of interface and implementation is a key distinction of COM programming. If the application programming interface (API) is abstracted from the implementation language and then frozen, consumers of that API will receive a guaranteed, established contract with the interface that ensures it will not be changed. This is perhaps the main reason why COM was invented: to maintain compatibility on a binary level so the client code can find and use the library it needs without worrying about linking to it. To make this sort of modularity possible at runtime, IDL interfaces are compiled into binary files called type libraries, which are described later in the section <a
  235:  href="#77056">"XPCOM Type Libraries</a>."
  236: <h4><a name=
  237: "77053"></a> Interfaces versus components</h4>
  238: <br/>
  239: It is important to understand that  
  240: most XPCOM components implement at least two interfaces. Like COM, each component needs the 
  241: <tt>QueryInterface</tt>, <tt>AddRef</tt>, and Release functions to be available as an XPCOM object.
  242: These methods are derived from a basic interface called <i>nsISupports</i>, which is the XPCOM 
  243: equivalent to Microsoft COM's <tt>IUnknown</tt>, shown in <a href="#77002">Table 8-1</a>.
  244: <br/>
  245: <i>Table 8-1: <a name="77002"></a></i>
  246: <i>The IUnknown interface</i>
  247: <br/>
  248: <table border="1">
  249:   <tr>
  250:     <td><b> Name</b></td>
  251:     <td><b> Type</b></td>
  252:     <td><b> Description</b></td>
  253:     <td><b> Parameters / return value</b></td>
  254:   </tr>
  255:   <tr>
  256:     <td>AddRef</td>
  257:     <td>ULONG AddRef(void)</td>
  258:     <td>Increments the reference count on the COM object.</td>
  259:     <td>Returns: int, which is the new incremented reference count on the object. This value 
  260:         may be useful for diagnostics or testing.
  261:     </td>
  262:   </tr>
  263:   <tr>
  264:     <td>QueryInterface</td>
  265:     <td> HRESULT QueryInterface(/* [in] */ REFIID riid, /* [iid_is][out] */ 
  266:          void **ppvObject)
  267:     </td>
  268:     <td>Retrieves a pointer to the requested interface.</td>
  269:     <td>Parameters: iid, which is an [in] identifier of the requested interface.<br/>
  270:         ppvObject, which is an [out] pointer to the interface pointer identified by iid. 
  271:         If the object does not support this interface, ppvObject is set to NULL.
  272:         Returns: HRESULT, which is the standard HRESULT value.
  273:     </td>
  274:   </tr>
  275:   <tr>
  276:     <td>Release</td>
  277:     <td>ULONG Release(void)</td>
  278:     <td>Decrements the reference count on the COM object.</td>
  279:     <td>Returns: int, which is the new decremented reference count on the object. This value 
  280:         may be useful for diagnostics or testing.
  281:     </td>
  282:   </tr>
  283: </table>
  284: 
  285: <br/>
  286: <br/>
  287: Tables 8-1 and 8-2 illustrate the minor differences between Microsoft's <i>nsIUnknown</i> and Mozilla's <i>nsISupports</i> root interfaces. The usage is covered in detail throughout this chapter.
  288: <br/>
  289: <i>Table 8-2: <a name="77004"></a></i>
  290: <i>The nsISupports interface</i>
  291: <br/>
  292: <table border="1">
  293:   <tr>
  294:     <td><b>Name</b></td>
  295:     <td><b>Type</b></td>
  296:     <td><b> Description</b></td>
  297:     <td><b> Parameters/return value</b></td>
  298:   </tr>
  299:   <tr>
  300:     <td>AddRef</td>
  301:     <td>NS_IMETHOD_(nsrefcnt)
  302:         <br/>AddRef(void)
  303:     </td>
  304:     <td>Increases the reference count for this interface. The associated instance will 
  305:         not be deleted unless the reference count is returned to zero.
  306:     </td>
  307:     <td>Returns: The resulting reference count.
  308:     </td>
  309:   </tr>
  310:   <tr>
  311:     <td>QueryInterface</td>
  312:     <td><i>NS_IMETHOD QueryInterface(REFNSIID aIID,</i> void** aInstancePtr)</td>
  313:     <td>A runtime mechanism for interface discovery.</td>
  314:     <td>Parameters: param aIID </td>[in], which is a requested interface IID.
  315:         param aInstancePtr [out], which is a pointer to an interface pointer that 
  316:         receives the result.<br/>
  317:         Returns: NS_OK if the interface is supported by the associated instance; 
  318:                  NS_NOINTERFACE if it is not; and NS_ERROR_INVALID_POINTER if 
  319:                  aInstancePtr is NULL.
  320:     </td>
  321:   </tr>
  322:   <tr>
  323:     <td>Release</td>
  324:     <td><i>NS_IMETHOD_(nsrefcnt) Release</i>(void)=0;</td>
  325:     <td>Decreases the reference count for this interface. Generally, if the reference 
  326:         count returns to zero, the associated instance is deleted.
  327:     </td>
  328:     <td>Returns: The resulting reference count.</td>
  329:   </tr>
  330: </table>
  331: <br/>
  332: 
  333: <h4><a name="77054"></a> Root interfaces</h4>
  334: <br/>
  335: <tt>QueryInterface</tt>, <tt>Addref</tt>, and <tt>Release</tt> are required methods that are implemented by every component. <tt>QueryInterface</tt> matches a specific interface with its implementation class module. <tt>Addref</tt> and <tt>Release</tt> are methods used for reference counting. When an instance of a component is created, one or more pointers may reference that object. For each reference, a count is incremented by one. When a reference is no longer used, <tt>Release</tt> is called to decrement the count. You must hold a reference count to ensure that no pointers reference an object after it is deleted. When pointers try to access objects that are deleted, the application core dumps. Reference counting can get tricky, which is why smart pointers manage <tt>Addref</tt> and <tt>Release</tt> for you, as described in the later section <a
  336:  href="#77073">"Useful C++ Macros and Types</a>."
  337: <br/>
  338: Defining <tt>QueryInterface</tt>, <tt>Addref</tt>, and <tt>Release</tt> every time an interface is created is clearly not very efficient. Instead, these methods are defined in the base interface called <i>nsISupports</i>. All interfaces inherit from this mother of all interfaces and don't need to redefine these three basic functions.
  339: <br/>
  340: XPIDL supports the C style syntax preparser directive <i>#include</i> to include other IDL files-not unlike MSCOM, which uses the import statement. At the top of any IDL file that you create, you need to include <i>nsISupports</i>:
  341: <pre>#include "nsISupports.idl"
  342: interface nsISimple : nsISupports {
  343: readonly attribute string value;
  344: };
  345: </pre>
  346:     <blockquote>
  347:       <hr>
  348:       <b>Core IDL Types</b> 
  349:       <p>The core types used in IDL interface files 
  350:       are listed in the file <i>xpcom/base/nsrootidl.idl</i>. This
  351:       file is included in nsISupports<i>.</i> (This means it is
  352:       included in every interface file, since all interfaces
  353:       inherit from <i>nsISupports</i>.) All interfaces used in a
  354:       system are valid IDL types. For example, <i>nsISimple</i> is
  355:       a valid type to use as a method parameter or a method return
  356:       type. Some of the main types listed in this interface
  357:       are:</p>
  358:       <hr>
  359:     </blockquote>
  360:     typedef boolean PRBool; typedef octet PRUint8; typedef unsigned
  361:     short PRUint16; typedef unsigned short PRUnichar; typedef
  362:     unsigned long PRUint32; typedef unsigned long long PRUint64;
  363:     typedef unsigned long long PRTime; typedef short PRInt16;
  364:     typedef long PRInt32; typedef long long PRInt64; typedef
  365:     unsigned long nsrefcnt; typedef unsigned long nsresult; typedef
  366:     unsigned long size_t; 
  367:     <h4><a name="77055"></a> The XPIDL compiler</h4>
  368:     <p>An IDL compiler is a tool that 
  369:     creates a binary
  370:     distribution file called a <i>type library</i> from an
  371:     interface description source file. Since support for many
  372:     different platforms is a requirement for Mozilla, a modified
  373:     version of the libIDL compiler from the Gnome project is used.
  374:     This variant is called the XPIDL compiler and is primarily used
  375:     to compile Mozilla's own dialect of IDL, conveniently called
  376:     XPIDL. The XPIDL compiler generates XPCOM interface
  377:     information, headers for XPCOM objects, and XPT type libraries
  378:     from which objects may be accessed dynamically through
  379:     XPConnect. It can also generate HTML files for documentation
  380:     and Java class stubs. Another feature of the XPIDL compiler is
  381:     the option to generate C++ code stubs. This feature creates
  382:     nearly all the declaratory C++ code you need when you start a
  383:     new project, which makes XPIDL useful as a coding wizard that
  384:     helps you get started. Code generation is covered later in this
  385:     chapter in the section <a href="#77079">"C++ Implementation of
  386:     nsISimple</a>."</p>
  387:     <p>The XPIDL compiler is located in <i>xpcom/typelib/xpidl/</i>
  388:     in the Mozilla sources. If you built Mozilla, you can add this
  389:     directory to your <tt>PATH</tt>:</p>
  390: <pre>
  391: $ PATH=$PATH:/usr/src/mozilla/xpcom/typelib/xpidl
  392: </pre>
  393:     <p>Using the compiler is fairly easy. If you use the help
  394:     command, you can see the usage syntax and other basic
  395:     information about the compiler:</p>
  396: <pre>
  397: $ ./xpidl --help
  398: Usage: xpidl [-m mode] [-w] [-v] [-I path] [-o basename] filename.idl
  399: -a emit annotations to typelib
  400: -w turn on warnings (recommended)
  401: -v verbose mode (NYI)
  402: -I add entry to start of include path for ``#include "nsIThing.idl"''
  403: -o use basename (e.g. ``/tmp/nsIThing'') for output
  404: -m specify output mode:
  405: header        Generate C++ header            (.h)
  406: typelib       Generate XPConnect typelib     (.xpt)
  407: doc           Generate HTML documentation    (.html)
  408: java          Generate Java interface        (.java)
  409: </pre>
  410:     <h3><a name="77056"></a> XPCOM Type Libraries</h3>
  411:     <p>The key to the component architecture of XPCOM is the
  412:     presence of binary-independent interface files that are used
  413:     uniformly across platforms, languages, and programming
  414:     environments. These interface files are compiled into
  415:     <i>.xpt</i> files by the XPIDL compiler. The Mozilla
  416:     <i>components</i> subdirectory is where type libraries and
  417:     modules are typically stored. If you create a cross-platform
  418:     type library for your component, you must place it in this
  419:     directory for it to be accessible to XPCOM.</p>
  420:     <h4><a name="77057"></a> Creating a type library file from an
  421:     IDL interface</h4>
  422:     <p>To create a (<i>.xpt</i>) typelib file, use 
  423:     the flag
  424:     <tt>-m typelib</tt> with warning (<tt>-w</tt>) and verbose
  425:     (<tt>-v</tt>) modes turned on. <tt>-o</tt> is used for the name
  426:     of the output file and <tt>-I</tt> is used to specify paths to
  427:     other IDL files you want to include. To successfully compile
  428:     your interface, you must always point to the directory where
  429:     <i>nsISupports</i> is located.</p>
  430: <pre>
  431: # include path to nsISupports.idl
  432: $ $XPIDL_INC = /usr/src/mozilla/xpcom/base
  433: #compile nsISimple.idl
  434: $ xpidl -m typelib -w -v -I $XPIDL_INC \
  435: > -o nsISimple nsISimple.idl
  436: </pre>
  437:     <p>The file created after compilation is <i>nsISimple.xpt</i>.
  438:     It provides the necessary type information about your interface
  439:     at runtime. Typelib files enumerate the methods of interfaces
  440:     and provide detailed type information for each method
  441:     parameter.</p>
  442:     <h3><a name="77058"></a> XPCOM Identifiers</h3>
  443:     <p>To simplify the process of 
  444:     dynamically finding, loading,
  445:     and binding interfaces, all classes and interfaces are assigned
  446:     IDs. An ID is a unique 128-bit number that is based on
  447:     universally unique 
  448:     identifiers (UUIDs) generated by various 
  449:     tools such as <i>uuidgen</i> (which
  450:     we will cover later in this chapter). They are stored in the
  451:     structure format defined below:</p>
  452: <pre>
  453: struct nsID {
  454: PRUint32 m0;
  455: PRUint16 m1, m2;
  456: PRUint8 m3[8];
  457: };
  458: </pre>
  459:     <p>To initialize an ID struct, declare it like this:</p>
  460: <pre>
  461: ID = {0x221ffe10, 0xae3c, 0x11d1,
  462: {0xb6, 0x6c, 0x00, 0x80, 0x5f, 0x8a, 0x26, 0x76}};
  463: </pre>
  464:     <p>One thing that gives XPCOM its modularity is the dynamic
  465:     allocation of objects through the use of unique identifiers at
  466:     runtime. This system of canonical identifiers is used for
  467:     interface querying and component instantiation. Having an
  468:     interface is important because it ensures that an immutable
  469:     binary holds a semantic contract defined for a specific
  470:     interface class.</p>
  471:     <p>The two types of identifiers used in XPCOM are the contract
  472:     ID and the class identifier. These identifiers are shuttled to
  473:     the Component Manager's <tt>createInstance( )</tt> or the
  474:     Service Manager's <tt>getService( )</tt> methods in order to
  475:     instantiate a component.</p>
  476:     <h4><a name="77059"></a> The Contract ID</h4>
  477:     <p>The program ID (<tt>progID</tt>), also known 
  478:     as the Contract ID, is a
  479:     unique human-readable string. <a href="#77010">Example 8-2</a>
  480:     shows various <tt>progID</tt>s for different components. This
  481:     example can be used to instantiate an XPCOM component through
  482:     the use of a Contract ID.</p>
  483:     <p><i>Example 8-2: <a name="77010"></a></i> <i>progIDs</i></p>
  484: <pre>
  485:  // progID: @mozilla.org/file/local;1
  486:  var f = Components.classes["@mozilla.org/file/local;1"];
  487:  // progID: @mozilla.org/browser/bookmarks-service;1
  488:  var bmks =
  489:    Components.classes["@mozilla.org/browser/bookmarks-service;1"].
  490:        getService(Components.interfaces.nsIBookmarksService);
  491: </pre>
  492:     <h4><a name="77060"></a> The class identifier</h4>
  493:     <p>The other type of identifier is the <tt>
  494:     classID</tt>, or CLSID.
  495:     The interface and implementation are identified by this 128-bit
  496:     numerical identifier string:</p>
  497: <pre>
  498: // clsid: {2e23e220-60be-11d3-8c4a-000064657374}
  499: var f = Components.classesByID["{2e23e220-60be-11d3-8c4a-000064657374}"];
  500: </pre>
  501:     <p>Using XPConnect, XPCOM interfaces, 
  502:     <tt>classID</tt>s, and <tt>progID</tt>s are stored as global
  503:     JavaScript objects and properties and can be manipulated
  504:     directly through the top-level <tt>Components</tt> object
  505:     discussed earlier.</p>
  506:     <h4><a name="77061"></a> Generating identifiers</h4>
  507:     <p>To obtain a UUID on Unix, you can 
  508:     use a command-line program
  509:     called <i>uuidgen</i> that generates a unique number for
  510:     you:</p>
  511: <pre>
  512: $ uuidgen
  513: ce32e3ff-36f8-425f-94be-d85b26e634ee
  514: </pre>
  515:     <p>On Windows, a program called <i>guidgen.exe</i> does 
  516:     the same thing
  517:     and also provides a graphical user interface if you'd rather
  518:     point and click.</p>
  519:     <p>Or you can use one of the special "bots" on IRC at the
  520:     <i>irc.mozilla.org</i> server.</p>
  521: <pre>
  522: irc irc.mozilla.org
  523: /join #mozilla
  524: /msg mozbot uuid
  525: </pre>
  526:     <p>This command makes the bot generate and return a uuid, which
  527:     you can then copy into your component source code. The
  528:     information can then be used to uniquely identify your
  529:     component.</p>
  530:     <h3><a name="77062"></a> Component Manager</h3>
  531:     <p>One major goal of XPCOM modularization 
  532:     is the removal of
  533:     link-time dependencies, or dependencies that arise when you
  534:     link libraries during compilation. The achievement of this goal
  535:     allows you to access and use modules at runtime. The trouble
  536:     then becomes finding those modules and figuring out which of
  537:     their interfaces you want to use. This problem is solved
  538:     through the use of the Component Manager.</p>
  539:     <p>The Component Manager is a special set of component
  540:     management classes and implementation classes that reside in
  541:     object libraries (<i>.dll</i>, <i>.so</i>, <i>.js</i>,
  542:     <i>.py</i>, etc.). These classes also include factories, which 
  543:     let you create
  544:     objects without having access to their class declarations. When
  545:     you bind to objects at runtime, as you do in XPCOM, you need
  546:     functionality like this to help you discover and use objects
  547:     without looking at their code. The Component Manager 
  548:     also includes the
  549:     Component Manager class itself, known as
  550:     <tt>nsComponentManager</tt>, which is a mapping of class IDs to
  551:     factories for the libraries they contain. The Component Manager
  552:     is responsible for the autoregistration of all new or add-on
  553:     modules located in the
  554:     <i>components</i> directory. This autoregistration happens
  555:     behind the scenes and allows you to use new components as they
  556:     become available without having to register them yourself.</p>
  557:     <p>A component author first creates 
  558:     an interface file that defines all APIs that will be publicly
  559:     available for a component. The component author then creates an
  560:     implementation for the methods and attributes in a separate
  561:     implementation class. For example, an <i>nsILocalFile</i>
  562:     interface may have an <tt>nsLocalFile</tt> implementation
  563:     class. Then a factory or module is needed to abstract the
  564:     implementation class, and reduce compile and link-time
  565:     dependencies. It then creates instances of the implementation
  566:     class through its own implementation of
  567:     <tt>QueryInterface</tt>. For example:</p>
  568: <pre>
  569: // create an instance of the implementation class
  570: var f = Components.classes["@mozilla.org/file/local;1"].createInstance();
  571: </pre>
  572:     <p>The variable <i>f</i> is assigned an instance of a
  573:     <i>nsLocalFile</i> implementation class using the
  574:     <i>nsIFactory</i> method <tt>createInstance( )</tt>. To match
  575:     the correct interface (<i>nsILocalFile</i> in this case) to the
  576:     implementation, you need a class instance to be created before
  577:     you can call on its member method <tt>QueryInterface(
  578:     )</tt>:</p>
  579: <pre>
  580: // QI for nsILocalFile interface
  581: var f = f.QueryInterface(Components.interfaces.nsILocalFile);
  582: </pre>
  583:     <p>Once you do this, the variable <i>f</i> is ready to use the
  584:     <i>nsILocalFile</i> interface to access the newly created
  585:     instance of the <tt>nsLocalFile</tt> class from script.</p>
  586:     <p>Simply put, a factory or module is a set of classes used by
  587:     the Component Manager to register and create an instance of the
  588:     component's implementation class. A factory can make its way
  589:     into the Mozilla component repository in several ways. The most
  590:     direct is through using the Component Manager method
  591:     <tt>RegisterFactory( )</tt>, which supports two different
  592:     registration mechanisms. The first mechanism, which takes a
  593:     class ID and a pointer to a factory, can be used on factories
  594:     that are actually linked into the executable. The second, which
  595:     takes a class ID and the path to a dynamically loadable
  596:     library, can be used both inside an executable at runtime and
  597:     externally by using the <tt>aPersist</tt> flag to tell the
  598:     repository to store the class ID/library relationship in its
  599:     permanent store. The Component Manager discovers new factories
  600:     or modules placed in the <i>components</i> directory and
  601:     queries those modules for the XPCOM components they provide.
  602:     The name, contract IDs, and class IDs are placed into a small
  603:     component registry database for quick retrieval. The factory
  604:     provides this information through a simple set of APIs required
  605:     by every XPCOM module. Module creation, covered later in this
  606:     chapter, describes the process through which all components
  607:     contain an implementation of a module or factory.</p>
  608:     <h3><a name="77063"></a> Getting and Using XPCOM</h3>
  609:     <p>Mozilla is a client application that implements XPCOM, so
  610:     everything you need to use or build new XPCOM components is
  611:     already included in the source code and/or the binaries.
  612:     Whenever you use the JavaScript <tt>Components</tt> object, as
  613:     described earlier, you use XPCOM.</p>
  614:     <p>If you'd rather not build the entire Mozilla browser and you
  615:     have no interest in existing Mozilla components or the large
  616:     footprint that comes with an entire distribution, then
  617:     standalone XPCOM is for you. To pull the
  618:     XPCOM source on Unix using Mac OS X or <i>cygwin</i> on
  619:     Windows, invoke the following commands:</p>
  620: <pre>
  621: cvs -z 3 co mozilla/client.mk
  622: cd mozilla
  623: gmake -f client.mk pull_all BUILD_MODULES=xpcom
  624: </pre>
  625:     <p>To build the XPCOM Stand Alone version, type:</p>
  626: <pre>
  627: configure --enable-modules=xpcom
  628: gmake
  629: </pre>
  630:     <p>When you build standalone
  631:     XPCOM, the directory <i>xpcom/sample</i> contains the source
  632:     code for a sample 
  633:     application and a <tt>nsTestSample</tt> component. The sample
  634:     application built from these sources, also called
  635:     <tt>nsTestSample</tt>, is installed in the Mozilla <i>bin</i>
  636:     directory. <i>libsample.so</i> (Unix), which is the component
  637:     that the sample application tries to instantiate, should have
  638:     been installed in <i>bin/components</i>. To run the test that
  639:     indicates whether standalone XPCOM is installed successfully,
  640:     change to the <i>mozilla/dist/bin</i> directory and run the
  641:     following commands:</p>
  642: <pre>
  643: ./run-mozilla.sh ./nsTestSample
  644: </pre>
  645:     <p>You should see the following output. If you do not, there is
  646:     a problem with the installation of standalone XPCOM:</p>
  647: <pre>
  648: Type Manifest File: /D/STAND_ALONE_XPCOM/mozilla/dist/bin/components/xpti.dat
  649: nsNativeComponentLoader: autoregistering begins.
  650: nsNativeComponentLoader: autoregistering succeeded
  651: nNCL: registering deferred (0)
  652: Inital print: initial value
  653: Set value to: XPCOM defies gravity
  654: Final print : XPCOM defies gravity
  655: Test passed.
  656: </pre>
  657:     <p>Using standalone XPCOM is a powerful way to use the Mozilla
  658:     framework of cross-platform COM. Even if you're just hacking on
  659:     Mozilla, standalone XPCOM is a great way to learn about and use
  660:     XPCOM for application development.</p>
  661:     <h2><a name="77064"></a> Creating XPCOM Components</h2>
  662:     <p>As we mentioned, one 
  663:     advantage of using XPCOM is that it separates the
  664:     implementation from the interface so you can write a component
  665:     in a language-agnostic manner. The services your component
  666:     provides are available to all other components despite the
  667:     language used to implement it. This means, for example, that
  668:     you can use JavaScript not only to access the services of an
  669:     XPCOM component, but also to create those services. As
  670:     described in <a href="ch05.html#77037">Chapter 5</a>, using
  671:     JavaScript as a modularized application programming language
  672:     provides the deepest level of scripting in Mozilla.</p>
  673:     <p>In your Mozilla build or
  674:     distribution, you will find a subdirectory named
  675:     <i>components</i>. Inside this directory, you will see many
  676:     compiled components. You will also see a number of JavaScript
  677:     components. If you look at the source of these components, you
  678:     can get an idea of how 
  679:     a JavaScript component is created. For example, look at the
  680:     files <i>nsFilePicker.js</i> and <i>nsSidebar.js</i>. These
  681:     JavaScript components are used in the Mozilla distribution.</p>
  682:     <p>JavaScript XPCOM components have the advantage over regular
  683:     scripts of being fast, reusable, and globally accessible to any
  684:     caller. They also have the advantage over C++-based XPCOM
  685:     components of being easier to write and maintain. The next few
  686:     sections describe the creation of a JavaScript-based XPCOM
  687:     component. If you would rather do your work in C++, then skip
  688:     to the C++ implementation section in this chapter.</p>
  689:     <h3><a name="77065"></a> Creating a JavaScript XPCOM
  690:     Component</h3>
  691:     <p>To create a JavaScript component, 
  692:     you need to create an IDL interface source file and a
  693:     JavaScript implementation source file. In the Mozilla sources,
  694:     naming source files with an <i>ns</i> prefix is common
  695:     practice, so the implementation file should be called something
  696:     like <i>nsSimple.js</i>. The interface source file, or IDL
  697:     file, uses a similar convention: it is typical for interfaces
  698:     to begin with <i>nsI</i>, using an <i>I</i> to distinguish them
  699:     as interfaces rather than implementations. Call the IDL source
  700:     file <i>nsISimple.idl</i>.</p>
  701:     <p>In addition to these two source files (<i>nsSimple.js</i>
  702:     and <i>nsISimple.idl</i>), you will compile a cross platform
  703:     binary interface file, or type library, with the XPIDL
  704:     compiler, calling it <i>nsISimple.xpt</i>. This <i>.xpt</i>
  705:     file tells Mozilla that the interface is available and
  706:     scriptable. You can use it on any platform that Mozilla
  707:     supports. In other words, you can pick up <i>nsISimple.xpt</i>,
  708:     which may have been compiled on Unix, drop it into Windows or
  709:     Mac OS, and use it.</p>
  710:     <p>All <i>.xpt</i> interface files for Mozilla live in the
  711:     <i>components</i> directory located in <i>mozilla/dist/bin</i>
  712:     if you are developing with the Mozilla source code. Otherwise,
  713:     for binary distributions of Mozilla, they are located in
  714:     <i>mozilla/components</i>. Mozilla checks this directory upon
  715:     start up, looking for any new components to register
  716:     automatically.</p>
  717:     <h4><a name="77066"></a> The XPIDL interface source file</h4>
  718:     <p>Usually, the first step in creating a new component is
  719:     writing the interface. To begin, open up your favorite text
  720:     editor and create a new file called <i>nsISimple.idl</i>.</p>
  721:     <p>The complete source code for the <i>nsISimple.idl</i>
  722:     interface file is:</p>
  723: <pre>
  724: #include "nsISupports.idl"
  725: [scriptable, uuid(ce32e3ff-36f8-425f-94be-d85b26e634ee)]
  726: interface nsISimple : nsISupports
  727: {
  728: attribute string yourName;
  729: void write( );
  730: void change(in string aValue);
  731: };
  732: </pre>
  733:     <p>The <tt>#include</tt> line above includes the file
  734:     <i>nsISupports.idl</i>, which defines this interface's base
  735:     class. The [scriptable, uuid..] line declares the interface
  736:     scriptable and assigns a UUID to the interface. You can use the
  737:     UUID provided, but creating your own using one of the UUID
  738:     generation tools described earlier is usually better. The third
  739:     line, next to the <tt>interface</tt> keyword, declares the
  740:     interface's name, <i>nsISimple</i>, and says that it derives
  741:     from <i>nsISupports</i>.</p>
  742:     <p>Various attributes and methods are defined within the
  743:     definition of the <tt>nsISimple</tt> interface. Attributes are
  744:     properties of interface objects. They may be read-only or
  745:     read/write variables. In <i>nsISimple</i>, an attribute called
  746:     <tt>yourName</tt> is of the type <tt>string</tt>. In this
  747:     implementation, you may get and set this attribute's value. Of
  748:     the methods defined in this interface, the <tt>write( )</tt>
  749:     method takes no arguments and the <tt>change( )</tt> method
  750:     takes an argument of type string called <tt>aValue</tt>. The
  751:     parameter <tt>aValue</tt> will be a new value that replaces the
  752:     current value held by <tt>yourName</tt>. The complete interface
  753:     IDL is:</p>
  754: <pre>
  755: #include "nsISupports.idl"
  756: [scriptable, uuid(ce32e3ff-36f8-425f-94be-d85b26e634ee)]
  757: interface nsISimple : nsISupports
  758: {
  759: attribute string yourName;
  760: void write( );
  761: void change(in string aValue);
  762: };
  763: </pre>
  764:     <h4><a name="77067"></a> JavaScript implementation file</h4>
  765:     <p>Once you have created an interface 
  766:     file that publicly defines the component's methods and
  767:     attributes, the next step is to implement those methods and
  768:     attributes in a separate source file. The listings below walk
  769:     through the implementation of <tt>nsISimple</tt> step by
  770:     step.</p>
  771:     <p>First, you must declare an empty function called
  772:     <tt>SimpleComponent</tt>, which is a standard constructor for a
  773:     JavaScript object prototype. It's a good idea to name the
  774:     component in a way that clearly describes both the component
  775:     and the interface, as <tt>SimpleComponent</tt> does (i.e.,
  776:     <tt>SimpleComponent</tt> is an implementation of the
  777:     <tt>nsISimple</tt> interface):</p>
  778: <pre>
  779: function SimpleComponent( ) {}
  780: </pre>
  781:     <p>With the function declared, we start defining the JavaScript
  782:     class prototype.</p>
  783: <pre>
  784: SimpleComponent.prototype = {
  785: mName : "a default value",
  786: </pre>
  787:     <p>In the prototype, we first create a member variable called
  788:     <i>mName</i> that will be the string placeholder for the IDL
  789:     attribute <tt>yourName</tt>. The variable assigns the string a
  790:     default value. Remember to place commas after all definitions
  791:     in a prototype. IDL attributes are always implemented as getter
  792:     functions. Methods marked with [noscript] will not be available
  793:     for use with scripting languages.</p>
  794:     <p>Next we implement the functions below for our definition of
  795:     <tt>attribute</tt> <tt>string</tt> <tt>yourName</tt> in our
  796:     file <i>nsISimple.idl</i>.</p>
  797: <pre>
  798: get yourName( )      { return this.mName; },
  799: set yourName(aName) { return this.mName = aName; },
  800: </pre>
  801:     <p>When someone calls an IDL attribute in an interface, getters
  802:     and setters are used to get or set values for the
  803:     attribute:</p>
  804: <pre>
  805: simple.yourName='foo';
  806: </pre>
  807:     <p>Or similarly read values from the attribute:</p>
  808: <pre>
  809: var foo = simple.yourName;
  810: </pre>
  811:     <p>We first call on the setter function to set a value to the
  812:     attribute <tt>yourName</tt> and then use the getter function to
  813:     obtain the currently set value of <tt>yourName</tt>.</p>
  814:     <p>The first function defined in <tt>nsISimple</tt> is called
  815:     <tt>void write( )</tt>. For this method, the implementation can
  816:     be as simple as the following code:</p>
  817: <pre>
  818: write : function ( ) { dump("Hello " + this.mName + "\n"); },
  819: </pre>
  820:     <p>This example implements the declaration <tt>void write(
  821:     )</tt> by dumping the current value of the variable
  822:     <i>mName</i> to <tt>stdout</tt>. The code uses the
  823:     <tt>this</tt> keyword to indicate that you are calling to the
  824:     component's own member variable <i>mName</i>.</p>
  825:     <p>The <tt>void change( )</tt> method is then implemented as
  826:     follows:</p>
  827: <pre>
  828: change : function (aValue) { this.mName = aValue; },
  829: </pre>
  830:     <p><tt>change( )</tt> is a method used to change the value
  831:     variable.</p>
  832:     <h4><a name="77068"></a> Implementing the required XPCOM
  833:     methods in JavaScript</h4>
  834:     <p>Once the definitions in the <i>nsISimple</i> interface 
  835:     are implemented, you need to implement required methods and
  836:     factories that make this JavaScript implementation class an
  837:     XPCOM component. Recall that all XPCOM components must
  838:     implement the <tt>nsISupports</tt> interface.</p>
  839:     <p><a href="#77012">Example 8-3</a> shows an implementation of
  840:     <tt>QueryInterface</tt> specific to our new component.
  841:     <tt>QueryInterface</tt> ensures that the correct interface
  842:     (<tt>nsISimple</tt>) is used by matching the <tt>iid</tt> with
  843:     the <tt>nsISimple</tt> interface that this component
  844:     implements. If the interface doesn't match, then the argument
  845:     is invalid. In this case, the exception
  846:     <i>Components.results.NS_ERROR_NO_INTERFACE</i> is thrown,
  847:     which maps to the error code number 2147500034, and code
  848:     execution is stopped. If the interface identifier parameter
  849:     matches the interface, then an instance of the implementation
  850:     class object <tt>SimpleComponent</tt> with its interface is
  851:     returned as a ready-to-use XPCOM component. In XPCOM, every
  852:     component you implement must have a
  853:     <tt>QueryInterface</tt> method.</p>
  854:     <p><i>Example 8-3: <a name="77012"></a></i> <i>QueryInterface
  855:     method for nsISimple interface</i></p>
  856: <pre>
  857:    QueryInterface: function (iid)
  858:    {
  859:     if(!iid.equals(Components.interfaces.nsISimple)
  860:          &amp;&amp; !iid.equals(Components.interfaces.nsISupports))
  861:         throw Components.results.NS_ERROR_NO_INTERFACE;
  862:     return this;
  863:    }
  864: </pre>
  865:     <p>The next requirement is to create a JavaScript object called
  866:     <tt>Module</tt>. This module implements the methods needed for
  867:     autoregistration and component return type objects.</p>
  868: <pre>
  869: var Module = {
  870: firstTime  : true,
  871: </pre>
  872:     <p>The Boolean <tt>firstTime</tt> is a flag used only when the
  873:     component is initially registered:</p>
  874: <pre>
  875: registerSelf: function (compMgr, fileSpec, location, type) {
  876: if (this.firstTime) {
  877: dump("*** first time registration of Simple JS component\n");
  878: this.firstTime = false;
  879: throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
  880: }
  881: </pre>
  882:     <p>The Component Manager can do a lot in the registration
  883:     process, but you have to add some logic for first time
  884:     registration so the Component Manager has the information it
  885:     needs. <tt>RegisterSelf</tt> is called at registration time
  886:     (component installation) and is responsible for notifying the
  887:     component manager of all components implemented in this module.
  888:     The <tt>fileSpec</tt>, <tt>location</tt>, and <tt>type</tt>
  889:     parameters can be passed on to the <tt>registerComponent</tt>
  890:     method unmolested. Next, register the component with the
  891:     Component Manager using code like the following example. The
  892:     parameters include the CID, a description, a <tt>progID</tt>,
  893:     and the other parameters you can pass without changing:</p>
  894: <pre>
  895: dump(" ***** Registering: Simple JS component! ****\n");
  896: compMgr.registerComponentWithType(this.myCID,
  897: "My JS Component",
  898: this.myProgID, fileSpec,
  899: location, true, true,
  900: type);
  901: },
  902: </pre>
  903:     <p>The <tt>GetClassObject</tt> 
  904:     method produces
  905:     <tt>Factory</tt> and <tt>SingletonFactory</tt> objects.
  906:     Singleton objects are specialized for services that allow only
  907:     one instance of the object. Upon success, the method returns an
  908:     instance of the components factory, which is the implementation
  909:     class less its interface:</p>
  910: <pre>
  911: getClassObject : function (compMgr, cid, iid) {
  912: if (!cid.equals(this.myCID))
  913: throw Components.results.NS_ERROR_NO_INTERFACE;
  914: if (!iid.equals(Components.interfaces.nsIFactory))
  915: throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  916: return this.myFactory;
  917: },
  918: </pre>
  919:     <p>In the previous list, the member variables <i>myCID</i> and
  920:     <i>myProgID</i> are the class ID and the human-readable
  921:     canonical program ID, respectively:</p>
  922: <pre>
  923: myCID: Components.ID("{98aa9afd-8b08-415b-91ed-01916a130d16}"),
  924: myProgID: "@mozilla.org/js_simple_component;1",
  925: </pre>
  926:     <p>The member object <tt>myFactory</tt> is the components
  927:     factory, which through its own member function,
  928:     <tt>createInstance( )</tt>, constructs and returns an instance
  929:     of the complete component (if the <tt>iid</tt> parameter is
  930:     specified and is the correct interface). Otherwise, if no
  931:     <tt>iid</tt> parameter is used, the <tt>iid</tt> of
  932:     <i>nsISupports</i> is used and an instance of the module is
  933:     created that will then need a subsequent call to
  934:     <tt>QueryInterface</tt> to instantiate the object as a
  935:     component.</p>
  936: <pre>
  937: myFactory: {
  938: createInstance: function (outer, iid) {
  939: dump("CI: " + iid + "\n");
  940: if (outer != null)
  941: throw Components.results.NS_ERROR_NO_AGGREGATION;
  942: return (new SimpleComponent( )).QueryInterface(iid);
  943: }
  944: },
  945: </pre>
  946:     <p>The method <tt>canUnload</tt> unloads the module when
  947:     shutdown occurs and is the last function in the module. The
  948:     <tt>componentManager</tt> calls the method <tt>NSGetModule</tt>
  949:     to initialize these required XPCOM methods and objects:</p>
  950: <pre>
  951: canUnload: function(compMgr) {
  952: dump("****** Unloading: Simple JS component! ****** \n");
  953: return true;
  954: }
  955: function NSGetModule(compMgr, fileSpec) { return Module; }
  956: </pre>
  957:     <p>The code in <a href="#77014">Example 8-4</a> shows 
  958:     the implementation for the <i>nsISimple</i> interface in its
  959:     entirety.</p>
  960:     <p><i>Example 8-4: <a name="77014"></a></i> <i>JavaScript
  961:     implementation of nsISimple</i></p>
  962: <pre>
  963: 
  964: function SimpleComponent(){}
  965: 
  966: SimpleComponent.prototype = {
  967: 
  968:     get yourName()        { return this.mName; },
  969:     set yourName(aName)   { return this.mName = aName; },
  970: 
  971:     write: function () { dump("Hello " + this.mName + "\n"); },
  972:     change: function (aValue) { this.mName = aValue; },
  973:     mName: "a default value",
  974: 
  975:     QueryInterface: function (iid) {
  976:         if (!iid.equals(Components.interfaces.nsISimple)
  977:             && !iid.equals(Components.interfaces.nsISupports))
  978:         {
  979:             throw Components.results.NS_ERROR_NO_INTERFACE;
  980:         }
  981:         return this;
  982:     }
  983: }
  984: 
  985: var Module = {
  986:     firstTime: true,
  987: 
  988:     registerSelf: function (compMgr, fileSpec, location, type) {
  989:         if (this.firstTime) {
  990:             dump("*** Deferring registration of simple JS components\n");
  991:             this.firstTime = false;
  992:             throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
  993:         }
  994:         debug("*** Registering sample JS components\n");
  995:         compMgr =
  996: compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  997:         compMgr.registerFactoryLocation(this.myCID,
  998:                                         "Simple JS Component",
  999:                                         this.myProgID,
 1000:                                         fileSpec,
 1001:                                         location,
 1002:                                         type);
 1003:     },
 1004: 
 1005:     getClassObject : function (compMgr, cid, iid) {
 1006:         if (!cid.equals(this.myCID))
 1007:         throw Components.results.NS_ERROR_NO_INTERFACE
 1008:         if (!iid.equals(Components.interfaces.nsIFactory))
 1009:         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
 1010:         return this.myFactory;
 1011:     },
 1012: 
 1013:     myCID: Components.ID("{98aa9afd-8b08-415b-91ed-01916a130d16}"),
 1014:     myProgID: "@mozilla.org/js_simple_component;1",
 1015: 
 1016:     myFactory: {
 1017:         createInstance: function (outer, iid) {
 1018:             dump("CI: " + iid + "\n");
 1019:             if (outer != null)
 1020:             throw Components.results.NS_ERROR_NO_AGGREGATION;
 1021:             return (new SimpleComponent()).QueryInterface(iid);
 1022:         }
 1023:     },
 1024: 
 1025:     canUnload: function(compMgr) {
 1026:         dump("****** Unloading: Simple JS component! ****** \n");
 1027:         return true;
 1028:     }
 1029: }; // END Module
 1030: 
 1031: function NSGetModule(compMgr, fileSpec) { return Module; }
 1032: 
 1033: 
 1034: function SimpleComponent(){}
 1035: 
 1036: SimpleComponent.prototype = {
 1037: 
 1038:     get yourName()        { return this.mName; },
 1039:     set yourName(aName)   { return this.mName = aName; },
 1040: 
 1041:     write: function () { dump("Hello " + this.mName + "\n"); },
 1042:     change: function (aValue) { this.mName = aValue; },
 1043:     mName: "a default value",
 1044: 
 1045:     QueryInterface: function (iid) {
 1046:         if (!iid.equals(Components.interfaces.nsISimple)
 1047:             && !iid.equals(Components.interfaces.nsISupports))
 1048:         {
 1049:             throw Components.results.NS_ERROR_NO_INTERFACE;
 1050:         }
 1051:         return this;
 1052:     }
 1053: }
 1054: 
 1055: var Module = {
 1056:     firstTime: true,
 1057: 
 1058:     registerSelf: function (compMgr, fileSpec, location, type) {
 1059:         if (this.firstTime) {
 1060:             dump("*** Deferring registration of simple JS components\n");
 1061:             this.firstTime = false;
 1062:             throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
 1063:         }
 1064:         debug("*** Registering sample JS components\n");
 1065:         compMgr =
 1066: compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
 1067:         compMgr.registerFactoryLocation(this.myCID,
 1068:                                         "Simple JS Component",
 1069:                                         this.myProgID,
 1070:                                         fileSpec,
 1071:                                         location,
 1072:                                         type);
 1073:     },
 1074: 
 1075:     getClassObject : function (compMgr, cid, iid) {
 1076:         if (!cid.equals(this.myCID))
 1077:         throw Components.results.NS_ERROR_NO_INTERFACE
 1078:         if (!iid.equals(Components.interfaces.nsIFactory))
 1079:         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
 1080:         return this.myFactory;
 1081:     },
 1082: 
 1083:     myCID: Components.ID("{98aa9afd-8b08-415b-91ed-01916a130d16}"),
 1084:     myProgID: "@mozilla.org/js_simple_component;1",
 1085: 
 1086:     myFactory: {
 1087:         createInstance: function (outer, iid) {
 1088:             dump("CI: " + iid + "\n");
 1089:             if (outer != null)
 1090:             throw Components.results.NS_ERROR_NO_AGGREGATION;
 1091:             return (new SimpleComponent()).QueryInterface(iid);
 1092:         }
 1093:     },
 1094: 
 1095:     canUnload: function(compMgr) {
 1096:         dump("****** Unloading: Simple JS component! ****** \n");
 1097:         return true;
 1098:     }
 1099: }; // END Module
 1100: 
 1101: function NSGetModule(compMgr, fileSpec) { return Module; }
 1102: 
 1103: </pre>
 1104:     <h3><a name="77069"></a> Compiling the Component</h3>
 1105:     <p>Once you create an IDL source 
 1106:     file and a JavaScript implementation file, you need to compile
 1107:     <tt>nsISimple.idl</tt> into a <i>.xpt</i> type library.</p>
 1108:     <h4><a name="77070"></a> Compiling the type library</h4>
 1109:     <p>To compile the XPIDL interface file
 1110:     <i>nsISimple.idl</i>, you need to add the path of the XPIDL
 1111:     compiler to your environment. As mentioned earlier, the XPIDL
 1112:     compiler is located at <i>mozilla/xpcom/typelib/xpidl</i>. Here
 1113:     is the output of a <i>Unix/cygwin/OSX</i> session showing the
 1114:     compilation starting with the source file
 1115:     (<i>nsISimple.idl</i>) created earlier in the chapter.
 1116:     Afterwards, <i>nsISimple.xpt</i> and <i>nsSimple.js</i> are
 1117:     copied to the <i>components</i> directory:</p>
 1118: <pre>
 1119: $ ls
 1120: nsISimple.idl  nsSimple.js
 1121: $ PATH=$PATH:/usr/src/mozilla/xpcom/typelib/xpidl
 1122: $ echo $PATH
 1123: /sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/bin:/usr/X11R6/bin:/root/bin:/usr/src/mozilla/xpcom/typelib/xpidl
 1124: $ export XPIDL_INC=/usr/src/mozilla/xpcom/base
 1125: $ echo $XPIDL_INC
 1126: /usr/src/mozilla/xpcom/base
 1127: $ xpidl -m typelib -w -v -I $XPIDL_INC \
 1128: > -o nsISimple nsISimple.idl
 1129: $ ls
 1130: nsISimple.idl  nsISimple.xpt  nsSimple.js
 1131: $ cp nsISimple.xpt nsSimple.js \
 1132: > /usr/src/mozilla/dist/bin/components/
 1133: </pre>
 1134:     <p>This output illustrates the compilation of the
 1135:     <i>nsISimple.idl</i> source file into the <i>nsISimple.xpt</i>
 1136:     typelib file. The newly compiled <i>typelib</i> file and the
 1137:     JavaScript implementation file are then copied to the Mozilla
 1138:     distribution components directory where component registration
 1139:     will occur automatically when Mozilla is launched.</p>
 1140:     <h4><a name="77071"></a> Creating a Makefile for your component
 1141:     project</h4>
 1142:     <p>All previous steps were done manually.
 1143:     You can also create a Makefile to automate this process by
 1144:     using GNU make, in which case you would create a Makefile with
 1145:     the following variables and targets defined:</p>
 1146: <pre>
 1147: TOP_SRC=/usr/src/mozilla
 1148: INST_DIR=$(TOP_SRC)/dist/bin/components
 1149: XPIDL=$(TOP_SRC)/xpcom/typelib/xpidl
 1150: XPIDL_INC=$(TOP_SRC)/xpcom/base
 1151: FLAGS=-m typelib -w -v -I $(XPIDL_INC) -o
 1152: all:
 1153: $(XPIDL)/xpidl $(FLAGS) \
 1154: nsISimple nsISimple.idl
 1155: install:
 1156: cp nsISimple.xpt nsSimple.js $(INST_DIR)
 1157: clean:
 1158: rm -rf *.xpt
 1159: uninstall:
 1160: rm -f $(INST_DIR)/nsISimple.xpt
 1161: rm -f $(INST_DIR)/nsSimple.js
 1162: </pre>
 1163:     <p>Remember that you must indent after your targets with a
 1164:     <tt><tab></tt>.</p>
 1165:     <p>In this file, which can be used on Unix, Windows using
 1166:     <i>cygwin</i>, or Mac OS X, the <tt>TOP_SRC</tt> environment
 1167:     variable points to the Mozilla source tree's top-level
 1168:     directory, the <tt>INST_DIR</tt> points to the directory where
 1169:     the component should be installed, and the XPIDL variables
 1170:     drive the XPIDL executable and its environment and compiler
 1171:     flags. The "all" Makefile target compiles and creates the type
 1172:     library <i>nsISimple.xpt</i>.</p>
 1173:     <p>Note that in addition to the type 
 1174:     libraries, the XPIDL compiler compiles header files, Java class
 1175:     files, and special HTML documentation, if necessary.</p>
 1176:     <h3><a name="77072"></a> Testing the Component</h3>
 1177:     <p>When you start up <i>xpcshell</i>, the Component Manager
 1178:     finds the new <tt>nsISimple</tt> component and registers it.
 1179:     The result of your test should look similar to <a href=
 1180:     "#77016">Example 8-5</a>.</p>
 1181:     <p><i>Example 8-5: <a name="77016"></a></i> <i>Scripting the
 1182:     "simple" component in xpcshell</i></p>
 1183: <pre>
 1184:  $ cd /usr/src/mozilla/dist/bin/
 1185:  $ ./run-mozilla.sh ./xpcshell
 1186:  Type Manifest File: /home/petejc/MOZILLA/mozilla/dist/bin/components/xpti.dat
 1187:  nsNativeComponentLoader: autoregistering begins.
 1188:  nsNativeComponentLoader: autoregistering succeeded
 1189:  *** first time registration of Simple JS component
 1190:  nNCL: registering deferred (0)
 1191:   ***** Registering: Simple JS component! ****
 1192:  nNCL: registering deferred (0)
 1193:  js>const Simple=new Components.Constructor("@mozilla.org/js_simple_component;1", "nsISimple");
 1194:  js> var simple=new Simple( );
 1195:  CI: {ce32e3ff-36f8-425f-94be-d85b26e634ee}
 1196:  js> for(var list in simple)
 1197:  print(list);
 1198:  QueryInterface
 1199:  yourName
 1200:  write
 1201:  change
 1202:  js> simple.yourName;
 1203:  a default value
 1204:  js> simple.yourName="Pete";
 1205:  Pete
 1206:  js> simple.write( );
 1207:  Hello Pete
 1208:  null
 1209:  js> simple.change("Brian");
 1210:  null
 1211:  js> simple.write( );
 1212:  Hello Brian
 1213:  null
 1214:  js> simple.yourName;
 1215:  Brian
 1216:  js> quit( );
 1217:  CanUnload_enumerate: skipping native
 1218:  ****** Unloading: Simple JS component! ******
 1219: </pre>
 1220:     <p>Once the component is tested and registered as an XPCOM
 1221:     object, you can use JavaScript from a local web page or from
 1222:     the chrome to create an <tt>nsISimple</tt> object and use it as
 1223:     you would any ordinary JavaScript object:</p>
 1224: <pre>
 1225: <script type="application/x-JavaScript">
 1226: netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 1227: var Simple=new Components.Constructor("@mozilla.org/js_simple_component;1", "nsISimple");
 1228: var s = new Simple( );
 1229: for(var list in s)
 1230: document.write(list+"<br/>\n");
 1231: </script>
 1232: </pre>
 1233:     <p>In addition to creating a component in JavaScript, you can
 1234:     implement XPCOM components in C++ and Python. The next sections
 1235:     cover the C++ implementation of the <tt>nsISimple</tt>
 1236:     interface.</p>
 1237:     <h3><a name="77073"></a> Useful C++ Macros and Types</h3>
 1238:     <p>Before you begin working on an actual implementation of a C++
 1239:     component, familiarize yourself with some of the tools that
 1240:     make C++ programming for XPCOM a little easier. Templates,
 1241:     special types, and macros can ease some of the extra
 1242:     housekeeping that programming XPCOM requires.</p>
 1243:     <p>More tools than we can cover in this introduction are
 1244:     available, but this section reviews some of the most common,
 1245:     including a macro that implements the <tt>nsISupports</tt>
 1246:     methods <tt>QueryInterface</tt>, <tt>AddRef</tt>, and
 1247:     <tt>Release</tt>, macros for testing <tt>nsresults</tt>,
 1248:     <tt>smartpointers</tt>, and special types.</p>
 1249:     <h4><a name="77074"></a> The NS_IMPL_ISUPPORTS1_CI macro</h4>
 1250:     <p>Rather than having to implement <tt>QueryInterface</tt>,
 1251:     <tt>AddRef</tt>, and the <tt>Release</tt> methods like we did
 1252:     in our JavaScript component, the <tt>NS_IMPL_ISUPPORTS</tt>
 1253:     macro inserts the implementation code for you.</p>
 1254:     <p>To use this macro for the <tt>nsISimple</tt> interface,
 1255:     type:</p>
 1256: <pre>
 1257: NS_IMPL_ISUPPORTS1_CI(nsSimpleImpl, nsISimple)
 1258: </pre>
 1259:     <p>The following lines define this macro:</p>
 1260: <pre>
 1261: #define NS_IMPL_ISUPPORTS1(_class, _interface) \
 1262: NS_IMPL_ADDREF(_class)                         \
 1263: NS_IMPL_RELEASE(_class)                        \
 1264: NS_IMPL_QUERY_INTERFACE1(_class, _interface)
 1265: </pre>
 1266:     <p>As you can see, the macro is made up of other macros that
 1267:     implement basic methods of the <tt>nsISupports</tt> interface.
 1268:     Unless you need to modify these macros, they should be left as
 1269:     is. This macro is used later on when we create our C++
 1270:     component.</p>
 1271:     <p><a href="#77018">Example 8-6</a> shows a reference 
 1272:     implementation of the <tt>QueryInterface</tt> method in
 1273:     C++.</p>
 1274:     <p><i>Example 8-6: <a name="77018"></a></i> <i>Reference
 1275:     implementation of QueryInterface</i></p>
 1276: <pre>
 1277:  NS_IMETHODIMP
 1278:  nsMyImplementation::QueryInterface( REFNSIID aIID, void** aInstancePtr )
 1279:  {
 1280:    NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!");
 1281:    if ( !aInstancePtr )
 1282:      return NS_ERROR_NULL_POINTER;
 1283:    nsISupports* foundInterface;
 1284:    if ( aIID.Equals(nsCOMTypeInfo<nsIX>::GetIID( )) )
 1285:      foundInterface = NS_STATIC_CAST(nsIX*, this);
 1286:    else if ( aIID.Equals(nsCOMTypeInfo<nsIY>::GetIID( )) )
 1287:      foundInterface = NS_STATIC_CAST(nsIY*, this);
 1288:    else if ( aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID( )) )
 1289:      foundInterface = NS_STATIC_CAST(nsISupports*, NS_STATIC_CAST(nsIX*, this));
 1290:    else
 1291:      foundInterface = 0;
 1292:    nsresult status;
 1293:    if ( !foundInterface ) {
 1294:      status = NS_NOINTERFACE;
 1295:    } else {
 1296:      NS_ADDREF(foundInterface);
 1297:      status = NS_OK;
 1298:    }
 1299:    *aInstancePtr = foundInterface;
 1300:    return status;
 1301:  }
 1302: </pre>
 1303:     <h4><a name="77075"></a> The results macros</h4>
 1304:     <p>Since all XPCOM methods return
 1305:     result codes called <i>nsresults</i>, another useful macro is
 1306:     the <tt>NS_SUCCEEDED</tt> macro. This indicates whether an
 1307:     XPCOM accessor has returned a successful result. It is defined
 1308:     in <i>nsError.h</i>:</p>
 1309: <pre>
 1310: #define NS_SUCCEEDED(_nsresult) (!((_nsresult) &amp; 0x80000000))
 1311: </pre>
 1312:     <p>A related macro, <tt>NS_FAILED</tt>, is indicates whether an
 1313:     XPCOM accessor returned a failure code result. It too is
 1314:     defined in <i>nsError.h</i>. The following code demonstrates
 1315:     the typical use of these two macros:</p>
 1316: <pre>
 1317: nsresult rv;
 1318: nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1", &amp;rv));
 1319: if (NS_FAILED(rv)) {
 1320: printf("FAILED\n");
 1321: return rv;
 1322: }
 1323: if (NS_SUCCEEDED(rv)) {
 1324: printf(" SUCCEEDED \n");
 1325: return rv;
 1326: }
 1327: </pre>
 1328:     <p>You may have noticed that the declaration of the identifier
 1329:     <tt>rv</tt> as the type <tt>nsresult</tt>. <tt>nsresult</tt> is
 1330:     a 32-bit unsigned integer declared in <i>nscore.h</i>:</p>
 1331: <pre>
 1332: typedef PRUint32 nsresult;
 1333: </pre>
 1334:     <p>We assign an <i>nsCOMPtr</i> or smart pointer named
 1335:     <tt>file</tt> to a newly created instance of the
 1336:     <tt>nsILocalFile</tt> component. Using the <tt>NS_FAILED</tt>
 1337:     and <tt>NS_SUCCEEDED</tt> macros, we test for the
 1338:     <tt>nsresult</tt> to see if our attempt to create an instance
 1339:     of the component failed. If it did, <tt>rv</tt> would be
 1340:     assigned an integer with a specific error return code. Return
 1341:     codes are defined in <i>nsError.h</i>. Alternatively, you can
 1342:     test your results for the success code:</p>
 1343: <pre>
 1344: nsresult rv = nsComponentManager::CreateInstance("@mozilla.org/file/local;1",
 1345: nsnull,
 1346: NS_GET_IID(nsILocalFile),
 1347: (void **)&amp;refp);
 1348: </pre>
 1349:     <p>If a result is successful, the value of <tt>rv</tt> returns
 1350:     <tt>NS_OK</tt>, which is 0.</p>
 1351:     <p>Return codes are used in XPCOM instead of exceptions.
 1352:     Exceptions are not allowed because of their inconsistent
 1353:     implementation across different compilers. All error code
 1354:     numbers equate to a specific type of error. For example
 1355:     <tt>NS_ERROR_FAILURE</tt> and <tt>NS_ERROR_NULL_POINTER</tt>
 1356:     are common types of error code return values used throughout
 1357:     the Mozilla code base. If a value returned to <tt>rv</tt> was
 1358:     <tt>NS_ERROR_NULL_POINTER</tt>, the test for failure would be
 1359:     true and the code would return the numerical result code for
 1360:     <tt>NS_ERROR_NULL_POINTER</tt>.</p>
 1361:     <h4><a name="77076"></a> The nsnull type</h4>
 1362:     <p>Another widely use type is <tt>nsnull</tt>, 
 1363:     defined in <i>nscore.h</i>. Here is the definition:</p>
 1364: <pre>
 1365: #define nsnull 0
 1366: </pre>
 1367:     <p>This definition, <tt>nsnull</tt>, is the most common way to
 1368:     use <tt>null</tt>. The following code shows how to use
 1369:     <tt>nsnull</tt>:</p>
 1370: <pre>
 1371: nsresult rv;
 1372: nsCOMPtr<nsILocalFile> file =
 1373: do_CreateInstance("@mozilla.org/file/local;1", &amp;rv);
 1374: if (NS_SUCCEEDED(rv)) {
 1375: char* msg = "we successfully created an instance of file\n";
 1376: *_retval = (char*) nsMemory::Alloc(PL_strlen(msg) + 1);
 1377: if (!*_retval)
 1378: return NS_ERROR_OUT_OF_MEMORY;
 1379: PL_strcpy(*_retval, msg);
 1380: } else {
 1381: *_retval = nsnull;
 1382: }
 1383: </pre>
 1384:     <h4><a name="77077"></a> The NS_IMETHODIMP macro</h4>
 1385:     <p>If you look in the Mozilla C++ source code, you will see the
 1386:     macro <tt>NS_IMETHODIMP</tt> used frequently. This macro
 1387:     identifies the type of your interface implementation method. It
 1388:     is also defined in <i>nscore.h,</i> as shown in <a href=
 1389:     "#77020">Example 8-7</a>.</p>
 1390:     <p><i>Example 8-7: <a name="77020"></a></i> <i>Platform macros
 1391:     in xpcom/base/nscore.h</i></p>
 1392: <pre>
 1393:  #define NS_IMETHODIMP NS_IMETHODIMP_(nsresult)
 1394:  #ifdef NS_WIN32
 1395:    #define NS_IMETHODIMP_(type) type _ _stdcall
 1396:  #elif defined(XP_MAC)
 1397:    #define NS_IMETHODIMP_(type) type
 1398:  #elif defined(XP_OS2)
 1399:    #define NS_IMETHODIMP_(type) type
 1400:  #else
 1401:    #define NS_IMETHODIMP_(type) type
 1402:  #endif
 1403: </pre>
 1404:     <p><a href="#77022">Example 8-8</a> shows a typical use of the
 1405:     <tt>NS_IMETHODIMP</tt> macro. All methods that implement an
 1406:     interface are of the type <tt>NS_IMETHODIMP</tt>.</p>
 1407:     <p><i>Example 8-8: <a name="77022"></a></i> <i>NS_IMETHOD
 1408:     macro</i></p>
 1409: <pre>
 1410:  NS_IMETHODIMP
 1411:  nsMyImpl::GetSomeString(char** _retval)
 1412:  {
 1413:    nsresult rv;
 1414:    nsCOMPtr<nsILocalFile> file =
 1415:    do_CreateInstance("@mozilla.org/file/local;1", &amp;rv);
 1416:    if (NS_SUCCEEDED(rv)) {
 1417:      char* msg = "we successfully created an instance of file\n";
 1418:      *_retval = (char*) nsMemory::Alloc(PL_strlen(msg) + 1);
 1419:      if (!*_retval)
 1420:        return NS_ERROR_OUT_OF_MEMORY;
 1421:      PL_strcpy(*_retval, msg);
 1422:    } else {
 1423:      *_retval = nsnull;
 1424:    }
 1425:    return NS_OK;
 1426:  }
 1427: </pre>
 1428:     <p>The macro in <a href="#77022">Example 8-8</a> declares the
 1429:     method <tt>GetSomeString</tt> as an XPCOM implementation.</p>
 1430:     <h4><a name="77078"></a> nsCOMPtr smart pointer</h4>
 1431:     <p>As described earlier, XPCOM provides 
 1432:     a C++ tool called a smart pointer to manage reference counting.
 1433:     A smart pointer is a template class that acts syntactically,
 1434:     just like an ordinary pointer in C or C++. You can apply
 1435:     <tt>*</tt> to dereference the pointer, <tt>-></tt>, or
 1436:     access what the pointer refers to. Unlike a raw COM interface
 1437:     pointer, however, <tt>nsCOMPtr</tt> manages <tt>AddRef</tt>,
 1438:     <tt>Release</tt>, and <tt>QueryInterface</tt> for you, thereby
 1439:     preventing memory leaks.</p>
 1440:     <p>Here is how to create a raw pointer:</p>
 1441: <pre>
 1442: nsILocalFile *refp(nsnull);
 1443: nsresult rv = nsComponentManager::CreateInstance("@mozilla.org/file/local;1",
 1444: nsnull,
 1445: NS_GET_IID(nsILocalFile),
 1446: (void **)&amp;refp);
 1447: if (refp)
 1448: printf("%p\n", (void*)refp);
 1449: </pre>
 1450:     <p>After you create a new object that <tt>refp</tt> points to,
 1451:     <tt>refp</tt> is considered an owning reference, and any other
 1452:     pointers that point to it must be "refcounted." <a href=
 1453:     "#77024">Example 8-9</a> uses <tt>anotherPtr</tt> andoneMorePtr
 1454:     to point to <tt>refp</tt>, and manually manages <tt>AddRef</tt>
 1455:     and <tt>Release</tt>.</p>
 1456:     <p><i>Example 8-9: <a name="77024"></a></i> <i>Manual reference
 1457:     counting using raw pointers</i></p>
 1458: <pre>
 1459:  nsILocalFile *refp(nsnull);
 1460:  nsresult rv = nsComponentManager::CreateInstance("@mozilla.org/file/local;1",
 1461:     nsnull,
 1462:     NS_GET_IID(nsILocalFile),
 1463:     (void **)&amp;refp);
 1464:  nsILocalFile *anotherPtr = refp;
 1465:  NS_IF_ADDREF(anotherPtr); // increment refcount
 1466:  nsILocalFile *oneMorePtr = refp;
 1467:  NS_IF_ADDREF(oneMorePtr); // increment refcount
 1468:  if (!someCondition) {
 1469:    NS_RELEASE(anotherPtr); // decrement refcount
 1470:    return NS_OK;
 1471:  }
 1472:  . . .
 1473:  NS_RELEASE(anotherPtr); // decrement refcount
 1474:  NS_RELEASE(oneMorePtr); // decrement refcount
 1475:  return NS_OK;
 1476:  }
 1477: </pre>
 1478:     <p>In <a href="#77024">Example 8-9</a>, if
 1479:     <tt>someCondition</tt> is false, <tt>anotherPtr</tt> is
 1480:     released and the function then returns (<tt>NS_OK</tt>). But
 1481:     what about <tt>oneMorePtr</tt>? In this instance, it is never
 1482:     released; if you remember, an object cannot be released from
 1483:     memory until our <tt>refcount</tt> is at zero. The
 1484:     <tt>refcount</tt> is out of sync, <tt>oneMorePtr</tt> is never
 1485:     decremented before the return, and the object is thus left
 1486:     dangling in memory. With the <tt>refcount</tt> off, the object
 1487:     leaks. Remember that <tt>Release( )</tt> calls the C++
 1488:     <tt>delete</tt> operator to free up the allocated XPCOM object
 1489:     only when the count is decremented to 0. If <tt>Release</tt>
 1490:     thinks there are still references to the object because the
 1491:     <tt>refcount</tt> hasn't been properly decremented,
 1492:     <tt>delete</tt> is never called. The correct code is shown
 1493:     below:</p>
 1494: <pre>
 1495: if (!someCondition) {
 1496: NS_RELEASE(anotherPtr); // decrement refcount
 1497: NS_RELEASE(oneMorePtr); // decrement refcount
 1498: return NS_OK;
 1499: }
 1500: </pre>
 1501:     <p>As you can see, manual management of reference counting is
 1502:     prone to error. To alleviate this burden and extra code bloat,
 1503:     <tt>nsCOMPtr</tt> implements <tt>AddRef</tt> and
 1504:     <tt>Release</tt> for you and makes life much easier. Before the
 1505:     <tt>nsCOMPtr</tt> class is removed from the stack, it calls
 1506:     <tt>Release</tt> in its destructor. After all references are
 1507:     properly released, <tt>delete</tt> is called and the object is
 1508:     freed from memory. <a href="#77026">Example 8-10</a> shows a
 1509:     typical use of <tt>nsCOMPtr</tt>. Example 8-10<a name=
 1510:     "77026"></a> <i>Using nsCOMPtr in your code</i></p>
 1511: <pre>
 1512:  nsCOMPtr<nsILocalFile> refp = do_CreateInstance("@mozilla.org/file/local;1");
 1513:  nsCOMPtr<nsILocalFile> anotherPtr = refp;
 1514:  nsCOMPtr<nsILocalFile> oneMorePtr = refp;
 1515:  nsresult rv;
 1516:  if (!someCondition)
 1517:    return NS_OK;
 1518:  . . .
 1519:  //no need to release here because nsCOMPtr smart pointer's destructor
 1520:  // will call release automatically and the above references will be
 1521:  // properly decremented.
 1522:  return NS_OK;
 1523: </pre>
 1524:     <p>Wherever the code returns, all pointers holding references
 1525:     to the <tt>nsLocalFile</tt> XPCOM object are released
 1526:     automatically in the <tt>nsCOMPtr</tt> class destructor before
 1527:     the instructions are removed from the stack. By letting
 1528:     <tt>nsCOMPtr</tt> manage <tt>AddRef</tt> and <tt>Release</tt>
 1529:     for you, you remove a margin for error, code complexity, and
 1530:     bloat.</p>
 1531:     <h3><a name="77079"></a> C++ Implementation of nsISimple</h3>
 1532:     <p>Now that you have seen some of 
 1533:     the C++ tools you need for XPCOM, you can turn to an actual
 1534:     implementation.</p>
 1535:     <p>Earlier in this chapter, the section <a href=
 1536:     "#77065">"Creating a JavaScript XPCOM Component</a>" showed you
 1537:     how to create an interface and implement it in JavaScript.
 1538:     However, you may need a C++ implementation to benefit from the
 1539:     better performance offered by a compiled language.</p>
 1540:     <p>Most components used in Mozilla are written in C++. This
 1541:     section discusses how to create a C++ implementation for the
 1542:     <tt>nsISimple</tt> interface. A few more steps are involved,
 1543:     but as you will see, they are generally similar to the
 1544:     processes described in the JavaScript component section,
 1545:     facilitated to some extent by the available tools and templates
 1546:     discussed previously.</p>
 1547:     <h4><a name="77080"></a> Creating a C++ component</h4>
 1548:     <p>First, you must find a good place 
 1549:     to put the source file you create for the component. In your
 1550:     local Mozilla source tree, <i>mozilla/xpcom/sample/</i> is a
 1551:     great place to start because it's the directory in which the
 1552:     sample XPCOM interface and implementations already reside.</p>
 1553:     <p>First, create a new directory and call it <i>simple</i>:</p>
 1554: <pre>
 1555: $ mkdir simple
 1556: $ cd simple
 1557: </pre>
 1558:     <p>You can place the <tt>nsISimple</tt> interface you created
 1559:     earlier in this new directory as a file called
 1560:     <i>nsISimple.idl</i>:</p>
 1561: <pre>
 1562: #include "nsISupports.idl"
 1563: [scriptable, uuid(ce32e3ff-36f8-425f-94be-d85b26e634ee)]
 1564: interface nsISimple : nsISupports
 1565: {
 1566: attribute string yourName;
 1567: void write( );
 1568: void change(in string aName);
 1569: };
 1570: </pre>
 1571:     <p>Once you have the interface source file in which the
 1572:     attribute <tt>yourName</tt> and the methods <tt>write( )</tt>
 1573:     and <tt>change( )</tt> are defined, you can create a header
 1574:     file for the implementation source file.</p>
 1575:     <h4><a name="77081"></a> nsISimple C++ header file</h4>
 1576:     <p>Earlier, you created the type 
 1577:     library <i>nsISimple.xpt</i> for the JavaScript component and
 1578:     installed it in the components subdirectory. Since we've
 1579:     already covered those steps, we can move forward to generating
 1580:     a C++ header file. To create a C++ header file from your
 1581:     original IDL, run your IDL file through the <i>xpidl</i>
 1582:     compiler:</p>
 1583: <pre>
 1584: $ xpidl -m header -w -v -I $XPIDL_INC \
 1585: > -o nsISimple nsISimple.idl
 1586: </pre>
 1587:     <p>The generated file is <i>nsISimple.h</i> and is shown in <a
 1588:     href="#77028">Example 8-11</a>. Example 8-11<a name=
 1589:     "77028"></a> <i>nsISimple header file generated by xpidl
 1590:     compiler</i></p>
 1591: <pre>
 1592:  /*
 1593:   * DO NOT EDIT.  THIS FILE IS GENERATED FROM nsISimple.idl
 1594:   */
 1595:  #ifndef _ _gen_nsISimple_h_ _
 1596:  #define _ _gen_nsISimple_h_ _
 1597:  #ifndef _ _gen_nsISupports_h_ _
 1598:  #include "nsISupports.h"
 1599:  #endif
 1600:  /* For IDL files that don't want to include root IDL files. */
 1601:  #ifndef NS_NO_VTABLE
 1602:  #define NS_NO_VTABLE
 1603:  #endif
 1604:  /* starting interface:    nsISimple */
 1605:  #define NS_ISIMPLE_IID_STR "ce32e3ff-36f8-425f-94be-d85b26e634ee"
 1606:  #define NS_ISIMPLE_IID \
 1607:    {0xce32e3ff, 0x36f8, 0x425f, \
 1608:      { 0x94, 0xbe, 0xd8, 0x5b, 0x26, 0xe6, 0x34, 0xee }}
 1609:  class NS_NO_VTABLE nsISimple : public nsISupports {
 1610:   public:
 1611:    NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISIMPLE_IID)
 1612:    /* attribute string yourName; */
 1613:    NS_IMETHOD GetYourName(char * *aYourName) = 0;
 1614:    NS_IMETHOD SetYourName(const char * aYourName) = 0;
 1615:    /* void write ( ); */
 1616:    NS_IMETHOD Write(void) = 0;
 1617:    /* void change (in string aName); */
 1618:    NS_IMETHOD Change(const char *aName) = 0;
 1619:  };
 1620:  /* Use this macro when declaring classes that implement this interface. */
 1621:  #define NS_DECL_NSISIMPLE \
 1622:    NS_IMETHOD GetYourName(char * *aYourName); \
 1623:    NS_IMETHOD SetYourName(const char * aYourName); \
 1624:    NS_IMETHOD Write(void); \
 1625:    NS_IMETHOD Change(const char *aName);
 1626:  /* Use this macro to declare functions that forward the behavior of this interface to another object. */
 1627:  #define NS_FORWARD_NSISIMPLE(_to) \
 1628:    NS_IMETHOD GetYourName(char * *aYourName) { return _to ## GetYourName(aYourName); } \
 1629:    NS_IMETHOD SetYourName(const char * aYourName) { return _to ## SetYourName(aYourName); } \
 1630:    NS_IMETHOD Write(void) { return _to ## Write( ); } \
 1631:    NS_IMETHOD Change(const char *aName) { return _to ## Change(aName); }
 1632:  /* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */
 1633:  #define NS_FORWARD_SAFE_NSISIMPLE(_to) \
 1634:    NS_IMETHOD GetYourName(char * *aYourName) { return !_to ## ? NS_ERROR_NULL_POINTER : _to ##->GetYourName(aYourName); } \
 1635:    NS_IMETHOD SetYourName(const char * aYourName) { return !_to ## ? NS_ERROR_NULL_POINTER : _to ##->SetYourName(aYourName); } \
 1636:    NS_IMETHOD Write(void) { return !_to ## ? NS_ERROR_NULL_POINTER : _to ##-> Write( ); } \
 1637:    NS_IMETHOD Change(const char *aName) { return !_to ## ? NS_ERROR_NULL_POINTER : _to ##-> Change(aName); }
 1638:  #if 0
 1639:  /* Use the code below as a template for the implementation class for this interface. */
 1640:  /* Header file */
 1641:  class nsSimple : public nsISimple
 1642:  {
 1643:  public:
 1644:    NS_DECL_ISUPPORTS
 1645:    NS_DECL_NSISIMPLE
 1646:    nsSimple( );
 1647:    virtual ~nsSimple( );
 1648:    /* additional members */
 1649:  };
 1650:  /* Implementation file */
 1651:  NS_IMPL_ISUPPORTS1(nsSimple, nsISimple)
 1652:  nsSimple::nsSimple( )
 1653:  {
 1654:    NS_INIT_ISUPPORTS( );
 1655:    /* member initializers and constructor code */
 1656:  }
 1657:  nsSimple::~nsSimple( )
 1658:  {
 1659:    /* destructor code */
 1660:  }
 1661:  /* attribute string yourName; */
 1662:  NS_IMETHODIMP nsSimple::GetYourName(char * *aYourName)
 1663:  {
 1664:      return NS_ERROR_NOT_IMPLEMENTED;
 1665:  }
 1666:  NS_IMETHODIMP nsSimple::SetYourName(const char * aYourName)
 1667:  {
 1668:      return NS_ERROR_NOT_IMPLEMENTED;
 1669:  }
 1670:  /* void write ( ); */
 1671:  NS_IMETHODIMP nsSimple::Write( )
 1672:  {
 1673:      return NS_ERROR_NOT_IMPLEMENTED;
 1674:  }
 1675:  /* void change (in string aName); */
 1676:  NS_IMETHODIMP nsSimple::Change(const char *aName)
 1677:  {
 1678:      return NS_ERROR_NOT_IMPLEMENTED;
 1679:  }
 1680:  /* End of implementation class template. */
 1681:  #endif
 1682:  #endif /* _ _gen_nsISimple_h_ _ */
 1683: </pre>
 1684:     <p>As you can see, the <i>xpidl</i> compiler can do a lot of
 1685:     work for you. The code generated in <a href="#77028">Example
 1686:     8-11</a> is a C++ header file that declares the methods of
 1687:     <tt>nsISimple</tt>. It provides the class definition, macros
 1688:     for using the interface, and a template for the class
 1689:     implementation, which contains stubbed-out declaratory code
 1690:     that you can paste into your implementation file to quickly get
 1691:     started.</p>
 1692:     <h4><a name="77082"></a> Creating the implementation file</h4>
 1693:     <p>The implementation file actually 
 1694:     contains the C++ code that implements the member functions and
 1695:     properties declared in your interface. For <tt>nsISimple</tt>,
 1696:     these members are the <tt>yourName</tt> attribute and the
 1697:     <tt>write( )</tt> and <tt>change( )</tt> methods.</p>
 1698:     <p>First you need to generate a new UUID for the new
 1699:     implementation class you'll write. Every XPCOM implementation
 1700:     class must have its own UUID:</p>
 1701: <pre>
 1702: $ uuidgen
 1703: 79e9424f-2c4d-4cae-a762-31b334079252
 1704: </pre>
 1705:     <p>As part of the generated file <i>nsISimple.h</i>, all the
 1706:     code stubs you need to get started are ready to be copied and
 1707:     pasted into the C++ source files. You can use those stubs as a
 1708:     guide to implement the component. In a text editor, create a
 1709:     new file called <i>nsSimple.h</i> and enter the code shown in
 1710:     <a href="#77030">Example 8-12</a>.</p>
 1711:     <p>To maintain clarity, the C++ implementation class is named
 1712:     <tt>nsSimpleImpl</tt>, where the default class name generated
 1713:     by the <i>xpidl</i> compiler is <tt>nsSimple</tt> and the
 1714:     header file, <i>nsSimple.h</i>, is shown in <a href=
 1715:     "#77030">Example 8-12</a>. Example 8-12<a name="77030"></a>
 1716:     <i>The component header file nsSimple.h</i></p>
 1717: <pre>
 1718:  #include "nsISimple.h"
 1719:  // 79e9424f-2c4d-4cae-a762-31b334079252
 1720:  #define NS_SIMPLE_CID \
 1721:  { 0x79e9424f, 0x2c4d, 0x4cae, { 0xa7, 0x62, 0x31, 0xb3, 0x34, 0x07, 0x92, 0x52 } }
 1722:  #define NS_SIMPLE_CONTRACTID "@mozilla.org/cpp_simple;1"
 1723:  class nsSimpleImpl : public nsISimple
 1724:  {
 1725:  public:
 1726:      nsSimpleImpl( );
 1727:      virtual ~nsSimpleImpl( );
 1728:      // nsISupports interface
 1729:      NS_DECL_ISUPPORTS
 1730:      NS_DECL_NSISIMPLE
 1731:  private:
 1732:      char* mName;
 1733:  };
 1734: </pre>
 1735:     <p><a href="#77030">Example 8-12</a> includes the ID-generated
 1736:     header file <i>nsISimple.h</i>, which holds the C++
 1737:     declarations for the interface class <tt>nsISimple</tt>. It
 1738:     then takes the new UUID and breaks it into a class ID struct
 1739:     defined as <tt>NS_SIMPLE_CID</tt>. Next, it defines the
 1740:     contract ID for this implementation class.</p>
 1741:     <p>The example uses a completely different class ID and
 1742:     contract ID than the one used for the JavaScript component
 1743:     because it's a different implementation class and needs to have
 1744:     it's own unique identification (even though it implements the
 1745:     same interface).</p>
 1746:     <p>Now the example makes the class declaration of the
 1747:     implementation, called <tt>nsSimpleImpl</tt>, which inherits
 1748:     from <tt>nsISimple</tt>, defining the class constructor and
 1749:     virtual destructor. <tt>NS_DECL_ISUPPORTS</tt> is a macro that
 1750:     holds the declaration of our required <tt>QueryInterface</tt>,
 1751:     <tt>AddRef</tt>, and <tt>Release</tt> methods.
 1752:     <tt>NS_DECL_NSISIMPLE</tt> is created in the generated header
 1753:     file <i>nsISimple.h</i>. It expands to the used interface
 1754:     method declarations. Finally <a href="#77030">Example 8-12</a>
 1755:     shows the addition of the <tt>char*</tt> member variable
 1756:     identified as <i>mName</i>. This variable is used to hold the
 1757:     value of the interface attribute <tt>yourName</tt>, just as it
 1758:     did earlier in the JavaScript class implementation.</p>
 1759:     <p>Once you have the header file, you are ready to start the
 1760:     implementation source file. With a text editor, create a new
 1761:     file called <i>nsSimple.cpp</i>. As in any C++ source file, you
 1762:     should add the header files required by the implementation:</p>
 1763: <pre>
 1764: #include "plstr.h"
 1765: #include "stdio.h"
 1766: #include "nsCOMPtr.h"
 1767: #include "nsMemory.h"
 1768: #include "nsSimple.h"
 1769: </pre>
 1770:     <p>Start by adding the implementation of our class constructor
 1771:     and destructor:</p>
 1772: <pre>
 1773: // c++ constructor
 1774: nsSimpleImpl::nsSimpleImpl( ) : mName(nsnull)
 1775: {
 1776: // NS_INIT_REFCNT( );  // has been depricated use NS_INIT_ISUPPORTS()
 1777: NS_INIT_ISUPPORTS();
 1778: mName = PL_strdup("default value");
 1779: }
 1780: // c++ destructor
 1781: nsSimpleImpl::~nsSimpleImpl( )
 1782: {
 1783: if (mName)
 1784: PL_strfree(mName);
 1785: }
 1786: </pre>
 1787:     <p>Then add the macro <tt>NS_IMPL_ISUPPORTS1_CI</tt>. As
 1788:     discussed earlier, this macro conveniently implements
 1789:     <tt>QueryInterface</tt>, <tt>AddRef</tt>, and
 1790:     <tt>Release</tt>:</p>
 1791: <pre>
 1792: NS_IMPL_ISUPPORTS1_CI(nsSimpleImpl, nsISimple);
 1793: </pre>
 1794:     <p>Next you are ready to implement the actual
 1795:     <tt>nsISimple</tt> interface methods:</p>
 1796: <pre>
 1797: NS_IMETHODIMP
 1798: nsSimpleImpl::GetYourName(char** aName)
 1799: {
 1800: NS_PRECONDITION(aName != nsnull, "null ptr");
 1801: if (!aName)
 1802: return NS_ERROR_NULL_POINTER;
 1803: if (mName) {
 1804: *aName = (char*) nsMemory::Alloc(PL_strlen(mName) + 1);
 1805: if (! *aName)
 1806: return NS_ERROR_NULL_POINTER;
 1807: PL_strcpy(*aName, mName);
 1808: }
 1809: else {
 1810: *aName = nsnull;
 1811: }
 1812: return NS_OK;
 1813: }
 1814: </pre>
 1815:     <p>A C++ implementation of an IDL method is 
 1816:     declared as the type <tt>NS_IMETHODIMP</tt>. The implementation
 1817:     starts with the getter method <tt>GetYourName</tt>, which takes
 1818:     a <tt>char**</tt> parameter for the method's return value.
 1819:     Return values in C++ XPCOM components are marshaled via method
 1820:     arguments because interface implementations must always return
 1821:     a numerical <tt>nsresult</tt>, as described earlier. To ensure
 1822:     that the <tt>aName</tt> parameter is a pointer, use the macro
 1823:     <tt>NS_PRECONDITION</tt> to warn if null, follow with a null
 1824:     test in the line below, and return the error result code
 1825:     <tt>NS_ERROR_NULL_POINTER</tt>. Then test whether the member
 1826:     variable <i>mName</i> holds a value. If it does, allocate the
 1827:     necessary memory to accommodate the size of the copy. Then by
 1828:     using <tt>PL_strcpy</tt>, you can assign the value to the
 1829:     parameter <tt>aName</tt>. Otherwise, <i>mName</i> is null and
 1830:     you can assign null into <tt>aName</tt> and return:</p>
 1831: <pre>
 1832: NS_IMETHODIMP
 1833: nsSimpleImpl::SetYourName(const char* aName)
 1834: {
 1835: NS_PRECONDITION(aName != nsnull, "null ptr");
 1836: if (!aName)
 1837: return NS_ERROR_NULL_POINTER;
 1838: if (mName) {
 1839: PL_strfree(mName);
 1840: }
 1841: mName = PL_strdup(aName);
 1842: return NS_OK;
 1843: }
 1844: </pre>
 1845:     <p>After implementing the getter, implement the setter. Again,
 1846:     use <tt>NS_PRECONDITION</tt> and then a null test on the
 1847:     <tt>aName</tt>. If that parameter holds data, you can free it
 1848:     by using <tt>PL_strfree</tt> and calling <tt>PL_strdup</tt>.
 1849:     Then assign the new value to class member <tt>mName</tt>:</p>
 1850: <pre>
 1851: NS_IMETHODIMP
 1852: nsSimpleImpl::Write( )
 1853: {
 1854: printf("%s\n", mName);
 1855: return NS_OK;
 1856: }
 1857: NS_IMETHODIMP
 1858: nsSimpleImpl::Change(const char* aName)
 1859: {
 1860: return SetYourName(aName);
 1861: }
 1862: </pre>
 1863:     <p>Finally, implement the <tt>Write</tt> and <tt>Change</tt>
 1864:     methods by using <tt>printf</tt> to write the value of
 1865:     <tt>mName</tt> to <tt>stdout</tt> and set a new value to
 1866:     <tt>mName</tt>. <a href="#77032">Example 8-13</a> shows the C++
 1867:     source code in its entirety. 
 1868:     </p>
 1869:     
 1870:     <p>
 1871:     Example 8-13<a name="77032"></a>
 1872:     <i>nsSimple.cpp</i></p>
 1873: <pre>
 1874:  #include "plstr.h"
 1875:  #include "stdio.h"
 1876:  #include "nsSimple.h"
 1877:  #include "nsCOMPtr.h"
 1878:  #include "nsMemory.h"
 1879:  // c++ constructor
 1880:  nsSimpleImpl::nsSimpleImpl( ) : mName(nsnull)
 1881:  {
 1882:      // NS_INIT_REFCNT( );  // has been depricated use NS_INIT_ISUPPORTS()
 1883:      NS_INIT_ISUPPORTS();
 1884:      mValue = PL_strdup("default value");
 1885:  }
 1886:  // c++ destructor
 1887:  nsSimpleImpl::~nsSimpleImpl( )
 1888:  {
 1889:      if ( )
 1890:          PL_strfree( );
 1891:  }
 1892:  // This macro implements the nsISupports interface methods
 1893:  // QueryInterface, AddRef and Release
 1894:  NS_IMPL_ISUPPORTS1_CI(nsSimpleImpl, nsISimple);
 1895:  NS_IMETHODIMP
 1896:  nsSimpleImpl::GetYourName(char** aName)
 1897:  {
 1898:      NS_PRECONDITION(aName != nsnull, "null ptr");
 1899:      if (!aName)
 1900:          return NS_ERROR_NULL_POINTER;
 1901:      if ( ) {
 1902:          *aName = (char*) nsMemory::Alloc(PL_strlen( ) + 1);
 1903:          if (! *aName)
 1904:              return NS_ERROR_NULL_POINTER;
 1905:          PL_strcpy(*aName, );
 1906:      }
 1907:      else {
 1908:          *aName = nsnull;
 1909:      }
 1910:      return NS_OK;
 1911:  }
 1912:  NS_IMETHODIMP
 1913:  nsSimpleImpl::SetYourName(const char* aName)
 1914:  {
 1915:     NS_PRECONDITION(aName != nsnull, "null ptr");
 1916:      if (!aName)
 1917:          return NS_ERROR_NULL_POINTER;
 1918:      if ( ) {
 1919:          PL_strfree( );
 1920:      }
 1921:       = PL_strdup(aName);
 1922:      return NS_OK;
 1923:  }
 1924:  NS_IMETHODIMP
 1925:  nsSimpleImpl::Write( )
 1926:  {
 1927:    printf("%s\n", );
 1928:    return NS_OK;
 1929:  }
 1930:  NS_IMETHODIMP
 1931:  nsSimpleImpl::Change(const char* aName)
 1932:  {
 1933:    return SetYourName(aName);
 1934:  }
 1935: </pre>
 1936:     <h3><a name="77083"></a> The nsSimple module code</h3>
 1937:     <p>As you needed to do with the JavaScript implementation, 
 1938:     a file called <i>nsSimpleModule.cpp</i> and enter the code shown in <a
 1939:     href="#77034">Example 8-14</a>. Example 8-14<a name=
 1940:     "77034"></a> <i>nsSimpleModule.cpp</i></p>
 1941: <pre>
 1942:  #include "nsIGenericFactory.h"
 1943:  #include "nsSimple.h"
 1944:  NS_GENERIC_FACTORY_CONSTRUCTOR(nsSimpleImpl)
 1945:  static NS_METHOD nsSimpleRegistrationProc(nsIComponentManager *aCompMgr,
 1946:                                            nsIFile *aPath,
 1947:                                            const char *registryLocation,
 1948:                                            const char *componentType,
 1949:                                            const nsModuleComponentInfo *info)
 1950:  {
 1951:      return NS_OK;
 1952:  }
 1953:  static NS_METHOD nsSimpleUnregistrationProc(nsIComponentManager *aCompMgr,
 1954:                                              nsIFile *aPath,
 1955:                                              const char *registryLocation,
 1956:                                              const nsModuleComponentInfo *info)
 1957:  {
 1958:      return NS_OK;
 1959:  }
 1960:  // For each class that wishes to support nsIClassInfo, add a line like this
 1961:  NS_DECL_CLASSINFO(nsSimpleImpl)
 1962:  static nsModuleComponentInfo components</td>[ ] =
 1963:  {
 1964:    { "A Simple Component",    // a message to display when component is loaded
 1965:      NS_SIMPLE_CID,           // our UUID
 1966:      NS_SIMPLE_CONTRACTID,    // our human readable PROGID or CLSID
 1967:      nsSimpleImplConstructor,
 1968:      nsSimpleRegistrationProc      /* NULL if you dont need one */,
 1969:      nsSimpleUnregistrationProc    /* NULL if you dont need one */,
 1970:      NULL /* no factory destructor */,
 1971:      NS_CI_INTERFACE_GETTER_NAME(nsSimpleImpl),
 1972:      NULL /* no language helper */,
 1973:      &amp;NS_CLASSINFO_NAME(nsSimpleImpl)
 1974:    }
 1975:  };
 1976:  NS_IMPL_NSGETMODULE(nsSimpleModule, components)
 1977: </pre>
 1978:     <h4><a name="77084"></a> The final steps for a C++
 1979:     component</h4>
 1980:     <p>Once you have an interface file <i>nsISimple.idl</i>, a C++
 1981:     source file <i>nsSimple.cpp</i> with its header file
 1982:     <i>nsSimple.h</i>, and a module file <i>nsSimpleModule.cpp</i>,
 1983:     you can create a Makefile like the one shown in <a href=
 1984:     "#77036">Example 8-15</a>. This Makefile can compile the
 1985:     sources into an XPCOM component.</p>
 1986:     <p>A Makefile directs the Mozilla build system to build the
 1987:     sources and install them into the Mozilla
 1988:     <i>dist/bin/components</i> directory. To use the Makefile, run
 1989:     gmake to compile and install the component library file. 
 1990:     Example 8-15<a name="77036"></a> <i>Sample Makefile</i><br/>
 1991:     </p>
 1992: <pre>
 1993:  
 1994: DEPTH         = ../../..
 1995: topsrcdir     = ../../..
 1996: srcdir        = .
 1997: VPATH         = .
 1998: include $(DEPTH)/config/autoconf.mk
 1999: MODULE        = xpcom
 2000: XPIDL_MODULE  = simple
 2001: LIBRARY_NAME  = simple
 2002: IS_COMPONENT  = 1
 2003: MODULE_NAME   = nsSimpleModule
 2004: REQUIRES      = string \
 2005:                 xpcom \
 2006:                 $(NULL)
 2007: CPPSRCS   =              \
 2008:     nsSimple.cpp         \
 2009:     nsSimpleModule.cpp   \
 2010:     $(NULL)
 2011: XPIDLSRCS = nsISimple.idl
 2012: include $(topsrcdir)/config/config.mk
 2013: LIBS    +=        \
 2014:     $(XPCOM_LIBS) \
 2015:     $(NSPR_LIBS)  \
 2016:     $(NULL)
 2017: include $(topsrcdir)/config/rules.mk
 2018: EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS)
 2019: install:: $(TARGETS)
 2020: </pre>
 2021:     <p>To test the newly compiled component, you can use
 2022:     <i>xpcshell</i> like you did for the JavaScript component. <a
 2023:     href="#77038">Example 8-16</a> shows a session with
 2024:     <i>xpcshell</i> that tests the new component. Example 8-16<a
 2025:     name="77038"></a> <i>Sample use of component in
 2026:     xpcshell</i></p>
 2027: <pre>
 2028:  $ ./run-mozilla.sh ./xpcshell
 2029:  Type Manifest File: /usr/src/commit_mozilla/mozilla/dist/bin/components/xpti.dat
 2030:  nsNativeComponentLoader: autoregistering begins.
 2031:  *** Registering nsSimpleModule components (all right -- a generic module!)
 2032:  nsNativeComponentLoader: autoregistering succeeded
 2033:  nNCL: registering deferred (0)
 2034:  js> var Simple = new Components.Constructor("@mozilla.org/cpp_simple;1", "nsISimple");
 2035:  js> var s = new Simple( );
 2036:  js> s.yourName;
 2037:  default value
 2038:  js> s.write( );
 2039:  default value
 2040:  js> s.change('pete');
 2041:  js> s.yourName;
 2042:  pete
 2043:  js> s.yourName = 'brian';
 2044:  brian
 2045:  js>
 2046: </pre>
 2047:     <h4><a name="77085"></a> Creating an instance of an existing
 2048:     Mozilla component</h4>
 2049:     <p>Creating an instance of a
 2050:     component and accessing methods and attributes is different in
 2051:     C++ than it is in JavaScript. Using the <i>nsILocalFile</i>
 2052:     interface lets you walk through the code to create an instance
 2053:     of this component from C++:</p>
 2054: <pre>
 2055: nsCOMPtr<nsILocalFile>
 2056: file(do_CreateInstance("@mozilla.org/file/local;1"));
 2057: </pre>
 2058:     <p>You can also instantiate the object as follows:</p>
 2059: <pre>
 2060: nsresult rv;
 2061: nsCOMPtr<nsILocalFile> file =
 2062: do_CreateInstance("@mozilla.org/file/local;1", &amp;rv);
 2063: if (NS_FAILED(rv))
 2064: return rv;
 2065: </pre>
 2066:     <p>Both techniques assign an <tt>nsCOMPtr</tt> to a newly
 2067:     allocated instance of an <tt>nsLocalFile</tt> object.</p>
 2068:     <p><a href="#77040">Example 8-17</a> accesses the public
 2069:     methods available from this component by using the pointer
 2070:     identifier <tt>file</tt>. Example 8-17<a name="77040"></a>
 2071:     <i>Example 8-17: Testing for nsresults from component
 2072:     methods</i></p>
 2073: <pre>
 2074:  if (file) {
 2075:    nsresult rv;
 2076:    rv = file->InitWithPath(NS_LITERAL_STRING("/tmp"));
 2077:    if (NS_FAILED(rv))
 2078:      return rv;
 2079:    PRBool exists;
 2080:    rv = file->Exists(&amp;exists);
 2081:    if (NS_FAILED(rv))
 2082:      return rv;
 2083:    if (exists)
 2084:      print("yep it exists!\n");
 2085:    nsAutoString leafName;
 2086:    rv = file->GetLeafName(leafName);
 2087:    if (NS_FAILED(rv))
 2088:      return rv;
 2089:    if (!leafName.IsEmpty( ))
 2090:      printf("leaf name is %s\n", NS_ConvertUCS2toUTF8(leafName).get( ));
 2091:  }
 2092: </pre>
 2093:     <p>Always test accessors of all XPCOM public methods, getters,
 2094:     and setters. Failures can appear at any time, so be sure to use
 2095:     result checking in your implementations.</p>
 2096:     <h3><a name="77086"></a> Other Languages for XPCOM</h3>
 2097:     <p>Although most components available from XPCOM are written in
 2098:     C++, the XPConnect/XPCOM pairing can also accommodate other
 2099:     languages. Language independence is a goal of the XPCOM
 2100:     architecture. Currently, implementations for Python (PyXPCOM)
 2101:     and Ruby (rbXPCOM) exist, with other language bindings being
 2102:     developed. In this respect, the Mozilla framework dovetails
 2103:     with one of the main trends in application development, which
 2104:     is to mix different languages in the development
 2105:     environment.</p>
 2106:     <h4><a name="77087"></a> PyXPCOM: the Python binding for
 2107:     XPCOM</h4>
 2108:     <p>Python has emerged as a very popular programming
 2109:     language in the last couple of years. It even does some of the
 2110:     application work and other heavy lifting that were the province
 2111:     of C++. Mozilla now offers a Python "binding" similar to the
 2112:     XPConnect binding for JavaScript that allows you to write
 2113:     application code in Python, compile it in XPCOM, and make it
 2114:     available like you would any C++ component in the Mozilla
 2115:     application framework. As with other XPCOM programming
 2116:     languages, you must create an implementation file (in Python)
 2117:     and an interface file (in IDL), as shown in Examples 8-18 and
 2118:     8-19, respectively.</p>
 2119:     <p>The terms and constructs for Python components are similar
 2120:     to those of C++. In the implementation, you need to import
 2121:     components from the XPCOM module to access the standard public
 2122:     members. The syntax is the same as that for importing any
 2123:     regular Python library:</p>
 2124: <pre>
 2125: from xpcom import components
 2126: </pre>
 2127:     <p>The IDL for a Python implementation of an XPCOM component
 2128:     can be identical to one for a JavaScript- or C++-based
 2129:     component (which is the point of XPCOM, after all). As in any
 2130:     component, your IDL needs to include <i>nsISupports.idl</i> and
 2131:     declare itself as scriptable with a unique UUID:</p>
 2132: <pre>
 2133: [scriptable, uuid(6D9F47DE-ADC1-4a8e-8E7D-2F7B037239BF)]
 2134: </pre>
 2135:     <p>JavaScript accesses the component in the same way, using
 2136:     classes and interface members of the component's interfaces to
 2137:     set up an instance of the component:</p>
 2138: <pre>
 2139: Components.classes["@foo.com/appSysUtils;1"].
 2140: getService(Components.interfaces.appISysUtils);
 2141: </pre>
 2142:     <p>With these foundations, and assuming that you have to have a
 2143:     Python distribution on your system that Mozilla can access, you
 2144:     are ready to go! <a href="#77042">Example 8-18</a> shows a
 2145:     complete implementation of a PyXPCOM component. This file needs
 2146:     to be saved with a <i>.py</i> extension and put in the
 2147:     <i>components</i> directory and registered like any other
 2148:     component. Example 8-18<a name="77042"></a> <i>Sample Python
 2149:     component implementation</i></p>
 2150: <pre>
 2151:  import sys, os
 2152:  from xpcom import components, nsError, ServerException
 2153:  class appSysUtils:
 2154:      _com_interfaces_ = </td>[components.interfaces.appISysUtils]
 2155:      _reg_clsid_ = "{56F686E0-A989-4714-A5D6-D77BC850C5C0}"
 2156:      _reg_contractid_ = "@foo.com/appSysUtils;1"
 2157:      _reg_desc_ = "System Utilities Service"
 2158:      def _ _init_ _(self):
 2159:          self.F_OK = os.F_OK
 2160:          self.R_OK = os.R_OK
 2161:          self.W_OK = os.W_OK
 2162:          self.X_OK = os.X_OK
 2163:      # ...
 2164:      def Access(self, filename, mode):
 2165:          return os.access(filename, mode)
 2166: </pre>
 2167:     <p>The special attributes defined in 
 2168:     the <tt>appSysUtils</tt>
 2169:     class correspond to the special identifiers you must use in
 2170:     XPCOM to make your code a reusable component (see <a href=
 2171:     "#77058">"XPCOM Identifiers</a>," earlier in this chapter). <a
 2172:     href="#77006">Table 8-3</a> describes these attributes.</p>
 2173:     <p><i>Table 8-3: <a name="77006"></a></i> <i>Special XPCOM
 2174:     attributes in Python</i></p>
 2175:     <i>nsISupports</i>.
 2176:     <table width="100%" border="1">
 2177:       <tr>
 2178:         <td><b>Attribute</b></td>
 2179:         <td><b>Description</b></td>
 2180:       </tr>
 2181:       <tr>
 2182:         <td>_com_interfaces_</td>
 2183:         <td>The interface IDs supported by this component. This
 2184:         attribute is required. It can be a single IID or a list,
 2185:         but you do not have to list base interfaces such as</td>
 2186:       </tr>
 2187:       <tr>
 2188:         <td>_reg_contractid_</td>
 2189:         <td>The component's contract ID. Required.</td>
 2190:       </tr>
 2191:       <tr>
 2192:         <td>_reg_clsid_</td>
 2193:         <td>The Class ID (CLSID) or progID of the component in the
 2194:         form: @domain/component;version.Required.</td>
 2195:       </tr>
 2196:       <tr>
 2197:         <td>_reg_desc_</td>
 2198:         <td>A description of the component. Optional.</td>
 2199:       </tr>
 2200:     </table>
 2201:     <p><a href="#77044">Example 8-19</a> is the IDL file you also
 2202:     need to create a Python component. Example 8-19<a name=
 2203:     "77044"></a> <i>IDL for the Python component</i></p>
 2204: <pre>
 2205:  #include "nsISupports.idl"
 2206:  // some useful system utilities
 2207:  </td>[scriptable, uuid(6D9F47DE-ADC1-4a8e-8E7D-2F7B037239BF)]
 2208:  interface appSysUtils : nsISupports {
 2209:      boolean IsFile(in string filename);
 2210:      boolean IsDir(in string dirname);
 2211:      void Stat(in string filename,
 2212:                out PRUint32 st_mode,
 2213:                out PRUint32 st_ino,
 2214:                out PRUint32 st_dev,
 2215:                out PRUint32 st_nlink,
 2216:                out PRUint32 st_uid,
 2217:                out PRUint32 st_gid,
 2218:                out PRUint32 st_size,
 2219:                out PRUint32 st_atime,
 2220:                out PRUint32 st_mtime,
 2221:                out PRUint32 st_ctime);
 2222:      boolean Access(in string filename, in PRUint32 mode);
 2223:      readonly attribute PRUint32 F_OK;
 2224:      readonly attribute PRUint32 R_OK;
 2225:      readonly attribute PRUint32 W_OK;
 2226:      readonly attribute PRUint32 X_OK;
 2227:  };
 2228: </pre>
 2229:     <p>Finally, <a href="#77046">Example 8-20</a> shows how this
 2230:     component might be used in script-for example, in a function
 2231:     you define for an event handler in the XUL interface. Example
 2232:     8-20<a name="77046"></a> <i>Using the Python component in
 2233:     script</i></p>
 2234: <pre>
 2235:  var appSysUtils = Components.classes</td>["@foo.com/appSysUtils;1"].getService(Components        interfaces.appISysUtils);
 2236:  // Read-write status
 2237:  var write = appSysUtils.Access(url, appSysUtils.W_OK);
 2238:  var read = appSysUtils.Access(url, appSysUtils.R_OK);
 2239:  var rwcheck = document.getElementById('rwCheckbox');
 2240:  if (read)  {
 2241:      if (write &amp;&amp; read)
 2242:          ro = false;
 2243:      else
 2244:          ro = true;
 2245:      rwcheck.setAttribute('checked', ro);
 2246:  }
 2247: </pre>
 2248:     <p>The component is a small system utility that checks the
 2249:     read/write permissions status of a file on the local
 2250:     filesystem. The JavaScript uses it to display a visual notifier
 2251:     of the status in the UI. In this case, the DOM's
 2252:     <tt>rwcheck</tt> node refers to a checkbox. It's easy to
 2253:     imagine this component being extended to do other things, such
 2254:     as getting information about a file (the <tt>Stat</tt> stub is
 2255:     in the IDL). The source code, samples, and documentation for
 2256:     PyXPCOM are located in the Mozilla tree at
 2257:     <i>mozilla/extensions/python</i>.</p>
 2258:     <h3><a name="77088"></a> XPCOM as an Open Cross-Platform
 2259:     Solution</h3>
 2260:     <p>XPCOM can be an entire book 
 2261:     in itself. This chapter has merely touched
 2262:     upon the role it plays in Mozilla application development.
 2263:     Understanding the basics of this framework is vital to
 2264:     understanding the very foundation of Mozilla's componentized
 2265:     architecture.</p>
 2266:     <p>Although other component-based systems exist on various
 2267:     platforms-MSCOM for Microsoft or a CORBA system for GNOME, for
 2268:     example-if you want to write truly cross-platform
 2269:     component-based applications, then XPCOM is the best tool for
 2270:     the job. It can be deployed on any platform Mozilla is ported
 2271:     to, and can be scripted by using JavaScript or Python.</p>
 2272:     <p>Above all, XPCOM is entirely open source, so there are no
 2273:     costs associated with it, no proprietary secrets in how it's
 2274:     put together, and you have various software licenses to choose
 2275:     from. Although XPCOM has become a solid framework, its
 2276:     developers are still making improvements and uncovering and
 2277:     fixing bugs. However, XPCOM offers tremendous flexibility as a
 2278:     software development framework and the Mozilla community is an
 2279:     excellent technical support resource for all technologies
 2280:     covered in this book.</p>
 2281:     <hr>
 2282:     <br/>
 2283:     <br/>
 2284:     File a <a href=
 2285:     "http://mozdev.org/bugs/enter_bug.cgi?product=books">Bug</a>
 2286:     for chapter 8. 
 2287:     <?php $hide_text_control=1; $post_to_list=NO; $author='reviewers@mozdev.org'; // require(NOTES); ?>

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>