rautomation 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +3 -3
  4. data/History.rdoc +17 -0
  5. data/README.rdoc +2 -1
  6. data/Rakefile +23 -6
  7. data/VERSION +1 -1
  8. data/ext/IAccessibleDLL/Release/IAccessibleDLL.dll +0 -0
  9. data/ext/UiaDll/Release/UiaDll.dll +0 -0
  10. data/ext/UiaDll/UiaDll/{AutomatedComboBox.cpp → AutomatedSelectList.cpp} +22 -11
  11. data/ext/UiaDll/UiaDll/{AutomatedComboBox.h → AutomatedSelectList.h} +17 -4
  12. data/ext/UiaDll/UiaDll/AutomatedTable.cpp +55 -13
  13. data/ext/UiaDll/UiaDll/AutomatedTable.h +16 -3
  14. data/ext/UiaDll/UiaDll/AutomationControl.cpp +28 -0
  15. data/ext/UiaDll/UiaDll/AutomationControl.h +56 -0
  16. data/ext/UiaDll/UiaDll/AutomationFinder.cpp +57 -0
  17. data/ext/UiaDll/UiaDll/AutomationFinder.h +48 -0
  18. data/ext/UiaDll/UiaDll/ControlMethods.cpp +15 -0
  19. data/ext/UiaDll/UiaDll/MenuItemSelector.h +2 -0
  20. data/ext/UiaDll/UiaDll/MenuMethods.cpp +58 -0
  21. data/ext/UiaDll/UiaDll/SelectListMethods.cpp +37 -0
  22. data/ext/UiaDll/UiaDll/SelectionItem.cpp +10 -0
  23. data/ext/UiaDll/UiaDll/SelectionItem.h +21 -0
  24. data/ext/UiaDll/UiaDll/StringHelper.cpp +33 -2
  25. data/ext/UiaDll/UiaDll/StringHelper.h +6 -0
  26. data/ext/UiaDll/UiaDll/StringMethods.cpp +8 -0
  27. data/ext/UiaDll/UiaDll/TableMethods.cpp +76 -0
  28. data/ext/UiaDll/UiaDll/Toggle.cpp +2 -0
  29. data/ext/UiaDll/UiaDll/Toggle.h +22 -0
  30. data/ext/UiaDll/UiaDll/UiaDll.cpp +96 -327
  31. data/ext/UiaDll/UiaDll/UiaDll.vcxproj +15 -4
  32. data/ext/UiaDll/UiaDll/UiaDll.vcxproj.filters +91 -22
  33. data/ext/UiaDll/UiaDll/dllmain.cpp +1 -1
  34. data/ext/UiaDll/UiaDll/stdafx.h +38 -21
  35. data/ext/WindowsForms/Release/WindowsForms.exe +0 -0
  36. data/ext/WindowsForms/WindowsForms.sln +10 -0
  37. data/ext/WindowsForms/WindowsForms/AutomatableMonthCalendar.cs +59 -0
  38. data/ext/WindowsForms/WindowsForms/AutomationHelpers/AutomationProvider.cs +91 -0
  39. data/ext/WindowsForms/WindowsForms/MainFormWindow.Designer.cs +32 -10
  40. data/ext/WindowsForms/WindowsForms/MainFormWindow.cs +10 -0
  41. data/ext/WindowsForms/WindowsForms/WindowsForms.csproj +15 -6
  42. data/lib/rautomation/adapter/ms_uia.rb +1 -0
  43. data/lib/rautomation/adapter/ms_uia/checkbox.rb +2 -10
  44. data/lib/rautomation/adapter/ms_uia/constants.rb +1 -0
  45. data/lib/rautomation/adapter/ms_uia/control.rb +14 -67
  46. data/lib/rautomation/adapter/ms_uia/functions.rb +2 -18
  47. data/lib/rautomation/adapter/ms_uia/list_box.rb +5 -27
  48. data/lib/rautomation/adapter/ms_uia/list_item.rb +2 -29
  49. data/lib/rautomation/adapter/ms_uia/radio.rb +1 -1
  50. data/lib/rautomation/adapter/ms_uia/select_list.rb +5 -6
  51. data/lib/rautomation/adapter/ms_uia/table.rb +15 -50
  52. data/lib/rautomation/adapter/ms_uia/text_field.rb +1 -1
  53. data/lib/rautomation/adapter/ms_uia/uia_dll.rb +226 -58
  54. data/lib/rautomation/adapter/ms_uia/value_control.rb +21 -0
  55. data/lib/rautomation/adapter/ms_uia/window.rb +6 -104
  56. data/lib/rautomation/adapter/win_32/functions.rb +0 -23
  57. data/lib/rautomation/adapter/win_32/keys.rb +64 -61
  58. data/rautomation.gemspec +6 -1
  59. data/spec/adapter/autoit/mouse_spec.rb +1 -1
  60. data/spec/adapter/ms_uia/select_list_spec.rb +0 -21
  61. data/spec/adapter/ms_uia/table_spec.rb +13 -11
  62. data/spec/adapter/ms_uia/text_field_spec.rb +15 -8
  63. data/spec/adapter/ms_uia/value_control_spec.rb +11 -0
  64. data/spec/adapter/ms_uia/window_spec.rb +7 -1
  65. data/spec/adapter/win_32/mouse_spec.rb +1 -1
  66. data/spec/adapter/win_32/text_field_spec.rb +5 -5
  67. data/spec/adapter/win_32/window_spec.rb +1 -1
  68. data/spec/text_field_spec.rb +18 -23
  69. data/spec/window_spec.rb +1 -3
  70. metadata +45 -34
  71. data/ext/UiaDll/UiaDll/ToggleStateHelper.cpp +0 -33
@@ -12,7 +12,7 @@ module RAutomation
12
12
  end
13
13
 
14
14
  def set?
15
- UiaDll::get_is_selected(uia_element)
15
+ UiaDll::is_selected(search_information)
16
16
  end
17
17
 
18
18
  alias_method :exists?, :exist?
@@ -16,12 +16,12 @@ module RAutomation
16
16
  end
17
17
 
18
18
  def selected?
19
- @index == UiaDll::get_combobox_selected_index(@select_list.control_hwnd)
19
+ @index == UiaDll::select_list_selected_index(@select_list.control_hwnd)
20
20
  end
21
21
 
22
22
  def select
23
23
  @select_list.assert_enabled
24
- UiaDll::select_combo_by_index @select_list.control_hwnd, @index
24
+ UiaDll::select_list_select_index @select_list.search_information, @index
25
25
  end
26
26
 
27
27
  alias_method :set, :select
@@ -33,8 +33,7 @@ module RAutomation
33
33
  end
34
34
 
35
35
  def set(value)
36
- list = UiaDll::element_from_handle(@hwnd)
37
- UiaDll::set_value(list, value)
36
+ UiaDll::select_list_select_value(search_information, value)
38
37
  end
39
38
 
40
39
  def options(options = {})
@@ -72,7 +71,7 @@ module RAutomation
72
71
  end
73
72
 
74
73
  def select(index)
75
- UiaDll::select_combo_by_index @hwnd, index
74
+ UiaDll::select_list_select_index search_information, index
76
75
  end
77
76
 
78
77
  def list_item_height
@@ -104,7 +103,7 @@ module RAutomation
104
103
  private
105
104
 
106
105
  def item_count
107
- UiaDll::get_combobox_count(@hwnd)
106
+ UiaDll::select_list_count(search_information)
108
107
  end
109
108
 
110
109
  end
@@ -13,11 +13,11 @@ module RAutomation
13
13
  end
14
14
 
15
15
  def exists?
16
- UiaDll::data_item_exists hwnd, row, column
16
+ UiaDll::table_coordinate_valid? hwnd, row, column
17
17
  end
18
18
 
19
19
  def value
20
- UiaDll::cell_value_at hwnd, row, column
20
+ UiaDll::table_value_at hwnd, row, column
21
21
  end
22
22
 
23
23
  alias_method :text, :value
@@ -51,11 +51,11 @@ module RAutomation
51
51
  end
52
52
 
53
53
  def value
54
- UiaDll::cell_value_at @hwnd, @locators[:index]
54
+ UiaDll::table_value_at @hwnd, @locators[:index]
55
55
  end
56
56
 
57
57
  def exists?
58
- UiaDll::data_item_exists(@hwnd, @locators[:index])
58
+ UiaDll::table_coordinate_valid?(@hwnd, @locators[:index])
59
59
  end
60
60
 
61
61
  def self.locators_match?(locators, item)
@@ -87,60 +87,25 @@ module RAutomation
87
87
  end
88
88
 
89
89
  def strings
90
- rows = []
91
- header_columns = []
90
+ headers = UiaDll.table_headers(hwnd)
91
+ values = UiaDll.table_values(hwnd)
92
+ return values if headers.empty?
92
93
 
93
- raise "Not a list control" unless of_type_table?
94
-
95
-
96
- children_count = count_children(uia_element)
97
-
98
- children = FFI::MemoryPointer.new :pointer, children_count
99
- UiaDll::find_children(uia_element, children)
100
-
101
-
102
- children.read_array_of_pointer(children_count).each do |child|
103
- grandchildren_count = count_children(child)
104
-
105
- if grandchildren_count > 0
106
-
107
- grandchildren = FFI::MemoryPointer.new :pointer, grandchildren_count
108
- UiaDll::find_children(child, grandchildren)
109
-
110
- grandchildren.read_array_of_pointer(grandchildren_count).each do |grandchild|
111
- grandchild_name = FFI::MemoryPointer.new :char, UiaDll::get_name(grandchild, nil) + 1
112
- UiaDll::get_name(grandchild, grandchild_name)
113
- header_columns.push grandchild_name.read_string
114
- end
115
- else
116
- grandchild_name = FFI::MemoryPointer.new :char, UiaDll::get_name(child, nil) + 1
117
- UiaDll::get_name(child, grandchild_name)
118
- header_columns = grandchild_name.read_string
119
- end
120
-
121
- rows.push header_columns
122
- header_columns = []
123
- end
124
-
125
- rows
94
+ all_strings = [] << headers
95
+ values.each_slice(headers.count) {|r| all_strings << r }
96
+ all_strings
126
97
  end
127
98
 
128
- # def select(row)
129
- # Functions.select_table_row(Window.oleacc_module_handle, Functions.control_hwnd(@window.hwnd, @locators), row)
130
- # end
131
-
132
- def select(index)
133
- UiaDll::select_data_item hwnd, index - 1
99
+ def select(which_item)
100
+ UiaDll::table_select hwnd, which_item
134
101
  end
135
102
 
136
- #todo - replace with UIA version
137
- def selected?(row)
138
- state = Functions.get_table_row_state(Window.oleacc_module_handle, hwnd, row)
139
- state & Constants::STATE_SYSTEM_SELECTED != 0
103
+ def selected?(which_item)
104
+ UiaDll::table_row_is_selected hwnd, which_item
140
105
  end
141
106
 
142
107
  def row_count
143
- UiaDll::get_data_item_count hwnd
108
+ UiaDll::table_row_count hwnd
144
109
  end
145
110
 
146
111
  def exist?
@@ -42,7 +42,7 @@ module RAutomation
42
42
  end
43
43
 
44
44
  def exist?
45
- super && matches_type?(Constants::UIA_EDIT_CONTROL_TYPE)
45
+ super && matches_type?(Constants::UIA_EDIT_CONTROL_TYPE, Constants::UIA_DOCUMENT_CONTROL_TYPE)
46
46
  end
47
47
 
48
48
  alias_method :exists?, :exist?
@@ -7,73 +7,243 @@ module RAutomation
7
7
  module UiaDll
8
8
  extend FFI::Library
9
9
 
10
+ HowToFind = enum(:hwnd, 1,
11
+ :id,
12
+ :value,
13
+ :focus,
14
+ :point)
15
+
16
+
17
+ class FindData < FFI::Union
18
+ layout :string_data, [:uint8, 256],
19
+ :int_data, :int,
20
+ :point_data, [:int, 2]
21
+ end
22
+
23
+ class SearchCriteria < FFI::Struct
24
+ def self.from_locator(parent, locator)
25
+ info = SearchCriteria.new
26
+ info.parent_window = parent
27
+ info.index = locator[:index] || 0
28
+
29
+ case
30
+ when locator[:hwnd]
31
+ info.how = :hwnd
32
+ info.data = locator[:hwnd]
33
+ when locator[:id]
34
+ info.how = :id
35
+ info.data = locator[:id]
36
+ when locator[:value]
37
+ info.how = :value
38
+ info.data = locator[:value]
39
+ when locator[:point]
40
+ info.how = :point
41
+ info.data = locator[:point]
42
+ when locator[:focus]
43
+ info.how = :focus
44
+ end
45
+ info
46
+ end
47
+
48
+ def how
49
+ self[:how]
50
+ end
51
+
52
+ def how=(value)
53
+ self[:how] = value
54
+ end
55
+
56
+ def index
57
+ self[:index]
58
+ end
59
+
60
+ def index=(value)
61
+ self[:index] = value
62
+ end
63
+
64
+ def parent_window
65
+ self[:hwnd]
66
+ end
67
+
68
+ def parent_window=(parent)
69
+ self[:hwnd] = parent
70
+ end
71
+
72
+ def data
73
+ case how
74
+ when :hwnd
75
+ return self[:data][:int_data]
76
+ when :id, :value
77
+ return self[:data][:string_data].to_ptr.read_string
78
+ when :point
79
+ return self[:data][:point_data].to_ptr.read_array_of_int(2)
80
+ else
81
+ return nil
82
+ end
83
+ end
84
+
85
+ def data=(value)
86
+ case how
87
+ when :hwnd
88
+ self[:data][:int_data] = value
89
+ when :id, :value
90
+ self[:data][:string_data] = value
91
+ when :point
92
+ self[:data][:point_data].to_ptr.write_array_of_int(value)
93
+ end
94
+ end
95
+
96
+ layout :hwnd, :int,
97
+ :index, :int,
98
+ :how, HowToFind, :data, FindData
99
+ end
100
+
10
101
  ffi_lib File.dirname(__FILE__) + '/../../../../ext/UiaDll/Release/UiaDll.dll'
11
102
  ffi_convention :stdcall
12
103
 
13
- attach_function :find_window, :RA_FindWindow,
14
- [:string], :pointer
15
- attach_function :is_offscreen, :RA_IsOffscreen,
16
- [:pointer], :bool
104
+ # Generic Control methods
105
+ attach_function :ElementExists, [SearchCriteria.by_ref], :bool
106
+ attach_function :process_id, :ProcessId, [SearchCriteria.by_ref], :int
107
+ attach_function :Control_GetValue, [:long, :pointer, :int], :void
108
+ attach_function :set_control_value, :Control_SetValue, [:long, :string], :void
109
+ attach_function :BoundingRectangle, [SearchCriteria.by_ref, :pointer], :int
110
+ attach_function :current_control_type, :ControlType, [SearchCriteria.by_ref], :int
111
+ attach_function :Name, [SearchCriteria.by_ref, :pointer, :int], :void
112
+ attach_function :ClassName, [SearchCriteria.by_ref, :pointer, :int], :void
113
+ attach_function :GetClassNames,
114
+ [SearchCriteria.by_ref, :pointer], :int
115
+
116
+ def self.exists?(search_information)
117
+ ElementExists search_information
118
+ end
119
+
120
+ def self.bounding_rectangle(search_information)
121
+ boundary = FFI::MemoryPointer.new :long, 4
122
+ BoundingRectangle search_information, boundary
123
+ boundary.read_array_of_long(4)
124
+ end
125
+
126
+ def self.get_control_value(hwnd)
127
+ string_from(:Control_GetValue, hwnd)
128
+ end
129
+
130
+ def self.name(search_information)
131
+ string_from(:Name, search_information)
132
+ end
133
+
134
+ def self.class_name(search_information)
135
+ string_from(:ClassName, search_information)
136
+ end
137
+
138
+ def self.children_class_names(search_information)
139
+ strings_from :GetClassNames, search_information
140
+ end
141
+
142
+ # Toggle methods
143
+ attach_function :is_set, :IsSet, [SearchCriteria.by_ref], :bool
144
+
145
+ # Selection Item methods
146
+ attach_function :is_selected, :IsSelected, [SearchCriteria.by_ref], :bool
147
+
148
+ # Select List methods
149
+ attach_function :SelectList_Selection,
150
+ [SearchCriteria.by_ref, :pointer, :int], :void
151
+ attach_function :select_list_count, :SelectList_Count,
152
+ [SearchCriteria.by_ref], :int
153
+ attach_function :select_list_selected_index, :SelectList_SelectedIndex,
154
+ [:long], :int
155
+ attach_function :select_list_value_at, :SelectList_ValueAt,
156
+ [:long, :int, :pointer, :int], :bool
157
+ attach_function :select_list_select_index, :SelectList_SelectIndex,
158
+ [SearchCriteria.by_ref, :int], :bool
159
+ attach_function :select_list_select_value, :SelectList_SelectValue,
160
+ [SearchCriteria.by_ref, :pointer], :int
161
+
162
+ def self.selection(search_information)
163
+ string_from(:SelectList_Selection, search_information)
164
+ end
165
+
166
+ # Menu methods
167
+ attach_function :select_menu_item, :Menu_SelectPath,
168
+ [:long, :pointer, :int, :varargs], :void
169
+ attach_function :menu_item_exists, :Menu_ItemExists,
170
+ [:long, :varargs], :bool
171
+
172
+ # Table methods
173
+ attach_function :Table_GetHeaders,
174
+ [:long, :pointer], :int
175
+ attach_function :Table_GetValues,
176
+ [:long, :pointer], :int
177
+ attach_function :Table_FindValues,
178
+ [SearchCriteria.by_ref, :pointer], :int
179
+ attach_function :table_row_count, :Table_RowCount,
180
+ [:long], :int
181
+ attach_function :Table_CoordinateIsValid,
182
+ [:long, :int, :int], :bool
183
+ attach_function :Table_ValueAt,
184
+ [:long, :int, :int, :pointer, :int], :void
185
+ attach_function :Table_SelectByIndex,
186
+ [:long, :int], :void
187
+ attach_function :Table_SelectByValue,
188
+ [:long, :string], :void
189
+ attach_function :table_row_is_selected, :Table_IsSelectedByIndex,
190
+ [:long, :int], :bool
191
+
192
+ def self.table_select(hwnd, which_item)
193
+ case which_item
194
+ when Integer
195
+ Table_SelectByIndex hwnd, which_item
196
+ when String
197
+ Table_SelectByValue hwnd, which_item
198
+ end
199
+ end
200
+
201
+ def self.table_value_at(hwnd, row, column=0)
202
+ string_from(:Table_ValueAt, hwnd, row, column)
203
+ end
204
+
205
+ def self.table_coordinate_valid?(hwnd, row, column=0)
206
+ Table_CoordinateIsValid hwnd, row, column
207
+ end
208
+
209
+ def self.table_headers(hwnd)
210
+ strings_from :Table_GetHeaders, hwnd
211
+ end
212
+
213
+ def self.table_values(hwnd)
214
+ strings_from :Table_GetValues, hwnd
215
+ end
216
+
217
+ def self.find_table_values(search_information)
218
+ strings_from :Table_FindValues, search_information
219
+ end
220
+
221
+ # String methods
222
+ attach_function :clean_up_strings, :String_CleanUp,
223
+ [:pointer, :int], :void
224
+
17
225
  attach_function :element_from_handle, :RA_ElementFromHandle,
18
226
  [:long], :pointer
19
227
  attach_function :element_from_point, :RA_ElementFromPoint,
20
228
  [:int, :int], :pointer
21
- attach_function :get_focused_element, :RA_GetFocusedElement,
22
- [], :pointer
23
229
  attach_function :find_child_by_id, :RA_FindChildById,
24
230
  [:pointer, :string], :pointer
25
- attach_function :find_child_by_name, :RA_FindChildByName,
26
- [:pointer, :string], :pointer
27
231
  attach_function :current_native_window_handle, :RA_CurrentNativeWindowHandle,
28
232
  [:pointer], :long
29
233
  attach_function :set_focus, :RA_SetFocus,
30
234
  [:pointer], :bool
31
- attach_function :current_control_type, :RA_GetCurrentControlType,
32
- [:pointer], :int
33
- attach_function :desktop_handle, :RA_GetDesktopHandle,
34
- [], :long
35
235
  attach_function :move_mouse, :RA_MoveMouse,
36
236
  [:int,:int], :long
37
237
  attach_function :click_mouse, :RA_ClickMouse,
38
238
  [], :long
39
- attach_function :bounding_rectangle, :RA_CurrentBoundingRectangle,
40
- [:pointer, :pointer], :int
41
239
  attach_function :is_offscreen, :RA_CurrentIsOffscreen,
42
240
  [:pointer, :pointer], :int
43
241
  attach_function :find_children, :RA_FindChildren,
44
242
  [:pointer, :pointer], :int
45
- attach_function :get_name, :RA_GetName,
46
- [:pointer, :pointer], :int
47
- attach_function :get_class_name, :RA_GetClassName,
48
- [:pointer, :pointer], :int
49
- attach_function :get_is_selected, :RA_GetIsSelected,
50
- [:pointer], :bool
51
- attach_function :get_is_set, :RA_GetIsSet,
52
- [:pointer], :bool
243
+ attach_function :get_control_name, :RA_GetControlName,
244
+ [:long, :pointer, :int], :bool
53
245
  attach_function :select, :RA_Select,
54
246
  [:pointer], :int
55
- attach_function :find_window_by_pid, :RA_FindWindowByPID,
56
- [:int], :pointer
57
- attach_function :current_process_id, :RA_GetCurrentProcessId,
58
- [:pointer], :int
59
- attach_function :select_combo_by_index, :RA_SelectComboByIndex,
60
- [:long, :int], :bool
61
- attach_function :set_value, :RA_SelectComboByValue,
62
- [:pointer, :pointer], :int
63
- attach_function :select_menu_item, :RA_SelectMenuItem,
64
- [:long, :pointer, :int, :varargs], :void
65
- attach_function :menu_item_exists, :RA_MenuItemExists,
66
- [:long, :varargs], :bool
67
- attach_function :get_combobox_count, :RA_GetComboOptionsCount,
68
- [:long], :int
69
- attach_function :get_combobox_value, :RA_GetComboValueByIndex,
70
- [:long, :int, :pointer, :int], :bool
71
- attach_function :get_combobox_selected_index, :RA_GetSelectedComboIndex,
72
- [:long], :int
73
- attach_function :get_data_item_count, :RA_GetDataItemCount,
74
- [:long], :int
75
- attach_function :select_data_item, :RA_SelectDataItem,
76
- [:long, :int], :void
77
247
  attach_function :expand_by_value, :RA_ExpandItemByValue,
78
248
  [:long, :string], :void
79
249
  attach_function :expand_by_index, :RA_ExpandItemByIndex,
@@ -82,27 +252,25 @@ module RAutomation
82
252
  [:long, :string], :void
83
253
  attach_function :collapse_by_index, :RA_CollapseItemByIndex,
84
254
  [:long, :int], :void
85
- attach_function :data_item_exists_by_value, :RA_DataItemExistsByValue,
86
- [:long, :string], :bool
87
- attach_function :RA_DataItemExists,
88
- [:long, :int, :int], :bool
89
-
90
- attach_function :RA_CellValueAt,
91
- [:long, :int, :int, :pointer, :int], :void
92
-
93
255
  attach_function :control_click, :RA_Click,
94
256
  [:long, :pointer, :int], :void
95
257
  attach_function :control_mouse_click, :RA_PointAndClick,
96
258
  [:long, :pointer, :int], :void
97
259
 
98
- def self.cell_value_at(hwnd, row, column=0)
99
- string = FFI::MemoryPointer.new :char, 1024
100
- RA_CellValueAt hwnd, row, column, string, 1024
101
- string.read_string
260
+ private
261
+ def self.strings_from(method, hwnd)
262
+ string_count = send method, hwnd, nil
263
+ pointer = FFI::MemoryPointer.new :pointer, string_count
264
+ send method, hwnd, pointer
265
+ strings = pointer.get_array_of_string 0, string_count
266
+ clean_up_strings pointer, string_count
267
+ strings
102
268
  end
103
269
 
104
- def self.data_item_exists(hwnd, row, column=0)
105
- RA_DataItemExists hwnd, row, column
270
+ def self.string_from(method, *args)
271
+ pointer = FFI::MemoryPointer.new :pointer, 1024
272
+ send method, *(args << pointer << 1024)
273
+ pointer.read_string
106
274
  end
107
275
  end
108
276
  end