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 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