著作一覧 |
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のスクリプトとして実行されていると、以下の動きとなる。
ASRは、この処理を、最初、以下のように実装していた。
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は一応、完成した(ソース)。
しかし、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することになったりしたのであった。
で、これが終わったらリリースするのだが、最近、昼の仕事が忙しいのであった。なので、もうちょっとかかりそうな雰囲気。
ジェズイットを見習え |