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



85
86
87
88
89
# File 'lib/watir/winClicker.rb', line 85

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



178
179
180
# File 'lib/watir/winClicker.rb', line 178

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



261
262
263
264
# File 'lib/watir/winClicker.rb', line 261

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



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

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



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

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



166
167
168
169
170
171
172
173
174
# File 'lib/watir/winClicker.rb', line 166

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



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
309
310
311
312
313
# File 'lib/watir/winClicker.rb', line 284

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.



269
270
271
272
273
274
275
276
277
278
279
# File 'lib/watir/winClicker.rb', line 269

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



319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
# File 'lib/watir/winClicker.rb', line 319

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



449
450
451
452
453
454
# File 'lib/watir/winClicker.rb', line 449

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



136
137
138
139
140
141
142
143
144
145
# File 'lib/watir/winClicker.rb', line 136

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



402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
# File 'lib/watir/winClicker.rb', line 402

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



184
185
186
187
188
189
# File 'lib/watir/winClicker.rb', line 184

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



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

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



349
350
351
# File 'lib/watir/winClicker.rb', line 349

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



356
357
358
# File 'lib/watir/winClicker.rb', line 356

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



364
365
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
391
392
393
394
395
396
# File 'lib/watir/winClicker.rb', line 364

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



469
470
471
472
473
474
475
476
477
478
479
# File 'lib/watir/winClicker.rb', line 469

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



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/watir/winClicker.rb', line 205

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



458
459
460
461
462
463
# File 'lib/watir/winClicker.rb', line 458

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



253
254
255
256
257
# File 'lib/watir/winClicker.rb', line 253

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



430
431
432
# File 'lib/watir/winClicker.rb', line 430

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.



112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/watir/winClicker.rb', line 112

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



128
129
130
131
132
# File 'lib/watir/winClicker.rb', line 128

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



436
437
438
# File 'lib/watir/winClicker.rb', line 436

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



483
484
485
486
487
488
489
490
491
492
493
494
# File 'lib/watir/winClicker.rb', line 483

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



95
96
97
# File 'lib/watir/winClicker.rb', line 95

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

#with_dl_callback(type, prc) ⇒ Object



192
193
194
195
196
197
198
199
200
# File 'lib/watir/winClicker.rb', line 192

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