RubyScriptをOrthoclaseで使えるようにしたい (2)
RubyScriptをOrthoclaseで動かしたいので,もっともっとがんばってみた.
イベントの接続は@LimeExt.ConnectObject(@event, "event_")で接続すればいいことに気付いたけど,今度はRubyScriptのディスパッチャが転けた.
デバッガで原因を探ってみると,どうやら,RubyScriptWrapper::SearchMethodでModule#methodsを引くときに,StringValuePtrを使うと何故かグローバルメンバの@eventを見に行って,callメソッドを探そうとするらしい.意味が分からない.ruby1.9.1を使っている所為だろうか・・・?
とりあえず,その部分をrb_obj_as_stringに書き換えることで解決を図った.
VALUE v = rb_ary_entry(obj, j); char* pmname = RSTRING_PTR(rb_obj_as_string(v)); if (stricmp(reinterpret_cast<char*>(pName), pmname) == 0)
スクリプトがモジュールに包まれる構造になっているので,イベントハンドラを書くときは,モジュールのクラスメソッドとして書かないと行けない.ちょっと面倒だ.
#RubyScript @LimeExt.ConnectObject(@event, "event_") def self.event_onLoad @event.print("RubyScriptでLimeChatスクリプティング!") end
しかし,このコードを実行すると実は非常に不味いことが起きる.RubyGCの特性で,Win32OLEオブジェクトたちがいつまで経っても解放されないので,なにも対策をとらないと,メモリリークを起こすことになる.LimeExtオブジェクトはスクリプト毎のオブジェクト接続を管理しているので,消えてもらわないと間違いなくバグる.幸いなことに,Win32OLEクラスは明示的に保持するオブジェクトを解放するメソッド__releaseを持っている.たぶんデバッグ目的の物体だろうけど・・・とりあえず,これをevent_onUnload時に呼んでおけば,無事解放されるようになる,はず.
#RubyScript # イベントを受け取る準備 @LimeExt.ConnectObject(@event, "event_") def self.event_onUnload # 明示的に解放する @LimeExt.__release @event.__release @window.__release end def self.event_onLoad @event.print("RubyScriptでLimeChatスクリプティング!") end
しかし,結局RubyScript側の修正が必要だったか・・・なんか,元のソースコードではグローバルメンバを登録するとぶっ飛ぶバグがあるらしい?(メンバ名NULLの条件分岐?)ので,どっちにせよ修正は避けられなかったに違いない,たぶん.
あと,Win32OLEのsendとeventのsendがかち合ってそのまま呼べないんだけど,invokeを使えば上手く呼び出せるようだ.
def self.event_onChannelText(prefix, channel, text) if text == 'おはよう' @event.invoke("send", channel, 'おはよ〜@ruby') end end
その後
Win32OLEEX.Attachすると__releaseしても無視されると言う仕様によって,見事にリソースリークが生きていた.
CRScriptCore::GetOleObjectのm_listOleObjにpoleを追加している部分で,Wrapperにも食べさせるようにすれば,きちんと__releaseしてくれるらしい.
VALUE CRScriptCore::GetOleObject(VALUE self, LPCOLESTR pstrName) { ... ATLTRACE(_T("add OLE Object into list:%08X\n"), pole); m_listOleObj.push_back(reinterpret_cast<oledata*>(pole)); CRubyWrapper::GetCWrapper()->AddOle(0, pole); } return obj; }
下の方で,RubyのThread固有データ含んでるから解放したら死ぬとかいって#if 0されたコードがあるのが気掛かり.まあ,WrapperはRuby VMと同じスレッドに居るんじゃない?!と言うことでよしとしよう・・・