uia 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +11 -0
- data/ext/UiaDll/UiaDll.Test/ElementInformationTest.cpp +104 -0
- data/ext/UiaDll/UiaDll.Test/ElementStub.h +11 -1
- data/ext/UiaDll/UiaDll/ConditionMethods.cpp +1 -1
- data/ext/UiaDll/UiaDll/ElementMethods.cpp +33 -23
- data/ext/UiaDll/UiaDll/ElementStructures.h +72 -21
- data/ext/UiaDll/UiaDll/ExpandCollapseMethods.cpp +3 -3
- data/ext/UiaDll/UiaDll/InvokePatternMethods.cpp +1 -1
- data/ext/UiaDll/UiaDll/MenuItemMethods.cpp +2 -2
- data/ext/UiaDll/UiaDll/MouseMethods.cpp +1 -1
- data/ext/UiaDll/UiaDll/RangeValueMethods.cpp +2 -2
- data/ext/UiaDll/UiaDll/SelectionItemMethods.cpp +4 -4
- data/ext/UiaDll/UiaDll/SelectionMethods.cpp +2 -2
- data/ext/UiaDll/UiaDll/StringHelper.h +5 -0
- data/ext/UiaDll/UiaDll/TableItemMethods.cpp +1 -1
- data/ext/UiaDll/UiaDll/TableMethods.cpp +3 -3
- data/ext/UiaDll/UiaDll/TextMethods.cpp +1 -1
- data/ext/UiaDll/UiaDll/ToggleMethods.cpp +2 -2
- data/ext/UiaDll/UiaDll/ValuePatternMethods.cpp +2 -2
- data/ext/UiaDll/UiaDll/WindowMethods.cpp +3 -3
- data/lib/uia/library.rb +3 -2
- data/lib/uia/version.rb +1 -1
- data/spec/uia/element_spec.rb +1 -1
- metadata +4 -4
data/ChangeLog
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
=== Version 0.4.2 / 2014-05-21
|
2
|
+
* Enhancements
|
3
|
+
* Exceptions on the .NET side of things now include stack trace
|
4
|
+
information
|
5
|
+
* Better errors when elements that are expected to exist are no longer
|
6
|
+
there
|
7
|
+
|
8
|
+
* Bug Fixes
|
9
|
+
* Fixes a potential memory leak if an ElementNotAvailableException
|
10
|
+
occurs when grabbing elements
|
11
|
+
|
1
12
|
=== Version 0.4.1 / 2014-05-14
|
2
13
|
* Enhancements
|
3
14
|
* Element#help_text
|
@@ -133,3 +133,107 @@ TEST_F(ElementInformationTest, ItIsNullIfThereAreNoElements) {
|
|
133
133
|
array<Element^>^ nullElements = nullptr;
|
134
134
|
ASSERT_EQ(NULL, ElementInformation::From(nullElements));
|
135
135
|
}
|
136
|
+
|
137
|
+
TEST_F(ElementInformationTest, BadThingsHappenInChildren_ItCleansUpWhatItAllocated) {
|
138
|
+
auto badElement = gcnew ElementStub("Bad element", 123);
|
139
|
+
badElement->SetupBoundingRectangleToThrow();
|
140
|
+
|
141
|
+
Exception^ caughtException = nullptr;
|
142
|
+
|
143
|
+
try {
|
144
|
+
ElementInformation::From(gcnew ElementStub("Good element", 456), badElement);
|
145
|
+
} catch(Exception^ e) { caughtException = e; }
|
146
|
+
|
147
|
+
ASSERT_TRUE(caughtException != nullptr);
|
148
|
+
}
|
149
|
+
|
150
|
+
TEST_F(ElementInformationTest, BadThingsHappenForSingleElement_ItCleansUp) {
|
151
|
+
auto badElement = gcnew ElementStub("Bad element", 123);
|
152
|
+
badElement->SetupBoundingRectangleToThrow();
|
153
|
+
|
154
|
+
Exception^ caughtException = nullptr;
|
155
|
+
|
156
|
+
try {
|
157
|
+
ElementInformation::From(badElement);
|
158
|
+
} catch(Exception^ e) { caughtException = e; }
|
159
|
+
|
160
|
+
// should have cleaned up memory
|
161
|
+
ASSERT_TRUE(caughtException != nullptr);
|
162
|
+
}
|
163
|
+
|
164
|
+
#define GRAB_VARARGS(argument_list, arg_type, arg_count) \
|
165
|
+
va_list arguments;\
|
166
|
+
va_start(arguments, arg0);\
|
167
|
+
list<##arg_type##> ##argument_list##;\
|
168
|
+
##argument_list##.push_back(arg0);\
|
169
|
+
for(auto index = 1; index < ##arg_count##; ++index) {\
|
170
|
+
auto value = va_arg(arguments, ##arg_type##);\
|
171
|
+
##argument_list##.push_back(value);\
|
172
|
+
}
|
173
|
+
|
174
|
+
#define ASSERT_EXPECTED_EL_TO_STRING(expectedValue) \
|
175
|
+
auto length = 0; \
|
176
|
+
auto expectedLength = strlen(expectedValue) + 1; \
|
177
|
+
ASSERT_EQ(expectedLength, length = el.ToString(NULL, 0)); \
|
178
|
+
auto actual = new char[expectedLength]; \
|
179
|
+
el.ToString(actual, expectedLength); \
|
180
|
+
ASSERT_STREQ(expectedValue, actual); \
|
181
|
+
delete[] actual;
|
182
|
+
|
183
|
+
TEST(ElementInformation, ToString_AllEmpty)
|
184
|
+
{
|
185
|
+
ElementInformation el;
|
186
|
+
ASSERT_EXPECTED_EL_TO_STRING("id: (null), name: (null), handle: 0x0, runtime_id: (null)");
|
187
|
+
}
|
188
|
+
|
189
|
+
TEST(ElementInformation, ToString_HasId)
|
190
|
+
{
|
191
|
+
ElementInformation el;
|
192
|
+
el.id = StringHelper::ToUnmanaged("someId");
|
193
|
+
ASSERT_EXPECTED_EL_TO_STRING("id: someId, name: (null), handle: 0x0, runtime_id: (null)");
|
194
|
+
}
|
195
|
+
|
196
|
+
TEST(ElementInformation, ToString_HasName)
|
197
|
+
{
|
198
|
+
ElementInformation el;
|
199
|
+
el.name = StringHelper::ToUnmanaged("someName");
|
200
|
+
ASSERT_EXPECTED_EL_TO_STRING("id: (null), name: someName, handle: 0x0, runtime_id: (null)");
|
201
|
+
}
|
202
|
+
|
203
|
+
TEST(ElementInformation, ToString_HasHandle)
|
204
|
+
{
|
205
|
+
ElementInformation el;
|
206
|
+
el.nativeWindowHandle = 0x123;
|
207
|
+
ASSERT_EXPECTED_EL_TO_STRING("id: (null), name: (null), handle: 0x123, runtime_id: (null)");
|
208
|
+
}
|
209
|
+
|
210
|
+
TEST(ElementInformation, ToString_HasRuntimeId)
|
211
|
+
{
|
212
|
+
ElementInformation el;
|
213
|
+
el.runtimeId = new int[2];
|
214
|
+
el.runtimeId[0] = 123; el.runtimeId[1] = 456;
|
215
|
+
el.runtimeIdLength = 2;
|
216
|
+
ASSERT_EXPECTED_EL_TO_STRING("id: (null), name: (null), handle: 0x0, runtime_id: [123, 456]");
|
217
|
+
}
|
218
|
+
|
219
|
+
TEST(ElementInformation, ToString_AllTheThings)
|
220
|
+
{
|
221
|
+
ElementInformation el;
|
222
|
+
el.name = StringHelper::ToUnmanaged("someName");
|
223
|
+
el.id = StringHelper::ToUnmanaged("someId");
|
224
|
+
el.nativeWindowHandle = 0xffff;
|
225
|
+
el.runtimeId = new int[1];
|
226
|
+
el.runtimeId[0] = 42789;
|
227
|
+
el.runtimeIdLength = 1;
|
228
|
+
ASSERT_EXPECTED_EL_TO_STRING("id: someId, name: someName, handle: 0xffff, runtime_id: [42789]");
|
229
|
+
}
|
230
|
+
|
231
|
+
TEST(ElementInformation, ToManagedString)
|
232
|
+
{
|
233
|
+
ElementInformation el;
|
234
|
+
el.name = StringHelper::ToUnmanaged("someName");
|
235
|
+
|
236
|
+
auto actual = StringHelper::ToUnmanaged(el.ToManagedString());
|
237
|
+
ASSERT_STREQ("id: (null), name: someName, handle: 0x0, runtime_id: (null)", actual);
|
238
|
+
delete[] actual;
|
239
|
+
}
|
@@ -59,7 +59,16 @@ public:
|
|
59
59
|
|
60
60
|
virtual property array<int>^ BoundingRectangle
|
61
61
|
{
|
62
|
-
array<int>^ get() override {
|
62
|
+
array<int>^ get() override {
|
63
|
+
if( _throwOnBoundingRectangle ) {
|
64
|
+
throw gcnew System::Windows::Automation::ElementNotAvailableException("oops");
|
65
|
+
}
|
66
|
+
return gcnew array<int> {0, 0, 0, 0};
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
void SetupBoundingRectangleToThrow() {
|
71
|
+
_throwOnBoundingRectangle = true;
|
63
72
|
}
|
64
73
|
|
65
74
|
virtual property int NativeWindowHandle
|
@@ -96,4 +105,5 @@ private:
|
|
96
105
|
bool _isEnabled;
|
97
106
|
bool _isVisible;
|
98
107
|
bool _hasKeyboardFocus;
|
108
|
+
bool _throwOnBoundingRectangle;
|
99
109
|
};
|
@@ -25,7 +25,7 @@ extern "C" {
|
|
25
25
|
|
26
26
|
return new SearchCondition(patternIds);
|
27
27
|
} catch(Exception^ e) {
|
28
|
-
StringHelper::CopyToUnmanagedString(e
|
28
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
29
29
|
return NULL;
|
30
30
|
}
|
31
31
|
}
|
@@ -5,12 +5,22 @@ using namespace UIA::Helper;
|
|
5
5
|
|
6
6
|
extern "C" {
|
7
7
|
Element^ ElementFrom(ElementInformationPtr element) {
|
8
|
-
|
9
|
-
|
8
|
+
Element^ foundElement = nullptr;
|
9
|
+
|
10
|
+
try {
|
11
|
+
if( element->nativeWindowHandle > 0 ) {
|
12
|
+
foundElement = Element::ByHandle(IntPtr(element->nativeWindowHandle));
|
13
|
+
} else {
|
14
|
+
foundElement = Element::ByRuntimeId(ArrayHelper::ToArray(element->runtimeId, element->runtimeIdLength));
|
15
|
+
}
|
16
|
+
} catch(Exception^) { }
|
17
|
+
|
18
|
+
if( nullptr == foundElement ) {
|
19
|
+
throw gcnew Exception(String::Format("Element no longer exists ({0})", element->ToManagedString()));
|
10
20
|
}
|
11
21
|
|
12
|
-
|
13
|
-
}
|
22
|
+
return foundElement;
|
23
|
+
}
|
14
24
|
__declspec(dllexport) void Element_Release(ElementInformationPtr elementInformation) {
|
15
25
|
delete elementInformation;
|
16
26
|
}
|
@@ -19,7 +29,7 @@ extern "C" {
|
|
19
29
|
try {
|
20
30
|
element->Refresh(ElementFrom(element));
|
21
31
|
} catch(Exception^ e) {
|
22
|
-
StringHelper::CopyToUnmanagedString(e
|
32
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
23
33
|
}
|
24
34
|
}
|
25
35
|
|
@@ -27,7 +37,7 @@ extern "C" {
|
|
27
37
|
try {
|
28
38
|
ElementFrom(element)->SendKeys(gcnew String(keysToSend));
|
29
39
|
} catch(Exception^ e) {
|
30
|
-
StringHelper::CopyToUnmanagedString(e
|
40
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
31
41
|
}
|
32
42
|
}
|
33
43
|
|
@@ -36,18 +46,18 @@ extern "C" {
|
|
36
46
|
auto scope = (TreeScope) Enum::Parse(TreeScope::typeid, gcnew String(treeScope));
|
37
47
|
return ElementInformation::From(ElementFrom(element)->FindFirst(scope, ConditionHelper::ConditionFrom(conditions)));
|
38
48
|
} catch(Exception^ e) {
|
39
|
-
StringHelper::CopyToUnmanagedString(e
|
49
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
40
50
|
}
|
41
51
|
|
42
52
|
return NULL;
|
43
53
|
}
|
44
54
|
|
45
|
-
|
55
|
+
#pragma managed(push, off)
|
46
56
|
__declspec(dllexport) ElementInformationPtr FindFirst(ElementInformationPtr element, const char* treeScope, char* errorInfo, const int errorInfoLength, const int count, SearchConditionPtr arg0, ...) {
|
47
57
|
GRAB_VARARGS(conditions, SearchConditionPtr, count);
|
48
58
|
return ManagedFindFirst(element, treeScope, conditions, errorInfo, errorInfoLength);
|
49
59
|
}
|
50
|
-
|
60
|
+
#pragma managed(pop)
|
51
61
|
|
52
62
|
int ManagedFindAll(ElementInformationPtr element, ElementInformation** elements, const char* treeScope, list<SearchConditionPtr>& conditions, char* errorInfo, const int errorInfoLength) {
|
53
63
|
try {
|
@@ -56,24 +66,24 @@ extern "C" {
|
|
56
66
|
*elements = ElementInformation::From(foundElements);
|
57
67
|
return foundElements->Length;
|
58
68
|
} catch(Exception^ e) {
|
59
|
-
StringHelper::CopyToUnmanagedString(e
|
69
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
60
70
|
}
|
61
71
|
|
62
72
|
return 0;
|
63
73
|
}
|
64
74
|
|
65
|
-
|
75
|
+
#pragma managed(push, off)
|
66
76
|
__declspec(dllexport) int FindAll(ElementInformationPtr parent, ElementInformation** elements, const char* treeScope, char* errorInfo, const int errorInfoLength, const int count, SearchConditionPtr arg0, ...) {
|
67
77
|
GRAB_VARARGS(conditions, SearchConditionPtr, count);
|
68
78
|
return ManagedFindAll(parent, elements, treeScope, conditions, errorInfo, errorInfoLength);
|
69
79
|
}
|
70
|
-
|
80
|
+
#pragma managed(pop)
|
71
81
|
|
72
82
|
__declspec(dllexport) ElementInformationPtr Element_FindById(const char* automationId, char* errorInfo, const int errorLength) {
|
73
83
|
try {
|
74
84
|
return ElementInformation::From(Element::ById(gcnew String(automationId)));
|
75
85
|
} catch(Exception^ error) {
|
76
|
-
StringHelper::CopyToUnmanagedString(error
|
86
|
+
StringHelper::CopyToUnmanagedString(error, errorInfo, errorLength);
|
77
87
|
}
|
78
88
|
|
79
89
|
return NULL;
|
@@ -83,7 +93,7 @@ extern "C" {
|
|
83
93
|
try {
|
84
94
|
return ElementInformation::From(Element::ByName(gcnew String(name)));
|
85
95
|
} catch(Exception^ error) {
|
86
|
-
StringHelper::CopyToUnmanagedString(error
|
96
|
+
StringHelper::CopyToUnmanagedString(error, errorInfo, errorLength);
|
87
97
|
}
|
88
98
|
|
89
99
|
return NULL;
|
@@ -93,7 +103,7 @@ extern "C" {
|
|
93
103
|
try {
|
94
104
|
return ElementInformation::From(Element::ByProcessId(processId));
|
95
105
|
} catch(Exception^ error) {
|
96
|
-
StringHelper::CopyToUnmanagedString(error
|
106
|
+
StringHelper::CopyToUnmanagedString(error, errorInfo, errorLength);
|
97
107
|
}
|
98
108
|
|
99
109
|
return NULL;
|
@@ -103,7 +113,7 @@ extern "C" {
|
|
103
113
|
try {
|
104
114
|
return new ElementInformation(Element::ByHandle(IntPtr(windowHandle)));
|
105
115
|
} catch(Exception^ error) {
|
106
|
-
StringHelper::CopyToUnmanagedString(error
|
116
|
+
StringHelper::CopyToUnmanagedString(error, errorInfo, errorLength);
|
107
117
|
}
|
108
118
|
|
109
119
|
return NULL;
|
@@ -113,7 +123,7 @@ extern "C" {
|
|
113
123
|
try {
|
114
124
|
return ElementInformation::From(Element::ByRuntimeId(ArrayHelper::ToArray(runtimeIds, numberOfIds)));
|
115
125
|
} catch(Exception^ error) {
|
116
|
-
StringHelper::CopyToUnmanagedString(error
|
126
|
+
StringHelper::CopyToUnmanagedString(error, errorInfo, errorLength);
|
117
127
|
}
|
118
128
|
|
119
129
|
return NULL;
|
@@ -125,7 +135,7 @@ extern "C" {
|
|
125
135
|
*children = ElementInformation::From(windows);
|
126
136
|
return windows->Length;
|
127
137
|
} catch(Exception^ e) {
|
128
|
-
StringHelper::CopyToUnmanagedString(e
|
138
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
129
139
|
return 0;
|
130
140
|
}
|
131
141
|
}
|
@@ -136,7 +146,7 @@ extern "C" {
|
|
136
146
|
*children = ElementInformation::From(elements);
|
137
147
|
return elements->Length;
|
138
148
|
} catch(Exception^ error) {
|
139
|
-
StringHelper::CopyToUnmanagedString(error
|
149
|
+
StringHelper::CopyToUnmanagedString(error, errorInfo, errorLength);
|
140
150
|
return 0;
|
141
151
|
}
|
142
152
|
}
|
@@ -147,7 +157,7 @@ extern "C" {
|
|
147
157
|
*descendants = ElementInformation::From(elements);
|
148
158
|
return elements->Length;
|
149
159
|
} catch(Exception^ error) {
|
150
|
-
StringHelper::CopyToUnmanagedString(error
|
160
|
+
StringHelper::CopyToUnmanagedString(error, errorInfo, errorLength);
|
151
161
|
return 0;
|
152
162
|
}
|
153
163
|
}
|
@@ -156,7 +166,7 @@ extern "C" {
|
|
156
166
|
try {
|
157
167
|
ElementFrom(element)->ClickClickablePoint();
|
158
168
|
} catch(Exception^ error) {
|
159
|
-
StringHelper::CopyToUnmanagedString(error
|
169
|
+
StringHelper::CopyToUnmanagedString(error, errorInfo, errorLength);
|
160
170
|
}
|
161
171
|
}
|
162
172
|
|
@@ -164,7 +174,7 @@ extern "C" {
|
|
164
174
|
try {
|
165
175
|
ElementFrom(element)->ClickCenter();
|
166
176
|
} catch(Exception^ error) {
|
167
|
-
StringHelper::CopyToUnmanagedString(error
|
177
|
+
StringHelper::CopyToUnmanagedString(error, errorInfo, errorLength);
|
168
178
|
}
|
169
179
|
}
|
170
180
|
|
@@ -172,7 +182,7 @@ extern "C" {
|
|
172
182
|
try {
|
173
183
|
ElementFrom(element)->SetFocus();
|
174
184
|
} catch(Exception^ error) {
|
175
|
-
StringHelper::CopyToUnmanagedString(error
|
185
|
+
StringHelper::CopyToUnmanagedString(error, errorInfo, errorLength);
|
176
186
|
}
|
177
187
|
}
|
178
188
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
#pragma once
|
2
2
|
#include "ArrayHelper.h"
|
3
3
|
#include "StringHelper.h"
|
4
|
+
#include <stdio.h>
|
4
5
|
|
5
6
|
typedef struct _ElementInformation {
|
6
7
|
int nativeWindowHandle;
|
@@ -34,8 +35,14 @@ typedef struct _ElementInformation {
|
|
34
35
|
|
35
36
|
auto elementInformation = new _ElementInformation[elements->Length];
|
36
37
|
auto index = 0;
|
37
|
-
|
38
|
-
|
38
|
+
|
39
|
+
try {
|
40
|
+
for each(auto element in elements) {
|
41
|
+
elementInformation[index++].Refresh(element);
|
42
|
+
}
|
43
|
+
} catch(Exception^) {
|
44
|
+
delete[] elementInformation;
|
45
|
+
throw;
|
39
46
|
}
|
40
47
|
|
41
48
|
return elementInformation;
|
@@ -43,28 +50,52 @@ typedef struct _ElementInformation {
|
|
43
50
|
|
44
51
|
void Refresh(Element^ element) {
|
45
52
|
Reset();
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
53
|
+
|
54
|
+
try {
|
55
|
+
id = StringHelper::ToUnmanaged(element->Id);
|
56
|
+
name = StringHelper::ToUnmanaged(element->Name);
|
57
|
+
className = StringHelper::ToUnmanaged(element->ClassName);
|
58
|
+
nativeWindowHandle = element->NativeWindowHandle;
|
59
|
+
runtimeId = ArrayHelper::FromArray(element->RuntimeId);
|
60
|
+
runtimeIdLength = element->RuntimeId->Length;
|
61
|
+
controlTypeId = element->ControlTypeId;
|
62
|
+
patterns = ArrayHelper::FromArray(element->SupportedPatternIds);
|
63
|
+
patternsLength = element->SupportedPatternIds->Length;
|
64
|
+
|
65
|
+
isEnabled = element->IsEnabled;
|
66
|
+
isVisible = element->IsVisible;
|
67
|
+
hasKeyboardFocus = element->HasKeyboardFocus;
|
68
|
+
|
69
|
+
helpText = StringHelper::ToUnmanaged(element->HelpText);
|
70
|
+
|
71
|
+
auto r = element->BoundingRectangle;
|
72
|
+
for(auto coord = 0; coord < 4; coord++) {
|
73
|
+
boundingRectangle[coord] = r[coord];
|
74
|
+
}
|
75
|
+
} catch(Exception^) {
|
76
|
+
Reset();
|
77
|
+
throw;
|
65
78
|
}
|
66
79
|
}
|
67
80
|
|
81
|
+
const int ToString(char* s, const int length) {
|
82
|
+
const char* format = "id: %s, name: %s, handle: 0x%x, runtime_id: %s";
|
83
|
+
auto runtimeIdString = RuntimeIdString();
|
84
|
+
auto neededLength = _snprintf(s, length, format, id, name, nativeWindowHandle, runtimeIdString) + 1;
|
85
|
+
delete[] runtimeIdString;
|
86
|
+
return neededLength;
|
87
|
+
}
|
88
|
+
|
89
|
+
String^ ToManagedString() {
|
90
|
+
auto length = ToString(NULL, 0);
|
91
|
+
auto s = new char[length];
|
92
|
+
ToString(s, length);
|
93
|
+
|
94
|
+
auto managedString = gcnew String(s);
|
95
|
+
delete[] s;
|
96
|
+
return managedString;
|
97
|
+
}
|
98
|
+
|
68
99
|
~_ElementInformation() {
|
69
100
|
Reset();
|
70
101
|
}
|
@@ -75,4 +106,24 @@ private:
|
|
75
106
|
name = NULL; runtimeId = NULL; patterns = NULL; id = NULL; className = NULL; helpText = NULL;
|
76
107
|
}
|
77
108
|
|
109
|
+
char* RuntimeIdString() {
|
110
|
+
if(NULL == runtimeId || runtimeIdLength == 0) return NULL;
|
111
|
+
|
112
|
+
auto max = 1000;
|
113
|
+
auto s = new char[max];
|
114
|
+
strcpy(s, "[");
|
115
|
+
|
116
|
+
char current[20] = {0};
|
117
|
+
|
118
|
+
for(auto index = 0; index < runtimeIdLength; ++index) {
|
119
|
+
_snprintf(current, 20, "%d, ", runtimeId[index]);
|
120
|
+
strncat_s(s, max, current, _TRUNCATE);
|
121
|
+
}
|
122
|
+
s[strlen(s) - 2] = NULL;
|
123
|
+
|
124
|
+
strncat_s(s, max, "]", _TRUNCATE);
|
125
|
+
|
126
|
+
return s;
|
127
|
+
}
|
128
|
+
|
78
129
|
} ElementInformation, *ElementInformationPtr;
|
@@ -10,7 +10,7 @@ extern "C" {
|
|
10
10
|
auto info = ElementFrom(element)->As<ExpandCollapsePattern^>(ExpandCollapsePattern::Pattern)->Current;
|
11
11
|
return new ExpandCollapseInfo(info.ExpandCollapseState.ToString());
|
12
12
|
} catch(Exception^ e) {
|
13
|
-
StringHelper::CopyToUnmanagedString(e
|
13
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
14
14
|
return NULL;
|
15
15
|
}
|
16
16
|
}
|
@@ -19,7 +19,7 @@ extern "C" {
|
|
19
19
|
try {
|
20
20
|
ElementFrom(element)->As<ExpandCollapsePattern^>(ExpandCollapsePattern::Pattern)->Expand();
|
21
21
|
} catch(Exception^ e) {
|
22
|
-
StringHelper::CopyToUnmanagedString(e
|
22
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
23
23
|
}
|
24
24
|
}
|
25
25
|
|
@@ -27,7 +27,7 @@ extern "C" {
|
|
27
27
|
try {
|
28
28
|
ElementFrom(element)->As<ExpandCollapsePattern^>(ExpandCollapsePattern::Pattern)->Collapse();
|
29
29
|
} catch(Exception^ e) {
|
30
|
-
StringHelper::CopyToUnmanagedString(e
|
30
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
31
31
|
}
|
32
32
|
}
|
33
33
|
}
|
@@ -5,7 +5,7 @@ extern "C" {
|
|
5
5
|
try {
|
6
6
|
ElementFrom(element)->As<InvokePattern^>(InvokePattern::Pattern)->Invoke();
|
7
7
|
} catch(Exception^ e) {
|
8
|
-
StringHelper::CopyToUnmanagedString(e
|
8
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
9
9
|
}
|
10
10
|
}
|
11
11
|
}
|
@@ -24,7 +24,7 @@ extern "C" {
|
|
24
24
|
try {
|
25
25
|
MenuItemPath(element, items)->As<InvokePattern^>(InvokePattern::Pattern)->Invoke();
|
26
26
|
} catch(Exception^ e) {
|
27
|
-
StringHelper::CopyToUnmanagedString(e
|
27
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
28
28
|
}
|
29
29
|
}
|
30
30
|
|
@@ -34,7 +34,7 @@ extern "C" {
|
|
34
34
|
} catch(MenuItemNotFound^) {
|
35
35
|
return NULL;
|
36
36
|
} catch(Exception^ e) {
|
37
|
-
StringHelper::CopyToUnmanagedString(e
|
37
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
38
38
|
return NULL;
|
39
39
|
}
|
40
40
|
}
|
@@ -7,7 +7,7 @@ extern "C" {
|
|
7
7
|
try {
|
8
8
|
Mouse::Drag(startX, startY, endX, endY);
|
9
9
|
} catch(Exception^ e) {
|
10
|
-
StringHelper::CopyToUnmanagedString(e
|
10
|
+
StringHelper::CopyToUnmanagedString(e, errorInformation, errorInformationLength);
|
11
11
|
}
|
12
12
|
}
|
13
13
|
}
|
@@ -9,7 +9,7 @@ extern "C" {
|
|
9
9
|
try {
|
10
10
|
return new RangeValueInformation(ElementFrom(element)->As<RangeValuePattern^>(RangeValuePattern::Pattern)->Current);
|
11
11
|
} catch(Exception^ e) {
|
12
|
-
StringHelper::CopyToUnmanagedString(e
|
12
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
13
13
|
return NULL;
|
14
14
|
}
|
15
15
|
}
|
@@ -18,7 +18,7 @@ extern "C" {
|
|
18
18
|
try {
|
19
19
|
return ElementFrom(element)->As<RangeValuePattern^>(RangeValuePattern::Pattern)->SetValue(value);
|
20
20
|
} catch(Exception^ e) {
|
21
|
-
StringHelper::CopyToUnmanagedString(e
|
21
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
22
22
|
}
|
23
23
|
}
|
24
24
|
|
@@ -10,7 +10,7 @@ extern "C" {
|
|
10
10
|
auto info = ElementFrom(element)->As<SelectionItemPattern^>(SelectionItemPattern::Pattern)->Current;
|
11
11
|
return new SelectionItemInformation(info);
|
12
12
|
} catch(Exception^ e) {
|
13
|
-
StringHelper::CopyToUnmanagedString(e
|
13
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
14
14
|
return NULL;
|
15
15
|
}
|
16
16
|
}
|
@@ -19,7 +19,7 @@ extern "C" {
|
|
19
19
|
try {
|
20
20
|
ElementFrom(element)->As<SelectionItemPattern^>(SelectionItemPattern::Pattern)->Select();
|
21
21
|
} catch(Exception^ e) {
|
22
|
-
StringHelper::CopyToUnmanagedString(e
|
22
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
23
23
|
}
|
24
24
|
}
|
25
25
|
|
@@ -27,7 +27,7 @@ extern "C" {
|
|
27
27
|
try {
|
28
28
|
ElementFrom(element)->As<SelectionItemPattern^>(SelectionItemPattern::Pattern)->AddToSelection();
|
29
29
|
} catch(Exception^ e) {
|
30
|
-
StringHelper::CopyToUnmanagedString(e
|
30
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
31
31
|
}
|
32
32
|
}
|
33
33
|
|
@@ -35,7 +35,7 @@ extern "C" {
|
|
35
35
|
try {
|
36
36
|
ElementFrom(element)->As<SelectionItemPattern^>(SelectionItemPattern::Pattern)->RemoveFromSelection();
|
37
37
|
} catch(Exception^ e) {
|
38
|
-
StringHelper::CopyToUnmanagedString(e
|
38
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
39
39
|
}
|
40
40
|
}
|
41
41
|
}
|
@@ -9,7 +9,7 @@ extern "C" {
|
|
9
9
|
try {
|
10
10
|
return new SelectionInformation(ElementFrom(element)->As<SelectionPattern^>(SelectionPattern::Pattern)->Current);
|
11
11
|
} catch(Exception^ e) {
|
12
|
-
StringHelper::CopyToUnmanagedString(e
|
12
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
13
13
|
return NULL;
|
14
14
|
}
|
15
15
|
}
|
@@ -20,7 +20,7 @@ extern "C" {
|
|
20
20
|
*selections = ElementInformation::From(selectedElements);
|
21
21
|
return selectedElements->Length;
|
22
22
|
} catch(Exception^ e) {
|
23
|
-
StringHelper::CopyToUnmanagedString(e
|
23
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
24
24
|
return 0;
|
25
25
|
}
|
26
26
|
}
|
@@ -5,6 +5,11 @@ using namespace System::Runtime::InteropServices;
|
|
5
5
|
ref class StringHelper
|
6
6
|
{
|
7
7
|
public:
|
8
|
+
static void CopyToUnmanagedString(Exception^ e, char* destination, const int destinationSize)
|
9
|
+
{
|
10
|
+
CopyToUnmanagedString(e->Message + e->StackTrace, destination, destinationSize);
|
11
|
+
}
|
12
|
+
|
8
13
|
static void CopyToUnmanagedString(String^ source, char* destination, const int destinationSize)
|
9
14
|
{
|
10
15
|
auto unmanagedString = Marshal::StringToHGlobalAnsi(source);
|
@@ -9,7 +9,7 @@ extern "C" {
|
|
9
9
|
try {
|
10
10
|
return new TableItemInformation(ElementFrom(element)->As<TableItemPattern^>(TableItemPattern::Pattern)->Current);
|
11
11
|
} catch(Exception^ e) {
|
12
|
-
StringHelper::CopyToUnmanagedString(e
|
12
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
13
13
|
return NULL;
|
14
14
|
}
|
15
15
|
}
|
@@ -9,7 +9,7 @@ extern "C" {
|
|
9
9
|
try {
|
10
10
|
return new TableInformation(ElementFrom(element)->As<TablePattern^>(TablePattern::Pattern)->Current);
|
11
11
|
} catch(Exception^ e) {
|
12
|
-
StringHelper::CopyToUnmanagedString(e
|
12
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
13
13
|
return NULL;
|
14
14
|
}
|
15
15
|
}
|
@@ -20,7 +20,7 @@ extern "C" {
|
|
20
20
|
*headers = ElementInformation::From(Element::From(headerElements));
|
21
21
|
return headerElements->Length;
|
22
22
|
} catch(Exception^ e) {
|
23
|
-
StringHelper::CopyToUnmanagedString(e
|
23
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
24
24
|
return 0;
|
25
25
|
}
|
26
26
|
}
|
@@ -30,7 +30,7 @@ extern "C" {
|
|
30
30
|
auto table = ElementFrom(element);
|
31
31
|
return ElementInformation::From(table->Find(TreeScope::Children, gcnew PropertyCondition(AutomationElement::ControlTypeProperty, ControlType::DataItem))[index]);
|
32
32
|
} catch(Exception^ e) {
|
33
|
-
StringHelper::CopyToUnmanagedString(e
|
33
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
34
34
|
return NULL;
|
35
35
|
}
|
36
36
|
}
|
@@ -10,7 +10,7 @@ extern "C" {
|
|
10
10
|
auto info = ElementFrom(element)->As<TogglePattern^>(TogglePattern::Pattern)->Current;
|
11
11
|
return new ToggleInformation(info.ToggleState.ToString());
|
12
12
|
} catch(Exception^ e) {
|
13
|
-
StringHelper::CopyToUnmanagedString(e
|
13
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
14
14
|
return NULL;
|
15
15
|
}
|
16
16
|
}
|
@@ -19,7 +19,7 @@ extern "C" {
|
|
19
19
|
try {
|
20
20
|
ElementFrom(element)->As<TogglePattern^>(TogglePattern::Pattern)->Toggle();
|
21
21
|
} catch(Exception^ e) {
|
22
|
-
StringHelper::CopyToUnmanagedString(e
|
22
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
23
23
|
}
|
24
24
|
}
|
25
25
|
}
|
@@ -9,7 +9,7 @@ extern "C" {
|
|
9
9
|
try {
|
10
10
|
ElementFrom(element)->As<ValuePattern^>(ValuePattern::Pattern)->SetValue(gcnew String(value));
|
11
11
|
} catch(Exception^ e) {
|
12
|
-
StringHelper::CopyToUnmanagedString(e
|
12
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
13
13
|
}
|
14
14
|
}
|
15
15
|
|
@@ -18,7 +18,7 @@ extern "C" {
|
|
18
18
|
auto valuePattern = ElementFrom(element)->As<ValuePattern^>(ValuePattern::Pattern);
|
19
19
|
return new ValuePatternInformation(valuePattern->Current);
|
20
20
|
} catch(Exception^ e) {
|
21
|
-
StringHelper::CopyToUnmanagedString(e
|
21
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
22
22
|
return NULL;
|
23
23
|
}
|
24
24
|
}
|
@@ -9,7 +9,7 @@ extern "C" {
|
|
9
9
|
try {
|
10
10
|
return new WindowInformation(ElementFrom(element)->As<WindowPattern^>(WindowPattern::Pattern)->Current);
|
11
11
|
} catch(Exception^ e) {
|
12
|
-
StringHelper::CopyToUnmanagedString(e
|
12
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
13
13
|
return NULL;
|
14
14
|
}
|
15
15
|
}
|
@@ -18,7 +18,7 @@ extern "C" {
|
|
18
18
|
try {
|
19
19
|
ElementFrom(element)->As<WindowPattern^>(WindowPattern::Pattern)->SetWindowVisualState((WindowVisualState) Enum::Parse(WindowVisualState::typeid, gcnew String(visualState), false));
|
20
20
|
} catch(Exception^ e) {
|
21
|
-
StringHelper::CopyToUnmanagedString(e
|
21
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
22
22
|
}
|
23
23
|
}
|
24
24
|
|
@@ -26,7 +26,7 @@ extern "C" {
|
|
26
26
|
try {
|
27
27
|
ElementFrom(element)->As<WindowPattern^>(WindowPattern::Pattern)->Close();
|
28
28
|
} catch(Exception^ e) {
|
29
|
-
StringHelper::CopyToUnmanagedString(e
|
29
|
+
StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
|
30
30
|
}
|
31
31
|
}
|
32
32
|
}
|
data/lib/uia/library.rb
CHANGED
@@ -172,8 +172,9 @@ module Uia
|
|
172
172
|
end
|
173
173
|
|
174
174
|
def self.try_catch(&block)
|
175
|
-
|
176
|
-
|
175
|
+
buffer_size = 4096
|
176
|
+
string_buffer = FFI::MemoryPointer.new :char, buffer_size
|
177
|
+
result = block.call(string_buffer, buffer_size)
|
177
178
|
error_info = string_buffer.read_string
|
178
179
|
raise error_info unless error_info.empty?
|
179
180
|
result
|
data/lib/uia/version.rb
CHANGED
data/spec/uia/element_spec.rb
CHANGED
@@ -128,7 +128,7 @@ describe Uia::Element do
|
|
128
128
|
context 'pattern' do
|
129
129
|
Then { element.find(pattern: :range_value).id == 'numericUpDown1' }
|
130
130
|
Then { element.find(pattern: [:selection_item, :range_value]).id == 'numericUpDown1' }
|
131
|
-
Then { expect { element.find(pattern: [:not_valid, :range_value]) }.to raise_error RuntimeError,
|
131
|
+
Then { expect { element.find(pattern: [:not_valid, :range_value]) }.to raise_error RuntimeError, /IsNotValidPatternAvailableProperty is not a valid AutomationProperty/ }
|
132
132
|
end
|
133
133
|
|
134
134
|
context 'combinations' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-05-
|
12
|
+
date: 2014-05-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -262,7 +262,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
262
262
|
version: '0'
|
263
263
|
segments:
|
264
264
|
- 0
|
265
|
-
hash: -
|
265
|
+
hash: -370470925
|
266
266
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
267
267
|
none: false
|
268
268
|
requirements:
|
@@ -271,7 +271,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
271
271
|
version: '0'
|
272
272
|
segments:
|
273
273
|
- 0
|
274
|
-
hash: -
|
274
|
+
hash: -370470925
|
275
275
|
requirements: []
|
276
276
|
rubyforge_project:
|
277
277
|
rubygems_version: 1.8.28
|