Phlip wrote:
> Watirists:
>
> After running a test with Watir over and over again, my WinXP box
> shows signs of "handle exhaustion". Simple windows and such don't
> open. This shows that when Watir creates its secret Internet Explorer
> object, and destroys it (wie.close(), right?) something leaks in the
> OLE layer. So the theory is memory fills up with leaked objects, and
> the first symptom is we run out of kernel HANDLEs.
>
> Then I fixed some Watir tests by making my rig build a new IE object
> once per test case, not once per test batch. (The dynamic updates and
> such were colliding and giving false test negatives.)
>
> So now the effect happens much faster. What to do?
>
>   
Use this instead.

(I plan to commit this to Watir, but since you asked, i'm sending it 
direct. Using this you do ie = IE.new_process to create an IE and 
ie.kill to close it. This creates a separate IE process for each Window, 
which should prevent any memory leaks. It also prevents the problems 
that some people have complained about where cookies are being shared 
between different browsers. Arguably, this should really be the default 
behavior of IE.new)

# based on http://svn.instiki.org/instiki/trunk/test/watir/e2e.rb
# and http://rubyforge.org/pipermail/wtr-general/2005-November/004108.html

require 'watir'

class IEProcess
  def self.start
    startup_info = [68].pack('lx64')
    process_info = [0, 0, 0, 0].pack('llll')
   
    # TODO: make this portable
    startup_command = 'C:\Program Files\Internet Explorer\IEXPLORE.EXE'
   
    result = Win32API.new('kernel32.dll', 'CreateProcess', 'pplllllppp', 
'l').
      call(
           nil,
           startup_command,
           0, 0, 1, 0, 0, '.', startup_info, process_info)
   
    # TODO print the error code, or better yet a text message
    raise "Failed to start IEXPLORE." if result == 0
   
    process_id = process_info.unpack('llll')[2]
    puts "Process ID: #{process_id}"
    self.new process_id
  end
 
  def initialize process_id
    @process_id = process_id
  end
  attr_reader :process_id
   
  def stop
    right_to_terminate_process = 1
    handle = Win32API.new('kernel32.dll', 'OpenProcess', 'lil', 'l').
      call(right_to_terminate_process, 0, @process_id)
    Win32API.new('kernel32.dll', 'TerminateProcess', 'll', 
'l').call(handle, 0)
  end
 
  def window
    shell = WIN32OLE.new 'Shell.Application'
    while true do
      shell.windows.each do |window|

        process_id = Watir.process_id_from_hwnd window.hwnd       

        # puts "Window Name: #{window.name}, Process ID: #{process_id}"
        return window if process_id == @process_id
       
      end
    end
  end
 
end

module Watir
  def self.process_id_from_hwnd hwnd
        pid_info = ' ' * 32
        Win32API.new("user32", "GetWindowThreadProcessId", 'ip', 'i').
          call(hwnd, pid_info)
        process_id =  pid_info.unpack("L")[0]
  end

  def IE.new_process
    iep = IEProcess.start
    ie = IE.bind iep.window
    ie.process_id = iep.process_id
    ie
  end
 
  class IE
    def process_id
      @process_id ||= Watir.process_id_from_hwnd @ie.hwnd
    end
    attr_writer :process_id
    def kill
      iep = IEProcess.new process_id
      iep.stop
    end
  end
end


_______________________________________________
Wtr-general mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/wtr-general

Reply via email to