• Skip to main content
  • Select language
  • Skip to search
MDN Web Docs
  • Technologies
    • HTML
    • CSS
    • JavaScript
    • Graphics
    • HTTP
    • APIs / DOM
    • WebExtensions
    • MathML
  • References & Guides
    • Learn web development
    • Tutorials
    • References
    • Developer Guides
    • Accessibility
    • Game development
    • ...more docs
Add-ons
  1. MDN
  2. Mozilla
  3. Add-ons
  4. Add-on SDK
  5. Low-Level APIs
  6. platform/xpcom

platform/xpcom

In This Article
  1. Usage
    1. Implementing XPCOM Interfaces
    2. Implementing XPCOM Factories
      1. Using class ID
      2. Replacing Factories
      3. Registration
    3. Implementing XPCOM Services
    4. Registering and Unregistering
  2. Globals
    1. Constructors
      1. Factory(options)
    2. Functions
      1. register(factory)
      2. unregister(factory)
      3. isRegistered(factory)
      4. autoRegister(path)
      5. factoryByID(id)
      6. factoryByContract(contract)
  3. Unknown
    1. Methods
      1. QueryInterface(interface)
    2. Properties
      1. interfaces
  4. Factory
    1. Methods
      1. createInstance(outer, iid)
      2. lockFactory()
      3. QueryInterface()
    2. Properties
      1. interfaces
      2. id
      3. contract
  5. Service

Add-ons using the techniques described in this document are considered a legacy technology in Firefox. Don't use these techniques to develop new add-ons. Use WebExtensions instead. If you maintain an add-on which uses the techniques described here, consider migrating it to use WebExtensions.

From Firefox 53 onwards, no new legacy add-ons will be accepted on addons.mozilla.org (AMO).

From Firefox 57 onwards, WebExtensions will be the only supported extension type, and Firefox will not load other types.

Even before Firefox 57, changes coming up in the Firefox platform will break many legacy extensions. These changes include multiprocess Firefox (e10s), sandboxing, and multiple content processes. Legacy extensions that are affected by these changes should migrate to WebExtensions if they can. See the "Compatibility Milestones" document for more.

A wiki page containing resources, migration paths, office hours, and more, is available to help developers transition to the new technologies.

Unstable

Implement XPCOM objects, factories, and services.

Usage

The xpcom module makes it simpler to perform three main tasks:

  • Implement XPCOM object interfaces
  • Implement and register XPCOM factories
  • Implement and register XPCOM services

If all you need to do is use XPCOM objects that someone else has implemented, then you don't need to use this module. You can just use require("chrome") to get direct access to the Components object, and access XPCOM objects from there.

Implementing XPCOM Interfaces

This module exports a class called Unknown which implements the fundamental XPCOM interface nsISupports. By subclassing Unknown, either using standard JavaScript inheritance or using the SDK's heritage module, you can provide your own implementations of XPCOM interfaces.

"Unknown" is named after the "IUnknown" interface in COM.

For example, the add-on below implements the nsIObserver interface to listen for and log all topic notifications:

var { Class } = require('sdk/core/heritage');
var { Unknown } = require('sdk/platform/xpcom');
var { Cc, Ci } = require('chrome')
var observerService = Cc['@mozilla.org/observer-service;1'].
                        getService(Ci.nsIObserverService);
var StarObserver = Class({
  extends:  Unknown,
  interfaces: [ 'nsIObserver' ],
  topic: '*',
  register: function register() {
    observerService.addObserver(this, this.topic, false);
  },
  unregister: function() {
    observerService.removeObserver(this, this.topic);
  },
  observe: function observe(subject, topic, data) {
    console.log('star observer:', subject, topic, data);
  }
});
var starobserver = StarObserver();
starobserver.register();

Implementing XPCOM Factories

The xpcom module exports a class called Factory which implements the nsIFactory interface. You can use this class to register factories for XPCOM components you have defined.

For example, this add-on defines a subclass of Unknown called HelloWorld that implements a function called hello. By creating a Factory and passing it the contract ID for the HelloWorld component and the HelloWorld constructor, we enable XPCOM clients to access the HelloWorld component, given its contract ID.

In this example the HelloWorld component is available to JavaScript only, so we use the technique documented under the "Using wrappedJSObject" section of How to Build an XPCOM Component in JavaScript.

var { Class } = require('sdk/core/heritage');
var { Unknown, Factory } = require('sdk/platform/xpcom');
var { Cc, Ci } = require('chrome');
var contractId = '@me.org/helloworld';
// Define a component
var HelloWorld = Class({
  extends: Unknown,
  get wrappedJSObject() this,
  hello: function() {return 'Hello World';}
});
// Create and register the factory
var factory = Factory({
  contract: contractId,
  Component: HelloWorld
});
// XPCOM clients can retrieve and use this new
// component in the normal way
var wrapper = Cc[contractId].createInstance(Ci.nsISupports);
var helloWorld = wrapper.wrappedJSObject;
console.log(helloWorld.hello());

Using class ID

You can specify a class ID for the factory by setting the id option in the factory's constructor. If you don't specify a class ID, then the factory will generate one. Either way, it will be accessible as the value of the factory's id property.

XPCOM users can look up the factory using the class ID instead of the contract ID. Here's the example above, rewritten to use class ID instead of contract ID for lookup:

var { Class } = require('sdk/core/heritage');
var { Unknown, Factory } = require('sdk/platform/xpcom');
var { Cc, Ci, components } = require('chrome');
// Define a component
var HelloWorld = Class({
  extends: Unknown,
  get wrappedJSObject() this,
  hello: function() {return 'Hello World';}
});
// Create and register the factory
var factory = Factory({
  Component: HelloWorld
});
var id = factory.id;
// Retrieve the factory by class ID
var wrapper = components.classesByID[id].createInstance(Ci.nsISupports);
var helloWorld = wrapper.wrappedJSObject;
console.log(helloWorld.hello());

Replacing Factories

If the factory you create has the same contract ID as an existing registered factory, then your factory will replace the existing one. However, the Components.classes object commonly used to look up factories by contract ID will not be updated at run time. To access the replacement factory you need to do something like this:

var id = Components.manager.QueryInterface(Ci.nsIComponentRegistrar).
  contractIDToCID('@me.org/helloworld');
var wrapper = Components.classesByID[id].createInstance(Ci.nsISupports);

The xpcom module exports a function factoryByContract to simplify this technique:

var wrapper = xpcom.factoryByContract('@me.org/helloworld').createInstance(Ci.nsISupports);

Registration

By default, factories are registered and unregistered automatically. To learn more about this, see Registering and Unregistering.

Implementing XPCOM Services

The xpcom module exports a class called Service which you can use to define XPCOM services, making them available to all XPCOM users.

This example implements a logging service that just appends a timestamp to all logged messages. The logger itself is implemented by subclassing the Unknown class, then we create a service which associates the logger's constructor with its contract ID. After this, XPCOM users can access the service using the getService() API:

var { Class } = require('sdk/core/heritage');
var { Unknown, Service } = require('sdk/platform/xpcom');
var { Cc, Ci } = require('chrome');
var contractId = '@me.org/timestampedlogger';
// Implement the service by subclassing Unknown
var TimeStampedLogger = Class({
  extends: Unknown,
  get wrappedJSObject() this,
  log: function(message) {
    console.log(new Date().getTime() + ' : ' + message);
  }
});
// Register the service using the contract ID
var service = Service({
  contract: contractId,
  Component: TimeStampedLogger
});
// Access the service using getService()
var wrapper = Cc[contractId].getService(Ci.nsISupports);
var logger = wrapper.wrappedJSObject;
logger.log('a timestamped message');

By default, services are registered and unregistered automatically. To learn more about this, see Registering and Unregistering.

Registering and Unregistering

By default, factories and services are registered with XPCOM automatically when they are created, and unregistered automatically when the add-on that created them is unloaded.

You can override this behavior using the register and unregister options to the factory or service constructor:

var xpcom = require('sdk/platform/xpcom');
var factory = xpcom.Factory({
  contract: contractId,
  Component: HelloWorld,
  register: false,
  unregister: false,
});

If you disable automatic registration in this way, you can use the register() function to register factories and services:

xpcom.register(factory);

You can use the corresponding unregister() function to unregister them, whether or not you have disabled automatic unregistration:

xpcom.unregister(factory);

You can find out whether a factory or service has been registered by using the isRegistered() function:

if (xpcom.isRegistered(factory))
  xpcom.unregister(factory);

Globals

Constructors

Factory(options)

Parameters

options : object
Required options:

Name Type  
Component constructor

Constructor for the component this factory creates. This will typically return a descendant of Unknown, although it may return a custom object that satisfies the nsISupports interface.

Optional options:

Name Type  
contract string

A contract ID. Users of XPCOM can use this value to retrieve the factory from Components.classes:

var factory = Components.classes['@me.org/request']
var component = factory.createInstance(Ci.nsIRequest);

This parameter is formally optional, but if you don't specify it, users won't be able to retrieve your factory using a contract ID. If specified, the contract ID is accessible as the value of the factory's contract property.

id string

A class ID. Users of XPCOM can use this value to retrieve the factory using Components.classesByID:

var factory = components.classesByID[id];
var component = factory.createInstance(Ci.nsIRequest);

This parameter is optional. If you don't supply it, the factory constructor will generate a fresh ID. Either way, it's accessible as the value of the factory's id property.

register boolean

By default, the factory is registered as soon as it is constructed. By including this option, set to false, the factory is not automatically registered and you must register it manually using the register() function.

unregister boolean

By default, the factory is unregistered as soon as the add-on which created it is unloaded. By including this option, set to false, the factory is not automatically unregistered and you must unregister it manually using the unregister() function.

Functions

register(factory)

Register the factory or service supplied. If the factory or service is already registered, this function throws Components.results.NS_ERROR_FACTORY_EXISTS.

By default, factories and services are registered automatically, so you should only call register() if you have overridden the default behavior.

Parameters

factory : object
The factory or service to register.

unregister(factory)

Unregister the factory or service supplied. If the factory or service is not registered, this function does nothing.

By default, factories and services are unregistered automatically when the add-on that registered them is unloaded.

Parameters

factory : object
The factory or service to unregister.

isRegistered(factory)

Find out whether a factory or service is registered.

Parameters

factory : object

Returns

boolean : True if the factory or service is registered, false otherwise.

autoRegister(path)

Register a component (.manifest) file or all component files in a directory. See nsIComponentRegistrar.autoRegister() for details.

Parameters

path : string
Path to a component file to be registered or a directory containing component files to be registered.

factoryByID(id)

Given a class ID, this function returns the associated factory or service. If the factory or service isn't registered, this function returns null.

This function wraps Components.ClassesByID.

Parameters

id : string
A class ID.

Returns

object : The factory or service identified by the class ID.

factoryByContract(contract)

Given a contract ID this function returns the associated factory or service. If the factory or service isn't registered, this function throws Components.results.NS_ERROR_FACTORY_NOT_REGISTERED.

This function is similar to the standard Components.classes[contractID] with one significant difference: that Components.classes is not updated at runtime.

So if a factory is registered with the contract ID "@me.org/myComponent", and another factory is already registered with that contract ID, then:

Components.classes["@me.org/myComponent"]

will return the old factory, while:

xpcom.factoryByContract("@me.org/myComponent")

will return the new one.

Parameters

contract : string
Contract ID of the factory or service to retrieve.

Returns

object : The factory or service identified by the contract ID.

Unknown

This is the base class for all XPCOM objects. It is not intended to be used directly but you can subclass it, either using standard JavaScript inheritance or using the SDK's heritage module, to create new implementations of XPCOM interfaces. For example, this subclass implements the nsIRequest interface:

var { Class } = require('sdk/core/heritage');
var { Unknown } = require('sdk/platform/xpcom');
var Request = Class({
  extends: Unknown,
  interfaces: [ 'nsIRequest' ],
  initialize: function initialize() {
    this.pending = false;
  },
  isPending: function() { return this.pending; },
  resume: function() { console.log('resuming...'); },
  suspend: function() { console.log('suspending...'); },
  cancel: function() { console.log('canceling...'); }
});

This component definition:

  • specifies that we support nsIRequest using the interfaces property.
  • initializes pending in initialize()
  • adds our implementation of the nsIRequest interface

Although Request also implements nsISupports, there is no need to add it here, because the base class Unknown declares support for nsISupports and this is accounted for when retrieving objects.

We can register a factory for this component by using the Factory class to associate its constructor with its contract ID:

var { Factory } = require('sdk/platform/xpcom');
var { Cc, Ci } = require('chrome');
var contractId = '@me.org/request'
// Create and register the factory
var factory = Factory({
  contract: contractId,
  Component: Request
});

Now XPCOM users can access our implementation in the normal way:

var request = Cc[contractId].createInstance(Ci.nsIRequest);
request.resume();

Methods

QueryInterface(interface)

This method is called automatically by XPCOM, so usually you don't need to call it yourself. It is passed an interface identifier and searches for the identifier in the interfaces property of:

  • this object
  • any of this object's ancestors
  • any classes in the implements array property of the instance (for example, any classes added to this object via the implements option defined in heritage).

If it finds a match, it returns this, otherwise it throws Components.results.NS_ERROR_NO_INTERFACE.

Parameters

interface : iid
The interface to ask for. This is typically given as a property of the Components.interfaces object.

Returns

object : The object itself(this).

Properties

interfaces

The set of interfaces supported by this class. Unknown sets this to nsISupports.

Factory

Use this class to register an XPCOM factory. To register a factory for a component, construct a Factory, giving it:

  • a constructor for the component
  • a contract ID and/or a class ID
// Create and register the factory
var factory = Factory({
  contract: '@me.org/myComponent',
  Component: MyComponent
});
  • The component constructor typically returns a descendant of Unknown, although it may return a custom object that satisfies the nsISupports interface.
  • The contract ID and/or class ID may be used by XPCOM clients to retrieve the factory. If a class ID is not given, a new one will be generated. The contract ID and class ID are accessible as the values of the contract and id properties, respectively.
  • By default, the factory is registered when it is created and unregistered when the add-on that created it is unloaded. To override this behavior, you can pass register and/or unregister options, set to false. If you do this, you can use the register() and unregister() functions to register and unregister.

Methods

createInstance(outer, iid)

Creates an instance of the component associated with this factory.

Parameters

outer : null
This argument must be null, or the function throws Cr.NS_ERROR_NO_AGGREGATION.

iid : iid
Interface identifier. These objects are usually accessed through the Components.interfaces, or Ci, object. The methods of this interface will be callable on the returned object.

If the object implements an interface that's already defined in XPCOM, you can pass that in here:

var about = aboutFactory.createInstance(null, Ci.nsIAboutModule);
// You can now access the nsIAboutModule interface of the 'about' object

If you will be getting the wrappedJSObject property from the returned object to access its JavaScript implementation, pass Ci.nsISupports here:

var custom = factory.createInstance(null, Ci.nsISupports).wrappedJSObject;
// You can now access the interface defined for the 'custom' object
Returns

object : The component created by the factory.

lockFactory()

This method is required by the nsIFactory interface, but as in most implementations it does nothing interesting.

QueryInterface()

See the documentation for Unknown.QueryInterface().

Properties

interfaces

The set of interfaces supported by this object. Factory sets this to nsIFactory.

id

This factory's class ID.

contract

This factory's contract ID.

Service

Use this class to register an XPCOM service. To register a service for a component, construct a Service, giving it:

  • a constructor for the object implementing the service
  • a contract ID and/or a class ID
var service = Service({
  contract: contractId,
  Component: AlertService
});

After this, XPCOM users can access the service implementation by supplying the contract ID:

var alertService = Cc[contractId].getService(Ci.nsIAlertsService);
alertService.showAlertNotification(...);

The Service interface is identical to the Factory interface, so refer to the Factory interface documentation for details.

Document Tags and Contributors

 Contributors to this page: wbamberg
 Last updated by: wbamberg, Dec 1, 2016, 10:33:11 AM
See also
  1. WebExtensions
  2. Getting started
    1. What are WebExtensions?
    2. Your first WebExtension
    3. Your second WebExtension
    4. Anatomy of a WebExtension
    5. Example WebExtensions
  3. How to
    1. Intercept HTTP requests
    2. Modify a web page
    3. Add a button to the toolbar
    4. Implement a settings page
  4. Concepts
    1. Using the JavaScript APIs
    2. User interface components
    3. Content scripts
    4. Match patterns
    5. Internationalization
    6. Content Security Policy
    7. Native messaging
  5. Porting
    1. Porting a Google Chrome extension
    2. Porting a legacy Firefox add-on
    3. Embedded WebExtensions
    4. Comparison with the Add-on SDK
    5. Comparison with XUL/XPCOM extensions
    6. Chrome incompatibilities
  6. Firefox workflow
    1. Temporary Installation in Firefox
    2. Debugging
    3. Getting started with web-ext
    4. web-ext command reference
    5. WebExtensions and the Add-on ID
    6. Publishing your WebExtension
  7. JavaScript APIs
    1. Browser support for JavaScript APIs
    2. alarms
    3. bookmarks
    4. browserAction
    5. browsingData
    6. commands
    7. contextMenus
    8. contextualIdentities
    9. cookies
    10. downloads
    11. events
    12. extension
    13. extensionTypes
    14. history
    15. i18n
    16. identity
    17. idle
    18. management
    19. notifications
    20. omnibox
    21. pageAction
    22. runtime
    23. sessions
    24. sidebarAction
    25. storage
    26. tabs
    27. topSites
    28. webNavigation
    29. webRequest
    30. windows
  8. Manifest keys
    1. applications
    2. author
    3. background
    4. browser_action
    5. chrome_url_overrides
    6. commands
    7. content_scripts
    8. content_security_policy
    9. default_locale
    10. description
    11. developer
    12. homepage_url
    13. icons
    14. manifest_version
    15. name
    16. omnibox
    17. options_ui
    18. page_action
    19. permissions
    20. short_name
    21. sidebar_action
    22. version
    23. web_accessible_resources
  9. Add-on SDK
  10. Getting started
    1. Installation
    2. Getting started
    3. Troubleshooting
  11. High-Level APIs
    1. addon-page
    2. base64
    3. clipboard
    4. context-menu
    5. hotkeys
    6. indexed-db
    7. l10n
    8. notifications
    9. page-mod
    10. page-worker
    11. panel
    12. passwords
    13. private-browsing
    14. querystring
    15. request
    16. selection
    17. self
    18. simple-prefs
    19. simple-storage
    20. system
    21. tabs
    22. timers
    23. ui
    24. url
    25. webextension
    26. widget
    27. windows
  12. Low-Level APIs
    1. /loader
    2. chrome
    3. console/plain-text
    4. console/traceback
    5. content/content
    6. content/loader
    7. content/mod
    8. content/symbiont
    9. content/worker
    10. core/heritage
    11. core/namespace
    12. core/promise
    13. dev/panel
    14. event/core
    15. event/target
    16. frame/hidden-frame
    17. frame/utils
    18. fs/path
    19. io/byte-streams
    20. io/file
    21. io/text-streams
    22. lang/functional
    23. lang/type
    24. loader/cuddlefish
    25. loader/sandbox
    26. net/url
    27. net/xhr
    28. places/bookmarks
    29. places/favicon
    30. places/history
    31. platform/xpcom
    32. preferences/event-target
    33. preferences/service
    34. remote/child
    35. remote/parent
    36. stylesheet/style
    37. stylesheet/utils
    38. system/child_process
    39. system/environment
    40. system/events
    41. system/runtime
    42. system/unload
    43. system/xul-app
    44. tabs/utils
    45. test/assert
    46. test/harness
    47. test/httpd
    48. test/runner
    49. test/utils
    50. ui/button/action
    51. ui/button/toggle
    52. ui/frame
    53. ui/id
    54. ui/sidebar
    55. ui/toolbar
    56. util/array
    57. util/collection
    58. util/deprecate
    59. util/list
    60. util/match-pattern
    61. util/object
    62. util/uuid
    63. window/utils
  13. Firefox for Android
  14. Getting started
    1. Walkthrough
    2. Debugging
    3. Code snippets
  15. APIs
    1. Accounts.jsm
    2. BrowserApp
    3. HelperApps.jsm
    4. Home.jsm
    5. HomeProvider.jsm
    6. JavaAddonManager.jsm
    7. NativeWindow
    8. Notifications.jsm
    9. PageActions.jsm
    10. Prompt.jsm
    11. RuntimePermissions.jsm
    12. Snackbars.jsm
    13. Sound.jsm
    14. Tab
  16. Legacy
  17. Restartless extensions
    1. Overview
  18. Overlay extensions
    1. Overview
  19. Themes
  20. Lightweight themes
    1. Overview
  21. Complete themes
    1. Overview
  22. Publishing add-ons
  23. Guides
    1. Signing and distribution overview
    2. Submit an add-on
    3. Review policies
    4. Developer agreement
    5. Featured add-ons
    6. Contact addons.mozilla.org
  24. Community and support
  25. Channels
    1. Add-ons blog
    2. Add-on forums
    3. Stack Overflow
    4. Development newsgroup
    5. IRC Channel