Mar 23, 2010

nsIVariantを使ってるアドオンが終了していた、と思ったら僕の知識の方が終了していた件

SCRAPBLOG : JavaScript 製 XPCOM で配列構造・列挙構造のデータをメソッドの戻り値にする

独自に開発したXPCOMコンポーネントに対して配列を渡したり、あるいは戻り値を配列で受け取ったり、ということをやる方法はいくつかある。上記エントリではコメント欄も含めると4つの方法が紹介されていて、そのうちコメント欄にある2つはJavaScriptの配列をそのまま受け渡せるという点で有用だ。特にnsIVariantインターフェースを使うやり方は、戻り値に使う時に余計な引数を定義しなくていいので、実際にそのXPCOMコンポーネントをJavaScriptから使う時にとても使い勝手がいい。

ということでXUL/Migemoでは積極的にnsIVariantを使ってたんだけど、これがMinefield(検証したバージョンは3.7a4pre)で動かなくなってた。

結論から言うと、これはnsIVariantインターフェースのIIDが6c9eb060-8c6a-11d5-90f3-0010a4e73d9aから81e4c2de-acac-4ad6-901a-b5fb1b851a0dに変更されたせいで起こっている問題で、nsIDOMRangeのIIDが変更された時に起こった問題と同様の物だ。

変更が入ったのは昨年9月で、HTML5の新しい仕様に対応するための作業の一環として、何らかの必要があってインターフェースに機能を加えると同時にIIDも変わったらしい。nsIVariantはFROZENなインターフェースじゃないから、nsIDOMRangeの時のようにIIDが元に戻されることは多分あり得ない。よって、考えられる対策は以下のいずれかということになる 。

  • APIをXPCOM経由で提供する事を諦める。Firefox 2以前、Thunderbird 2以前を切り捨てて、JavaScriptコードモジュールとして書き直す。
  • Firefox 3.6以前用とFirefox 3.7以降用とでXPIDLのコンパイル後のバイナリを分けて、Firefoxのバージョン別に2つのXPIファイルを提供するようにする。

JavaScriptコードモジュールにするデメリットは、Thunderbird 2で利用できなくなってしまう点と、APIが変わってしまう点。バイナリを分けるデメリットは、リリースの時の作業がめんどくさくなる(XPIファイルが2つになるので)という点。どっちを選んでも大変なのは変わらない……

APIが変わってしまうことは避けたかったので、結局、後者の方で対処することにした。

前から使ってるXPI生成用シェルスクリプトに起動オプションでサフィックスを指定できるようにして、

こんなショボいスクリプトを作って、前出のスクリプトと一緒に

call xpidl.bat xulrunner-sdk-1.9.2
bash makexpi.sh -n xulmigemo -v 0 -s "1.9.2"

call xpidl.bat xulrunner-sdk-central
bash makexpi.sh -n xulmigemo -v 0 -s "central"

てな感じで実行するようにして(make.bat / make.sh)、MozillaのFTPサイトからXULRunner SDKのファイル一式を入手して

  • xulmigemo
    • make.bat (make.sh)
    • xpidl.bat (xpidl.sh)
    • makexpi.sh
    • install.rdfなど
  • xulrunner-sdk-1.9.2
    • bin
      • xpidl.exe (xpidl)
    • idl
  • xulrunner-sdk-central
    • bin
      • xpidl.exe (xpidl)
    • idl

という感じにファイルを配置するようにした。

XPIを作りたい時にはXULRunner SDKが必要になってしまうけど、スクリプトいっこ走らせれば xulmigemo-mozilla-1.9.2.xpi と xulmigemo-mozilla-central.xpi という風に複数のXPIを出力できるようになったので、リリースにかかる手間は少しは軽減された……のかな……

追記。Gomitaさんのコメントを見て、IDLファイルからincludeの行を消して試してみたら、それでちゃんとコンパイルできた。なんでだ……!!!

えーと。ずっと勘違いしてたんだけど、#include "nsISupports.idl" みたいな行は、interface xmIXMigemoFileAccess : nsISupports てな感じでインターフェース定義の継承元に別のインターフェースを使う場合にだけ必要で、戻り値や引数に使う分には単に interface nsIVariant; とだけ書いておけばいいみたいですね……そうすると、コンパイル時には余計なIIDが含まれなくなって、Firefox 3.6まででも3.7以降でも問題なく使えるXPTファイルが作られるみたい。

まとめ。

  • IDLファイルの書き方を間違えておらず、最小限の記述だけにしてあれば、コンパイルしたXPTファイルはFirefox 3.6まででもFirefox 3.7以降でも使える。
    • 継承元に使うインターフェースはその内容が定義されたIDLファイルをincludeした上で interface インターフェース名; と書く。
    • そうでない物(引数や戻り値でしか使わないインターフェース)は interface インターフェース名; だけ書く。
  • Minefield 3.7におけるnsIVariantのIIDの変更の影響を受けるのは、nsIVariantを継承元としてさらに拡張したインターフェースを定義する場合だけ。

そんなわけで、xmIXMigemo.idlの頭の所はずいぶんスッキリしました。

#include "nsISupports.idl"
#include "nsIObserver.idl"

interface nsIObserver;
interface nsIFile;
interface nsIVariant;
interface nsIDOMWindow;
interface nsIDOMDocument;
interface nsIDOMRange;
interface nsIDOMElement;
interface nsIDOMNode;


/* Utilities: You can use them for your language without additional implementation. */

[scriptable, uuid(4aca3120-ae38-11de-8a39-0800200c9a66)]
interface xmIXMigemoFileAccess : nsISupports
{
(以下略)
エントリを編集します。

wikieditish message: Ready to edit this entry.











拡張機能