WIN32OLE_EVENTオブジェクトを途中でGCできないのは、
次のようなスクリプトを考慮しているから
ie = WIN32OLE.new('InternetExplorer.Application')
ev = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents')
ev.on_event{|*args| handler(*args)}
# ここでGC発生
ie.visible = true
ie.navigate(url) # handlerに通知したい
# ここで二度目のGC発生
while true
WIN32OLE_EVENT.message_loop
sleep 0.1
end
ev.on_event でイベントハンドラを定義しても、
その直後にGCが発生してevがGCされてしまうと
イベントを拾うことができない。
そこで、WIN32OLEオブジェクトがGCされない間、
つまり ieがGCされない間、evがGCされなければいいじゃん
という意見を頂戴した。
一瞬、いい案に思えたんだけど、上の例の二度目の
GCの後でも、ieはGCされても、InternetExplorerのプロセスは残るし
マウスで、Internet Explorerを操作できる。
その間にevがGCされると、イベントを拾うことができなくなる。
(現状では、evはGCされないので、イベントを拾い続ける。)
結局のところ、単純に ev がGCされるてもいいときは、
通知を受ける必要がなくなったときで、
それは、スクリプトを書いている人が判断すりゃいいじゃん
という投げやりな結論になってしまった。
ということで、もう通知は必要ないよというためのメソッド
WIN32OLE_EVENT#unadviseを trunkに追加してみた。
本当にGCされるかどうかは、まだ検証していないのだけど、
unadviseするとそれ以降は、通知されなくなるのは確認済み。
こういうのを用意すると、逆のWIN32OLE_EVENT#adviseも
欲しくなるんじゃないかと思うのだけど、
そっちは手元でテスト中なのでコミットはまだ。
名前は、IConnectionPoint の Unadviseから取ったんだけど、
ピンとこない人の方が多いかな。
最近のコメント