Question about WIN32OLE_EVENT

So, I'm clear on how to attach to events:

      @ie = WIN32OLE.new( 'InternetExplorer.Application' )
      browserEvents = WIN32OLE_EVENT.new( @ie, 'DWebBrowserEvents2' )
      browserEvents.on_event { |*args| eventHandler( *args ) }

But how does one detach from events?

I'm working on a little utility that will generate Watir scripts using
IE automation. In the following code I am attaching to the browser
events to capture when a new HTML document is loaded. When a document
is loaded I want to attach to the document's events. When a new
document is loaded I want to detach from the old document's events.

Here's the code so far. At the moment, each newly loaded document adds
to a growing list of event handlers, causing each click to produce
multiple calls to printClickStatement.

Thanks,

-=michael=-

#requires
require 'win32ole'

##//////////////////////////////////////////////////////////////////////
///////////////////////////////

···

##
## Main WatirMaker class. It handles the IE automation, which primarily
means event handling.
##
##//////////////////////////////////////////////////////////////////////
///////////////////////////////
class WatirMaker

##//////////////////////////////////////////////////////////////////////
////////////////////////////
   ##
   ## Initializer executed when "new" is called.
   ##

##//////////////////////////////////////////////////////////////////////
////////////////////////////
   def initialize
      
   end

##//////////////////////////////////////////////////////////////////////
////////////////////////////
   ##
   ## Handles all events from the browser and the HTML document.
   ##

##//////////////////////////////////////////////////////////////////////
////////////////////////////
   def eventHandler( event, *args )
      case event
      when "BeforeNavigate2"
         webBrowser = args[0]
         url = args[1]
         frameName = args[3]
         
         if frameName == ""
            @webBrowsers = Hash.new
            if @documentEventHandlers != nil
               @documentEventHandlers.each_value { |value|
value.on_event( 'onclick' ) {} }
            end
            @documentEventHandlers = Hash.new
         end
         
         @webBrowsers[url] = webBrowser
         printNavigateComment( url, frameName )
         
      when "NavigateComplete2"
         #printNavigateComment( args[1], nil )
         
      when "DocumentComplete"
         url = args[1]
         webBrowser = @webBrowsers[url]

         if ( webBrowser.Type == "HTML Document" &&
!@documentEventHandlers.has_key?( url ) )
            @documentEventHandlers[url] =
                  WIN32OLE_EVENT.new( webBrowser.document,
'HTMLDocumentEvents2' )

            @documentEventHandlers[url].on_event( 'onclick' ) { |*args|
               printClickStatement( args[0] )
            }
         end
         
      when "OnQuit"
         throw :done
      end
   end

##//////////////////////////////////////////////////////////////////////
////////////////////////////
   ##
   ## Print comment showing the page navigated to.
   ##

##//////////////////////////////////////////////////////////////////////
////////////////////////////
   def printNavigateComment( url, frameName )
      puts ""
      puts "# frame loaded: '" + frameName + "'" if frameName != nil
      puts "# navigated to: '" + url + "'"
      puts ""
   end

##//////////////////////////////////////////////////////////////////////
////////////////////////////
   ##
   ## Print Watir statement for click events.
   ##

##//////////////////////////////////////////////////////////////////////
////////////////////////////
   def printClickStatement( eventObj )

      how, what = getHowWhat( eventObj.srcElement )

      case eventObj.srcElement.tagName
      when "INPUT"
         case eventObj.srcElement.getAttribute( "type" )
         when "submit"
            # TODO: must figure out a way to get the frame that contains
the srcElement. The frame
            # will be necessary to properly reference the element.
            puts "ie.button( " + how + ", '" + what + "' ).click"
         end
      end

   end

##//////////////////////////////////////////////////////////////////////
////////////////////////////
   ##
   ## Returns the "how" and the "what" values.
   ##
   ## Note: may need different getHowWhat methods for different element
types because each element
   ## type supports different "how" values.
   ##

##//////////////////////////////////////////////////////////////////////
////////////////////////////
   def getHowWhat( element )

      if element.getAttribute( "id" ) != ""
         return ":id", element.getAttribute( "id" )
      elsif element.getAttribute( "name" ) != ""
         return ":name", element.getAttribute( "name" )
      else
         # TODO: must get the actual index of the item using the
         # IHTMLDocument3::getElementsByTagName method
         return ":index", 1

      end

   end

##//////////////////////////////////////////////////////////////////////
////////////////////////////
   ##
   ## Starts recording all interactions with IE.
   ##

##//////////////////////////////////////////////////////////////////////
////////////////////////////
   def startRecording
   
      # initialize IE
      @ie = WIN32OLE.new( 'InternetExplorer.Application' )
      @ie.visible = TRUE
      @ie.gohome

      browserEvents = WIN32OLE_EVENT.new( @ie, 'DWebBrowserEvents2' )

      browserEvents.on_event { |*args| eventHandler( *args ) }
      
      # print script header
      puts
"##/////////////////////////////////////////////////////////////////////
/////////////////////////////"
      puts "##"
      puts "## Watir script recorded by WatirMaker."
      puts "##"
      puts
"##/////////////////////////////////////////////////////////////////////
/////////////////////////////"
      puts ""
      puts "#requires"
      puts "require 'watir'"
      puts ""
      puts "#includes"
      puts "include Watir"
      puts ""
      puts "ie = IE.new"
      puts "ie.set_fast_speed()"
      puts "ie.ie.gohome"
      puts ""

      # capture events
      catch( :done ) {
         loop {
            WIN32OLE_EVENT.message_loop
         }
      }
      
      # IE takes a moment to close.
      # Making it invisible in the interim produces a slightly nicer
user experience.
      @ie.visible = FALSE
   end
   
end # end class

--
Michael Kelly
Sr. Software Engineer
Eleven Wireless Inc. - The Possibilities are Wireless
http://www.elevenwireless.com <http://www.elevenwireless.com/>

"Michael Kelly" <mkelly@elevenwireless.com> wrote...

So, I'm clear on how to attach to events:

      @ie = WIN32OLE.new( 'InternetExplorer.Application' )
      browserEvents = WIN32OLE_EVENT.new( @ie, 'DWebBrowserEvents2' )
      browserEvents.on_event { |*args| eventHandler( *args ) }

But how does one detach from events?

# Replace the current event handler with an empty one:
browserEvents.on_event {}

I'm working on a little utility that will generate Watir scripts using
IE automation. ...

Let us know - that sounds really useful!

Cheers,
Dave

Unfortunately, there is no way to detach from events.
So, use global flag variable instead.

  $attached = true
  def eventHandler(*args)
    if ($attached)
      ....
    end
  end
  # attach event handler
  browserEvents.on_event{|*args| eventHandler(*args)}
   ...
  # dettach event handler
  $attached = false

In future release, Win32OLE provides the method to detach event.

  Regards,
  Masaki Suketa

···

In message "Question about WIN32OLE_EVENT." on 05/08/05, "Michael Kelly" <mkelly@elevenwireless.com> writes:

So, I'm clear on how to attach to events:

      @ie = WIN32OLE.new( 'InternetExplorer.Application' )
      browserEvents = WIN32OLE_EVENT.new( @ie, 'DWebBrowserEvents2' )
      browserEvents.on_event { |*args| eventHandler( *args ) }

But how does one detach from events?