XPCOM (Cross Platform Component Object Model)

XPCOMとは、プラットフォームに依存しないコンポーネントを作成するための仕組みです。これによりJavaScriptでは実現できない処理を、C++Javaなどで記述できます。

Firefox 53以降、XPCOMを利用したアドオンはAMOに登録できません。Firefox 53 - Add-ons/2017 - MozillaWiki

現在ではXPCOMの利用は非推奨とされています。The Future of Developing Firefox Add-ons | Mozilla Add-ons Blog (2015/08/21)

コンポーネントのオブジェクトの取得 (XPConnect)

XPConnectによって、JavaScriptオブジェクトからXPCOMオブジェクトにアクセスできるようになります。それはコンポーネント クラスのIDであるContractIDを指定して、

Components.classes[ 'ContractID' ]
Components.classes | MDN

のようにすることで、それに関連付けられたXPCOMコンポーネントのオブジェクトを取得できます。

ContractID

ContractIDは、

@ドメイン名/モジュール名/コンポーネント名;バージョン番号

の形式で表され、おもに次のようなものがあります。

  • ユーザー設定
    • @mozilla.org/preferences-service;1
    • @mozilla.org/preferences;1
  • Web操作
    • @mozilla.org/browser/shistory-internal;1
    • @mozilla.org/browser/shistory;1
    • @mozilla.org/embedding/browser/nsWebBrowser;1
    • @mozilla.org/docshell;1
  • ウィンドウ操作
    • @mozilla.org/alerts-service;1
    • @mozilla.org/appshell/window-mediator;1
    • @mozilla.org/embedcomp/window-watcher;1
    • @mozilla.org/embedcomp/prompt-service;1
  • クリップボード
    • @mozilla.org/widget/clipboard;1
    • @mozilla.org/widget/transferable;1
  • その他
    • @mozilla.org/eventlistenerservice;1
    • @mozilla.org/intl/stringbundle;1
    • @mozilla.org/network/file-input-stream;1
XPCOM Interface Reference - Mozilla | MDN

コンポーネントへのアクセス

XPCOM インスタンス (XPCOM instance)

XPCOMコンポーネントのインスタンスを取得する方法には、次の3つがあります。

var sound = Components.classes[ '@mozilla.org/sound;1' ]
    .createInstance( Components.interfaces.nsISound );
var sound= Components.classes[ '@mozilla.org/sound;1' ]
    .createInstance()
    .QueryInterface( Components.interfaces.nsISound );
var Cc = Components.classes[ '@mozilla.org/sound;1' ];
var sound = new Cc( Components.interfaces.nsISound );

XPCOM コンポーネントのインスタンスを作成する - Components.classes | MDN

XPCOM サービス (XPCOM services)

XPCOMオブジェクトによっては、新規に作成されたオブジェクトではなく、XPCOMオブジェクト自体から使用できるものがあります。そのようなXPCOMのオブジェクトをサービスと呼び、XPCOMオブジェクトからgetService()によって取得できます。

コンポーネントのインターフェイス

var localFile = Components.classes[ '@mozilla.org/file/local;1' ]
    .createInstance( Components.interfaces.nsILocalFile );

これは、それぞれのオブジェクトの参照を取得することで、

var Cc = Components.classes;
var Ci = Components.interfaces;

var file = Cc[ '@mozilla.org/file/local;1' ];
var localFile = file.createInstance( Ci.nsILocalFile );

のように記述することもできます。実際に既存のアドオンでは、このような用例を多く見受けます。Using components - Mozilla | MDN

この参照を定数で保持することもできます。

const Cc = Components.classes;
const Ci = Components.interfaces;

しかしこの定数名は他で宣言されることがあるため、これをグローバルなスコープで行うと「TypeError: redeclaration of var Cc」として例外が発生することがあります。よってVarで変数として宣言するのが安全です。Redeclaration of a constant - what the..? • mozillaZine Forums

nsISupports

nsISupportsはすべてのインターフェイスで継承されていて、QueryInterface()メソッドのみを実装しています。

QueryInterface()

コンポーネントから、指定のインターフェイスを取得できます。

void QueryInterface(
    in nsIIDRef uuid, // インターフェイスのUUID
    [iid_is(uuid),retval] out nsQIResult result //
    );
QueryInterface() - nsISupports - XPCOM Interface Reference | MDN

nsIPrefBranch

nsIPrefBranchオブジェクトは、ユーザー設定のルートとして生成されます。

var prefBranch = Components.classes[ '@mozilla.org/preferences-service;1' ]
    .getService( Components.interfaces.nsIPrefBranch );

nsILocalFile

nsILocalFileオブジェクトは、ファイル操作のためのインスタンスとして生成されます。

var localFile = Components.classes[ '@mozilla.org/file/local;1' ]
    .createInstance( Components.interfaces.nsILocalFile );

XPCOMUtils.jsm

generateQI()

インターフェイスの配列を与えるだけで、簡単にQueryInterface()関数を実装できます。

function generateQI(
    interfaces // インターフェイスの配列
    );
generateQI() - XPCOMUtils.jsm - Mozilla | MDN

戻り値で、QueryInterface()関数が返されます

Firefoxアドオンの情報サイトから、まとめて検索