-
Notifications
You must be signed in to change notification settings - Fork 53
Expand file tree
/
Copy pathClientSideProviders.cs
More file actions
213 lines (182 loc) · 8.31 KB
/
ClientSideProviders.cs
File metadata and controls
213 lines (182 loc) · 8.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
// (c) Copyright Microsoft, 2012.
// This source is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
// All other rights reserved.
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Automation.Providers;
using UIAComWrapperInternal;
using Interop.UIAutomationClient;
using UIAutomationClient = Interop.UIAutomationClient;
namespace System.Windows.Automation
{
[Flags]
public enum ClientSideProviderMatchIndicator
{
None,
AllowSubstringMatch,
DisallowBaseClassNameMatch
}
// Defines a client-side provider creation function
// I would prefer not to use UIAutomationClient types in the API surface
// In the original API, this was a System.Windows.Automation.Providers type.
// But I cannot pass anything but a UIAutomationClient type into
// the COM API's return parameter.
public delegate IRawElementProviderSimple ClientSideProviderFactoryCallback(IntPtr hwnd, int idChild, int idObject);
[StructLayout(LayoutKind.Sequential)]
public struct ClientSideProviderDescription
{
private string _className;
private string _imageName;
private ClientSideProviderMatchIndicator _flags;
private ClientSideProviderFactoryCallback _proxyFactoryCallback;
public ClientSideProviderDescription(ClientSideProviderFactoryCallback clientSideProviderFactoryCallback, string className)
{
this._className = (className != null) ? className.ToLower(CultureInfo.InvariantCulture) : null;
this._flags = ClientSideProviderMatchIndicator.None;
this._imageName = null;
this._proxyFactoryCallback = clientSideProviderFactoryCallback;
}
public ClientSideProviderDescription(ClientSideProviderFactoryCallback clientSideProviderFactoryCallback, string className, string imageName, ClientSideProviderMatchIndicator flags)
{
this._className = (className != null) ? className.ToLower(CultureInfo.InvariantCulture) : null;
this._imageName = (imageName != null) ? imageName.ToLower(CultureInfo.InvariantCulture) : null;
this._flags = flags;
this._proxyFactoryCallback = clientSideProviderFactoryCallback;
}
public string ClassName
{
get
{
return this._className;
}
}
public ClientSideProviderMatchIndicator Flags
{
get
{
return this._flags;
}
}
public string ImageName
{
get
{
return this._imageName;
}
}
public ClientSideProviderFactoryCallback ClientSideProviderFactoryCallback
{
get
{
return this._proxyFactoryCallback;
}
}
}
internal class ProxyFactoryCallbackWrapper : UIAutomationClient.IUIAutomationProxyFactory
{
private ClientSideProviderFactoryCallback _callback;
private int _serialNumber;
static private int _staticSerialNumber = 1;
public ProxyFactoryCallbackWrapper(ClientSideProviderFactoryCallback callback)
{
System.Diagnostics.Debug.Assert(callback != null);
_callback = callback;
_serialNumber = _staticSerialNumber;
System.Threading.Interlocked.Increment(ref _staticSerialNumber);
}
#region IUIAutomationProxyFactory Members
IRawElementProviderSimple UIAutomationClient.IUIAutomationProxyFactory.CreateProvider(IntPtr hwnd, int idObject, int idChild)
{
IRawElementProviderSimple provider = _callback(hwnd, idChild, idObject);
return provider;
}
string UIAutomationClient.IUIAutomationProxyFactory.ProxyFactoryId
{
get
{
return "ProxyFactory" + this._serialNumber.ToString();
}
}
#endregion
}
public static class ClientSettings
{
// Methods
public static void RegisterClientSideProviderAssembly(AssemblyName assemblyName)
{
Utility.ValidateArgumentNonNull(assemblyName, "assemblyName");
// Load the assembly
Assembly assembly = null;
try
{
assembly = Assembly.Load(assemblyName);
}
catch (System.IO.FileNotFoundException)
{
throw new ProxyAssemblyNotLoadedException(String.Format("Assembly {0} not found", assemblyName));
}
// Find the official type
string name = assemblyName.Name + ".UIAutomationClientSideProviders";
Type type = assembly.GetType(name);
if (type == null)
{
throw new ProxyAssemblyNotLoadedException(String.Format("Could not find type {0} in assembly {1}", name, assemblyName));
}
// Find the descriptor table
FieldInfo field = type.GetField("ClientSideProviderDescriptionTable", BindingFlags.Public | BindingFlags.Static);
if ((field == null) || (field.FieldType != typeof(ClientSideProviderDescription[])))
{
throw new ProxyAssemblyNotLoadedException(String.Format("Could not find register method on type {0} in assembly {1}", name, assemblyName));
}
// Get the table value
ClientSideProviderDescription[] clientSideProviderDescription = field.GetValue(null) as ClientSideProviderDescription[];
// Write it through
if (clientSideProviderDescription != null)
{
ClientSettings.RegisterClientSideProviders(clientSideProviderDescription);
}
}
public static void RegisterClientSideProviders(ClientSideProviderDescription[] clientSideProviderDescription)
{
Utility.ValidateArgumentNonNull(clientSideProviderDescription, "clientSideProviderDescription ");
// Convert providers to native code representation
List<UIAutomationClient.IUIAutomationProxyFactoryEntry> entriesList =
new List<UIAutomationClient.IUIAutomationProxyFactoryEntry>();
foreach (ClientSideProviderDescription provider in clientSideProviderDescription)
{
// Construct a wrapper for the proxy factory callback
Utility.ValidateArgumentNonNull(provider.ClientSideProviderFactoryCallback, "provider.ClientSideProviderFactoryCallback");
ProxyFactoryCallbackWrapper wrapper = new ProxyFactoryCallbackWrapper(provider.ClientSideProviderFactoryCallback);
// Construct a factory entry
UIAutomationClient.IUIAutomationProxyFactoryEntry factoryEntry =
Automation.Factory.CreateProxyFactoryEntry(wrapper);
factoryEntry.AllowSubstringMatch = ((provider.Flags & ClientSideProviderMatchIndicator.AllowSubstringMatch) != 0) ? 1 : 0;
factoryEntry.CanCheckBaseClass = ((provider.Flags & ClientSideProviderMatchIndicator.DisallowBaseClassNameMatch) != 0) ? 0 : 1;
factoryEntry.ClassName = provider.ClassName;
factoryEntry.ImageName = provider.ImageName;
// Add it to the list
entriesList.Add(factoryEntry);
}
// Get the proxy map from Automation and restore the default table
UIAutomationClient.IUIAutomationProxyFactoryMapping map = Automation.Factory.ProxyFactoryMapping;
map.RestoreDefaultTable();
// Decide where to insert
// MSDN recommends inserting after non-control and container proxies
uint insertBefore;
uint count = (uint)map.count;
for (insertBefore = 0; insertBefore < count; ++insertBefore)
{
string proxyFactoryId = map.GetEntry(insertBefore).ProxyFactory.ProxyFactoryId;
if (!proxyFactoryId.Contains("Non-Control") && !proxyFactoryId.Contains("Container"))
{
break;
}
}
// Insert our new entries
map.InsertEntries(insertBefore, entriesList.ToArray());
}
}
}