class WIN32OLE_EVENT

[edit]

要約

OLEオートメーションサーバからのイベント通知を制御するクラスです。

OLEオートメーションサーバによっては、サーバの処理の過程でクライアントがあらかじめ登録したメソッドを呼び出すものがあります。このサーバが登録したメソッドを呼び出す動作を「イベント」と呼びます。WIN32OLE_EVENTを利用すると、ブロックの形式でイベントを受け取るメソッドをサーバへ登録できます。

サンプルコード

ie = WIN32OLE.new('InternetExplorer.Application.1')
event = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents2')
b = false
event.on_event('DocumentComplete') do |disp, uri|
  disp.document.getElementsByTagName('a').each do |e|
    puts "#{e.innerHTML}=#{e.href}"   #=> ダウンロード=http://www.ruby-lang.org/ja/downloads/ など
  end
  disp.quit
  b = true
end
ie.Navigate2 'http://www.ruby-lang.org/ja/'
loop do
  break if b
  WIN32OLE_EVENT.message_loop
end

目次

特異メソッド
インスタンスメソッド

特異メソッド

message_loop -> ()[permalink][rdoc][edit]

Windowsのメッセージポンプを実行します。

message_loopメソッドは、Windowsメッセージがキューイングされている限りメッセージの読み出しとディスパッチを実行します。

COMのスレッド間/プロセス間通信はスレッド内で呼び出しをシリアライズするためにWindowsメッセージを利用します。このため、ほとんどのイベント処理は Windowsメッセージを読み取ってディスパッチすることで通知されます。

ie = WIN32OLE.new('InternetExplorer.Application.1')
event = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents2')
b = false
event.on_event('DocumentComplete') do |disp, uri|
  disp.document.getElementsByTagName('a').each do |e|
    puts "#{e.innerHTML}=#{e.href}"   #=> ダウンロード=http://www.ruby-lang.org/ja/downloads/ など
  end
  disp.quit
  b = true
end
ie.Navigate2 'http://www.ruby-lang.org/ja/'
loop do
  break if b
  WIN32OLE_EVENT.message_loop
end

なお、メソッド名はloopですが、呼び出し時および既にキューイングされたメッセージの処理中にキューされたメッセージの処理が終わると呼び出し元に制御が戻ります。このため、イベント通知までに長い時間がかかる場合はすべてのイベントを受信するまでループを実行する必要があります。このとき他のスレッドに制御を与える必要があれば、Kernel.#sleepなどを呼び出してください。message_loopメソッドの呼び出し中はRubyのスレッドの切り替えは行われません。

new(ole, event = nil) -> WIN32OLE_EVENT[permalink][rdoc][edit]

OLEオートメーションサーバのイベント受信機構をオブジェクト化して返します。

newメソッドは、OLEオートメーションサーバがイベント通知に利用するインターフェイスを取得し、オブジェクトとして返します。

[PARAM] ole:
イベントの通知元のWIN32OLEオブジェクトを指定します。
[PARAM] event:
イベントのインターフェイスを示すインターフェイス名または IIDを文字列で指定します。省略時にはoleパラメータで指定したオブジェクトの既定のイベントインターフェイスを利用します。
[RETURN]
指定したオブジェクトのイベントを管理するWIN32OLE_EVENTオブジェクト。
[EXCEPTION] RuntimeError:
eventパラメータで指定したIIDが見つかりません。またはオブジェクトがイベントをサポートしていません。

以下の3例はいずれも同等です。

デフォルトイベントインターフェイスを指定した例

ie = WIN32OLE.new('InternetExplorer.Application')
ev = WIN32OLE_EVENT.new(ie)

インターフェイス名を指定した例

ie = WIN32OLE.new('InternetExplorer.Application')
ev = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents2')

IIDを指定した例

ie = WIN32OLE.new('InternetExplorer.Application')
ev = WIN32OLE_EVENT.new(ie, '{34A715A0-6587-11D0-924A-0020AFC7AC4D}')

インスタンスメソッド

handler -> object[permalink][rdoc][edit]

WIN32OLE_EVENT#handler=メソッドで登録したイベントハンドラオブジェクトを返します。

[RETURN]
イベントハンドラオブジェクト。未登録ならばnil。
handler=(obj) -> ()[permalink][rdoc][edit]

イベント処理を実行するオブジェクトを登録します。

イベントハンドラをメソッドとして持つオブジェクトをイベントハンドラとして登録します。

イベントハンドラはイベント名に「on」を前置します。もし、イベントに対応するonメソッドが実装されていなければmethod_missingが呼ばれます。イベント名は大文字小文字を区別するため、正確な記述が必要です。

[PARAM] obj:
イベントに対応するメソッドを持つオブジェクト。イベント受信を解除するにはnilを指定します。
class IeHandler
  def initialize
    @completed = false
  end
  attr_reader :completed
  def onDocumentComplete(disp, uri)
    disp.document.getElementsByTagName('a').each do |e|
      puts "#{e.innerHTML}=#{e.href}"
    end
    @completed = true
  end
  def method_missing(id, *args)
    puts "event=#{id.to_s}, args=#{args.inspect}"
  end
end

ie = WIN32OLE.new('InternetExplorer.Application.1')
event = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents2')
event.handler = IeHandler.new
ie.Navigate2 'http://www.ruby-lang.org/ja/'
loop do
  break if event.handler.completed
  WIN32OLE_EVENT.message_loop
end
ie.Quit

WIN32OLE_EVENT#on_eventなどの呼び出しでブロックが登録されている場合、そちらが優先されます。

off_event(event = nil) -> ()[permalink][rdoc][edit]

WIN32OLE_EVENT#on_eventで登録したブロックを解除します。

[PARAM] event:
文字列またはシンボルで登録時に指定したイベント名を指定しま

す。nilの場合、WIN32OLE_EVENT#on_eventに対してnilを指定したブロックを解除します。

ev = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents')
ev.on_event(:NavigateComplete) {|url| puts url }
...
ev.off_event(:NavigateComplete)
on_event(event = nil) {|*args| ... } -> ()[permalink][rdoc][edit]

イベント通知を受けるブロックを登録します。

引数にはイベントのメソッド名を指定します。引数を省略した場合は、すべてのイベントを対象とするブロックの登録となります。

[PARAM] event:
イベント名を文字列かシンボルで指定します。イベント名は大文字小文字を区別します。省略時にはすべてのイベントが対象となります。
[PARAM] args:
サーバがイベント通知時に指定した引数です。 eventパラメータを省略した場合、第1引数にはイベントのメソッド名が文字列で与えられます。引数の変更が必要な場合は、 WIN32OLE_EVENT#on_event_with_outargsを利用してください。
[EXCEPTION] WIN32OLERuntimeError:
WIN32OLE_EVENT#unadviseによってイベントソースと切断済みです。
ie = WIN32OLE.new('InternetExplorer.Application')
ev = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents2')
ev.on_event("NavigateComplete2") do |browser, url|
  puts url
end

同じオブジェクトに対してeventパラメータを指定したブロックと指定しないブロックが混在している場合、通知されたイベントに対応するブロックがあればそちらだけが呼び出されます。

ie = WIN32OLE.new('InternetExplorer.Application')
ev = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents2')
ev.on_event("NavigateComplete2") do |browser, url|
  puts url
end
ev.on_event do |*args|   # <- NavigateComplete2イベント時は実行されない
  puts args[0]
end
...

当メソッドはイベント名の大文字小文字を区別するほか、イベント名の存在確認を行いません。このため、誤ったイベント名を記述してもエラーとはならず、単にイベントを受け取れなくなります。

on_event_with_outargs(event = nil) {|*args| ... } -> ()[permalink][rdoc][edit]

イベント通知を受けて結果を呼び出し元へ返すブロックを登録します。

引数にはイベントのメソッド名を指定します。引数を省略した場合は、すべてのイベントを対象とするブロックの登録となります。

WIN32OLE_EVENT#on_eventと異なり、イベントのブロック変数に戻り値を設定できます。

[PARAM] event:
イベント名を文字列かシンボルで指定します。イベント名は大文字小文字を区別します。省略時にはすべてのイベントが対象となります。
[PARAM] args:
サーバがイベント通知時に指定した引数の配列です。 eventパラメータを省略した場合、第1要素にはイベントのメソッド名が文字列で与えられます。なお、引数に値を設定するには、ブロック変数を分割せずに配列の形式で受けてください。
[EXCEPTION] WIN32OLERuntimeError:
WIN32OLE_EVENT#unadviseによってイベントソースと切断済みです。
ie = WIN32OLE.new('InternetExplorer.Application')
ev = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents2')
ev.on_event('BeforeNavigate2') do |*args|
  args[6] = true unless args[4]  # Cancel = true unless PostData
end

当メソッドはイベント名の大文字小文字を区別するほか、イベント名の存在確認を行いません。このため、誤ったイベント名を記述してもエラーとはならず、単にイベントを受け取れなくなります。

unadvise -> ()[permalink][rdoc][edit]

イベント通知元をオブジェクトから切断します。

当メソッド実行後は、イベント通知を受けられなくなります。また、このオブジェクトを利用したWIN32OLE_EVENT#on_eventなどの呼び出しはエラー(WIN32OLERuntimeErrorの通知)となります。

WIN32OLE_EVENTオブジェクトは一度生成すると、イベントハンドラが登録されている限りオブジェクトを解放しません。というのは、イベントの通知元のオブジェクトと相互参照されるため、自動的に解放することができないからです。結果として、OLEオートメーションサーバの解放もスクリプトが終了するまで行われません。

この状態が望ましくないアプリケーション(サーバがリソースを消費する、あるいはスクリプトの寿命が非常に長いなど)で、積極的にサーバを解放したい場合に限り、当メソッドを呼び出してください。