Class: Autogui::Application

Inherits:
Object
  • Object
show all
Includes:
Windows::Handle, Windows::Process, Windows::Synchronize
Defined in:
lib/win32/autogui/application.rb

Overview

The Application class wraps a binary application so that it can be started and controlled via Ruby. This class is meant to be subclassed.

Examples:


class Calculator < Autogui::Application

  def initialize(options = {})
    defaults = {
                 :name => "calc",
                 :title => "Calculator"
               }
    super defaults.merge(options)
  end

  def edit_window
    main_window.children.find {|w| w.window_class == 'Edit'}
  end

  def dialog_about
    Autogui::EnumerateDesktopWindows.new.find do |w| 
      w.title.match(/About Calculator/) && (w.pid == pid)
    end
  end

  def clear_entry
    set_focus
    keystroke(VK_DELETE)
  end
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Application

Returns a new instance of Application.

Examples:

initialize an application on the path


Application.new :name => "calc"  

initialize with full DOS path


Application.new :name => "\\windows\\system32\\calc.exe"  

Parameters:

  • options (Hash) (defaults to: {})

    initialize options

Options Hash (options):

  • :name (String)

    a valid win32 exe name with optional path

  • :title (String)

    the application window title, used along with the pid to locate the application main window, defaults to :name

  • :parameters (Number)

    command line parameters used by Process.create

  • :create_process_timeout (Number) — default: 10

    timeout in seconds to wait for the create_process to return

  • :main_window_timeout (Number) — default: 10

    timeout in seconds to wait for main_window to appear



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/win32/autogui/application.rb', line 104

def initialize(options = {})

  unless options.kind_of?(Hash)
    raise ArgumentError, 'Initialize expecting options to be a Hash'
  end

  @name = options[:name] || name
  @title = options[:title] || name
  @main_window_timeout = options[:main_window_timeout] || 10
  @create_process_timeout = options[:create_process_timeout] || 10
  @parameters = options[:parameters]

  # sanity checks
  raise 'Application name not set' unless name 

  start
end

Instance Attribute Details

#create_process_timeoutNumber

Returns the wait timeout in seconds used by Process.create.

Returns:

  • (Number)

    the wait timeout in seconds used by Process.create



87
88
89
# File 'lib/win32/autogui/application.rb', line 87

def create_process_timeout
  @create_process_timeout
end

#main_window_timeoutNumber

Returns the main_window wait timeout in seconds.

Returns:

  • (Number)

    the main_window wait timeout in seconds



84
85
86
# File 'lib/win32/autogui/application.rb', line 84

def main_window_timeout
  @main_window_timeout
end

#nameString

Returns the executable name of the application.

Returns:

  • (String)

    the executable name of the application



69
70
71
# File 'lib/win32/autogui/application.rb', line 69

def name
  @name
end

#parametersString

Returns the executable application parameters.

Returns:

  • (String)

    the executable application parameters



72
73
74
# File 'lib/win32/autogui/application.rb', line 72

def parameters
  @parameters
end

#pidNumber (readonly)

Returns the process identifier (PID) returned by Process.create.

Returns:

  • (Number)

    the process identifier (PID) returned by Process.create



78
79
80
# File 'lib/win32/autogui/application.rb', line 78

def pid
  @pid
end

#thread_idNumber (readonly)

Returns the process thread id returned by Process.create.

Returns:

  • (Number)

    the process thread id returned by Process.create



81
82
83
# File 'lib/win32/autogui/application.rb', line 81

def thread_id
  @thread_id
end

#titleString

Returns window title of the application.

Returns:

  • (String)

    window title of the application



75
76
77
# File 'lib/win32/autogui/application.rb', line 75

def title
  @title
end

Instance Method Details

#clipboardClipboard

Examples:

set the clipboard text and paste it with Control-V


@calculator.edit_window.set_focus
@calculator.clipboard.text = "12345"
@calculator.edit_window.text.strip.should == "0."
keystroke(VK_CONTROL, VK_V) 
@calculator.edit_window.text.strip.should == "12,345."

Returns:



241
242
243
# File 'lib/win32/autogui/application.rb', line 241

def clipboard
  @clipboard || Autogui::Clipboard.new
end

#close(options = {}) ⇒ Object

Call the main_window’s close method

PostMessage SC_CLOSE and optionally wait for the window to close

Parameters:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :wait_for_close (Boolean) — default: true

    sleep while waiting for timeout or close

  • :timeout (Boolean) — default: 5

    wait_for_close timeout in seconds



194
195
196
# File 'lib/win32/autogui/application.rb', line 194

def close(options={})
  main_window.close(options)
end

#combined_textString

The main_window text including all child windows joined together with newlines. Faciliates matching text.

Examples:

partial match of the Window’s calulator’s about dialog copywrite text


dialog_about = @calculator.dialog_about
dialog_about.title.should == "About Calculator"
dialog_about.combined_text.should match(/Microsoft . Calculator/)

Returns:

  • (String)

    with newlines



227
228
229
# File 'lib/win32/autogui/application.rb', line 227

def combined_text
  main_window.combined_text if running? 
end

#killObject

Send SIGKILL to force the application to die



199
200
201
# File 'lib/win32/autogui/application.rb', line 199

def kill
  Process::kill(9, pid)
end

#main_windowAutogui::Window

The application main window found by enumerating windows by title and application pid. This method will keep looking unit main_window_timeout (default: 10s) is exceeded.

Returns:

Raises:

  • (Exception)

    if the main window cannot be found

See Also:



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/win32/autogui/application.rb', line 167

def main_window
  return @main_window if @main_window

  timeout(main_window_timeout) do
    begin
      # There may be multiple instances, use title and pid to id our main window
      @main_window = Autogui::EnumerateDesktopWindows.new.find do |w| 
        w.title.match(title) && w.pid == pid 
      end
      sleep 0.1 
     end until @main_window
  end

  # sanity checks
  raise "cannot find main_window, check application title" unless @main_window

  @main_window
end

#running?Boolean

Returns if the application is currently running.

Returns:

  • (Boolean)

    if the application is currently running



204
205
206
# File 'lib/win32/autogui/application.rb', line 204

def running?
  main_window && (main_window.is_window?)
end

#set_focusNumber

Set the application input focus to the main_window

Returns:

  • (Number)

    nonzero number if sucess, nil or zero if failed



212
213
214
# File 'lib/win32/autogui/application.rb', line 212

def set_focus
  main_window.set_focus if running? 
end

#startNumber

Start up the binary application via Process.create and set the window focus to the main_window

Returns:

  • (Number)

    the pid

Raises:

  • (Exception)

    if create_process_timeout exceeded

  • (Exception)

    if start failed for any reason other than create_process_timeout



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/win32/autogui/application.rb', line 130

def start
  
  command_line = name
  command_line = name + ' ' + parameters if parameters

  # returns a struct, raises an error if fails
  process_info = Process.create(
     :command_line => command_line,
     :close_handles => false,
     :creation_flags => Process::DETACHED_PROCESS
  )
  @pid = process_info.process_id
  @thread_id = process_info.thread_id
  process_handle = process_info.process_handle
  thread_handle = process_info.thread_handle

  # wait for process
  ret = WaitForInputIdle(process_handle, (create_process_timeout * 1000))

  # done with the handles
  CloseHandle(process_handle)
  CloseHandle(thread_handle)

  raise "Start command failed on create_process_timeout" if ret == WAIT_TIMEOUT 
  raise "Start command failed while waiting for idle input, reason unknown" unless (ret == 0)
  @pid
end