トップ «前の日記(2009-02-14) 最新 次の日記(2009-02-16)» 編集

日々の破片

Subscribe with livedoor Reader
著作一覧

2009-02-15

_ ActiveScriptingホストの良くわからない動作

2chで見たのだが、ASR(というパッケージではなく、ActiveScriptRuby=RScript18.dllのこと)が以下のHTAの実行に失敗し、結果的にスタックオーバーフローで死ぬ。

<html><head><hta:application>
<script language="RubyScript">
  alert('r');
</script>
<script language="JavaScript">
  alert('j');
</script>
</head><body></body></html>

ActiveScriptingのホスト(この場合、MSHTA)は、スクリプトが利用するホスト側オブジェクトをIActiveScript::AddNamedItemメソッドを呼び出して登録する。MSHTAの場合は、windowがそれに当たる。

ASRは、この呼び出しを受けると、IActiveScriptSite::GetItemInfoメソッドを呼び出して、必要な情報を得て、Rubyのスクリプトがwindowオブジェクトを操作できるようにする。この時、スクリプトからのアクセス用にWindow、@windowの2種類の変数を用意する。それに加えて、ある時点から、JScript同様にグローバルなオブジェクト(AddNamedItemメソッド呼び出し時にSCRIPTITEM_GLOBALMEMBERSフラグが指定される)については、直接スクリプトが記述できるように(あたかもmainオブジェクトのprivateメソッドのように)登録しておく。

なお、ここでの問題とは直接関係しないが、イベントを通知するための仕組みは、ホストに対してIDispatch*を与えることで実現している。たとえば、HTML要素にonclick属性を指定すると、ホストは、IActiveScriptParseProcedure::ParseProcedureTextメソッドを呼び出し、スクリプトのパース結果をCOMの呼び出し可能なオブジェクトとして要求する。したがって

<input type="button" id="eventSource" onclick="alert('hello')">
と書くと、alert('hello')を実行するIDispatch*をActiveScriptは生成し、それをホストへ与える。ホストはイベントを通知したくなると、該当IDispatch*のデフォルトメンバをInvokeする。ASRはこれをProcオブジェクトとして実装している。

本題に戻ると、おそらく、スクリプト側での拡張を認めるためだと思うが、ホストは、AddNamedItemメソッドで設定したオブジェクトについても、IActiveScript::GetScriptDispatchメソッドを呼び出し、ActiveScript側のオブジェクトのIDispatch*を取りに来る。

このとき、RubyScriptのみがMSHTAのスクリプトとして実行されていると、以下の動きとなる。

  • AddNamedItem 'window' -> windowオブジェクト用のWin32OLEオブジェクトを作成する。このとき、IActiveScriptSite::GetItemInfoメソッドを呼び出してIDispatchEx*を取得しておく
  • GetScriptDispatch 'window' -> 上記オブジェクトに保持したIDispacthEx*をホストへ返す。

ASRは、この処理を、最初、以下のように実装していた。

  • AddNamedItem 'window' -> windowオブジェクト用のWin32OLEオブジェクトを作成する。このとき、IActiveScriptSite::GetItemInfoメソッドを呼び出してIDispatchEx*を取得しておく(Rubyのスクリプト用)
  • GetScriptDispatch 'window' -> 指定されたRubyのオブジェクト(ホストのオブジェクトは想定外)がなければテンポラリなオブジェクトを生成し、そのIDispatch*を返す。そのため、最初Ruby側のオブジェクトを探し、次に、IActiveScriptSite::GetItemInfoを呼び出してホスト側オブジェクトを探す

MSHTA上にRScriptのみしか存在しなければ、ホストはGetItemInfoに対して自分が保持する(この場合であれば)windowのIDispatchEx*を返すので、そこで終了する。

ところが、JScriptが共存すると、話が異なる。

ホストはJScriptに対してAddNamedItemを呼ぶ。JScriptはGetItemInfoを呼ぶ。ホストは拡張している可能性からASRのGetScriptDisaptchを呼ぶ。ASRは、上記のテンポラリオブジェクトのためにGetItemInfoを呼ぶ。ホストは拡張している可能性からASRのGetScriptDispatchを呼ぶ。ASRは、上記のテンポラリオブジェクトのために……スタックオーバーフローする。

結局、ホスト側のオブジェクトとしてすでに登録されていれば、そのIDispatchEx*をGetScriptDisaptchの結果として返すことで、このループを回避できる。

という修正をしたASRを作った。

msiは、たぶん、1.8.7の次期パッチ版がもうすぐリリースされると思うのでその時作ることにして、とりあえず、RScript18.dllのみのzipをダウンロードページに置いた。

_ ASR 1.9.1の予定

ASRは一応、完成した(ソース)。

しかし、soleb.rbを実行すると、うまく行かない。Swinにもう少し修正が必要なようだ。具体的には、実行すると表示(ASCIIのところ)がおかしく、最終的に、

C:/PROGRA~2/RUBY-1~1.1/lib/ruby/vendor_ruby/1.9.1/vr/vrcontrol.rb:672:in `encode': "\xE6\x8D\x81" from UTF-8 to Windows-31J in conversion from UTF-16LE to Windows-31J (Encoding::UndefinedConversionError)

となる。

とりあえず、これはこれとして、ASRのサンプルとしての意味もあるのでsolebの真似をHTAで作ったholebというのを作ることにした。

その過程で、スレッドピンポンでinstance_evalすることになったりしたのであった。

で、これが終わったらリリースするのだが、最近、昼の仕事が忙しいのであった。なので、もうちょっとかかりそうな雰囲気。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|

ジェズイットを見習え