You are currently viewing a snapshot of www.mozilla.org taken on April 21, 2008. Most of this content is highly out of date (some pages haven't been updated since the project began in 1998) and exists for historical purposes only. If there are any pages on this archive site that you think should be added back to www.mozilla.org, please file a bug.


TOC PREV NEXT INDEX

Embedding Gecko Basics


XPCOM


The most important of the Mozilla technologies is XPCOM, the Cross-Platform Component Object Model. XPCOM provides a framework which manages the creation, ownership, and deletion of objects and other data throughout Mozilla. If you have used MSCOM, you will recognize certain basic similarities. But there are also significant differences - XPCOM is cross-platform and designed to run largely in a single thread - and the two are not at this time compatible.

The interface

At the core of XPCOM is the concept of the interface. An interface is simply a description of a set of methods, attributes, and related constants all associated with a particular functionality: it is completely distinct from the class that implements those things. The interface serves as a kind of contract: any object that supports a particular interface guarantees that it will perform the services described in it. To keep the interface as language neutral as possible, it is written in a special language, the Interface Definition Language, or IDL. Interface files are often referred to as .idl files. In addition to specifying the functionality of the interface, these files also carry the interface's IID, its globally unique identifying number.

Much of the communication within Gecko takes place in terms of these abstract structures (by convention, their names follow the form nsISomething).

//this
void ProcessSample(nsISample* aSample) {
	aSample->Poke("Hello"); 
//not this
void ProcessSample(nsSampleImpl* aSample) {
	aSample->Poke("hello"); 

@status FROZEN

XPCOM's level of abstraction produces great flexibility in the system. Implementations are free to change as needed. But, to work, the interfaces themselves must remain fixed. Throughout Mozilla's initial design and development period, interfaces have been somewhat fluid, but as the project has matured, more and more of the interfaces have been marked FROZEN. Any interface so marked is guaranteed not to change in the future.

Most of the main interfaces key to the embedding effort are now frozen, but it's always a good idea to check before using any interface. An interface's status is listed in the .idl file's comments. A frozen interface is marked @status FROZEN. You can search for frozen interfaces by using the mozilla cross referencing tool at lxr.mozilla.org/seamonkey/search?string=%40status+FROZEN. Until it is frozen, an interface may change at any time. For more information on the freezing process, see the embedding project page at: mozilla.org/projects/embedding/.

Once an interface has been frozen, it is added to the Gecko Embedding API Reference at mozilla.org/projects/embedding/embedapiref/embedapi.html.

nsISupports

A single object can support more than one interface. In fact, essentially all objects support at least two interfaces - a minimum of one that does something specifically useful and one, nsISupports, that serves a more general purpose. In a sense, nsISupports is the progenitor of all XPCOM interfaces. All interfaces inherit from it, most directly so. It serves two main functions - runtime type discovery and object lifetime management. It is functionally identical to IUnknown in MSCOM.

Since an object can support multiple interfaces, it is perfectly possible to have a pointer to one interface and want to know whether that same object also supports a different interface whose functionality you might also need. The first nsISupports method, QueryInterface, does exactly that: it asks, in effect, I know that this object is of type A (supports interface A) but is it also of type B (supports interface B)? If it is (or does), QueryInterface returns to the caller a pointer bound to the newly requested interface.

void ProcessSample(nsISample* aSample) {
	nsIExample *example;
	nsresult rv;
	rv = aSample->QueryInterface(NS_GET_IID(nsIExample),(void **)&example); 
	if (NS_SUCCEEDED(rv)) {
		example->DoSomeOperation();
		NS_RELEASE(example); // using a macro to call Release 
	} 
} 

Because XPCOM uses an indirect method, the Component Manager, to actually instantiate objects, and because multiple pointers to the same object - often bound to different interfaces - can exist, it can quickly become very difficult for callers to keep accurate track of all of the objects to which those pointers point. Objects could be kept around in memory longer than they need to be, causing leaks, or objects could be deleted prematurely, causing dangling pointers. The other two methods in nsISupports, AddRef and Release, are designed to deal with this issue. Every time a pointer is given out AddRef must be called on the object, incrementing an internal counter. Every time a pointer is released, Release must be called, decrementing that same counter. When the counter reaches zero, there are no pointers to the object remaining and the object can safely delete itself. Control of the object's lifetime stays within the object itself. See below for information on XPCOM's "smart" pointer, nsCOMPtr, a utility which helps automate this process.

Object creation

The instantiation of objects is also an indirect process in XPCOM. Just as interfaces have a globally unique ID number (the IID), XPCOM classes are assigned their own GUIDs, the CID. In addition, they are also often given a text-based ID, called a contract ID. One or the other of these IDs is passed to a method on a persistent XPCOM component, the Component Manager, which actually creates the object. When a new library of classes (called a module in XPCOM) is first introduced into the system, it must register itself with the Component Manager, which maintains a registry that maps classes (with their IDs) to the libraries in which they reside.

A limited number of persistent services, supplied by singleton objects, are created and controlled by a companion to the Component Manager, the Service Manager. The Component Manager itself is an example of such a persistent service.

Summing up

Functionality in XPCOM is described by abstract interfaces, and most communication among parts of the system takes place in terms of those interfaces. The underlying objects that implement the interfaces, on the other hand, are created indirectly by the Component Manager based on a cross-indexed registry that it maintains.

One functionality shared by all interfaces is the ability to query the underlying object at runtime to see if also implements other interfaces. In theory an interface is fixed and unchangeable, but at this stage in the Mozilla codebase, only interfaces that have been declared FROZEN are guaranteed not to change significantly. Object lifetime management takes place inside the object itself through an internal counter that keeps track of the number of pointers to the object that have been added or released. The client's only responsibility is to increment and decrement the counter. When the internal counter reaches zero, the object deletes itself.

nsCOMPtr

Sometimes, however, even remembering to call AddRef and Release at the right times can be difficult. To make this process easier and more reliable, XPCOM has a built-in "smart" pointer, nsCOMPtr. This pointer takes care of calling AddRef and Release for you. Using nsCOMPtr whenever possible will make your code cleaner and more efficient. For more information on the smart pointer, see "The Complete nsCOMPtr User's Manual" at www.mozilla.org/projects/xpcom/nsCOMPtr.html.

Mozilla actually provides a large number of built-in macros (by convention, written in all caps in the code) and utilities like nsCOMPtr that can make the entire process of coding with XPCOM easier. Many of these can be found in the following files: nsCom.h, nsDebug.h, nsError.h, nsIServiceManager.h, and nsISupportsUtils.h Mozilla also supplies other development tools for tracking memory usage and the like. More information on these can be found at www.mozilla.org/performance/

For more information

More information on XPCOM in general can be found at mozilla.org/projects/xpcom/. For an overview of creating XPCOM components, see Chapter 8 of O'Reilly's Creating Applications with Mozilla, an open source version of which is available at books.mozdev.org/chapters/ch08.html. There is also a new book completely devoted to this topic, Creating XPCOM Components, available at http://mozilla.org/projects/xpcom/book/cxc/. A fuller explanation of some of the underlying logic to COM systems can be found in the early chapters of Essential COM by Don Box. While it focusses on MSCOM in particular, the book does provide an excellent background on some of the core rationales for using such an object model.


Written by: Ellen Evans | Comments, questions, complaints? Bug 141350
TOC PREV NEXT INDEX