uia 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|