Class: WinClicker

Inherits:
Object
  • Object
show all
Defined in:
lib/watir/winClicker.rb

Constant Summary collapse

WM_CLOSE =
0x0010
WM_KEYDOWN =
0x0100
WM_KEYUP =
0x0101
WM_CHAR =
0x0102
BM_CLICK =
0x00F5
WM_COMMAND =
0x0111
WM_SETTEXT =
0x000C
WM_GETTEXT =
0x000D
HWND_TOP =
0
HWND_BOTTOM =
1
HWND_TOPMOST =
-1
HWND_NOTOPMOST =
-2
SWP_SHOWWINDOW =
0x40
SWP_NOSIZE =
1
SWP_NOMOVE =
2
TRUE_1 =
1
WINCLASS_DIALOG =

these are constants for commonly used windows windows

"32770"

Instance Method Summary collapse

Constructor Details

#initializeWinClicker

these are the most used methods



49
50
51
52
53
# File 'lib/watir/winClicker.rb', line 49

def initialize
  @User32 = DL.dlopen("user32")
  # we must determine the path we are in
  @path_to_clicker = '"' + File.expand_path(File.dirname(__FILE__)) + '"'
end

Instance Method Details

#clearSecurityAlertBoxObject Also known as: clear_security_alert

Looks for a window titled “Security Alert”, clicks on Yes button



142
143
144
# File 'lib/watir/winClicker.rb', line 142

def clearSecurityAlertBox
  clickWindowsButton("Security Alert" , "&Yes" )
end

#clickButtonWithHandle(buttonhWnd) ⇒ Object Also known as: click_button_with_handle

Posts a message to the handle passed in to click



225
226
227
228
# File 'lib/watir/winClicker.rb', line 225

def clickButtonWithHandle(buttonhWnd)
  post_message = @User32['PostMessage', 'ILILL']
  r,rs = post_message.call(buttonhWnd, BM_CLICK, 0, 0)
end

#clickJavaScriptDialog(button = "OK", parenthWnd = -1)) ⇒ Object

Click on a dialog with title of “Internet Explorer” Default button to click is “OK” parenthWnd not used



114
115
116
# File 'lib/watir/winClicker.rb', line 114

def clickJavaScriptDialog(button="OK" , parenthWnd = -1)
  clickWindowsButton("Internet Explorer" , button )
end

#clickJSDialog_NewProcess(button = "OK") ⇒ Object

Calls system to launch a new process to click on the button defaults to “OK” button



120
121
122
123
124
125
126
# File 'lib/watir/winClicker.rb', line 120

def clickJSDialog_NewProcess(button = "OK" )
  myapp = "rubyw #{@path_to_clicker}/clickJSDialog.rb #{button}"
  log "Starting win clicker in a new process. Looking for button #{button}"
  log "Starting app: #{myapp}"
  # first argument to system call is a window title, in this case blank ""
  winsystem( "start \"\" #{myapp}" )
end

#clickJSDialog_Thread(button = "OK") ⇒ Object

as a thread



130
131
132
133
134
135
136
137
138
# File 'lib/watir/winClicker.rb', line 130

def clickJSDialog_Thread(button = "OK" )
  sleep 3
  n = 0
  while n < 3
    sleep 1
    clickWindowsButton("Internet Explorer" , button )
    n=n+1
  end
end

#clickWindowsButton(windowCaption, buttonCaption, maxWaitTime = 30) ⇒ Object Also known as: click_windows_button

this clicks the button with the name in the window with the caption. It keeps looking for the button until until the timeout expires



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/watir/winClicker.rb', line 248

def clickWindowsButton (windowCaption , buttonCaption , maxWaitTime=30 )
  sleep 1
  hwnd = -1
  begin 
    timeout(maxWaitTime) do
      hwnd = getWindowHandle(windowCaption)
      while hwnd == -1 
        hwnd = getWindowHandle(windowCaption)
        sleep 0.5
      end
      makeWindowActive(hwnd)
    end
  rescue Timeout::Error 
    return false
  rescue => e
    raise e
  end
  if hwnd != -1 
    makeWindowActive(hwnd)
  else
  end
  d = getChildHandle( hwnd , buttonCaption )
  if d != -1 
    makeWindowActive(hwnd)
    clickButtonWithHandle(d)
  else
    return false
  end
  return true
end

#clickWindowsButton_hwnd(hwnd, buttonCaption) ⇒ Object Also known as: click_windows_button_hwnd

Based on the parent window handle passed in, click on the button with the given caption.



233
234
235
236
237
238
239
240
241
242
243
# File 'lib/watir/winClicker.rb', line 233

def clickWindowsButton_hwnd (hwnd , buttonCaption )
  makeWindowActive(hwnd)
  d = getChildHandle( hwnd , buttonCaption )
  if d != -1 
    makeWindowActive(hwnd)
    clickButtonWithHandle(d)
  else
    return false
  end
  return true
end

#getChildHandle(hWnd, childCaption) ⇒ Object Also known as: get_chwnd

Enumerate through children of the parent hwnd, pass back the handle for the control with the given caption the caption is compared as a regex



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/watir/winClicker.rb', line 283

def getChildHandle ( hWnd , childCaption )
  enum_childWindows = @User32['EnumChildWindows' , 'IIPL' ]
  get_caption_length = @User32['GetWindowTextLengthA' ,'LI' ]    # format here - return value type (Long) followed by parameter types - int in this case -      see http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/~checkout~/ruby/ext/dl/doc/dl.txt?
  get_caption = @User32['GetWindowTextA', 'iLsL' ] 
  match_hwnd = -1  # hWnd of handle matching childCaption
  buff = " " * 16
  get_class_name = @User32['GetClassName', 'ILpI']

  bContinueEnum = -1
  enum_childWindowsProc = lambda {|chwnd,lparam|
    r,rs = get_class_name.call(chwnd, buff, buff.size)
    textLength, a = get_caption_length.call(chwnd)
    captionBuffer = " " * (textLength+1)

    t ,  textCaption  = get_caption.call(chwnd, captionBuffer  , textLength+1)    
    if /#{childCaption}/ =~ textCaption[1].to_s then
      match_hwnd = chwnd
      bContinueEnum = 0  # Windows "false" to discontinue enum_childWindow
    end
    bContinueEnum
  }
  with_dl_callback('ILL',enum_childWindowsProc) do |callback|
    r  = enum_childWindows.call(hWnd, callback  ,0)
  end
  return match_hwnd
end

#getControlText(hWnd) ⇒ Object Also known as: get_ctrl_txt

Get the text in the handle for the given control



413
414
415
416
417
418
# File 'lib/watir/winClicker.rb', line 413

def getControlText(hWnd)
  buff = " " * 256
  send_message = @User32['SendMessage',  'ILIIS']  
  r  ,rs  = send_message.call(hWnd , WM_GETTEXT , 256 , buff )
  return buff.to_s
end

#getFileRequesterFileNameObject

Return the text value from the first combo box on the Choose file dialog or nil if not found



100
101
102
103
104
105
106
107
108
109
# File 'lib/watir/winClicker.rb', line 100

def getFileRequesterFileName()
  # first set the Choose File Window to be active
  hWnd = getWindowHandle("Choose file" )
  if hWnd != -1
    makeWindowActive(hWnd)
    return getTextValueForFileNameField( hWnd ) 
  else
    return nil
  end
end

#getHandleOfControl(hWnd, controlClass, position) ⇒ Object Also known as: get_handle_of_ctrl

returns the handle (or -1 if its not found) of the nth control of this class in the parent window specified by the window handle



366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/watir/winClicker.rb', line 366

def getHandleOfControl (hWnd , controlClass, position )
  enum_childWindows = @User32['EnumChildWindows' , 'IIPL' ]
  get_caption_length = @User32['GetWindowTextLengthA' ,'LI' ]    # format here - return value type (Long) followed by parameter types - int in this case -      see http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/~checkout~/ruby/ext/dl/doc/dl.txt?
  get_caption = @User32['GetWindowTextA', 'iLsL' ] 
  control_hWnd = []
  buff = " " * 16
  get_class_name = @User32['GetClassName', 'ILpI']

  bContinueEnum = -1
  enum_childWindows_proc = lambda {|hWnd,lparam|
    r,rs = get_class_name.call(hWnd, buff, buff.size)
    if rs[1].to_s == controlClass  # there must be a better way of detecting this
      control_hWnd << hWnd
    end
    bContinueEnum
  }
  with_dl_callback('ILL',enum_childWindows_proc) do |callback|
    r  = enum_childWindows.call(hWnd, callback ,0)
  end
  controlHwnd = control_hWnd[position]
  if controlHwnd == nil then
    controlHwnd = -1
  end
  return controlHwnd 
end

#getParent(childhWnd) ⇒ Object Also known as: get_parent

Returns the parent handle for the given child handle



148
149
150
151
152
153
# File 'lib/watir/winClicker.rb', line 148

def getParent (childhWnd )
  # pass a hWnd into this function and it will return the parent hWnd
  getParentWindow = @User32['GetParent' , 'II' ]
  a , b = getParentWindow.call(childhWnd )
  return a
end

#getShortFileName(longName) ⇒ Object

returns the short path version of a long path 8.3 style



65
66
67
68
69
70
71
72
# File 'lib/watir/winClicker.rb', line 65

def getShortFileName(longName)
  size = 255
  buffer = " " * 255
  returnSize = Win32API.new("kernel32" , "GetShortPathNameA" , 'ppl'  , 'L').Call(longName ,  buffer , size )
  a = ""
  a = a + buffer[0...returnSize]        
  return a
end

#getStaticText(caption) ⇒ Object Also known as: get_static_text

Convenience method to return Static text for children of the window with the given caption



313
314
315
# File 'lib/watir/winClicker.rb', line 313

def getStaticText(caption)
  return getStaticTextFromWindow(caption, -1)
end

#getStaticText_hWnd(hWnd) ⇒ Object Also known as: get_static_text_hwnd

Convenience method to return Static text for children of the window handle



320
321
322
# File 'lib/watir/winClicker.rb', line 320

def getStaticText_hWnd (hWnd)
  return getStaticTextFromWindow("" , hWnd)
end

#getStaticTextFromWindow(windowCaption, hWnd) ⇒ Object Also known as: get_static_text_from_window

Return text as an array from child controls of the window given as either a handle or with the given caption that have a class type of Static



328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/watir/winClicker.rb', line 328

def getStaticTextFromWindow( windowCaption  , hWnd)
  enum_childWindows = @User32['EnumChildWindows' , 'IIPL' ]
  get_caption_length = @User32['GetWindowTextLengthA' ,'LI' ]    # format here - return value type (Long) followed by parameter types - int in this case -      see http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/~checkout~/ruby/ext/dl/doc/dl.txt?
  get_caption = @User32['GetWindowTextA', 'iLsL' ] 

  staticText = []
  buff = " " * 16
  get_class_name = @User32['GetClassName', 'ILpI']

  if hWnd == -1
    hWnd = getWindowHandle(windowCaption)
  end

  if hWnd == -1 
    return staticText
  end

  bContinueEnum = -1
  enum_childWindows_proc = lambda {|hWnd,lparam|
    r,rs = get_class_name.call(hWnd, buff, buff.size)
    if rs[1].to_s == "Static"  # there must be a better way of detecting this
      textLength, a = get_caption_length.call(hWnd)
      captionBuffer = " " * (textLength+1)
      t ,  textCaption  = get_caption.call(hWnd, captionBuffer  , textLength+1)    
      staticText << textCaption[1].to_s
    end
    bContinueEnum
  }
  with_dl_callback('ILL',enum_childWindows_proc) do |callback|
    r  = enum_childWindows.call(hWnd, callback  ,0)
  end
  return staticText
end

#getTextValueForFileNameField(parenthWnd) ⇒ Object Also known as: get_file_name

Get the text in the first combo box file requester methods returns nil on failure to locate the 1st combobox



433
434
435
436
437
438
439
440
441
442
443
# File 'lib/watir/winClicker.rb', line 433

def getTextValueForFileNameField(parenthWnd) 
  f = getHandleOfControl(parenthWnd, "ComboBox", 1)
  if f == -1 then
    # unable to find the first combobox
    return nil
  else
    # we have the control and now
    # can send it some messages
    return getWinText(f )
  end
end

#getWindowHandle(title, winclass = "") ⇒ Object Also known as: get_window_handle

Enumerates open windows and returns a window handle from a given title and window class Window class and title are matched regexes



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/watir/winClicker.rb', line 169

def getWindowHandle(title, winclass = "" )
  enum_windows = @User32['EnumWindows', 'IPL']
  get_class_name = @User32['GetClassName', 'ILpI']
  get_caption_length = @User32['GetWindowTextLengthA' ,'LI' ]    # format here - return value type (Long) followed by parameter types - int in this case -      see http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/~checkout~/ruby/ext/dl/doc/dl.txt?
  get_caption = @User32['GetWindowTextA', 'iLsL' ] 

  len = 32
  buff = " " * len
  classMatch = false

  bContinueEnum = -1  # Windows "true" to continue enum_windows.
  found_hwnd = -1

  enum_windows_proc = lambda {|hwnd,lparam|
    sleep 0.05
    r,rs = get_class_name.call(hwnd, buff, buff.size)

    if winclass != "" then
      if /#{winclass}/ =~ rs[1].to_s
        classMatch = true
      end
    else
      classMatch = true
    end

    if classMatch ==true
      textLength, a = get_caption_length.call(hwnd)
      captionBuffer = " " * (textLength+1)
      t ,  textCaption  = get_caption.call(hwnd, captionBuffer  , textLength+1)    
      if /#{title}/ =~ textCaption[1].to_s
        found_hwnd = hwnd
        bContinueEnum = 0 # False, discontinue enum_windows
      end
      bContinueEnum
    else
      bContinueEnum
    end
  }
  with_dl_callback('ILL',enum_windows_proc) do |callback|
    r,rs = enum_windows.call(callback, 0)
  end 
  return found_hwnd
end

#getWindowTitle(hWnd) ⇒ Object Also known as: get_win_title

get the title for the specified hwnd



422
423
424
425
426
427
# File 'lib/watir/winClicker.rb', line 422

def getWindowTitle(hWnd)
  buff = " " * 256
  getWindowText = @User32['GetWindowText' , 'ILSI']
  r , rs = getWindowText.call( hWnd , buff , 256 )
  return buff.to_s
end

#makeWindowActive(hWnd) ⇒ Object Also known as: make_window_active

Call SwitchToThisWindow win32api which will The SwitchToThisWindow function is called to switch focus to a specified window and bring it to the foreground



217
218
219
220
221
# File 'lib/watir/winClicker.rb', line 217

def makeWindowActive (hWnd)
  switch_to_window = @User32['SwitchToThisWindow' , 'pLI'  ]
  # set it to be the one with focus
  switch_to_window.call(hWnd , 1)
end

#setComboBoxText(hWnd, textToSet) ⇒ Object Also known as: set_combo_txt

Call set text on the given window handle



394
395
396
# File 'lib/watir/winClicker.rb', line 394

def setComboBoxText(hWnd , textToSet)
  set_text(hWnd, textToSet)
end

#setFileRequesterFileName(textToSet, tryCount = 3) ⇒ Object

Set the first edit box in the Choose file dialog to textToSet we may need to play with the default try count. 3 is a reasonably safe value.



76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/watir/winClicker.rb', line 76

def setFileRequesterFileName( textToSet, tryCount = 3 )
  for i in (1..tryCount)
    # first set the Choose File Window to be active
    hWnd = getWindowHandle("Choose file" )
    if hWnd != -1
      makeWindowActive(hWnd)
      setTextValueForFileNameField( hWnd , textToSet) 
      clickWindowsButton_hwnd(hWnd, "&Open")
      return true
    end            
  end
  return false
end

#setFileRequesterFileName_newProcess(textToSet) ⇒ Object

fire off setting the file name for the Choose file dialog in a new process



92
93
94
95
96
# File 'lib/watir/winClicker.rb', line 92

def setFileRequesterFileName_newProcess ( textToSet )
  myapp = "rubyw #{@path_to_clicker}/setFileDialog.rb #{textToSet}"
  # first argument to system call is a window title, in this case blank ""      
  winsystem( "start \"\" #{myapp}" )
end

#setTextBoxText(hWnd, textToSet) ⇒ Object Also known as: set_textbox_txt

Call set text on the given window handle



400
401
402
# File 'lib/watir/winClicker.rb', line 400

def setTextBoxText(hWnd , textToSet)
  set_text(hWnd, textToSet)
end

#setTextValueForFileNameField(parenthWnd, textToSet) ⇒ Object Also known as: set_file_name

this sets the filename field to text to set



447
448
449
450
451
452
453
454
455
456
457
458
# File 'lib/watir/winClicker.rb', line 447

def setTextValueForFileNameField( parenthWnd , textToSet ) 
  # get the handle of the nth control that is an Edit box
  f = getHandleOfControl(parenthWnd, "Edit" , 0 )
  if f == -1 then
    # unable to get a handle on the first edit control
    return false
  else
    # we found the control and can now send it some messages
    setComboBoxText(f , textToSet)
    return true
  end
end

#winsystem(command) ⇒ Object

The system function passes command to the command interpreter, which executes the string as an operating-system command msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/crt_system.2c._wsystem.asp using win32api



59
60
61
# File 'lib/watir/winClicker.rb', line 59

def winsystem(command)
  pid  =  Win32API.new("crtdll", "system", ['P'], 'L').Call(command)
end

#with_dl_callback(type, prc) ⇒ Object



156
157
158
159
160
161
162
163
164
# File 'lib/watir/winClicker.rb', line 156

def with_dl_callback(type, prc)
  callback = DL.callback(type, &prc)
  error = nil
  begin
    yield callback
  ensure
    DL.remove_callback(callback)
  end
end