Chapter 8. XPCOM- P1
This chapter provides a high-level introduction to XPCOM component
technology. XPCOM can be difficult to master, but after reading this
chapter, you should have a good sense of what it is and the important part it
plays as Mozilla's core technology. You should be able to find and use
existing scriptable components in your own applications and create a simple
XPCOM component by using JavaScript or C++.
XPCOM permits a reusable code module to be globally accessible to a
Mozilla-based application. You do not need to worry about including
external source files in your application distribution and you can distribute
components by using XPInstall. This type of architecture makes the
development of core application services flexible and entirely modular.
The section Section 8.2.1 lets you create an interface from start to finish --
writing the implementation for that interface, compiling it into a type library,
registering it with Mozilla, and then testing the new component. One
advantage of using XPCOM is that you can create multiple implementations
for a single interface; following the JavaScript component section, we will
take the same nsISimple interface and implement it in C++ as well.
The section Section 8.2.5 includes some techniques and programming tasks
that are particular to C++ components, such as handling return values and
generating header files and useful macros. The section Section 8.2.7
introduces the XPCOM bindings for the Python language (pyXPCOM).
First, it provides an overview of XPCOM and how it relates to other
technologies used in Mozilla.
8.1. What Is XPCOM?

XPCOM is Mozilla's cross-platform component object model. Although it is
similar to Microsoft's COM technology, this chapter points out some
important differences.
Essentially, when you program in a component-based environment, you do
one of three things: you create a new component using existing components,
write a component that implements other components, and establish
interdependencies and a service network.
8.1.1. What Is a Component?
You've already seen components used in this book. In some cases, you may
have used the services of Mozilla components without knowing it -- for
example, when you created a XUL tree widget in the section Section 3.4.2 in
Chapter 3, and used its built-in layout and view capabilities. Some of this
functionality is defined in an interface called nsITreeView, which provides
specific methods and properties for a XUL tree, persisting its state, row, cell,
and column properties, navigation, and other object metadata used in a tree
object. Behind the scenes, you'll find an XPCOM-instantiated tree view
object where methods and properties associated with the XUL element are
accessed via DOM > JavaScript > XPConnect > XPCOM layers.
A component is a reusable or modular piece of code that implements a
clearly defined interface. In Mozilla, this code can exist as a singleton
service or an object instance. A singleton service is an object instance that is
created only once and then used by other code (usually called "callers,"
"clients," or "consumers"). An object instance is an object that is instantiated
once or many times. Components are written as classes that typically have
member variables and methods. The basic purpose of a component is to
implement a clearly defined set of APIs that exist in a public interface. The

interface exists separately so that the implementation is abstracted away, and
it can be changed without affecting the interface or breaking binary
compatibility. When interfaces are deployed in a production environment,
they are frozen, which means they are held in an immutable state --
theoretically for as long as the application exists. While MSCOM provides a
component-based programming model on Microsoft platforms, XPCOM
provides it on all platforms where Mozilla is available.
Example 8-1 shows how simple using XPCOM components can be. In two
lines, an XPConnect-wrapped nsIBookmarksService object is
instantiated, and one of its methods is called, providing easy access to this
XPCOM component from JavaScript.
Example 8-1. Using an XPCOM object in script
// create a bookmark service object in JS
var bmks =
Components.classes["@mozilla.org/browser/bookmarks-
service;1"].
getService(Components.interfaces.nsIBookmarksServic
e);
// call one of the object's methods:
// flush the bookmarks to disk if they've been
touched.
bmks.Flush( );

As you can see, the assignment of an XPCOM object to the variable bmks
takes only a single line. Once you are comfortable using XPCOM from
JavaScript, you can use any of Mozilla's scriptable interfaces in your
application. Once an object like bmks is created, as in Example 8-1, it can
be used to call any method in the nsIBookmarksService interface, of which
Flush( ) is an example.
8.1.2. XPConnect and the Component Object
As shown the previous example, the XPCOM object is called and
instantiated from script. For an interpreted language like JavaScript to call
and instantiate it, a bridge must bind JavaScript types to XPCOM types.
These type bindings are part of a technology called XPConnect.
In XPConnect, XPCOM interfaces, classIDs, and progIDs are stored as
global JavaScript objects and properties that can be manipulated directly
through a top-level object called Components. This object accesses any
component that is declared "scriptable" in an XPCOM IDL interface.
Through the Components object, you can access and use the services that
these interfaces provide. The Component object's top-level properties and
methods include:
QueryInterface
A method used to match an interface with a desired implementation.
The implementation can be in C, C++, JavaScript, Python, and other
languages for which appropriate bindings are created. You can have
multiple implementations for an interface. Through
QueryInterface, you can ask for and assign the desired interface
to its implementation. Each XPCOM object needs to implement

QueryInterface in order to return an instance of that object's
class:
js> var clz =
Components.classes['@mozilla.org/file/local;1'];
js> var inst = clz.getService( );
js> inst.QueryInterface(C.interfaces.nsILocalFile);
[xpconnect wrapped nsILocalFile @ 0x81b7040]
interfaces
A read-only object array containing all the interfaces declared
scriptable in the IDL file. The object name has the same name as the
interface it represents.
Components.interfaces.nsILocalFile
The source file for this particular interface, for example, is nsILocalFile.idl.
This XPIDL compiler compiles this file to produce a cross-platform binary
type library, nsILocalFile.xpt, which contains tokenized IDL in an
efficiently parsed form.
classes
A read-only array of all the XPCOM component classes indexed by
the ProgID (or human-readable name) of the component class. The
classes object has these properties associated with it:
toString Returns the string progID.
QueryInterface Used to QI this interface.
name Returns the string progid name.

number Returns the string components uuid
number.
valid Boolean verifies if the instance is
valid.
equals The Boolean used to match identical
instances.
initialize I don't know what this does.
createInstance Will create an instance of the
component; you can have many
instances.
getService Will instantiate the component as a
service; you can have only one
instance of a service.
classesByID
The same as classes, except this time the array is indexed by the
"canonical" or "well-established" form of their CLSID:
Components.classesByID['{dea98e50-1dd1-11b2-9344-
8902b4805a2e}'];
The classesByID object has the same properties object associated with it
as the class object. The properties are also used in the same way:
toString
QueryInterface

name
number
valid
equals
initialize
createInstance
getService
stack
A read-only property that represents 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:
js> var C=Components;
js> C.stack;
JS frame :: typein :: :: line 2
js> C.stack;
JS frame :: typein :: :: line 3
results
An object array of nserror results:
Components.results.NS_ERROR_FILE_ACCESS_DENIED;
2152857621
manager

A reflection of the XPCOM global native component manager
service. Using the component manager is the only way for a
component to actually be created. It uses the components factory to
create an instance of the class object.
ID
A constructor used for a component written in JavaScript This
component needs to register itself with the component manager by
using its own nsID (an ID that is not already registered and thus does
not appear in Components.classes).
Exception
A JavaScript constructor 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
Exception object that has properties associated with this object.
Exceptions are usually caught in a "catch" block.
Constructor
A JavaScript constructor object that constructs new instances of
XPCOM components:
js> var File=new Components.Constructor(
"@mozilla.org/file/local;1", "nsILocalFile",
"initWithPath");
The interface nsILocalFile and the method initWithPath are optional.
This example creates and initializes the nsILocalFile component.

isSucessCode
A function that determines if the results code argument is successful.
It takes an argument of nsresult and returns the Boolean values
true or false:
js>
Components.isSuccessCode(Components.results.NS_OK);
true
js>
Components.isSuccessCode(Components.results.NS_ERRO
R_FAILURE);
false
The methods and properties of the Components 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.
8.1.3. XPCOM Interfaces and the IDL
All XPCOM interfaces are defined 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.
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 Section 8.1.4.
8.1.3.1. Interfaces versus components
It is important to understand that most XPCOM components implement at
least two interfaces. Like COM, each component needs the
QueryInterface, AddRef, and Release functions to be available as an
XPCOM object. These methods are derived from a basic interface called
nsISupports, which is the XPCOM equivalent to Microsoft COM's
IUnknown, shown in Table 8-1.
Table 8-1. The IUnknown interface
Parameters /
Name Type Description
return value
Returns:
int, which is the
Increments the new
ULONG reference count incremented
AddRef
AddRef(void) on the COM reference count
object. on the object.
This value may
be useful for

Parameters /
Name Type Description
return value
diagnostics or
testing.
Parameters:
iid, which is an
[in] identifier of
the requested
interface.
ppvObject,
which is an
HRESULT [out] pointer to
QueryInterface(/* Retrieves a the interface
[in] */ REFIID pointer to the pointer
QueryInterface
riid, /* requested identified by
[iid_is][out] */ interface. iid. If the object
void **ppvObject) does not
support this
interface,
ppvObject is set
to NULL.
Returns:
HRESULT,
which is the

Parameters /
Name Type Description
return value
standard
HRESULT
value.
Returns:
int, which is the
new
Decrements the decremented
ULONG reference count reference count
Release
Release(void) on the COM on the object.
object. This value may
be useful for
diagnostics or
testing.
Tables 8-1 and 8-2 illustrate the minor differences between Microsoft's
nsIUnknown and Mozilla's nsISupports root interfaces. The usage is covered
in detail throughout this chapter.
Table 8-2. The nsISupports interface
Descripti
Name Type Parameters / return value
on
AddRef NS_IMETHOD_(nsre Increases Returns:

Descripti
Name Type Parameters / return value
on
fcnt) the The resulting reference
AddRef(void) reference count.
count for
this
interface.
The
associate
d instance
will not
be
deleted
unless the
reference
count is
returned
to zero.
A Parameters:
NS_IMETHOD runtime param aIID [in], which is a
QueryInterf QueryInterface(REF mechanis requested interface IID.
ace NSIID aIID, void** m for param aInstancePtr [out],
aInstancePtr) interface which is a pointer to an
discovery interface pointer that receives

Descripti
Name Type Parameters / return value
on
. the result.
Returns:
NS_OK if the interface is
supported by the associated
instance;
NS_NOINTERFACE if it is
not; and
NS_ERROR_INVALID_POI
NTER if aInstancePtr is
NULL.
Decreases
the
reference
count for
this Returns:
NS_IMETHOD_(nsre
interface.
Release fcnt) Release(void) = The resulting reference
Generally
0; count.
, if the
reference
count
returns to
zero, the