watir 1.6.5 → 1.6.6.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +461 -326
- data/VERSION +1 -0
- data/bin/watir-console +6 -6
- data/lib/changes.rb +3 -3
- data/lib/license.rb +38 -38
- data/lib/readme.rb +140 -140
- data/lib/watir/WindowHelper.rb +49 -49
- data/lib/watir/camel_case.rb +66 -66
- data/lib/watir/clickJSDialog.rb +19 -19
- data/lib/watir/close_all.rb +37 -37
- data/lib/watir/collections.rb +392 -344
- data/lib/watir/container.rb +857 -815
- data/lib/watir/contrib/enabled_popup.rb +20 -20
- data/lib/watir/contrib/ie-new-process.rb +27 -27
- data/lib/watir/contrib/page_checker.rb +29 -29
- data/lib/watir/cookiemanager.rb +55 -55
- data/lib/watir/core.rb +28 -0
- data/lib/watir/core_ext.rb +17 -17
- data/lib/watir/datahandler.rb +107 -107
- data/lib/watir/dialog.rb +46 -46
- data/lib/watir/element.rb +351 -343
- data/lib/watir/element_collections.rb +97 -97
- data/lib/watir/form.rb +170 -170
- data/lib/watir/frame.rb +59 -59
- data/lib/watir/html_element.rb +22 -0
- data/lib/watir/ie-class.rb +1006 -1009
- data/lib/watir/ie-process.rb +39 -39
- data/lib/watir/ie.rb +70 -133
- data/lib/watir/image.rb +130 -130
- data/lib/watir/input_elements.rb +614 -572
- data/lib/watir/irb-history.rb +30 -30
- data/lib/watir/link.rb +64 -64
- data/lib/watir/locator.rb +200 -176
- data/lib/watir/logger.rb +19 -19
- data/lib/watir/modal_dialog.rb +122 -122
- data/lib/watir/module.rb +37 -0
- data/lib/watir/non_control_elements.rb +145 -145
- data/lib/watir/page-container.rb +116 -107
- data/lib/watir/popup.rb +29 -29
- data/lib/watir/process.rb +19 -19
- data/lib/watir/screen_capture.rb +115 -115
- data/lib/watir/setFileDialog.rb +16 -16
- data/lib/watir/table.rb +395 -362
- data/lib/watir/watir_simple.rb +475 -475
- data/lib/watir/win32.rb +35 -35
- data/lib/watir/win32ole.rb +14 -14
- data/lib/watir/winClicker.rb +496 -496
- data/rakefile.rb +70 -0
- data/unittests/all_tests.rb +10 -10
- data/unittests/buttons_xpath_test.rb +69 -69
- data/unittests/checkbox_test.rb +179 -179
- data/unittests/checkbox_xpath_test.rb +107 -107
- data/unittests/click_no_wait_test.rb +21 -0
- data/unittests/core_tests.rb +17 -17
- data/unittests/css_test.rb +42 -35
- data/unittests/defer_test.rb +46 -46
- data/unittests/dialog_test.rb +77 -77
- data/unittests/div2_xpath_test.rb +21 -21
- data/unittests/div_test.rb +188 -188
- data/unittests/div_xpath_test.rb +96 -96
- data/unittests/element_test.rb +49 -0
- data/unittests/errorchecker_test.rb +32 -22
- data/unittests/filefield_test.rb +39 -39
- data/unittests/filefield_xpath_test.rb +33 -33
- data/unittests/form_test.rb +280 -280
- data/unittests/form_xpath_test.rb +252 -252
- data/unittests/frame_test.rb +155 -155
- data/unittests/google_form_test.rb +15 -15
- data/unittests/html/JavascriptClick.html +39 -39
- data/unittests/html/blankpage.html +11 -11
- data/unittests/html/buttons1.html +40 -40
- data/unittests/html/checkboxes1.html +89 -89
- data/unittests/html/click_no_wait.html +14 -0
- data/unittests/html/complex_table.html +36 -36
- data/unittests/html/cssTest.html +42 -42
- data/unittests/html/depot_store.html +59 -59
- data/unittests/html/div.html +93 -93
- data/unittests/html/div_xml.html +20 -20
- data/unittests/html/fileupload.html +45 -45
- data/unittests/html/formTest1.html +38 -38
- data/unittests/html/forms2.html +44 -44
- data/unittests/html/forms3.html +131 -131
- data/unittests/html/forms4.html +27 -27
- data/unittests/html/frame_buttons.html +3 -3
- data/unittests/html/frame_links.html +3 -3
- data/unittests/html/frame_multi.html +4 -4
- data/unittests/html/google_india.html +119 -119
- data/unittests/html/iframeTest.html +12 -12
- data/unittests/html/iframeTest1.html +6 -6
- data/unittests/html/iframeTest2.html +5 -5
- data/unittests/html/images1.html +66 -66
- data/unittests/html/javascriptevents.html +35 -35
- data/unittests/html/link_pass.html +10 -10
- data/unittests/html/links1.html +38 -38
- data/unittests/html/links2.html +10 -10
- data/unittests/html/links_multi.html +14 -14
- data/unittests/html/list_matters.html +720 -720
- data/unittests/html/lists.html +17 -17
- data/unittests/html/map_test.html +31 -31
- data/unittests/html/modal_dialog.html +10 -10
- data/unittests/html/modal_dialog_launcher.html +11 -11
- data/unittests/html/nestedFrames.html +6 -6
- data/unittests/html/new_browser.html +16 -16
- data/unittests/html/pass.html +12 -12
- data/unittests/html/popups1.html +59 -59
- data/unittests/html/pre.html +27 -27
- data/unittests/html/radioButtons1.html +71 -71
- data/unittests/html/select_tealeaf.html +54 -54
- data/unittests/html/selectboxes1.html +52 -52
- data/unittests/html/simple_table.html +26 -26
- data/unittests/html/simple_table_buttons.html +104 -104
- data/unittests/html/simple_table_columns.html +76 -76
- data/unittests/html/table1.html +181 -181
- data/unittests/html/tableCell_using_xpath.html +19 -19
- data/unittests/html/table_and_tablerow_to_a.html +174 -0
- data/unittests/html/textarea.html +30 -30
- data/unittests/html/textfields1.html +88 -88
- data/unittests/html/textsearch.html +44 -44
- data/unittests/html/wallofcheckboxes.html +1003 -1003
- data/unittests/html/xpath_nbsp.html +12 -12
- data/unittests/ie_exists_test.rb +33 -33
- data/unittests/ie_mock.rb +94 -94
- data/unittests/ie_test.rb +51 -51
- data/unittests/images_test.rb +157 -157
- data/unittests/images_xpath_test.rb +91 -91
- data/unittests/links_multi_test.rb +48 -48
- data/unittests/links_test.rb +175 -175
- data/unittests/links_xpath_test.rb +39 -39
- data/unittests/lists_test.rb +32 -32
- data/unittests/map_test.rb +98 -98
- data/unittests/minmax_test.rb +31 -31
- data/unittests/navigate_test.rb +39 -39
- data/unittests/nbsp_xpath_test.rb +16 -16
- data/unittests/non_core_tests.rb +12 -12
- data/unittests/other/WindowLogonExample.rb +27 -27
- data/unittests/other/WindowLogonExtra.rb +6 -6
- data/unittests/other/all_tests_concurrent.rb +57 -57
- data/unittests/other/jscriptExtraAlert.rb +6 -6
- data/unittests/other/jscriptExtraConfirmCancel.rb +6 -6
- data/unittests/other/jscriptExtraConfirmOk.rb +6 -6
- data/unittests/other/jscriptPushButton.rb +6 -6
- data/unittests/other/jscript_test.rb +63 -63
- data/unittests/other/navigate_exception_test.rb +24 -24
- data/unittests/other/rexml_unit_test.rb +27 -27
- data/unittests/other/screen_capture_test.rb +54 -54
- data/unittests/other/testcase_method_order_test.rb +35 -35
- data/unittests/other/testcase_verify_test.rb +24 -24
- data/unittests/other/wait_until_test.rb +99 -99
- data/unittests/pagecontainstext_test.rb +69 -69
- data/unittests/parent_child_test.rb +43 -43
- data/unittests/perf_test.rb +20 -20
- data/unittests/popups_test.rb +43 -43
- data/unittests/pre_test.rb +53 -53
- data/unittests/radios_test.rb +212 -212
- data/unittests/radios_xpath_test.rb +101 -101
- data/unittests/security_setting_test.rb +23 -23
- data/unittests/selectbox_test.rb +148 -148
- data/unittests/selectbox_xpath_test.rb +113 -113
- data/unittests/setup.rb +87 -77
- data/unittests/speed_settings_test.rb +67 -67
- data/unittests/table_and_tablerow_to_a_test.rb +117 -0
- data/unittests/table_cell_using_xpath_test.rb +35 -35
- data/unittests/table_test.rb +376 -376
- data/unittests/table_xpath_test.rb +110 -110
- data/unittests/test_tests.rb +9 -9
- data/unittests/textarea_test.rb +92 -92
- data/unittests/textarea_xpath_test.rb +78 -78
- data/unittests/textfield_for_ch_char_test.rb +31 -31
- data/unittests/textfields_test.rb +218 -218
- data/unittests/textfields_xpath_test.rb +111 -111
- data/unittests/window_tests.rb +10 -10
- data/unittests/windows/attach_to_existing_window_test.rb +53 -53
- data/unittests/windows/attach_to_new_window_test.rb +83 -83
- data/unittests/windows/close_window_test.rb +20 -20
- data/unittests/windows/frame_links_test.rb +25 -25
- data/unittests/windows/ie-each_test.rb +47 -47
- data/unittests/windows/iedialog_test.rb +54 -54
- data/unittests/windows/js_events_test.rb +42 -55
- data/unittests/windows/modal_dialog_test.rb +128 -128
- data/unittests/windows/new_test.rb +57 -57
- data/unittests/windows/open_close_test.rb +18 -18
- data/unittests/windows/send_keys_test.rb +33 -33
- data/unittests/xpath_tests.rb +10 -10
- metadata +85 -31
- data/lib/watir/utils.rb +0 -20
- data/lib/watir/version.rb +0 -5
data/lib/watir/win32.rb
CHANGED
@@ -1,36 +1,36 @@
|
|
1
|
-
module Watir
|
2
|
-
module Win32
|
3
|
-
# this will find the IEDialog.dll file in its build location
|
4
|
-
@@iedialog_file = (File.expand_path(File.dirname(__FILE__) + '/..') + "/watir/IEDialog/Release/IEDialog.dll").gsub('/', '\\')
|
5
|
-
|
6
|
-
GetUnknown = Win32API.new(@@iedialog_file, 'GetUnknown', ['l', 'p'], 'v')
|
7
|
-
User32 = DL.dlopen('user32')
|
8
|
-
if RUBY_VERSION =~ /^1\.8/
|
9
|
-
FindWindowEx = User32['FindWindowEx', 'LLLpp']
|
10
|
-
# method for this found in wet-winobj/wet/winobjects/WinUtils.rb
|
11
|
-
GetWindow = User32['GetWindow', 'ILL']
|
12
|
-
IsWindow = User32['IsWindow', 'II']
|
13
|
-
else
|
14
|
-
FindWindowEx = GetWindow = IsWindow = lambda do |*args|
|
15
|
-
raise NotImplementedError, "1.9's DL API not compatible with 1.8, see http://www.ruby-forum.com/topic/138277"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
## GetWindows Constants
|
20
|
-
GW_HWNDFIRST = 0
|
21
|
-
GW_HWNDLAST = 1
|
22
|
-
GW_HWNDNEXT = 2
|
23
|
-
GW_HWNDPREV = 3
|
24
|
-
GW_OWNER = 4
|
25
|
-
GW_CHILD = 5
|
26
|
-
GW_ENABLEDPOPUP = 6
|
27
|
-
GW_MAX = 6
|
28
|
-
|
29
|
-
|
30
|
-
# Does the window with the specified window handle (hwnd) exist?
|
31
|
-
def self.window_exists? hwnd
|
32
|
-
rtn, junk = IsWindow[hwnd]
|
33
|
-
rtn == 1
|
34
|
-
end
|
35
|
-
end
|
1
|
+
module Watir
|
2
|
+
module Win32
|
3
|
+
# this will find the IEDialog.dll file in its build location
|
4
|
+
@@iedialog_file = (File.expand_path(File.dirname(__FILE__) + '/..') + "/watir/IEDialog/Release/IEDialog.dll").gsub('/', '\\')
|
5
|
+
|
6
|
+
GetUnknown = Win32API.new(@@iedialog_file, 'GetUnknown', ['l', 'p'], 'v')
|
7
|
+
User32 = DL.dlopen('user32')
|
8
|
+
if RUBY_VERSION =~ /^1\.8/
|
9
|
+
FindWindowEx = User32['FindWindowEx', 'LLLpp']
|
10
|
+
# method for this found in wet-winobj/wet/winobjects/WinUtils.rb
|
11
|
+
GetWindow = User32['GetWindow', 'ILL']
|
12
|
+
IsWindow = User32['IsWindow', 'II']
|
13
|
+
else
|
14
|
+
FindWindowEx = GetWindow = IsWindow = lambda do |*args|
|
15
|
+
raise NotImplementedError, "1.9's DL API not compatible with 1.8, see http://www.ruby-forum.com/topic/138277"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
## GetWindows Constants
|
20
|
+
GW_HWNDFIRST = 0
|
21
|
+
GW_HWNDLAST = 1
|
22
|
+
GW_HWNDNEXT = 2
|
23
|
+
GW_HWNDPREV = 3
|
24
|
+
GW_OWNER = 4
|
25
|
+
GW_CHILD = 5
|
26
|
+
GW_ENABLEDPOPUP = 6
|
27
|
+
GW_MAX = 6
|
28
|
+
|
29
|
+
|
30
|
+
# Does the window with the specified window handle (hwnd) exist?
|
31
|
+
def self.window_exists? hwnd
|
32
|
+
rtn, junk = IsWindow[hwnd]
|
33
|
+
rtn == 1
|
34
|
+
end
|
35
|
+
end
|
36
36
|
end
|
data/lib/watir/win32ole.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
# load the correct version of win32ole
|
2
|
-
|
3
|
-
# Use our modified win32ole library
|
4
|
-
|
5
|
-
if RUBY_VERSION =~ /^1\.8/
|
6
|
-
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', 'watir', 'win32ole'))
|
7
|
-
else
|
8
|
-
# loading win32ole from stdlib on 1.9
|
9
|
-
end
|
10
|
-
|
11
|
-
|
12
|
-
require 'win32ole'
|
13
|
-
|
14
|
-
WIN32OLE.codepage = WIN32OLE::CP_UTF8
|
1
|
+
# load the correct version of win32ole
|
2
|
+
|
3
|
+
# Use our modified win32ole library
|
4
|
+
|
5
|
+
if RUBY_VERSION =~ /^1\.8/
|
6
|
+
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', 'watir', 'win32ole'))
|
7
|
+
else
|
8
|
+
# loading win32ole from stdlib on 1.9
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
require 'win32ole'
|
13
|
+
|
14
|
+
WIN32OLE.codepage = WIN32OLE::CP_UTF8
|
data/lib/watir/winClicker.rb
CHANGED
@@ -1,496 +1,496 @@
|
|
1
|
-
=begin
|
2
|
-
license
|
3
|
-
---------------------------------------------------------------------------
|
4
|
-
Copyright (c) 2004-2006, Paul Rogers and Bret Pettichord
|
5
|
-
All rights reserved.
|
6
|
-
|
7
|
-
Redistribution and use in source and binary forms, with or without
|
8
|
-
modification, are permitted provided that the following conditions are met:
|
9
|
-
|
10
|
-
1. Redistributions of source code must retain the above copyright notice,
|
11
|
-
this list of conditions and the following disclaimer.
|
12
|
-
|
13
|
-
2. Redistributions in binary form must reproduce the above copyright
|
14
|
-
notice, this list of conditions and the following disclaimer in the
|
15
|
-
documentation and/or other materials provided with the distribution.
|
16
|
-
|
17
|
-
3. Neither the names Paul Rogers, nor Bret Pettichord nor the names of any
|
18
|
-
other contributors to this software may be used to endorse or promote
|
19
|
-
products derived from this software without specific prior written
|
20
|
-
permission.
|
21
|
-
|
22
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
23
|
-
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
24
|
-
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
25
|
-
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
|
26
|
-
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
27
|
-
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
28
|
-
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
29
|
-
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
30
|
-
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
31
|
-
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
32
|
-
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
33
|
-
--------------------------------------------------------------------------
|
34
|
-
(based on BSD Open Source License)
|
35
|
-
=end
|
36
|
-
|
37
|
-
=begin rdoc
|
38
|
-
This is Watir's window clicker helper class, uses Win32 api
|
39
|
-
calls to access buttons and windows.
|
40
|
-
|
41
|
-
Typical usage:
|
42
|
-
# include this file in your script
|
43
|
-
require "watir/winClicker.rb"
|
44
|
-
|
45
|
-
# create a new instance of WinClicker and use it
|
46
|
-
wc = WinClicker.new
|
47
|
-
wc.clickWindowsButton("My Window", "Click Me", 30)
|
48
|
-
|
49
|
-
=end
|
50
|
-
|
51
|
-
#
|
52
|
-
# class to click javascript dialog boxes, file requester dialogs etc
|
53
|
-
require 'dl/import'
|
54
|
-
require 'dl/struct'
|
55
|
-
require "timeout"
|
56
|
-
require 'Win32API'
|
57
|
-
|
58
|
-
class WinClicker
|
59
|
-
|
60
|
-
WM_CLOSE = 0x0010
|
61
|
-
WM_KEYDOWN = 0x0100
|
62
|
-
WM_KEYUP = 0x0101
|
63
|
-
WM_CHAR = 0x0102
|
64
|
-
BM_CLICK = 0x00F5
|
65
|
-
WM_COMMAND = 0x0111
|
66
|
-
WM_SETTEXT = 0x000C
|
67
|
-
WM_GETTEXT = 0x000D
|
68
|
-
|
69
|
-
HWND_TOP = 0
|
70
|
-
HWND_BOTTOM = 1
|
71
|
-
HWND_TOPMOST = -1
|
72
|
-
HWND_NOTOPMOST = -2
|
73
|
-
|
74
|
-
SWP_SHOWWINDOW = 0x40
|
75
|
-
SWP_NOSIZE = 1
|
76
|
-
SWP_NOMOVE = 2
|
77
|
-
|
78
|
-
TRUE_1 = 1
|
79
|
-
|
80
|
-
# these are constants for commonly used windows windows
|
81
|
-
WINCLASS_DIALOG = "32770"
|
82
|
-
|
83
|
-
# these are the most used methods
|
84
|
-
|
85
|
-
def initialize
|
86
|
-
@User32 = DL.dlopen("user32")
|
87
|
-
# we must determine the path we are in
|
88
|
-
@path_to_clicker = '"' + File.expand_path(File.dirname(__FILE__)) + '"'
|
89
|
-
end
|
90
|
-
|
91
|
-
|
92
|
-
# The system function passes command to the command interpreter, which executes the string as an operating-system command
|
93
|
-
# http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_system.2c_._wsystem.asp
|
94
|
-
# using win32api
|
95
|
-
def winsystem(command)
|
96
|
-
pid = Win32API.new("crtdll", "system", ['P'], 'L').Call(command)
|
97
|
-
end
|
98
|
-
|
99
|
-
# returns the short path version of a long path
|
100
|
-
# 8.3 style
|
101
|
-
def getShortFileName(longName)
|
102
|
-
size = 255
|
103
|
-
buffer = " " * 255
|
104
|
-
returnSize = Win32API.new("kernel32" , "GetShortPathNameA" , 'ppl' , 'L').Call(longName , buffer , size )
|
105
|
-
a = ""
|
106
|
-
a = a + buffer[0...returnSize]
|
107
|
-
return a
|
108
|
-
end
|
109
|
-
|
110
|
-
# Set the first edit box in the Choose file dialog to textToSet
|
111
|
-
# we may need to play with the default try count. 3 is a reasonably safe value.
|
112
|
-
def setFileRequesterFileName( textToSet, tryCount = 3 )
|
113
|
-
for i in (1..tryCount)
|
114
|
-
# first set the Choose File Window to be active
|
115
|
-
hWnd = getWindowHandle("Choose file" )
|
116
|
-
if hWnd != -1
|
117
|
-
makeWindowActive(hWnd)
|
118
|
-
setTextValueForFileNameField( hWnd , textToSet)
|
119
|
-
clickWindowsButton_hwnd(hWnd, "&Open")
|
120
|
-
return true
|
121
|
-
end
|
122
|
-
end
|
123
|
-
return false
|
124
|
-
end
|
125
|
-
|
126
|
-
# fire off setting the file name for the Choose file dialog
|
127
|
-
# in a new process
|
128
|
-
def setFileRequesterFileName_newProcess ( textToSet )
|
129
|
-
myapp = "rubyw #{@path_to_clicker}/setFileDialog.rb #{textToSet}"
|
130
|
-
# first argument to system call is a window title, in this case blank ""
|
131
|
-
winsystem( "start \"\" #{myapp}" )
|
132
|
-
end
|
133
|
-
|
134
|
-
# Return the text value from the first combo box
|
135
|
-
# on the Choose file dialog or nil if not found
|
136
|
-
def getFileRequesterFileName()
|
137
|
-
# first set the Choose File Window to be active
|
138
|
-
hWnd = getWindowHandle("Choose file" )
|
139
|
-
if hWnd != -1
|
140
|
-
makeWindowActive(hWnd)
|
141
|
-
return getTextValueForFileNameField( hWnd )
|
142
|
-
else
|
143
|
-
return nil
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
# Click on a dialog with title of "Internet Explorer"
|
148
|
-
# Default button to click is "OK"
|
149
|
-
# parenthWnd not used
|
150
|
-
def clickJavaScriptDialog(button="OK" , parenthWnd = -1)
|
151
|
-
clickWindowsButton("Internet Explorer" , button )
|
152
|
-
end
|
153
|
-
|
154
|
-
# Calls system to launch a new process to click on the button
|
155
|
-
# defaults to "OK" button
|
156
|
-
def clickJSDialog_NewProcess(button = "OK" )
|
157
|
-
myapp = "rubyw #{@path_to_clicker}/clickJSDialog.rb #{button}"
|
158
|
-
log "Starting win clicker in a new process. Looking for button #{button}"
|
159
|
-
log "Starting app: #{myapp}"
|
160
|
-
# first argument to system call is a window title, in this case blank ""
|
161
|
-
winsystem( "start \"\" #{myapp}" )
|
162
|
-
end
|
163
|
-
|
164
|
-
|
165
|
-
# as a thread
|
166
|
-
def clickJSDialog_Thread(button = "OK" )
|
167
|
-
sleep 3
|
168
|
-
n = 0
|
169
|
-
while n < 3
|
170
|
-
sleep 1
|
171
|
-
clickWindowsButton("Internet Explorer" , button )
|
172
|
-
n=n+1
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
# Looks for a window titled "Security Alert", clicks
|
177
|
-
# on Yes button
|
178
|
-
def clearSecurityAlertBox
|
179
|
-
clickWindowsButton("Security Alert" , "&Yes" )
|
180
|
-
end
|
181
|
-
alias :clear_security_alert :clearSecurityAlertBox
|
182
|
-
|
183
|
-
# Returns the parent handle for the given child handle
|
184
|
-
def getParent (childhWnd )
|
185
|
-
# pass a hWnd into this function and it will return the parent hWnd
|
186
|
-
getParentWindow = @User32['GetParent' , 'II' ]
|
187
|
-
a , b = getParentWindow.call(childhWnd )
|
188
|
-
return a
|
189
|
-
end
|
190
|
-
alias :get_parent :getParent
|
191
|
-
|
192
|
-
def with_dl_callback(type, prc)
|
193
|
-
callback = DL.callback(type, &prc)
|
194
|
-
error = nil
|
195
|
-
begin
|
196
|
-
yield callback
|
197
|
-
ensure
|
198
|
-
DL.remove_callback(callback)
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
# Enumerates open windows and
|
203
|
-
# returns a window handle from a given title and window class
|
204
|
-
# Window class and title are matched regexes
|
205
|
-
def getWindowHandle(title, winclass = "" )
|
206
|
-
enum_windows = @User32['EnumWindows', 'IPL']
|
207
|
-
get_class_name = @User32['GetClassName', 'ILpI']
|
208
|
-
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?
|
209
|
-
get_caption = @User32['GetWindowTextA', 'iLsL' ]
|
210
|
-
|
211
|
-
len = 32
|
212
|
-
buff = " " * len
|
213
|
-
classMatch = false
|
214
|
-
|
215
|
-
bContinueEnum = -1 # Windows "true" to continue enum_windows.
|
216
|
-
found_hwnd = -1
|
217
|
-
|
218
|
-
enum_windows_proc = lambda {|hwnd,lparam|
|
219
|
-
sleep 0.05
|
220
|
-
r,rs = get_class_name.call(hwnd, buff, buff.size)
|
221
|
-
|
222
|
-
if winclass != "" then
|
223
|
-
if /#{winclass}/ =~ rs[1].to_s
|
224
|
-
classMatch = true
|
225
|
-
end
|
226
|
-
else
|
227
|
-
classMatch = true
|
228
|
-
end
|
229
|
-
|
230
|
-
if classMatch ==true
|
231
|
-
textLength, a = get_caption_length.call(hwnd)
|
232
|
-
captionBuffer = " " * (textLength+1)
|
233
|
-
t , textCaption = get_caption.call(hwnd, captionBuffer , textLength+1)
|
234
|
-
if /#{title}/ =~ textCaption[1].to_s
|
235
|
-
found_hwnd = hwnd
|
236
|
-
bContinueEnum = 0 # False, discontinue enum_windows
|
237
|
-
end
|
238
|
-
bContinueEnum
|
239
|
-
else
|
240
|
-
bContinueEnum
|
241
|
-
end
|
242
|
-
}
|
243
|
-
with_dl_callback('ILL',enum_windows_proc) do |callback|
|
244
|
-
r,rs = enum_windows.call(callback, 0)
|
245
|
-
end
|
246
|
-
return found_hwnd
|
247
|
-
end
|
248
|
-
alias :get_window_handle :getWindowHandle
|
249
|
-
|
250
|
-
# Call SwitchToThisWindow win32api which will
|
251
|
-
# The SwitchToThisWindow function is called to switch focus to a specified window
|
252
|
-
# and bring it to the foreground
|
253
|
-
def makeWindowActive (hWnd)
|
254
|
-
switch_to_window = @User32['SwitchToThisWindow' , 'pLI' ]
|
255
|
-
# set it to be the one with focus
|
256
|
-
switch_to_window.call(hWnd , 1)
|
257
|
-
end
|
258
|
-
alias :make_window_active :makeWindowActive
|
259
|
-
|
260
|
-
# Posts a message to the handle passed in to click
|
261
|
-
def clickButtonWithHandle(buttonhWnd)
|
262
|
-
post_message = @User32['PostMessage', 'ILILL']
|
263
|
-
r,rs = post_message.call(buttonhWnd, BM_CLICK, 0, 0)
|
264
|
-
end
|
265
|
-
alias :click_button_with_handle :clickButtonWithHandle
|
266
|
-
|
267
|
-
# Based on the parent window handle passed in,
|
268
|
-
# click on the button with the given caption.
|
269
|
-
def clickWindowsButton_hwnd (hwnd , buttonCaption )
|
270
|
-
makeWindowActive(hwnd)
|
271
|
-
d = getChildHandle( hwnd , buttonCaption )
|
272
|
-
if d != -1
|
273
|
-
makeWindowActive(hwnd)
|
274
|
-
clickButtonWithHandle(d)
|
275
|
-
else
|
276
|
-
return false
|
277
|
-
end
|
278
|
-
return true
|
279
|
-
end
|
280
|
-
alias :click_windows_button_hwnd :clickWindowsButton_hwnd
|
281
|
-
|
282
|
-
# this clicks the button with the name in the window with the caption. It keeps looking for the button until
|
283
|
-
# until the timeout expires
|
284
|
-
def clickWindowsButton (windowCaption , buttonCaption , maxWaitTime=30 )
|
285
|
-
sleep 1
|
286
|
-
hwnd = -1
|
287
|
-
begin
|
288
|
-
timeout(maxWaitTime) do
|
289
|
-
hwnd = getWindowHandle(windowCaption)
|
290
|
-
while hwnd == -1
|
291
|
-
hwnd = getWindowHandle(windowCaption)
|
292
|
-
sleep 0.5
|
293
|
-
end
|
294
|
-
makeWindowActive(hwnd)
|
295
|
-
end
|
296
|
-
rescue Timeout::Error
|
297
|
-
return false
|
298
|
-
rescue => e
|
299
|
-
raise e
|
300
|
-
end
|
301
|
-
if hwnd != -1
|
302
|
-
makeWindowActive(hwnd)
|
303
|
-
else
|
304
|
-
end
|
305
|
-
d = getChildHandle( hwnd , buttonCaption )
|
306
|
-
if d != -1
|
307
|
-
makeWindowActive(hwnd)
|
308
|
-
clickButtonWithHandle(d)
|
309
|
-
else
|
310
|
-
return false
|
311
|
-
end
|
312
|
-
return true
|
313
|
-
end
|
314
|
-
alias :click_windows_button :clickWindowsButton
|
315
|
-
|
316
|
-
# Enumerate through children of the parent hwnd, pass back
|
317
|
-
# the handle for the control with the given caption
|
318
|
-
# the caption is compared as a regex
|
319
|
-
def getChildHandle ( hWnd , childCaption )
|
320
|
-
enum_childWindows = @User32['EnumChildWindows' , 'IIPL' ]
|
321
|
-
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?
|
322
|
-
get_caption = @User32['GetWindowTextA', 'iLsL' ]
|
323
|
-
match_hwnd = -1 # hWnd of handle matching childCaption
|
324
|
-
buff = " " * 16
|
325
|
-
get_class_name = @User32['GetClassName', 'ILpI']
|
326
|
-
|
327
|
-
bContinueEnum = -1
|
328
|
-
enum_childWindowsProc = lambda {|chwnd,lparam|
|
329
|
-
r,rs = get_class_name.call(chwnd, buff, buff.size)
|
330
|
-
textLength, a = get_caption_length.call(chwnd)
|
331
|
-
captionBuffer = " " * (textLength+1)
|
332
|
-
|
333
|
-
t , textCaption = get_caption.call(chwnd, captionBuffer , textLength+1)
|
334
|
-
if /#{childCaption}/ =~ textCaption[1].to_s then
|
335
|
-
match_hwnd = chwnd
|
336
|
-
bContinueEnum = 0 # Windows "false" to discontinue enum_childWindow
|
337
|
-
end
|
338
|
-
bContinueEnum
|
339
|
-
}
|
340
|
-
with_dl_callback('ILL',enum_childWindowsProc) do |callback|
|
341
|
-
r = enum_childWindows.call(hWnd, callback ,0)
|
342
|
-
end
|
343
|
-
return match_hwnd
|
344
|
-
end
|
345
|
-
alias :get_chwnd :getChildHandle
|
346
|
-
|
347
|
-
# Convenience method to return Static text for
|
348
|
-
# children of the window with the given caption
|
349
|
-
def getStaticText(caption)
|
350
|
-
return getStaticTextFromWindow(caption, -1)
|
351
|
-
end
|
352
|
-
alias :get_static_text :getStaticText
|
353
|
-
|
354
|
-
# Convenience method to return Static text for
|
355
|
-
# children of the window handle
|
356
|
-
def getStaticText_hWnd (hWnd)
|
357
|
-
return getStaticTextFromWindow("" , hWnd)
|
358
|
-
end
|
359
|
-
alias :get_static_text_hwnd :getStaticText_hWnd
|
360
|
-
|
361
|
-
# Return text as an array from child controls of the window
|
362
|
-
# given as either a handle or with the given caption
|
363
|
-
# that have a class type of Static
|
364
|
-
def getStaticTextFromWindow( windowCaption , hWnd)
|
365
|
-
enum_childWindows = @User32['EnumChildWindows' , 'IIPL' ]
|
366
|
-
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?
|
367
|
-
get_caption = @User32['GetWindowTextA', 'iLsL' ]
|
368
|
-
|
369
|
-
staticText = []
|
370
|
-
buff = " " * 16
|
371
|
-
get_class_name = @User32['GetClassName', 'ILpI']
|
372
|
-
|
373
|
-
if hWnd == -1
|
374
|
-
hWnd = getWindowHandle(windowCaption)
|
375
|
-
end
|
376
|
-
|
377
|
-
if hWnd == -1
|
378
|
-
return staticText
|
379
|
-
end
|
380
|
-
|
381
|
-
bContinueEnum = -1
|
382
|
-
enum_childWindows_proc = lambda {|hWnd,lparam|
|
383
|
-
r,rs = get_class_name.call(hWnd, buff, buff.size)
|
384
|
-
if rs[1].to_s == "Static" # there must be a better way of detecting this
|
385
|
-
textLength, a = get_caption_length.call(hWnd)
|
386
|
-
captionBuffer = " " * (textLength+1)
|
387
|
-
t , textCaption = get_caption.call(hWnd, captionBuffer , textLength+1)
|
388
|
-
staticText << textCaption[1].to_s
|
389
|
-
end
|
390
|
-
bContinueEnum
|
391
|
-
}
|
392
|
-
with_dl_callback('ILL',enum_childWindows_proc) do |callback|
|
393
|
-
r = enum_childWindows.call(hWnd, callback ,0)
|
394
|
-
end
|
395
|
-
return staticText
|
396
|
-
end
|
397
|
-
alias :get_static_text_from_window :getStaticTextFromWindow
|
398
|
-
|
399
|
-
# returns the handle (or -1 if its not found) of the
|
400
|
-
# nth control of this class in the parent window specified
|
401
|
-
# by the window handle
|
402
|
-
def getHandleOfControl (hWnd , controlClass, position )
|
403
|
-
enum_childWindows = @User32['EnumChildWindows' , 'IIPL' ]
|
404
|
-
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?
|
405
|
-
get_caption = @User32['GetWindowTextA', 'iLsL' ]
|
406
|
-
control_hWnd = []
|
407
|
-
buff = " " * 16
|
408
|
-
get_class_name = @User32['GetClassName', 'ILpI']
|
409
|
-
|
410
|
-
bContinueEnum = -1
|
411
|
-
enum_childWindows_proc = lambda {|hWnd,lparam|
|
412
|
-
r,rs = get_class_name.call(hWnd, buff, buff.size)
|
413
|
-
if rs[1].to_s == controlClass # there must be a better way of detecting this
|
414
|
-
control_hWnd << hWnd
|
415
|
-
end
|
416
|
-
bContinueEnum
|
417
|
-
}
|
418
|
-
with_dl_callback('ILL',enum_childWindows_proc) do |callback|
|
419
|
-
r = enum_childWindows.call(hWnd, callback ,0)
|
420
|
-
end
|
421
|
-
controlHwnd = control_hWnd[position]
|
422
|
-
if controlHwnd == nil then
|
423
|
-
controlHwnd = -1
|
424
|
-
end
|
425
|
-
return controlHwnd
|
426
|
-
end
|
427
|
-
alias :get_handle_of_ctrl :getHandleOfControl
|
428
|
-
|
429
|
-
# Call set text on the given window handle
|
430
|
-
def setComboBoxText(hWnd , textToSet)
|
431
|
-
set_text(hWnd, textToSet)
|
432
|
-
end
|
433
|
-
alias :set_combo_txt :setComboBoxText
|
434
|
-
|
435
|
-
# Call set text on the given window handle
|
436
|
-
def setTextBoxText(hWnd , textToSet)
|
437
|
-
set_text(hWnd, textToSet)
|
438
|
-
end
|
439
|
-
alias :set_textbox_txt :setTextBoxText
|
440
|
-
|
441
|
-
# Private method to set text called by the two methods above
|
442
|
-
def set_text(hWnd, textToSet)
|
443
|
-
send_message = @User32['SendMessage', 'ILISS']
|
444
|
-
r ,rs = send_message.call(hWnd , WM_SETTEXT ,'',textToSet)
|
445
|
-
end
|
446
|
-
private :set_text
|
447
|
-
|
448
|
-
# Get the text in the handle for the given control
|
449
|
-
def getControlText(hWnd)
|
450
|
-
buff = " " * 256
|
451
|
-
send_message = @User32['SendMessage', 'ILIIS']
|
452
|
-
r ,rs = send_message.call(hWnd , WM_GETTEXT , 256 , buff )
|
453
|
-
return buff.to_s
|
454
|
-
end
|
455
|
-
alias :get_ctrl_txt :getControlText
|
456
|
-
|
457
|
-
# get the title for the specified hwnd
|
458
|
-
def getWindowTitle(hWnd)
|
459
|
-
buff = " " * 256
|
460
|
-
getWindowText = @User32['GetWindowText' , 'ILSI']
|
461
|
-
r , rs = getWindowText.call( hWnd , buff , 256 )
|
462
|
-
return buff.to_s
|
463
|
-
end
|
464
|
-
alias :get_win_title :getWindowTitle
|
465
|
-
|
466
|
-
# Get the text in the first combo box
|
467
|
-
# file requester methods returns nil on failure to
|
468
|
-
# locate the 1st combobox
|
469
|
-
def getTextValueForFileNameField(parenthWnd)
|
470
|
-
f = getHandleOfControl(parenthWnd, "ComboBox", 1)
|
471
|
-
if f == -1 then
|
472
|
-
# unable to find the first combobox
|
473
|
-
return nil
|
474
|
-
else
|
475
|
-
# we have the control and now
|
476
|
-
# can send it some messages
|
477
|
-
return getWinText(f )
|
478
|
-
end
|
479
|
-
end
|
480
|
-
alias :get_file_name :getTextValueForFileNameField
|
481
|
-
|
482
|
-
# this sets the filename field to text to set
|
483
|
-
def setTextValueForFileNameField( parenthWnd , textToSet )
|
484
|
-
# get the handle of the nth control that is an Edit box
|
485
|
-
f = getHandleOfControl(parenthWnd, "Edit" , 0 )
|
486
|
-
if f == -1 then
|
487
|
-
# unable to get a handle on the first edit control
|
488
|
-
return false
|
489
|
-
else
|
490
|
-
# we found the control and can now send it some messages
|
491
|
-
setComboBoxText(f , textToSet)
|
492
|
-
return true
|
493
|
-
end
|
494
|
-
end
|
495
|
-
alias :set_file_name :setTextValueForFileNameField
|
496
|
-
end
|
1
|
+
=begin
|
2
|
+
license
|
3
|
+
---------------------------------------------------------------------------
|
4
|
+
Copyright (c) 2004-2006, Paul Rogers and Bret Pettichord
|
5
|
+
All rights reserved.
|
6
|
+
|
7
|
+
Redistribution and use in source and binary forms, with or without
|
8
|
+
modification, are permitted provided that the following conditions are met:
|
9
|
+
|
10
|
+
1. Redistributions of source code must retain the above copyright notice,
|
11
|
+
this list of conditions and the following disclaimer.
|
12
|
+
|
13
|
+
2. Redistributions in binary form must reproduce the above copyright
|
14
|
+
notice, this list of conditions and the following disclaimer in the
|
15
|
+
documentation and/or other materials provided with the distribution.
|
16
|
+
|
17
|
+
3. Neither the names Paul Rogers, nor Bret Pettichord nor the names of any
|
18
|
+
other contributors to this software may be used to endorse or promote
|
19
|
+
products derived from this software without specific prior written
|
20
|
+
permission.
|
21
|
+
|
22
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
23
|
+
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
24
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
25
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
|
26
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
27
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
28
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
29
|
+
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
30
|
+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
31
|
+
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
32
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
--------------------------------------------------------------------------
|
34
|
+
(based on BSD Open Source License)
|
35
|
+
=end
|
36
|
+
|
37
|
+
=begin rdoc
|
38
|
+
This is Watir's window clicker helper class, uses Win32 api
|
39
|
+
calls to access buttons and windows.
|
40
|
+
|
41
|
+
Typical usage:
|
42
|
+
# include this file in your script
|
43
|
+
require "watir/winClicker.rb"
|
44
|
+
|
45
|
+
# create a new instance of WinClicker and use it
|
46
|
+
wc = WinClicker.new
|
47
|
+
wc.clickWindowsButton("My Window", "Click Me", 30)
|
48
|
+
|
49
|
+
=end
|
50
|
+
|
51
|
+
#
|
52
|
+
# class to click javascript dialog boxes, file requester dialogs etc
|
53
|
+
require 'dl/import'
|
54
|
+
require 'dl/struct'
|
55
|
+
require "timeout"
|
56
|
+
require 'Win32API'
|
57
|
+
|
58
|
+
class WinClicker
|
59
|
+
|
60
|
+
WM_CLOSE = 0x0010
|
61
|
+
WM_KEYDOWN = 0x0100
|
62
|
+
WM_KEYUP = 0x0101
|
63
|
+
WM_CHAR = 0x0102
|
64
|
+
BM_CLICK = 0x00F5
|
65
|
+
WM_COMMAND = 0x0111
|
66
|
+
WM_SETTEXT = 0x000C
|
67
|
+
WM_GETTEXT = 0x000D
|
68
|
+
|
69
|
+
HWND_TOP = 0
|
70
|
+
HWND_BOTTOM = 1
|
71
|
+
HWND_TOPMOST = -1
|
72
|
+
HWND_NOTOPMOST = -2
|
73
|
+
|
74
|
+
SWP_SHOWWINDOW = 0x40
|
75
|
+
SWP_NOSIZE = 1
|
76
|
+
SWP_NOMOVE = 2
|
77
|
+
|
78
|
+
TRUE_1 = 1
|
79
|
+
|
80
|
+
# these are constants for commonly used windows windows
|
81
|
+
WINCLASS_DIALOG = "32770"
|
82
|
+
|
83
|
+
# these are the most used methods
|
84
|
+
|
85
|
+
def initialize
|
86
|
+
@User32 = DL.dlopen("user32")
|
87
|
+
# we must determine the path we are in
|
88
|
+
@path_to_clicker = '"' + File.expand_path(File.dirname(__FILE__)) + '"'
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# The system function passes command to the command interpreter, which executes the string as an operating-system command
|
93
|
+
# http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_system.2c_._wsystem.asp
|
94
|
+
# using win32api
|
95
|
+
def winsystem(command)
|
96
|
+
pid = Win32API.new("crtdll", "system", ['P'], 'L').Call(command)
|
97
|
+
end
|
98
|
+
|
99
|
+
# returns the short path version of a long path
|
100
|
+
# 8.3 style
|
101
|
+
def getShortFileName(longName)
|
102
|
+
size = 255
|
103
|
+
buffer = " " * 255
|
104
|
+
returnSize = Win32API.new("kernel32" , "GetShortPathNameA" , 'ppl' , 'L').Call(longName , buffer , size )
|
105
|
+
a = ""
|
106
|
+
a = a + buffer[0...returnSize]
|
107
|
+
return a
|
108
|
+
end
|
109
|
+
|
110
|
+
# Set the first edit box in the Choose file dialog to textToSet
|
111
|
+
# we may need to play with the default try count. 3 is a reasonably safe value.
|
112
|
+
def setFileRequesterFileName( textToSet, tryCount = 3 )
|
113
|
+
for i in (1..tryCount)
|
114
|
+
# first set the Choose File Window to be active
|
115
|
+
hWnd = getWindowHandle("Choose file" )
|
116
|
+
if hWnd != -1
|
117
|
+
makeWindowActive(hWnd)
|
118
|
+
setTextValueForFileNameField( hWnd , textToSet)
|
119
|
+
clickWindowsButton_hwnd(hWnd, "&Open")
|
120
|
+
return true
|
121
|
+
end
|
122
|
+
end
|
123
|
+
return false
|
124
|
+
end
|
125
|
+
|
126
|
+
# fire off setting the file name for the Choose file dialog
|
127
|
+
# in a new process
|
128
|
+
def setFileRequesterFileName_newProcess ( textToSet )
|
129
|
+
myapp = "rubyw #{@path_to_clicker}/setFileDialog.rb #{textToSet}"
|
130
|
+
# first argument to system call is a window title, in this case blank ""
|
131
|
+
winsystem( "start \"\" #{myapp}" )
|
132
|
+
end
|
133
|
+
|
134
|
+
# Return the text value from the first combo box
|
135
|
+
# on the Choose file dialog or nil if not found
|
136
|
+
def getFileRequesterFileName()
|
137
|
+
# first set the Choose File Window to be active
|
138
|
+
hWnd = getWindowHandle("Choose file" )
|
139
|
+
if hWnd != -1
|
140
|
+
makeWindowActive(hWnd)
|
141
|
+
return getTextValueForFileNameField( hWnd )
|
142
|
+
else
|
143
|
+
return nil
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Click on a dialog with title of "Internet Explorer"
|
148
|
+
# Default button to click is "OK"
|
149
|
+
# parenthWnd not used
|
150
|
+
def clickJavaScriptDialog(button="OK" , parenthWnd = -1)
|
151
|
+
clickWindowsButton("Internet Explorer" , button )
|
152
|
+
end
|
153
|
+
|
154
|
+
# Calls system to launch a new process to click on the button
|
155
|
+
# defaults to "OK" button
|
156
|
+
def clickJSDialog_NewProcess(button = "OK" )
|
157
|
+
myapp = "rubyw #{@path_to_clicker}/clickJSDialog.rb #{button}"
|
158
|
+
log "Starting win clicker in a new process. Looking for button #{button}"
|
159
|
+
log "Starting app: #{myapp}"
|
160
|
+
# first argument to system call is a window title, in this case blank ""
|
161
|
+
winsystem( "start \"\" #{myapp}" )
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
# as a thread
|
166
|
+
def clickJSDialog_Thread(button = "OK" )
|
167
|
+
sleep 3
|
168
|
+
n = 0
|
169
|
+
while n < 3
|
170
|
+
sleep 1
|
171
|
+
clickWindowsButton("Internet Explorer" , button )
|
172
|
+
n=n+1
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Looks for a window titled "Security Alert", clicks
|
177
|
+
# on Yes button
|
178
|
+
def clearSecurityAlertBox
|
179
|
+
clickWindowsButton("Security Alert" , "&Yes" )
|
180
|
+
end
|
181
|
+
alias :clear_security_alert :clearSecurityAlertBox
|
182
|
+
|
183
|
+
# Returns the parent handle for the given child handle
|
184
|
+
def getParent (childhWnd )
|
185
|
+
# pass a hWnd into this function and it will return the parent hWnd
|
186
|
+
getParentWindow = @User32['GetParent' , 'II' ]
|
187
|
+
a , b = getParentWindow.call(childhWnd )
|
188
|
+
return a
|
189
|
+
end
|
190
|
+
alias :get_parent :getParent
|
191
|
+
|
192
|
+
def with_dl_callback(type, prc)
|
193
|
+
callback = DL.callback(type, &prc)
|
194
|
+
error = nil
|
195
|
+
begin
|
196
|
+
yield callback
|
197
|
+
ensure
|
198
|
+
DL.remove_callback(callback)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Enumerates open windows and
|
203
|
+
# returns a window handle from a given title and window class
|
204
|
+
# Window class and title are matched regexes
|
205
|
+
def getWindowHandle(title, winclass = "" )
|
206
|
+
enum_windows = @User32['EnumWindows', 'IPL']
|
207
|
+
get_class_name = @User32['GetClassName', 'ILpI']
|
208
|
+
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?
|
209
|
+
get_caption = @User32['GetWindowTextA', 'iLsL' ]
|
210
|
+
|
211
|
+
len = 32
|
212
|
+
buff = " " * len
|
213
|
+
classMatch = false
|
214
|
+
|
215
|
+
bContinueEnum = -1 # Windows "true" to continue enum_windows.
|
216
|
+
found_hwnd = -1
|
217
|
+
|
218
|
+
enum_windows_proc = lambda {|hwnd,lparam|
|
219
|
+
sleep 0.05
|
220
|
+
r,rs = get_class_name.call(hwnd, buff, buff.size)
|
221
|
+
|
222
|
+
if winclass != "" then
|
223
|
+
if /#{winclass}/ =~ rs[1].to_s
|
224
|
+
classMatch = true
|
225
|
+
end
|
226
|
+
else
|
227
|
+
classMatch = true
|
228
|
+
end
|
229
|
+
|
230
|
+
if classMatch ==true
|
231
|
+
textLength, a = get_caption_length.call(hwnd)
|
232
|
+
captionBuffer = " " * (textLength+1)
|
233
|
+
t , textCaption = get_caption.call(hwnd, captionBuffer , textLength+1)
|
234
|
+
if /#{title}/ =~ textCaption[1].to_s
|
235
|
+
found_hwnd = hwnd
|
236
|
+
bContinueEnum = 0 # False, discontinue enum_windows
|
237
|
+
end
|
238
|
+
bContinueEnum
|
239
|
+
else
|
240
|
+
bContinueEnum
|
241
|
+
end
|
242
|
+
}
|
243
|
+
with_dl_callback('ILL',enum_windows_proc) do |callback|
|
244
|
+
r,rs = enum_windows.call(callback, 0)
|
245
|
+
end
|
246
|
+
return found_hwnd
|
247
|
+
end
|
248
|
+
alias :get_window_handle :getWindowHandle
|
249
|
+
|
250
|
+
# Call SwitchToThisWindow win32api which will
|
251
|
+
# The SwitchToThisWindow function is called to switch focus to a specified window
|
252
|
+
# and bring it to the foreground
|
253
|
+
def makeWindowActive (hWnd)
|
254
|
+
switch_to_window = @User32['SwitchToThisWindow' , 'pLI' ]
|
255
|
+
# set it to be the one with focus
|
256
|
+
switch_to_window.call(hWnd , 1)
|
257
|
+
end
|
258
|
+
alias :make_window_active :makeWindowActive
|
259
|
+
|
260
|
+
# Posts a message to the handle passed in to click
|
261
|
+
def clickButtonWithHandle(buttonhWnd)
|
262
|
+
post_message = @User32['PostMessage', 'ILILL']
|
263
|
+
r,rs = post_message.call(buttonhWnd, BM_CLICK, 0, 0)
|
264
|
+
end
|
265
|
+
alias :click_button_with_handle :clickButtonWithHandle
|
266
|
+
|
267
|
+
# Based on the parent window handle passed in,
|
268
|
+
# click on the button with the given caption.
|
269
|
+
def clickWindowsButton_hwnd (hwnd , buttonCaption )
|
270
|
+
makeWindowActive(hwnd)
|
271
|
+
d = getChildHandle( hwnd , buttonCaption )
|
272
|
+
if d != -1
|
273
|
+
makeWindowActive(hwnd)
|
274
|
+
clickButtonWithHandle(d)
|
275
|
+
else
|
276
|
+
return false
|
277
|
+
end
|
278
|
+
return true
|
279
|
+
end
|
280
|
+
alias :click_windows_button_hwnd :clickWindowsButton_hwnd
|
281
|
+
|
282
|
+
# this clicks the button with the name in the window with the caption. It keeps looking for the button until
|
283
|
+
# until the timeout expires
|
284
|
+
def clickWindowsButton (windowCaption , buttonCaption , maxWaitTime=30 )
|
285
|
+
sleep 1
|
286
|
+
hwnd = -1
|
287
|
+
begin
|
288
|
+
timeout(maxWaitTime) do
|
289
|
+
hwnd = getWindowHandle(windowCaption)
|
290
|
+
while hwnd == -1
|
291
|
+
hwnd = getWindowHandle(windowCaption)
|
292
|
+
sleep 0.5
|
293
|
+
end
|
294
|
+
makeWindowActive(hwnd)
|
295
|
+
end
|
296
|
+
rescue Timeout::Error
|
297
|
+
return false
|
298
|
+
rescue => e
|
299
|
+
raise e
|
300
|
+
end
|
301
|
+
if hwnd != -1
|
302
|
+
makeWindowActive(hwnd)
|
303
|
+
else
|
304
|
+
end
|
305
|
+
d = getChildHandle( hwnd , buttonCaption )
|
306
|
+
if d != -1
|
307
|
+
makeWindowActive(hwnd)
|
308
|
+
clickButtonWithHandle(d)
|
309
|
+
else
|
310
|
+
return false
|
311
|
+
end
|
312
|
+
return true
|
313
|
+
end
|
314
|
+
alias :click_windows_button :clickWindowsButton
|
315
|
+
|
316
|
+
# Enumerate through children of the parent hwnd, pass back
|
317
|
+
# the handle for the control with the given caption
|
318
|
+
# the caption is compared as a regex
|
319
|
+
def getChildHandle ( hWnd , childCaption )
|
320
|
+
enum_childWindows = @User32['EnumChildWindows' , 'IIPL' ]
|
321
|
+
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?
|
322
|
+
get_caption = @User32['GetWindowTextA', 'iLsL' ]
|
323
|
+
match_hwnd = -1 # hWnd of handle matching childCaption
|
324
|
+
buff = " " * 16
|
325
|
+
get_class_name = @User32['GetClassName', 'ILpI']
|
326
|
+
|
327
|
+
bContinueEnum = -1
|
328
|
+
enum_childWindowsProc = lambda {|chwnd,lparam|
|
329
|
+
r,rs = get_class_name.call(chwnd, buff, buff.size)
|
330
|
+
textLength, a = get_caption_length.call(chwnd)
|
331
|
+
captionBuffer = " " * (textLength+1)
|
332
|
+
|
333
|
+
t , textCaption = get_caption.call(chwnd, captionBuffer , textLength+1)
|
334
|
+
if /#{childCaption}/ =~ textCaption[1].to_s then
|
335
|
+
match_hwnd = chwnd
|
336
|
+
bContinueEnum = 0 # Windows "false" to discontinue enum_childWindow
|
337
|
+
end
|
338
|
+
bContinueEnum
|
339
|
+
}
|
340
|
+
with_dl_callback('ILL',enum_childWindowsProc) do |callback|
|
341
|
+
r = enum_childWindows.call(hWnd, callback ,0)
|
342
|
+
end
|
343
|
+
return match_hwnd
|
344
|
+
end
|
345
|
+
alias :get_chwnd :getChildHandle
|
346
|
+
|
347
|
+
# Convenience method to return Static text for
|
348
|
+
# children of the window with the given caption
|
349
|
+
def getStaticText(caption)
|
350
|
+
return getStaticTextFromWindow(caption, -1)
|
351
|
+
end
|
352
|
+
alias :get_static_text :getStaticText
|
353
|
+
|
354
|
+
# Convenience method to return Static text for
|
355
|
+
# children of the window handle
|
356
|
+
def getStaticText_hWnd (hWnd)
|
357
|
+
return getStaticTextFromWindow("" , hWnd)
|
358
|
+
end
|
359
|
+
alias :get_static_text_hwnd :getStaticText_hWnd
|
360
|
+
|
361
|
+
# Return text as an array from child controls of the window
|
362
|
+
# given as either a handle or with the given caption
|
363
|
+
# that have a class type of Static
|
364
|
+
def getStaticTextFromWindow( windowCaption , hWnd)
|
365
|
+
enum_childWindows = @User32['EnumChildWindows' , 'IIPL' ]
|
366
|
+
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?
|
367
|
+
get_caption = @User32['GetWindowTextA', 'iLsL' ]
|
368
|
+
|
369
|
+
staticText = []
|
370
|
+
buff = " " * 16
|
371
|
+
get_class_name = @User32['GetClassName', 'ILpI']
|
372
|
+
|
373
|
+
if hWnd == -1
|
374
|
+
hWnd = getWindowHandle(windowCaption)
|
375
|
+
end
|
376
|
+
|
377
|
+
if hWnd == -1
|
378
|
+
return staticText
|
379
|
+
end
|
380
|
+
|
381
|
+
bContinueEnum = -1
|
382
|
+
enum_childWindows_proc = lambda {|hWnd,lparam|
|
383
|
+
r,rs = get_class_name.call(hWnd, buff, buff.size)
|
384
|
+
if rs[1].to_s == "Static" # there must be a better way of detecting this
|
385
|
+
textLength, a = get_caption_length.call(hWnd)
|
386
|
+
captionBuffer = " " * (textLength+1)
|
387
|
+
t , textCaption = get_caption.call(hWnd, captionBuffer , textLength+1)
|
388
|
+
staticText << textCaption[1].to_s
|
389
|
+
end
|
390
|
+
bContinueEnum
|
391
|
+
}
|
392
|
+
with_dl_callback('ILL',enum_childWindows_proc) do |callback|
|
393
|
+
r = enum_childWindows.call(hWnd, callback ,0)
|
394
|
+
end
|
395
|
+
return staticText
|
396
|
+
end
|
397
|
+
alias :get_static_text_from_window :getStaticTextFromWindow
|
398
|
+
|
399
|
+
# returns the handle (or -1 if its not found) of the
|
400
|
+
# nth control of this class in the parent window specified
|
401
|
+
# by the window handle
|
402
|
+
def getHandleOfControl (hWnd , controlClass, position )
|
403
|
+
enum_childWindows = @User32['EnumChildWindows' , 'IIPL' ]
|
404
|
+
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?
|
405
|
+
get_caption = @User32['GetWindowTextA', 'iLsL' ]
|
406
|
+
control_hWnd = []
|
407
|
+
buff = " " * 16
|
408
|
+
get_class_name = @User32['GetClassName', 'ILpI']
|
409
|
+
|
410
|
+
bContinueEnum = -1
|
411
|
+
enum_childWindows_proc = lambda {|hWnd,lparam|
|
412
|
+
r,rs = get_class_name.call(hWnd, buff, buff.size)
|
413
|
+
if rs[1].to_s == controlClass # there must be a better way of detecting this
|
414
|
+
control_hWnd << hWnd
|
415
|
+
end
|
416
|
+
bContinueEnum
|
417
|
+
}
|
418
|
+
with_dl_callback('ILL',enum_childWindows_proc) do |callback|
|
419
|
+
r = enum_childWindows.call(hWnd, callback ,0)
|
420
|
+
end
|
421
|
+
controlHwnd = control_hWnd[position]
|
422
|
+
if controlHwnd == nil then
|
423
|
+
controlHwnd = -1
|
424
|
+
end
|
425
|
+
return controlHwnd
|
426
|
+
end
|
427
|
+
alias :get_handle_of_ctrl :getHandleOfControl
|
428
|
+
|
429
|
+
# Call set text on the given window handle
|
430
|
+
def setComboBoxText(hWnd , textToSet)
|
431
|
+
set_text(hWnd, textToSet)
|
432
|
+
end
|
433
|
+
alias :set_combo_txt :setComboBoxText
|
434
|
+
|
435
|
+
# Call set text on the given window handle
|
436
|
+
def setTextBoxText(hWnd , textToSet)
|
437
|
+
set_text(hWnd, textToSet)
|
438
|
+
end
|
439
|
+
alias :set_textbox_txt :setTextBoxText
|
440
|
+
|
441
|
+
# Private method to set text called by the two methods above
|
442
|
+
def set_text(hWnd, textToSet)
|
443
|
+
send_message = @User32['SendMessage', 'ILISS']
|
444
|
+
r ,rs = send_message.call(hWnd , WM_SETTEXT ,'',textToSet)
|
445
|
+
end
|
446
|
+
private :set_text
|
447
|
+
|
448
|
+
# Get the text in the handle for the given control
|
449
|
+
def getControlText(hWnd)
|
450
|
+
buff = " " * 256
|
451
|
+
send_message = @User32['SendMessage', 'ILIIS']
|
452
|
+
r ,rs = send_message.call(hWnd , WM_GETTEXT , 256 , buff )
|
453
|
+
return buff.to_s
|
454
|
+
end
|
455
|
+
alias :get_ctrl_txt :getControlText
|
456
|
+
|
457
|
+
# get the title for the specified hwnd
|
458
|
+
def getWindowTitle(hWnd)
|
459
|
+
buff = " " * 256
|
460
|
+
getWindowText = @User32['GetWindowText' , 'ILSI']
|
461
|
+
r , rs = getWindowText.call( hWnd , buff , 256 )
|
462
|
+
return buff.to_s
|
463
|
+
end
|
464
|
+
alias :get_win_title :getWindowTitle
|
465
|
+
|
466
|
+
# Get the text in the first combo box
|
467
|
+
# file requester methods returns nil on failure to
|
468
|
+
# locate the 1st combobox
|
469
|
+
def getTextValueForFileNameField(parenthWnd)
|
470
|
+
f = getHandleOfControl(parenthWnd, "ComboBox", 1)
|
471
|
+
if f == -1 then
|
472
|
+
# unable to find the first combobox
|
473
|
+
return nil
|
474
|
+
else
|
475
|
+
# we have the control and now
|
476
|
+
# can send it some messages
|
477
|
+
return getWinText(f )
|
478
|
+
end
|
479
|
+
end
|
480
|
+
alias :get_file_name :getTextValueForFileNameField
|
481
|
+
|
482
|
+
# this sets the filename field to text to set
|
483
|
+
def setTextValueForFileNameField( parenthWnd , textToSet )
|
484
|
+
# get the handle of the nth control that is an Edit box
|
485
|
+
f = getHandleOfControl(parenthWnd, "Edit" , 0 )
|
486
|
+
if f == -1 then
|
487
|
+
# unable to get a handle on the first edit control
|
488
|
+
return false
|
489
|
+
else
|
490
|
+
# we found the control and can now send it some messages
|
491
|
+
setComboBoxText(f , textToSet)
|
492
|
+
return true
|
493
|
+
end
|
494
|
+
end
|
495
|
+
alias :set_file_name :setTextValueForFileNameField
|
496
|
+
end
|