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
