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 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 { return gcnew array<int> {0, 0, 0, 0}; }
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->Message, errorInfo, errorInfoLength);
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
- if( element->nativeWindowHandle > 0 ) {
9
- return Element::ByHandle(IntPtr(element->nativeWindowHandle));
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
- return Element::ByRuntimeId(ArrayHelper::ToArray(element->runtimeId, element->runtimeIdLength));
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
49
+ StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
40
50
  }
41
51
 
42
52
  return NULL;
43
53
  }
44
54
 
45
- #pragma managed(push, off)
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
- #pragma managed(pop)
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->Message + Environment::NewLine + e->StackTrace, errorInfo, errorInfoLength);
69
+ StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
60
70
  }
61
71
 
62
72
  return 0;
63
73
  }
64
74
 
65
- #pragma managed(push, off)
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
- #pragma managed(pop)
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->Message, errorInfo, errorLength);
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->Message, errorInfo, errorLength);
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->Message, errorInfo, errorLength);
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->Message, errorInfo, errorLength);
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->Message, errorInfo, errorLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorLength);
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->Message, errorInfo, errorLength);
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->Message, errorInfo, errorLength);
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->Message, errorInfo, errorLength);
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->Message, errorInfo, errorLength);
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
- for each(auto element in elements) {
38
- elementInformation[index++].Refresh(element);
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
- id = StringHelper::ToUnmanaged(element->Id);
47
- name = StringHelper::ToUnmanaged(element->Name);
48
- className = StringHelper::ToUnmanaged(element->ClassName);
49
- nativeWindowHandle = element->NativeWindowHandle;
50
- runtimeId = ArrayHelper::FromArray(element->RuntimeId);
51
- runtimeIdLength = element->RuntimeId->Length;
52
- controlTypeId = element->ControlTypeId;
53
- patterns = ArrayHelper::FromArray(element->SupportedPatternIds);
54
- patternsLength = element->SupportedPatternIds->Length;
55
-
56
- isEnabled = element->IsEnabled;
57
- isVisible = element->IsVisible;
58
- hasKeyboardFocus = element->HasKeyboardFocus;
59
-
60
- helpText = StringHelper::ToUnmanaged(element->HelpText);
61
-
62
- auto r = element->BoundingRectangle;
63
- for(auto coord = 0; coord < 4; coord++) {
64
- boundingRectangle[coord] = r[coord];
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInformation, errorInformationLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
33
+ StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
34
34
  return NULL;
35
35
  }
36
36
  }
@@ -10,7 +10,7 @@ extern "C" {
10
10
 
11
11
  return theText->Length;
12
12
  } catch(Exception^ e) {
13
- StringHelper::CopyToUnmanagedString(e->Message, errorInfo, errorInfoLength);
13
+ StringHelper::CopyToUnmanagedString(e, errorInfo, errorInfoLength);
14
14
  return 0;
15
15
  }
16
16
  }
@@ -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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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->Message, errorInfo, errorInfoLength);
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
- string_buffer = FFI::MemoryPointer.new :char, 1024
176
- result = block.call(string_buffer, 1024)
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
@@ -1,3 +1,3 @@
1
1
  module Uia
2
- VERSION = '0.4.1'
2
+ VERSION = '0.4.2'
3
3
  end
@@ -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, 'IsNotValidPatternAvailableProperty is not a valid AutomationProperty' }
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.1
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-14 00:00:00.000000000 Z
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: -1027979665
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: -1027979665
274
+ hash: -370470925
275
275
  requirements: []
276
276
  rubyforge_project:
277
277
  rubygems_version: 1.8.28