nsIWritableVariant, nsIWritablePropertyBag2について
最近XPCOMにハマってる*1訳ですけど、
いまいち分からん点があります。その前にタイトル通りnsIWritableVariantとnsIWritablePropertyBag2について現状試した結果についてつらつらとメモしておきます。
その前にXPConnect/XPCOMの説明
JavaScriptから見たXPConnect(Componentsオブジェクト)
軽く試したいならばMozRepl必須です。
XPConnectはざっくり言えばJSとXPCOMの橋渡しをする仕組みで、JS側から見るとComponentsオブジェクトにその機能が集約されます。
repl> repl.print(Components); [object nsXPCComponents]
repl> repl.inspect(Components); <object>.interfaces=[object] <object>.classes=[object] <object>.results=[object] <object>.ID=[function] <object>.stack=[object] <object>.utils=[object] <object>.lookupMethod=[function] <object>.isSuccessCode=[function] <object>.QueryInterface=[function] <object>.interfacesByID=[object] <object>.classesByID=[object] <object>.manager=[object] <object>.Exception=[function] <object>.Constructor=[function] <object>.reportError=[function]
詳しくはMDC内のXPConnect辺りを見て下さい。
で特に頻繁に使うのがComponents.classes, Components.interfacesで、これらは大概、
const Cc = Components.classes; const Ci = Components.interfaces;
なんて宣言をされている事が多いです。*2
class, interfaceってのは何かと言えば、XPCOMの概念でしてXPCOMのComponentってのは、
予め決められたidlで定めたinterfaceをclassと言う形で実装して行く事になってます。
まぁJavaっぽぃですね。ふんふん。
具体的には次で説明しまっす。
XPCOMとは何ぞや
MozillaなアプリにおいてC++によって拡張出来るコンポーネントシステムの事で、
他にもPerl, Ruby, Python, Javaでも拡張可能です。*3
またJavaScriptでも記述出来ます。
createInstance()でXPCOM Componentを使う
例えば今回話す予定のnsIWritableVariantを実装したクラスを使いたければ、@mozilla.org/hash-property-bag;1がそれを実装したクラスなので、
下記のように宣言します。
var aVariant = Cc["@mozilla.org/variant;1"].createInstance(Ci.nsIWritableVariant);
このcreateInstance()の引数中に実際に実装しているinterfaceのID*4を突っ込むとそのインターフェースで定義された型が使えるようになります。
ちなみにcreateInstanceの引数のiidをnsIWritableVariantの親インターフェースであるnsIVariant、さらには全ての基底インターフェスであるnsISupports、また省略した場合を試してみましょう。
repl> Cc["@mozilla.org/variant;1"].createInstance(Ci.nsIWritableVariant); [xpconnect wrapped nsIWritableVariant] repl> Cc["@mozilla.org/variant;1"].createInstance(Ci.nsIVariant); [xpconnect wrapped nsIVariant] repl> Cc["@mozilla.org/variant;1"].createInstance(Ci.nsISupports); [xpconnect wrapped nsISupports] repl> Cc["@mozilla.org/variant;1"].createInstance(); [xpconnect wrapped nsISupports]
このようになります。
getService(), QueryInterface()に関してはまた今度書くかも。
nsIWritableVariantを試してみる
そもそもこのnsIWritableVariantって汎用的に使える値なのかなと思ったんですが、
少なくともJS側で実際に入っている値が取得出来ない気がします。
と言うのも、
var _test = Cc["@mozilla.org/variable;1"].createInstance(Ci.nsIWritableVariant); _test.setAsAString("ZIGOROu");
と突っ込んでもZIGOROuと言う値がどうしても取れない。。。親インターフェースの定義を見ると確かに各種getterがある物の、使おうとしても使えない。多分[noscript], [noxpcom][notxpcom]とかついてるせいだと思うんですけども。
用途と使い方がいまいち理解出来ない訳なのです。
こうして書いたら識者がヒントをくれる事を祈って書いてみるテスト。(ぇ
nsIWritablePropertyBag2を試す
似たような形でやってみましょう。
repl> var _test = Cc["@mozilla.org/hash-property-bag;1"].createInstance(Ci.nsIWritablePropertyBag2); repl> _test [xpconnect wrapped nsIWritablePropertyBag2] repl> _test.setPropertyAsAString("name", "zigorou"); repl> _test.getPropertyAsAString("name"); zigorou
と言う感じできちんと値が取得出来ます。
そしてnsIWritablePropertyBag2の祖先インターフェースに当たるnsIPropertyBagにある、getProperty()も使ってみましょう。
repl> _test.getProperty("name"); zigorou
nsIVariantを返す事になってるはずなのに、普通に文字列として取れるじゃないですか。。。
ここで試しにQueryInterfaceを用いてnsIWritablePropertyBag*5に型を変えてみます。
repl> _test.QueryInterface(Ci.nsIWritablePropertyBag); [xpconnect wrapped (nsISupports, nsIWritablePropertyBag2, nsIWritablePropertyBag)] repl> _test.setProperty("company", "Cybozu Labs."); repl> _test.getProperty("company"); Cybozu Labs.
これもvalueの受け渡しはnsIVariantなのに問題無く設定と取得が出来てる。謎だ。
次は敢えてnsIWritableVariantで文字列を突っ込んで同等の事をしてみる。
repl> var _val = Cc["@mozilla.org/variant;1"].createInstance(Ci.nsIWritableVariant); repl> _val.setAsAString("xpcom"); repl> _test.setProperty("study", _val); repl> _test.getProperty("study"); [xpconnect wrapped nsIWritableVariant]
うむ、仕様通りに返って来た。でも中身に入れたxpcomが参照出来ない事実は変わらず。
と言う訳で
多分idlで定義してあるnoscript, noxpcomnotxpcomと言う指定の意味が分かればそれで良いとは思うんだけど、
もしご存知の方が居れば是非アドバイス下さい。
追記
http://www.mozilla.org/scriptable/xpidl/idl-authors-guide/keywords.htmlが一番詳しいかなぁ。
notxpcomは規則違反みたいな感じで書かれてる。ますます謎だ。