├── .gitignore ├── BuildUIACoreInterop.bat ├── CustomizeUiaInterop ├── CustomizeUiaInterop.csproj ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── app.config ├── GitVersion.yml ├── LICENSE ├── ManagedUiaCustomizationCore ├── AttributeDrivenPatternHelpers │ ├── AttributeDrivenPatternHandler.cs │ ├── PatternClientInstanceInterceptor.cs │ ├── PatternGuidAttribute.cs │ ├── PatternMethodAttribute.cs │ ├── PatternPropertyAttribute.cs │ ├── ProviderPatternMatcher.cs │ ├── ReflectionUtils.cs │ ├── StandalonePropertyAttribute.cs │ ├── TypeMember.cs │ └── UiaTypesHelper.cs ├── AttributeDrivenPatternSchema.cs ├── AutomationPeerAugmentationHelper.cs ├── CustomPatternBase.cs ├── IStandalonePropertyProvider.cs ├── ManagedUiaCustomizationCore.csproj ├── NativeMethods.cs ├── Properties │ └── AssemblyInfo.cs ├── Schema │ ├── CustomClientInstanceBase.cs │ ├── CustomPatternSchemaBase.cs │ ├── ISchemaMember.cs │ ├── UiaEventInfoHelper.cs │ ├── UiaMethodInfoHelper.cs │ ├── UiaParameterDescription.cs │ ├── UiaParameterHelper.cs │ ├── UiaParameterListHelper.cs │ ├── UiaPatternInfoHelper.cs │ └── UiaPropertyInfoHelper.cs ├── UiaCallFailedException.cs └── packages.config ├── README.md ├── UIAControls ├── BaseFragmentProvider.cs ├── BaseFragmentRootProvider.cs ├── BaseSimpleProvider.cs ├── ColorProviderClientInstance.cs ├── ColorProviderHandler.cs ├── ColorSchema.cs ├── Form1.Designer.cs ├── Form1.cs ├── Form1.resx ├── IColorPattern.cs ├── IColorProvider.cs ├── ITestPattern.cs ├── ITestProvider.cs ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── ReadyStateSchema.cs ├── TestPatternProvider.cs ├── TestProviderClientInstance.cs ├── TestProviderHandler.cs ├── TestSchema.cs ├── TriColorControl.Designer.cs ├── TriColorControl.cs ├── TriColorControl.resx ├── TriColorFragmentProvider.cs ├── TriColorProvider.cs ├── TriColorValue.cs ├── TriColorValueHelper.cs ├── UIAControls.csproj └── packages.config ├── UiaControlsTest ├── AttributeDrivenPatternSchemaTests.cs ├── CustomPatternBaseTests.cs ├── CustomPatternUnitTest.cs ├── Properties │ └── AssemblyInfo.cs ├── TargetApp.cs ├── UiaControlsTest.csproj ├── WpfAppTests.cs └── packages.config ├── UiaCustomPattersManaged.nuspec ├── UiaCustomPattersManaged.sln ├── WpfAppWithAdvTextControl ├── AdvTextBox.cs ├── AdvTextBoxAutomationPeer.cs ├── App.config ├── App.xaml ├── App.xaml.cs ├── AutomationElementRetievingPattern.cs ├── CaretPositionPattern.cs ├── ICaretPositionPattern.cs ├── ICaretPositionProvider.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── TestControl.cs ├── TestControlAutomationPeer.cs ├── TestOfMoreThanTwoPatternPropertiesPattern.cs ├── WpfAppWithAdvTextControl.csproj └── packages.config ├── build-and-publish.bat ├── install.ps1 └── packages └── repositories.config /.gitignore: -------------------------------------------------------------------------------- 1 | _ReSharper* 2 | *.opensdf 3 | *.sdf 4 | *.DotSettings 5 | [Bb]in/ 6 | [Oo]bj/ 7 | *.suo 8 | Debug/ 9 | *.user 10 | UiaClientInterop/UIAutomationClient_i.c 11 | UiaCoreInterop/UIAutomationCore_i.c 12 | packages/ 13 | Release/ 14 | *.VC.opendb 15 | *.VC.db 16 | .vs/ 17 | UiaCoreInterop/Build/ 18 | -------------------------------------------------------------------------------- /BuildUIACoreInterop.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set netfxtools=c:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\x64\ 4 | set ResultDir=.\UIACoreInterop\Build\ 5 | set framework=c:\Windows\Microsoft.NET\Framework64\v4.0.30319\ 6 | set VS=%VS140COMNTOOLS% 7 | 8 | echo Settings VS variables: %VS%vsvars32.bat 9 | call %VS%vsvars32.bat 10 | set WindowsSdkDir=c:\Program Files (x86)\Windows Kits\8.1\ 11 | 12 | mkdir %ResultDir% 13 | 14 | echo Running midl: %WindowsSdkDir%include\um\UIAutomationCore.idl -^> %ResultDir%UIAutomationCore.tlb 15 | midl /nologo /char signed /out %ResultDir% /tlb UIAutomationCore.tlb /h UIAutomationCore_h.h "%WindowsSdkDir%include\um\UIAutomationCore.idl" 16 | if errorlevel 1 goto somethingbad 17 | 18 | echo Importing TLB: %ResultDir%UIAutomationCore.tlb -^> %ResultDir%Raw\Interop.UIAutomationCore.dll 19 | tlbimp /machine:Agnostic /silent /out:%ResultDir%Raw\Interop.UIAutomationCore.dll /namespace:Interop.UIAutomationCore %ResultDir%UIAutomationCore.tlb 20 | if errorlevel 1 goto somethingbad 21 | 22 | echo Disassembling interop DLL: %ResultDir%Raw\Interop.UIAutomationCore.dll -^> %ResultDir%UIAutomationCore.il 23 | ildasm %ResultDir%Raw\Interop.UIAutomationCore.dll /out=%ResultDir%UIAutomationCore.il /nobar 24 | if errorlevel 1 goto somethingbad 25 | 26 | echo Building CustomizeUiaInterop project 27 | MSBuild.exe .\CustomizeUiaInterop\CustomizeUiaInterop.csproj /t:Build /p:Configuration=Debug;SolutionDir=. 28 | if errorlevel 1 goto somethingbad 29 | 30 | echo Customizing UIA IL: %ResultDir%UIAutomationCore.il -^> %ResultDir%Custom.UIAutomationCore.il 31 | .\CustomizeUiaInterop\bin\Debug\CustomizeUiaInterop %ResultDir%UIAutomationCore.il %ResultDir%Custom.UIAutomationCore.il 32 | if errorlevel 1 goto somethingbad 33 | 34 | echo Assembling IL: %ResultDir%Custom.UIAutomationCore.il -^> %ResultDir%Interop.UIAutomationCore.dll 35 | ilasm /dll /output=%ResultDir%Interop.UIAutomationCore.dll %ResultDir%Custom.UIAutomationCore.il 36 | if errorlevel 1 goto somethingbad 37 | 38 | echo Finished successfully 39 | goto end 40 | 41 | :somethingbad 42 | echo Something Bad Happened. 43 | exit /B 1 44 | 45 | :end 46 | exit /B 0 -------------------------------------------------------------------------------- /CustomizeUiaInterop/CustomizeUiaInterop.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.30729 7 | 2.0 8 | {12F27127-240F-4AAB-A233-D7C0A2BFC70B} 9 | Exe 10 | Properties 11 | CustomizeUiaInterop 12 | CustomizeUiaInterop 13 | v4.0 14 | 512 15 | 16 | 17 | true 18 | bin\Debug\ 19 | DEBUG;TRACE 20 | full 21 | AnyCPU 22 | prompt 23 | MinimumRecommendedRules.ruleset 24 | 25 | 26 | bin\Release\ 27 | TRACE 28 | true 29 | pdbonly 30 | AnyCPU 31 | prompt 32 | MinimumRecommendedRules.ruleset 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 52 | -------------------------------------------------------------------------------- /CustomizeUiaInterop/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace CustomizeUiaInterop 5 | { 6 | internal class Program 7 | { 8 | private static void ShowHelp() 9 | { 10 | Console.WriteLine("CustomizeUiaInterop "); 11 | } 12 | 13 | private static int Main(string[] args) 14 | { 15 | if (args.Length != 2) 16 | { 17 | ShowHelp(); 18 | return 1; 19 | } 20 | 21 | var inputFilePath = args[0]; 22 | var outputFilePath = args[1]; 23 | 24 | try 25 | { 26 | // Read all the text 27 | var contents = File.ReadAllText(inputFilePath); 28 | 29 | var updated = contents.Replace( 30 | @" .method public hidebysig newslot abstract virtual 31 | instance void RegisterPattern([in] valuetype Interop.UIAutomationCore.UIAutomationPatternInfo& pattern, 32 | [out] int32& pPatternId, 33 | [out] int32& pPatternAvailablePropertyId, 34 | [in] uint32 propertyIdCount, 35 | [out] int32& pPropertyIds, 36 | [in] uint32 eventIdCount, 37 | [out] int32& pEventIds) runtime managed internalcall", 38 | @" .method public hidebysig newslot abstract virtual 39 | instance void RegisterPattern([in] valuetype Interop.UIAutomationCore.UIAutomationPatternInfo& pattern, 40 | [out] int32& pPatternId, 41 | [out] int32& pPatternAvailablePropertyId, 42 | [in] uint32 propertyIdCount, 43 | [out] int32[] marshal([+3]) pPropertyIds, 44 | [in] uint32 eventIdCount, 45 | [out] int32[] marshal([+5]) pEventIds) runtime managed internalcall"); 46 | 47 | updated = updated.Replace( 48 | @" .method public hidebysig newslot virtual 49 | instance void RegisterPattern([in] valuetype Interop.UIAutomationCore.UIAutomationPatternInfo& pattern, 50 | [out] int32& pPatternId, 51 | [out] int32& pPatternAvailablePropertyId, 52 | [in] uint32 propertyIdCount, 53 | [out] int32& pPropertyIds, 54 | [in] uint32 eventIdCount, 55 | [out] int32& pEventIds) runtime managed internalcall", 56 | @" .method public hidebysig newslot virtual 57 | instance void RegisterPattern([in] valuetype Interop.UIAutomationCore.UIAutomationPatternInfo& pattern, 58 | [out] int32& pPatternId, 59 | [out] int32& pPatternAvailablePropertyId, 60 | [in] uint32 propertyIdCount, 61 | [out] int32[] marshal([+3]) pPropertyIds, 62 | [in] uint32 eventIdCount, 63 | [out] int32[] marshal([+5]) pEventIds) runtime managed internalcall"); 64 | 65 | updated = updated.Replace( 66 | @" .method public hidebysig newslot abstract virtual 67 | instance void CallMethod([in] uint32 index, 68 | [in] valuetype Interop.UIAutomationCore.UIAutomationParameter& pParams, 69 | [in] uint32 cParams) runtime managed internalcall", 70 | @" .method public hidebysig newslot abstract virtual 71 | instance int32 CallMethod([in] uint32 index, 72 | [in] valuetype Interop.UIAutomationCore.UIAutomationParameter[] marshal([+2]) pParams, 73 | [in] uint32 cParams) runtime managed internalcall preservesig"); 74 | 75 | updated = updated.Replace( 76 | @" .method public hidebysig newslot abstract virtual 77 | instance void GetProperty([in] uint32 index, 78 | [in] int32 cached, 79 | [in] valuetype Interop.UIAutomationCore.UIAutomationType 'type', 80 | [out] native int pPtr) runtime managed internalcall", 81 | @" .method public hidebysig newslot abstract virtual 82 | instance int32 GetProperty([in] uint32 index, 83 | [in] int32 cached, 84 | [in] valuetype Interop.UIAutomationCore.UIAutomationType 'type', 85 | [out] native int pPtr) runtime managed internalcall preservesig"); 86 | 87 | updated = updated.Replace( 88 | @" .method public hidebysig newslot abstract virtual 89 | instance void Dispatch([in] object marshal( iunknown ) pTarget, 90 | [in] uint32 index, 91 | [in] valuetype Interop.UIAutomationCore.UIAutomationParameter& pParams, 92 | [in] uint32 cParams) runtime managed internalcall", 93 | @" .method public hidebysig newslot abstract virtual 94 | instance void Dispatch([in] object marshal( iunknown ) pTarget, 95 | [in] uint32 index, 96 | [in] valuetype Interop.UIAutomationCore.UIAutomationParameter[] marshal([+3]) pParams, 97 | [in] uint32 cParams) runtime managed internalcall"); 98 | 99 | updated = updated.Replace( 100 | @".class public sequential ansi sealed beforefieldinit Interop.UIAutomationCore.UIAutomationPropertyInfo 101 | extends [mscorlib]System.ValueType 102 | { 103 | .pack 4", 104 | @".class public sequential ansi sealed beforefieldinit Interop.UIAutomationCore.UIAutomationPropertyInfo 105 | extends [mscorlib]System.ValueType 106 | { 107 | .pack 0"); 108 | 109 | updated = updated.Replace( 110 | @".class public sequential ansi sealed beforefieldinit Interop.UIAutomationCore.UIAutomationEventInfo 111 | extends [mscorlib]System.ValueType 112 | { 113 | .pack 4", 114 | @".class public sequential ansi sealed beforefieldinit Interop.UIAutomationCore.UIAutomationEventInfo 115 | extends [mscorlib]System.ValueType 116 | { 117 | .pack 0"); 118 | 119 | updated = updated.Replace( 120 | @".class public sequential ansi sealed beforefieldinit Interop.UIAutomationCore.UIAutomationPatternInfo 121 | extends [mscorlib]System.ValueType 122 | { 123 | .pack 4", 124 | @".class public sequential ansi sealed beforefieldinit Interop.UIAutomationCore.UIAutomationPatternInfo 125 | extends [mscorlib]System.ValueType 126 | { 127 | .pack 0"); 128 | 129 | updated = updated.Replace( 130 | @".class public sequential ansi sealed beforefieldinit Interop.UIAutomationCore.UIAutomationParameter 131 | extends [mscorlib]System.ValueType 132 | { 133 | .pack 4", 134 | @".class public sequential ansi sealed beforefieldinit Interop.UIAutomationCore.UIAutomationParameter 135 | extends [mscorlib]System.ValueType 136 | { 137 | .pack 0"); 138 | 139 | updated = updated.Replace( 140 | @".class public sequential ansi sealed beforefieldinit Interop.UIAutomationCore.UIAutomationMethodInfo 141 | extends [mscorlib]System.ValueType 142 | { 143 | .pack 4", 144 | @".class public sequential ansi sealed beforefieldinit Interop.UIAutomationCore.UIAutomationMethodInfo 145 | extends [mscorlib]System.ValueType 146 | { 147 | .pack 0"); 148 | 149 | // Write all the text 150 | File.WriteAllText(outputFilePath, updated); 151 | } 152 | catch (Exception e) 153 | { 154 | Console.WriteLine("Caught exception:"); 155 | Console.WriteLine(e.ToString()); 156 | return 1; 157 | } 158 | 159 | return 0; 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /CustomizeUiaInterop/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("CustomizeUiaInterop")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Microsoft Corp.")] 11 | [assembly: AssemblyProduct("CustomizeUiaInterop")] 12 | [assembly: AssemblyCopyright("Copyright © Microsoft Corp. 2010")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("ab07e456-ed44-4cc4-b30a-2bd2ec9dfa8e")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /CustomizeUiaInterop/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | assembly-versioning-scheme: MajorMinorPatch 2 | mode: ContinuousDelivery 3 | next-version: 0.1.0 4 | branches: {} 5 | ignore: 6 | sha: [] 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Ivan Danilov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/AttributeDrivenPatternHelpers/AttributeDrivenPatternHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Castle.DynamicProxy; 3 | using Interop.UIAutomationCore; 4 | 5 | namespace ManagedUiaCustomizationCore 6 | { 7 | public class AttributeDrivenPatternHandler : IUIAutomationPatternHandler 8 | { 9 | private static readonly ProxyGenerator _proxyGenerator = new ProxyGenerator(); 10 | private readonly CustomPatternSchemaBase _schema; 11 | 12 | public AttributeDrivenPatternHandler(CustomPatternSchemaBase schema) 13 | { 14 | _schema = schema; 15 | } 16 | 17 | public void CreateClientWrapper(IUIAutomationPatternInstance pPatternInstance, out object pClientWrapper) 18 | { 19 | var interceptor = new PatternClientInstanceInterceptor(_schema, pPatternInstance); 20 | pClientWrapper = _proxyGenerator.CreateInterfaceProxyWithoutTarget(_schema.PatternClientInterface, interceptor); 21 | } 22 | 23 | public void Dispatch(object pTarget, uint index, UIAutomationParameter[] pParams, uint cParams) 24 | { 25 | ISchemaMember dispatchingMember = _schema.GetMemberByIndex(index); 26 | if (dispatchingMember == null) 27 | throw new NotSupportedException("Dispatching of this method is not supported"); 28 | 29 | dispatchingMember.DispatchCallToProvider(pTarget, new UiaParameterListHelper(pParams)); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/AttributeDrivenPatternHelpers/PatternClientInstanceInterceptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Windows.Automation; 6 | using Castle.DynamicProxy; 7 | using Interop.UIAutomationCore; 8 | using UIAutomationClient; 9 | 10 | namespace ManagedUiaCustomizationCore 11 | { 12 | public class PatternClientInstanceInterceptor : IInterceptor 13 | { 14 | private readonly IUIAutomationPatternInstance _patternInstance; 15 | private readonly Dictionary _currentPropGetterNameToHelper; 16 | private readonly Dictionary _cachedPropGetterNameToHelper; 17 | private readonly Dictionary _methodInfoToHelper; 18 | 19 | public PatternClientInstanceInterceptor(CustomPatternSchemaBase schema, IUIAutomationPatternInstance patternInstance) 20 | { 21 | _patternInstance = patternInstance; 22 | _currentPropGetterNameToHelper = schema.Properties.ToDictionary(helper => string.Format("get_Current{0}", helper.Data.pProgrammaticName)); 23 | _cachedPropGetterNameToHelper = schema.Properties.ToDictionary(helper => string.Format("get_Cached{0}", helper.Data.pProgrammaticName)); 24 | 25 | // helpers are aware about provider methods, we have to map them from client-side pattern methods 26 | _methodInfoToHelper = new Dictionary(); 27 | foreach (var methodInfoHelper in schema.Methods) 28 | { 29 | var providerInfo = methodInfoHelper.ProviderMethodInfo; 30 | if (providerInfo == null) continue; 31 | 32 | var patternMethod = ProviderPatternMatcher.GetMatchingPatternMethod(schema.PatternClientInterface, providerInfo); 33 | if (patternMethod != null) 34 | _methodInfoToHelper[patternMethod] = methodInfoHelper; 35 | } 36 | } 37 | 38 | public void Intercept(IInvocation invocation) 39 | { 40 | UiaPropertyInfoHelper propHelper; 41 | UiaMethodInfoHelper methodHelper; 42 | if (_currentPropGetterNameToHelper.TryGetValue(invocation.Method.Name, out propHelper)) 43 | CallProperty(invocation, propHelper, cached: false); 44 | else if (_cachedPropGetterNameToHelper.TryGetValue(invocation.Method.Name, out propHelper)) 45 | CallProperty(invocation, propHelper, cached: true); 46 | else if (_methodInfoToHelper.TryGetValue(invocation.Method, out methodHelper)) 47 | CallMethod(invocation, methodHelper); 48 | else 49 | throw new NotSupportedException(string.Format("Method {0} is not expected", invocation.Method.Name)); 50 | } 51 | 52 | private void CallProperty(IInvocation invocation, UiaPropertyInfoHelper propHelper, bool cached) 53 | { 54 | // it is call for CurrentXxx property 55 | var param = new UiaParameterHelper(propHelper.UiaType); 56 | NativeMethods.WrapUiaComCall(() => _patternInstance.GetProperty(propHelper.Index, cached ? 1 : 0, propHelper.UiaType, param.Data)); 57 | object value = param.Value; 58 | if (invocation.Method.ReturnType == typeof(AutomationElement)) 59 | value = AutomationElement.Wrap((IUIAutomationElement)value); 60 | invocation.ReturnValue = value; 61 | } 62 | 63 | private void CallMethod(IInvocation invocation, UiaMethodInfoHelper methodHelper) 64 | { 65 | if (!methodHelper.SupportsDispatch) 66 | throw new InvalidOperationException("Called method {0} doesn't support automatic metadata-driven dispatch. You have to modify schema in order to use this feature so that corresponding UiaMethodInfoHelper supports dispatch."); 67 | var paramList = new UiaParameterListHelper(methodHelper); 68 | 69 | // 1. Fill In params to paramList from invocation arguments 70 | // we're using the fact that In params are always going before out params, so we may just go through 0..(cInParameters-1) 71 | for (int i = 0; i < methodHelper.Data.cInParameters; i++) 72 | { 73 | var desc = methodHelper.PatternMethodParamDescriptions[i]; 74 | var idx = methodHelper.GetProviderMethodArgumentIndex(desc.Name); 75 | paramList[i] = invocation.Arguments[idx]; 76 | } 77 | 78 | // 2. Call patternInstance method 79 | NativeMethods.WrapUiaComCall(() => _patternInstance.CallMethod(methodHelper.Index, paramList.Data, paramList.Count)); 80 | 81 | // 3. Fill Out params back to invocation from paramList 82 | for (int i = (int)methodHelper.Data.cInParameters; i < methodHelper.Data.cInParameters + methodHelper.Data.cOutParameters; i++) 83 | { 84 | object value = paramList[i]; 85 | var desc = methodHelper.PatternMethodParamDescriptions[i]; 86 | if (desc.Name == UiaTypesHelper.RetParamUnspeakableName) 87 | { 88 | if (invocation.Method.ReturnType == typeof(AutomationElement)) 89 | value = AutomationElement.Wrap((IUIAutomationElement)value); 90 | invocation.ReturnValue = value; 91 | } 92 | else 93 | { 94 | var idx = methodHelper.GetProviderMethodArgumentIndex(desc.Name); 95 | if (invocation.Method.GetParameters()[idx].ParameterType.GetElementType() == typeof(AutomationElement)) 96 | value = AutomationElement.Wrap((IUIAutomationElement)value); 97 | invocation.Arguments[idx] = value; 98 | } 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/AttributeDrivenPatternHelpers/PatternGuidAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ManagedUiaCustomizationCore 4 | { 5 | [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false)] 6 | public class PatternGuidAttribute : Attribute 7 | { 8 | /// Pattern would be registered in UIA under this GUID. Do not confuse with GUID of the pattern's client interface, 9 | /// which is how COM would identify. Both should be applied to the client interface and should be different 10 | public PatternGuidAttribute(string patternGuid) 11 | { 12 | Value = new Guid(patternGuid); 13 | } 14 | 15 | public Guid Value { get; private set; } 16 | } 17 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/AttributeDrivenPatternHelpers/PatternMethodAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ManagedUiaCustomizationCore 4 | { 5 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] 6 | public class PatternMethodAttribute : Attribute 7 | { 8 | /// 9 | /// true if UI Automation should set the focus on the object before calling the method; otherwise false. 10 | /// 11 | public bool DoSetFocus { get; set; } 12 | 13 | /// 14 | /// true if pattern method should not be invoked on target application's UI thread. It can be useful e.g. 15 | /// if the call should not block UI thread, but wait for something. 16 | /// 17 | public bool DoNotDispatchToUIThread { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/AttributeDrivenPatternHelpers/PatternPropertyAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ManagedUiaCustomizationCore 4 | { 5 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 6 | public class PatternPropertyAttribute : Attribute 7 | { 8 | public PatternPropertyAttribute(string guid) 9 | { 10 | Guid = new Guid(guid); 11 | } 12 | 13 | public Guid Guid { get; private set; } 14 | } 15 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/AttributeDrivenPatternHelpers/ProviderPatternMatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using System.Windows.Automation; 5 | 6 | namespace ManagedUiaCustomizationCore 7 | { 8 | internal class ProviderPatternMatcher 9 | { 10 | internal static MethodInfo GetMatchingPatternMethod(Type patternInterface, MethodInfo providerMethodInfo) 11 | { 12 | return patternInterface.GetMethods() 13 | .Where(m => m.Name == providerMethodInfo.Name) 14 | .FirstOrDefault(mi => MethodsMatch(providerMethodInfo, mi)); 15 | } 16 | 17 | private static bool MethodsMatch(MethodInfo providerMethod, MethodInfo patternMethod) 18 | { 19 | var providerParamTypes = providerMethod.GetParameters().Select(param => param.ParameterType).ToArray(); 20 | var patternParamTypes = patternMethod.GetParameters().Select(param => param.ParameterType).ToArray(); 21 | 22 | if (patternParamTypes.Length != providerParamTypes.Length) 23 | return false; 24 | return Enumerable.Range(0, patternParamTypes.Length) 25 | .All(idx => ParametersMatch(providerParamTypes[idx], patternParamTypes[idx])); 26 | } 27 | 28 | internal static bool ParametersMatch(Type serverParamType, Type clientParamType) 29 | { 30 | if (serverParamType.IsByRef != clientParamType.IsByRef) 31 | return false; 32 | 33 | if (UiaTypesHelper.IsElementOnServerSide(serverParamType)) 34 | { 35 | if (clientParamType.IsByRef) 36 | clientParamType = clientParamType.GetElementType(); 37 | return UiaTypesHelper.IsElementOnClientSide(clientParamType) 38 | || clientParamType == typeof(AutomationElement); 39 | } 40 | 41 | return serverParamType == clientParamType; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/AttributeDrivenPatternHelpers/ReflectionUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | 7 | namespace ManagedUiaCustomizationCore 8 | { 9 | public static class ReflectionUtils 10 | { 11 | internal static IEnumerable GetAttributes(this MemberInfo memberInfo) 12 | { 13 | return memberInfo.GetCustomAttributes(typeof(TA), true).Cast(); 14 | } 15 | 16 | internal static TA GetAttribute(this MemberInfo memberInfo) 17 | { 18 | return memberInfo.GetAttributes().FirstOrDefault(); 19 | } 20 | 21 | internal static IEnumerable GetMethodsMarkedWith(this Type type) 22 | { 23 | return from m in type.GetMethods(BindingFlags.Instance | BindingFlags.Public) 24 | where m.GetAttributes().Any() 25 | select m; 26 | } 27 | 28 | internal static IEnumerable GetPropertiesMarkedWith(this Type type) 29 | { 30 | return from m in type.GetProperties(BindingFlags.Instance | BindingFlags.Public) 31 | where m.GetAttributes().Any() 32 | select m; 33 | } 34 | 35 | internal static IEnumerable GetStaticFieldsMarkedWith(this Type type) 36 | { 37 | return from m in type.GetFields(BindingFlags.Static | BindingFlags.Public) 38 | where m.GetAttributes().Any() 39 | select m; 40 | } 41 | 42 | public static Func GetPropertyGetter(this PropertyInfo propInfo) 43 | { 44 | if (propInfo.GetGetMethod(false) == null) 45 | throw new InvalidOperationException("Given property has no public getter"); 46 | var param = Expression.Parameter(typeof(object), "t"); 47 | var expression = Expression.Lambda>( 48 | Expression.Convert( 49 | Expression.MakeMemberAccess( 50 | Expression.Convert(param, propInfo.DeclaringType), 51 | propInfo), 52 | typeof(object)), 53 | param); 54 | return expression.Compile(); 55 | } 56 | 57 | public static MethodInfo GetMethodInfo(Expression methodCallExpression) 58 | { 59 | var methodCall = methodCallExpression.Body as MethodCallExpression; 60 | return methodCall.Method; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/AttributeDrivenPatternHelpers/StandalonePropertyAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ManagedUiaCustomizationCore 4 | { 5 | [AttributeUsage(AttributeTargets.Field)] 6 | public class StandalonePropertyAttribute : Attribute 7 | { 8 | public Guid Guid { get; private set; } 9 | public Type Type { get; private set; } 10 | 11 | public StandalonePropertyAttribute(string guid, Type type) 12 | { 13 | Type = type; 14 | Guid = new Guid(guid); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/AttributeDrivenPatternHelpers/TypeMember.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using System.Reflection; 4 | 5 | namespace ManagedUiaCustomizationCore 6 | { 7 | public static class TypeMember 8 | { 9 | public static PropertyInfo PropertyInfo(Expression> expression) 10 | { 11 | var body = expression.Body as MemberExpression; 12 | 13 | if (body == null) 14 | throw new ArgumentException("'expression' should be a property expression"); 15 | 16 | var propInfo = body.Member as PropertyInfo; 17 | 18 | if (propInfo == null) 19 | throw new ArgumentException("'expression' should be a property expression"); 20 | 21 | return propInfo; 22 | } 23 | 24 | public static Func GetPropertyGetter(Expression> expression) 25 | { 26 | var propertyInfo = PropertyInfo(expression); 27 | return propertyInfo.GetPropertyGetter(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/AttributeDrivenPatternHelpers/UiaTypesHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Interop.UIAutomationCore; 4 | using UIAutomationClient; 5 | using IRawElementProviderSimple = Interop.UIAutomationCore.IRawElementProviderSimple; 6 | 7 | namespace ManagedUiaCustomizationCore 8 | { 9 | public static class UiaTypesHelper 10 | { 11 | public const string RetParamUnspeakableName = "<>retValue"; 12 | 13 | private static readonly Dictionary _typeMapping 14 | = new Dictionary 15 | { 16 | {typeof(int), UIAutomationType.UIAutomationType_Int}, 17 | {typeof(bool), UIAutomationType.UIAutomationType_Bool}, 18 | {typeof(string), UIAutomationType.UIAutomationType_String}, 19 | {typeof(double), UIAutomationType.UIAutomationType_Double}, 20 | }; 21 | 22 | public static UIAutomationType TypeToAutomationType(Type type) 23 | { 24 | if (IsElementOnServerSide(type)) 25 | return UIAutomationType.UIAutomationType_Element; 26 | if (type.IsEnum && type.GetEnumUnderlyingType() == typeof(int)) 27 | type = typeof(int); 28 | UIAutomationType res; 29 | if (_typeMapping.TryGetValue(type, out res)) 30 | return res; 31 | throw new NotSupportedException("Provided type is not supported"); 32 | } 33 | 34 | public static UIAutomationType TypeToOutAutomationType(Type type) 35 | { 36 | return TypeToAutomationType(type) | UIAutomationType.UIAutomationType_Out; 37 | } 38 | 39 | public static bool IsElementOnServerSide(Type type) 40 | { 41 | // strip ref/out modifier if needed, because it doesn't have GUID of underlying element type 42 | if (type.IsByRef) 43 | type = type.GetElementType(); 44 | return type.GUID == typeof(IRawElementProviderSimple).GUID; 45 | } 46 | 47 | public static bool IsElementOnClientSide(Type type) 48 | { 49 | // strip ref/out modifier if needed, because it doesn't have GUID of underlying element type 50 | if (type.IsByRef) 51 | type = type.GetElementType(); 52 | return type.GUID == typeof(IUIAutomationElement).GUID; 53 | } 54 | 55 | public static bool IsInType(UIAutomationType type) 56 | { 57 | return !IsOutType(type); 58 | } 59 | 60 | public static bool IsOutType(UIAutomationType type) 61 | { 62 | return (type & UIAutomationType.UIAutomationType_Out) != 0; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/AttributeDrivenPatternSchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Interop.UIAutomationCore; 6 | 7 | namespace ManagedUiaCustomizationCore 8 | { 9 | public class AttributeDrivenPatternSchema : CustomPatternSchemaBase 10 | { 11 | private readonly Type _patternProviderInterface; 12 | private readonly Type _patternClientInterface; 13 | private readonly Guid _patternGuid; 14 | private readonly string _patternName; 15 | private readonly UiaMethodInfoHelper[] _methods; 16 | private readonly UiaPropertyInfoHelper[] _properties; 17 | private readonly AttributeDrivenPatternHandler _handler; 18 | 19 | public AttributeDrivenPatternSchema(Type patternProviderInterface, Type patternClientInterface) 20 | { 21 | if (!patternProviderInterface.IsInterface) 22 | throw new ArgumentException("Provided pattern provider type should be an interface", "patternProviderInterface"); 23 | if (!patternClientInterface.IsInterface) 24 | throw new ArgumentException("Provided pattern client type should be an interface", "patternClientInterface"); 25 | _patternProviderInterface = patternProviderInterface; 26 | _patternClientInterface = patternClientInterface; 27 | 28 | var patternClientName = _patternClientInterface.Name; 29 | if (!patternClientName.EndsWith("Pattern") || !patternClientName.StartsWith("I")) 30 | throw new ArgumentException("Pattern client interface named incorrectly, should be IXxxPattern", "patternClientInterface"); 31 | var baseName = patternClientName.Substring(1, patternClientName.Length - "I".Length - "Pattern".Length); 32 | if (_patternProviderInterface.Name != string.Format("I{0}Provider", baseName)) 33 | throw new ArgumentException(string.Format("Pattern provider interface named incorrectly, should be I{0}Provider", baseName)); 34 | _patternName = string.Format("{0}Pattern", baseName); 35 | 36 | var patternGuidAttr = _patternProviderInterface.GetAttribute(); 37 | if (patternGuidAttr == null) throw new ArgumentException("Provided type should be marked with PatternGuid attribute"); 38 | _patternGuid = patternGuidAttr.Value; 39 | 40 | _methods = patternProviderInterface.GetMethodsMarkedWith().Select(GetMethodHelper).ToArray(); 41 | _properties = patternProviderInterface.GetPropertiesMarkedWith().Select(GetPropertyHelper).ToArray(); 42 | ValidateClientInterface(); 43 | _handler = new AttributeDrivenPatternHandler(this); 44 | } 45 | 46 | private void ValidateClientInterface() 47 | { 48 | var mErrors = GetMethodErrorsMsg(); 49 | var pErrors = GetPropertyErrosMsg(); 50 | if (!string.IsNullOrEmpty(mErrors) || !string.IsNullOrEmpty(pErrors)) 51 | throw new Exception(mErrors + pErrors); 52 | } 53 | 54 | private UiaPropertyInfoHelper GetPropertyHelper(PropertyInfo pInfo) 55 | { 56 | var propertyAttr = pInfo.GetAttribute(); // can'be null as otherwise it wouldn't get into this method 57 | var guid = propertyAttr.Guid; 58 | var programmaticName = pInfo.Name; 59 | var uiaType = UiaTypesHelper.TypeToAutomationType(pInfo.PropertyType); 60 | return new UiaPropertyInfoHelper(guid, programmaticName, uiaType, pInfo.GetPropertyGetter()); 61 | } 62 | 63 | private UiaMethodInfoHelper GetMethodHelper(MethodInfo mInfo) 64 | { 65 | var methodAttr = mInfo.GetAttribute(); // can'be null as otherwise it wouldn't get into this method 66 | var doSetFocus = methodAttr.DoSetFocus; 67 | return new UiaMethodInfoHelper(mInfo, doSetFocus); 68 | } 69 | 70 | public override string PatternName 71 | { 72 | get { return _patternName; } 73 | } 74 | 75 | public override Type PatternProviderInterface 76 | { 77 | get { return _patternProviderInterface; } 78 | } 79 | 80 | public override Type PatternClientInterface 81 | { 82 | get { return _patternClientInterface; } 83 | } 84 | 85 | public override Guid PatternGuid 86 | { 87 | get { return _patternGuid; } 88 | } 89 | 90 | public override UiaPropertyInfoHelper[] Properties 91 | { 92 | get { return _properties; } 93 | } 94 | 95 | public override UiaMethodInfoHelper[] Methods 96 | { 97 | get { return _methods; } 98 | } 99 | 100 | public override UiaEventInfoHelper[] Events 101 | { 102 | // not supported for now 103 | get { return new UiaEventInfoHelper[0]; } 104 | } 105 | 106 | public override IUIAutomationPatternHandler Handler 107 | { 108 | get { return _handler; } 109 | } 110 | 111 | private string GetPropertyErrosMsg() 112 | { 113 | var propsWithErrors = new List(); 114 | foreach (PropertyInfo providerPropInfo in _patternProviderInterface.GetProperties()) 115 | { 116 | string providerPropName = providerPropInfo.Name; 117 | var currentPropName = "Current" + providerPropName; 118 | var cachedPropName = "Cached" + providerPropName; 119 | var currentPropInfo = _patternClientInterface.GetProperty(currentPropName); 120 | var cachedPropInfo = _patternClientInterface.GetProperty(cachedPropName); 121 | if (currentPropInfo == null || cachedPropInfo == null) 122 | propsWithErrors.Add(string.Format("{0} -- doesn't have one or both matching properties in client-side pattern interface", providerPropName)); 123 | else if (currentPropInfo.PropertyType != cachedPropInfo.PropertyType) 124 | propsWithErrors.Add(string.Format("{0} -- Current{0} and Cached{0} properties from client-side pattern interface have different types", providerPropName)); 125 | else if (!ProviderPatternMatcher.ParametersMatch(providerPropInfo.PropertyType, currentPropInfo.PropertyType)) 126 | propsWithErrors.Add(string.Format("{0} -- types of provider and client interfaces' properties don't match", providerPropName)); 127 | } 128 | if (propsWithErrors.Count > 0) 129 | return string.Format("These properties from provider interface have issues:\n{0}", 130 | string.Join("\n", propsWithErrors)); 131 | return null; 132 | } 133 | 134 | private string GetMethodErrorsMsg() 135 | { 136 | var methodsWithErrors = (from methodInfoHelper in _methods 137 | select methodInfoHelper.ProviderMethodInfo 138 | into providerMethodInfo 139 | where ProviderPatternMatcher.GetMatchingPatternMethod(_patternClientInterface, providerMethodInfo) == null 140 | select providerMethodInfo.Name) 141 | .ToList(); 142 | 143 | if (methodsWithErrors.Count > 0) 144 | return string.Format("These methods from provider interface do not have matching methods in client-side pattern interface:\n{0}", 145 | string.Join(", ", methodsWithErrors)); 146 | return string.Empty; 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/CustomPatternBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Windows.Automation; 5 | 6 | namespace ManagedUiaCustomizationCore 7 | { 8 | public abstract class CustomPatternBase : AttributeDrivenPatternSchema 9 | { 10 | private readonly bool _usedInWpf; 11 | private UiaPropertyInfoHelper[] _standaloneProperties; 12 | 13 | protected CustomPatternBase(bool usedInWpf) 14 | : base(typeof(TProviderInterface), typeof(TPatternClientInterface)) 15 | { 16 | _usedInWpf = usedInWpf; 17 | ReflectStandaloneProperties(); 18 | Register(); 19 | if (_usedInWpf) 20 | AutomationPeerAugmentationHelper.Register(this); 21 | FillRegistrationInfo(); 22 | } 23 | 24 | public override UiaPropertyInfoHelper[] StandaloneProperties 25 | { 26 | get { return _standaloneProperties; } 27 | } 28 | 29 | private void ReflectStandaloneProperties() 30 | { 31 | var t = GetType(); 32 | var fs = t.GetStaticFieldsMarkedWith(); 33 | var standaloneProps = new List(); 34 | foreach (var fieldInfo in fs) 35 | { 36 | if (!fieldInfo.Name.EndsWith("Property")) 37 | throw new ArgumentException("Field {0} marked with StandalonePropertyAttribute but named incorrectly. Should be XxxProperty, where Xxx is the programmatic name of the property being registered"); 38 | var programmaticName = fieldInfo.Name.Remove(fieldInfo.Name.Length - "Property".Length); 39 | var attr = fieldInfo.GetAttribute(); 40 | var uiaType = UiaTypesHelper.TypeToAutomationType(attr.Type); 41 | standaloneProps.Add(new UiaPropertyInfoHelper(attr.Guid, programmaticName, uiaType)); 42 | } 43 | if (standaloneProps.Count > 0) 44 | _standaloneProperties = standaloneProps.ToArray(); 45 | } 46 | 47 | private void FillRegistrationInfo() 48 | { 49 | var t = GetType(); 50 | if (t.Name != PatternName) 51 | throw new ArgumentException(string.Format("Type is named incorrectly. Should be {0}", PatternName)); 52 | 53 | SetPatternRegistrationInfo(); 54 | 55 | foreach (var prop in Properties) 56 | SetPropertyRegistrationInfo(prop); 57 | if (StandaloneProperties != null) 58 | { 59 | foreach (var prop in StandaloneProperties) 60 | SetPropertyRegistrationInfo(prop); 61 | } 62 | } 63 | 64 | private void SetPatternRegistrationInfo() 65 | { 66 | var pri = GetType().GetField("Pattern", BindingFlags.Static | BindingFlags.Public); 67 | if (pri == null) 68 | throw new ArgumentException("Field Pattern not found on the type"); 69 | 70 | if (pri.FieldType == typeof(int)) 71 | pri.SetValue(null, PatternId); 72 | else if (pri.FieldType == typeof(AutomationPattern)) 73 | { 74 | if (!_usedInWpf) 75 | throw new ArgumentException("You can't use AutomationPattern registration info because you passed usedInWpf: false in constructor"); 76 | pri.SetValue(null, AutomationPattern.LookupById(PatternId)); 77 | } 78 | else 79 | throw new ArgumentException("Field Pattern should be either of type int of AutomationPattern"); 80 | } 81 | 82 | private void SetPropertyRegistrationInfo(UiaPropertyInfoHelper prop) 83 | { 84 | var propFieldName = prop.Data.pProgrammaticName + "Property"; 85 | var field = GetType().GetField(propFieldName, BindingFlags.Static | BindingFlags.Public); 86 | if (field == null) 87 | throw new ArgumentException(string.Format("Field {0} not found on the type", propFieldName)); 88 | if (field.FieldType == typeof(int)) 89 | field.SetValue(null, prop.PropertyId); 90 | else if (field.FieldType == typeof(AutomationProperty)) 91 | { 92 | if (!_usedInWpf) 93 | throw new ArgumentException("You can't use AutomationPattern registration info because you passed usedInWpf: false in constructor"); 94 | field.SetValue(null, AutomationProperty.LookupById(prop.PropertyId)); 95 | } 96 | else 97 | throw new ArgumentException("Fields for properties should be either of type int of AutomationProperty"); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/IStandalonePropertyProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Automation; 2 | 3 | namespace ManagedUiaCustomizationCore 4 | { 5 | public interface IStandalonePropertyProvider 6 | { 7 | object GetPropertyValue(AutomationProperty property); 8 | } 9 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/ManagedUiaCustomizationCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {21DB168C-E0EF-4E07-B24A-1E5BB64D2A17} 7 | Library 8 | Properties 9 | ManagedUiaCustomizationCore 10 | ManagedUiaCustomizationCore 11 | v4.0 12 | 512 13 | 14 | 15 | 16 | true 17 | bin\Debug\ 18 | DEBUG;TRACE 19 | full 20 | AnyCPU 21 | prompt 22 | MinimumRecommendedRules.ruleset 23 | 24 | 25 | bin\Release\ 26 | TRACE 27 | true 28 | pdbonly 29 | AnyCPU 30 | prompt 31 | MinimumRecommendedRules.ruleset 32 | 33 | 34 | 35 | ..\packages\Castle.Core.4.3.1\lib\net40\Castle.Core.dll 36 | 37 | 38 | False 39 | False 40 | ..\packages\UIAComWrapper.1.1.0.14\lib\net40\Interop.UIAutomationClient.dll 41 | 42 | 43 | ..\UIACoreInterop\Build\Interop.UIAutomationCore.dll 44 | False 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | ..\packages\UIAComWrapper.1.1.0.14\lib\net40\UIAComWrapper.dll 57 | True 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 | 102 | -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/NativeMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Windows.Automation; 4 | using Interop.UIAutomationCore; 5 | 6 | namespace ManagedUiaCustomizationCore 7 | { 8 | // P/Invoke declarations 9 | public class NativeMethods 10 | { 11 | [DllImport("UIAutomationCore.dll", EntryPoint = "UiaHostProviderFromHwnd", CharSet = CharSet.Unicode)] 12 | public static extern int UiaHostProviderFromHwnd(IntPtr hwnd, [MarshalAs(UnmanagedType.Interface)] out IRawElementProviderSimple provider); 13 | 14 | [DllImport("UIAutomationCore.dll", EntryPoint = "UiaReturnRawElementProvider", CharSet = CharSet.Unicode)] 15 | public static extern IntPtr UiaReturnRawElementProvider(IntPtr hwnd, IntPtr wParam, IntPtr lParam, IRawElementProviderSimple el); 16 | 17 | [DllImport("UIAutomationCore.dll", EntryPoint = "UiaRaiseAutomationEvent", CharSet = CharSet.Unicode)] 18 | public static extern int UiaRaiseAutomationEvent(IRawElementProviderSimple el, int eventId); 19 | 20 | [DllImport("UIAutomationCore.dll", EntryPoint = "UiaRaiseAutomationPropertyChangedEvent", CharSet = CharSet.Unicode)] 21 | public static extern int UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple el, int propertyId, object oldValue, object newValue); 22 | 23 | public static void WrapUiaComCall(Func preservesigCall) 24 | { 25 | try 26 | { 27 | var hr = preservesigCall(); 28 | if (hr != 0) 29 | throw Marshal.GetExceptionForHR(hr); 30 | } 31 | catch (COMException e) 32 | { 33 | Exception newEx; 34 | if (ConvertException(e, out newEx)) 35 | throw newEx; 36 | throw; 37 | } 38 | catch (Exception e) 39 | { 40 | throw new UiaCallFailedException("Automation call failure", e); 41 | } 42 | catch 43 | { 44 | throw new UiaCallFailedException("Automation call failure"); 45 | } 46 | } 47 | 48 | #region Taken from UIAComWrapper - exception wrapping 49 | 50 | private const int UIA_E_ELEMENTNOTAVAILABLE = -2147220991; 51 | private const int UIA_E_ELEMENTNOTENABLED = -2147220992; 52 | private const int UIA_E_NOCLICKABLEPOINT = -2147220990; 53 | private const int UIA_E_PROXYASSEMBLYNOTLOADED = -2147220989; 54 | 55 | private static bool ConvertException(COMException e, out Exception uiaException) 56 | { 57 | bool handled = true; 58 | switch (e.ErrorCode) 59 | { 60 | case UIA_E_ELEMENTNOTAVAILABLE: 61 | uiaException = new ElementNotAvailableException(e); 62 | break; 63 | 64 | case UIA_E_ELEMENTNOTENABLED: 65 | uiaException = new ElementNotEnabledException(e); 66 | break; 67 | 68 | case UIA_E_NOCLICKABLEPOINT: 69 | uiaException = new NoClickablePointException(e); 70 | break; 71 | 72 | case UIA_E_PROXYASSEMBLYNOTLOADED: 73 | uiaException = new ProxyAssemblyNotLoadedException(e); 74 | break; 75 | 76 | default: 77 | uiaException = null; 78 | handled = false; 79 | break; 80 | } 81 | return handled; 82 | } 83 | 84 | #endregion 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("UiaManagedCustomPatternCore")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("UiaManagedCustomPatternCore")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("e62635c7-0e87-4b72-888c-a43abd6b3c86")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/Schema/CustomClientInstanceBase.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Interop.UIAutomationCore; 3 | 4 | namespace ManagedUiaCustomizationCore 5 | { 6 | /// 7 | /// Base class for a custom pattern's client instance. 8 | /// Responsible for hiding some of the details of marshalling client-side custom calls; 9 | /// this is mostly syntactic sugar to keep the custom pattern instance neat. 10 | /// 11 | public class CustomClientInstanceBase 12 | { 13 | protected IUIAutomationPatternInstance PatternInstance; 14 | 15 | protected CustomClientInstanceBase(IUIAutomationPatternInstance patternInstance) 16 | { 17 | PatternInstance = patternInstance; 18 | } 19 | 20 | // Get a current property value for this custom property 21 | protected object GetCurrentPropertyValue(UiaPropertyInfoHelper propInfo) 22 | { 23 | var param = new UiaParameterHelper(propInfo.UiaType); 24 | PatternInstance.GetProperty(propInfo.Index, 0 /* fCached */, param.GetUiaType(), param.Data); 25 | return param.Value; 26 | } 27 | 28 | // Get a current property value by calling a method, rather than by using GetProperty 29 | protected object GetCurrentPropertyValueViaMethod(UiaMethodInfoHelper methodInfo) 30 | { 31 | // Create and init a parameter list 32 | var paramList = new UiaParameterListHelper(methodInfo); 33 | Debug.Assert(paramList.Count == 1); 34 | 35 | // Call through 36 | PatternInstance.CallMethod(methodInfo.Index, paramList.Data, paramList.Count); 37 | 38 | // Return the out-parameter 39 | return paramList[0]; 40 | } 41 | 42 | // Get a cached property value for this custom property 43 | protected object GetCachedPropertyValue(UiaPropertyInfoHelper propInfo) 44 | { 45 | var param = new UiaParameterHelper(propInfo.UiaType); 46 | PatternInstance.GetProperty(propInfo.Index, 1 /* fCached */, param.GetUiaType(), param.Data); 47 | return param.Value; 48 | } 49 | 50 | // Call a pattern instance method with this parameter list 51 | protected void CallMethod(UiaMethodInfoHelper methodInfo, UiaParameterListHelper paramList) 52 | { 53 | PatternInstance.CallMethod(methodInfo.Index, paramList.Data, paramList.Count); 54 | } 55 | 56 | // Call a pattern instance method with only in-params 57 | protected void CallMethod(UiaMethodInfoHelper methodInfo, params object[] methodParams) 58 | { 59 | // Create and init a parameter list 60 | var paramList = new UiaParameterListHelper(methodInfo); 61 | paramList.Initialize(methodParams); 62 | 63 | // Call through 64 | PatternInstance.CallMethod(methodInfo.Index, paramList.Data, paramList.Count); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/Schema/CustomPatternSchemaBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Interop.UIAutomationCore; 4 | 5 | namespace ManagedUiaCustomizationCore 6 | { 7 | /// 8 | /// Base class for defining a custom schema. 9 | /// Responsible for defining the minimum info for a custom schema and 10 | /// registering it with UI Automation. 11 | /// This class is not required by UIA and doesn't correspond to anything in UIA; 12 | /// it's a personal preference about the right way to represent what is similar 13 | /// between various schemas and what varies. 14 | /// 15 | public abstract class CustomPatternSchemaBase 16 | { 17 | private readonly Dictionary _members = new Dictionary(); 18 | private int _patternId; 19 | private int _patternAvailablePropertyId; 20 | private bool _registered; 21 | 22 | // The abstract properties define the minimal data needed to express 23 | // a custom pattern. 24 | 25 | /// 26 | /// The list of properties for this pattern. 27 | /// 28 | public abstract UiaPropertyInfoHelper[] Properties { get; } 29 | 30 | /// 31 | /// It is just a convenient shortcut. Because UIA on Win7 has a bug which doesn't allow 32 | /// to register more than two custom properties for given custom pattern, some properties 33 | /// that ideally should belong to pattern would be registered standalone. This is the list 34 | /// of such properties. 35 | /// 36 | public virtual UiaPropertyInfoHelper[] StandaloneProperties 37 | { 38 | get { return null; } 39 | } 40 | 41 | /// 42 | /// The list of methods for this pattern. 43 | /// 44 | public abstract UiaMethodInfoHelper[] Methods { get; } 45 | 46 | /// 47 | /// The list of events for this pattern. 48 | /// 49 | public abstract UiaEventInfoHelper[] Events { get; } 50 | 51 | /// 52 | /// The unique ID for this pattern. 53 | /// 54 | public abstract Guid PatternGuid { get; } 55 | 56 | /// 57 | /// The interface ID for the COM interface for this pattern on the client side. 58 | /// 59 | public virtual Guid PatternClientGuid 60 | { 61 | get { return PatternClientInterface.GUID; } 62 | } 63 | 64 | /// 65 | /// The interface ID for the COM interface for this pattern on the provider side. 66 | /// 67 | public virtual Guid PatternProviderGuid 68 | { 69 | get { return PatternProviderInterface.GUID; } 70 | } 71 | 72 | /// 73 | /// The programmatic name for this pattern. 74 | /// 75 | public abstract string PatternName { get; } 76 | 77 | /// 78 | /// Type of the provider interface 79 | /// 80 | public abstract Type PatternProviderInterface { get; } 81 | 82 | /// 83 | /// Type of the client-side interface 84 | /// 85 | public abstract Type PatternClientInterface { get; } 86 | 87 | /// 88 | /// An object that implements IUIAutomationPatternHandler to handle 89 | /// dispatching and client-pattern creation for this pattern 90 | /// 91 | public abstract IUIAutomationPatternHandler Handler { get; } 92 | 93 | /// 94 | /// The assigned ID for this pattern. 95 | /// 96 | public int PatternId 97 | { 98 | get { return _patternId; } 99 | } 100 | 101 | /// 102 | /// The assigned ID for the IsXxxxPatternAvailable property. 103 | /// 104 | public int PatternAvailablePropertyId 105 | { 106 | get { return _patternAvailablePropertyId; } 107 | } 108 | 109 | /// 110 | /// Helper method to register this pattern. 111 | /// 112 | public void Register() 113 | { 114 | if (_registered) return; 115 | 116 | // Get our pointer to the registrar 117 | IUIAutomationRegistrar registrar = new CUIAutomationRegistrarClass(); 118 | 119 | // Set up the pattern struct 120 | var patternInfo = new UiaPatternInfoHelper(PatternGuid, 121 | PatternName, 122 | PatternClientGuid, 123 | PatternProviderGuid, 124 | Handler); 125 | 126 | // Populate it with properties and methods 127 | uint index = 0; 128 | foreach (var propertyInfo in Properties) 129 | { 130 | patternInfo.AddProperty(propertyInfo); 131 | propertyInfo.Index = index++; 132 | if (propertyInfo.SupportsDispatch) 133 | _members[propertyInfo.Index] = propertyInfo; 134 | } 135 | foreach (var methodInfo in Methods) 136 | { 137 | patternInfo.AddMethod(methodInfo); 138 | methodInfo.Index = index++; 139 | if (methodInfo.SupportsDispatch) 140 | _members[methodInfo.Index] = methodInfo; 141 | } 142 | 143 | // Add the events, too, although they are not indexed 144 | foreach (var eventInfo in Events) 145 | { 146 | patternInfo.AddEvent(eventInfo); 147 | } 148 | 149 | // Register the pattern 150 | var patternData = patternInfo.Data; 151 | 152 | // Call register pattern 153 | int[] propertyIds = new int[patternData.cProperties]; 154 | int[] eventIds = new int[patternData.cEvents]; 155 | registrar.RegisterPattern(ref patternData, 156 | out _patternId, 157 | out _patternAvailablePropertyId, 158 | patternData.cProperties, 159 | propertyIds, 160 | patternData.cEvents, 161 | eventIds); 162 | 163 | // Write the property IDs back 164 | for (uint i = 0; i < propertyIds.Length; ++i) 165 | { 166 | Properties[i].PropertyId = propertyIds[i]; 167 | } 168 | for (var i = 0; i < eventIds.Length; ++i) 169 | { 170 | Events[i].EventId = eventIds[i]; 171 | } 172 | 173 | if (StandaloneProperties != null) 174 | RegisterStandaloneProperties(registrar); 175 | 176 | _registered = true; 177 | } 178 | 179 | private void RegisterStandaloneProperties(IUIAutomationRegistrar registrar) 180 | { 181 | foreach (var propertyInfoHelper in StandaloneProperties) 182 | { 183 | int id; 184 | var propInfo = propertyInfoHelper.Data; 185 | registrar.RegisterProperty(ref propInfo, out id); 186 | propertyInfoHelper.PropertyId = id; 187 | } 188 | } 189 | 190 | public ISchemaMember GetMemberByIndex(uint index) 191 | { 192 | if (!_registered) 193 | throw new InvalidOperationException("Pattern schema should be registered first"); 194 | 195 | ISchemaMember result; 196 | if (_members.TryGetValue(index, out result)) 197 | return result; 198 | return null; 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/Schema/ISchemaMember.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedUiaCustomizationCore 2 | { 3 | public interface ISchemaMember 4 | { 5 | void DispatchCallToProvider(object provider, UiaParameterListHelper paramList); 6 | bool SupportsDispatch { get; } 7 | } 8 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/Schema/UiaEventInfoHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Interop.UIAutomationCore; 3 | 4 | namespace ManagedUiaCustomizationCore 5 | { 6 | /// 7 | /// Helper class to gather data about a custom event 8 | /// Corresponds to UIAutomationEventInfo. 9 | /// 10 | public class UiaEventInfoHelper 11 | { 12 | private readonly Guid _eventGuid; 13 | private readonly string _programmaticName; 14 | private bool _built; 15 | private UIAutomationEventInfo _data; 16 | 17 | public UiaEventInfoHelper(Guid eventGuid, string programmaticName) 18 | { 19 | _programmaticName = programmaticName; 20 | _eventGuid = eventGuid; 21 | } 22 | 23 | /// 24 | /// Get a marshalled UIAutomationEventInfo struct for this Helper. 25 | /// 26 | public UIAutomationEventInfo Data 27 | { 28 | get 29 | { 30 | if (!_built) 31 | Build(); 32 | return _data; 33 | } 34 | } 35 | 36 | /// 37 | /// The unique identifier of this event 38 | /// 39 | public Guid Guid 40 | { 41 | get { return _eventGuid; } 42 | } 43 | 44 | /// 45 | /// The event ID of this event, assigned after registration 46 | /// 47 | public int EventId { get; set; } 48 | 49 | private void Build() 50 | { 51 | _data = new UIAutomationEventInfo {pProgrammaticName = _programmaticName, guid = _eventGuid}; 52 | _built = true; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/Schema/UiaParameterDescription.cs: -------------------------------------------------------------------------------- 1 | using Interop.UIAutomationCore; 2 | 3 | namespace ManagedUiaCustomizationCore 4 | { 5 | /// 6 | /// A description of a single parameter 7 | /// 8 | /// This does not match a UIA structure, but is used as a simple data class 9 | /// to help form those structures. 10 | /// 11 | public class UiaParameterDescription 12 | { 13 | private readonly string _name; 14 | private readonly UIAutomationType _uiaType; 15 | 16 | public UiaParameterDescription(string name, UIAutomationType type) 17 | { 18 | _name = name; 19 | _uiaType = type; 20 | } 21 | 22 | public string Name 23 | { 24 | get { return _name; } 25 | } 26 | 27 | public UIAutomationType UiaType 28 | { 29 | get { return _uiaType; } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/Schema/UiaParameterListHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Interop.UIAutomationCore; 4 | 5 | namespace ManagedUiaCustomizationCore 6 | { 7 | /// 8 | /// Helper class to assemble information about a parameter list 9 | /// 10 | public class UiaParameterListHelper 11 | { 12 | private readonly List _uiaParams = new List(); 13 | 14 | // Construct a parameter list from a method info structure 15 | public UiaParameterListHelper(UiaMethodInfoHelper methodInfo) 16 | { 17 | foreach (var inParamType in methodInfo.InParamTypes) 18 | { 19 | _uiaParams.Add(new UiaParameterHelper(inParamType)); 20 | } 21 | foreach (var outParamType in methodInfo.OutParamTypes) 22 | { 23 | _uiaParams.Add(new UiaParameterHelper(outParamType)); 24 | } 25 | } 26 | 27 | // Construct a parameter list from a given in-memory structure 28 | public UiaParameterListHelper(UIAutomationParameter[] pParams) 29 | { 30 | // Construct the parameter list from the marshalled data 31 | for (uint i = 0; i < pParams.Length; ++i) 32 | { 33 | _uiaParams.Add(new UiaParameterHelper(pParams[i].type, pParams[i].pData)); 34 | } 35 | } 36 | 37 | // Get a pointer to the whole parameter list marshalled into a block of memory 38 | public UIAutomationParameter[] Data 39 | { 40 | get 41 | { 42 | return _uiaParams.Select(p => p.ToUiaParam()).ToArray(); 43 | } 44 | } 45 | 46 | /// 47 | /// The count of parameters in this list 48 | /// 49 | public uint Count 50 | { 51 | get { return (uint) _uiaParams.Count; } 52 | } 53 | 54 | // Helper method to initialize the incoming parameters list. 55 | public void Initialize(params object[] inParams) 56 | { 57 | for (var i = 0; i < inParams.Length; ++i) 58 | { 59 | this[i] = inParams[i]; 60 | } 61 | } 62 | 63 | /// 64 | /// The value of the specified parameter in this list 65 | /// 66 | /// 67 | /// 68 | public object this[int i] 69 | { 70 | get { return _uiaParams[i].Value; } 71 | set { _uiaParams[i].Value = value; } 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/Schema/UiaPatternInfoHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.InteropServices; 4 | using Interop.UIAutomationCore; 5 | 6 | namespace ManagedUiaCustomizationCore 7 | { 8 | /// 9 | /// Helper class to assemble information about a custom pattern. 10 | /// Corresponds to UIAutomationPatternInfo 11 | /// 12 | public class UiaPatternInfoHelper 13 | { 14 | private readonly Guid _patternGuid; 15 | private readonly Guid _clientInterfaceId; 16 | private readonly Guid _providerInterfaceId; 17 | private readonly string _programmaticName; 18 | private readonly IUIAutomationPatternHandler _patternHandler; 19 | private readonly List _methods = new List(); 20 | private readonly List _properties = new List(); 21 | private readonly List _events = new List(); 22 | 23 | private bool _built; 24 | private UIAutomationPatternInfo _data; 25 | 26 | public UiaPatternInfoHelper(Guid patternGuid, 27 | string programmaticName, 28 | Guid clientInterfaceId, 29 | Guid providerInterfaceId, 30 | IUIAutomationPatternHandler patternHandler) 31 | { 32 | _programmaticName = programmaticName; 33 | _patternGuid = patternGuid; 34 | _clientInterfaceId = clientInterfaceId; 35 | _providerInterfaceId = providerInterfaceId; 36 | _patternHandler = patternHandler; 37 | } 38 | 39 | ~UiaPatternInfoHelper() 40 | { 41 | Marshal.FreeCoTaskMem(_data.pMethods); 42 | Marshal.FreeCoTaskMem(_data.pEvents); 43 | Marshal.FreeCoTaskMem(_data.pProperties); 44 | } 45 | 46 | /// 47 | /// Get a marshalled UIAutomationPatternInfo struct for this Helper. 48 | /// 49 | public UIAutomationPatternInfo Data 50 | { 51 | get 52 | { 53 | if (!_built) 54 | { 55 | Build(); 56 | } 57 | return _data; 58 | } 59 | } 60 | 61 | /// 62 | /// Add a property to this pattern 63 | /// 64 | /// 65 | public void AddProperty(UiaPropertyInfoHelper property) 66 | { 67 | _properties.Add(property); 68 | } 69 | 70 | /// 71 | /// Add a method to this pattern 72 | /// 73 | /// 74 | public void AddMethod(UiaMethodInfoHelper method) 75 | { 76 | _methods.Add(method); 77 | } 78 | 79 | /// 80 | /// Add an event to this pattern 81 | /// 82 | /// 83 | public void AddEvent(UiaEventInfoHelper eventHelper) 84 | { 85 | _events.Add(eventHelper); 86 | } 87 | 88 | private void Build() 89 | { 90 | // Basic data 91 | _data = new UIAutomationPatternInfo 92 | { 93 | pProgrammaticName = _programmaticName, 94 | guid = _patternGuid, 95 | clientInterfaceId = _clientInterfaceId, 96 | providerInterfaceId = _providerInterfaceId, 97 | pPatternHandler = _patternHandler, 98 | cMethods = (uint) _methods.Count 99 | }; 100 | 101 | // Build the list of methods 102 | if (_data.cMethods > 0) 103 | { 104 | _data.pMethods = Marshal.AllocCoTaskMem((int) (_data.cMethods*Marshal.SizeOf(typeof (UIAutomationMethodInfo)))); 105 | var methodPointer = _data.pMethods; 106 | for (var i = 0; i < _data.cMethods; ++i) 107 | { 108 | Marshal.StructureToPtr(_methods[i].Data, methodPointer, false); 109 | methodPointer = (IntPtr) (methodPointer.ToInt64() + Marshal.SizeOf(typeof (UIAutomationMethodInfo))); 110 | } 111 | } 112 | else 113 | { 114 | _data.pMethods = IntPtr.Zero; 115 | } 116 | 117 | // Build the list of properties 118 | _data.cProperties = (uint) _properties.Count; 119 | if (_data.cProperties > 0) 120 | { 121 | _data.pProperties = Marshal.AllocCoTaskMem((int) (_data.cProperties*Marshal.SizeOf(typeof (UIAutomationPropertyInfo)))); 122 | var propertyPointer = _data.pProperties; 123 | for (var i = 0; i < _data.cProperties; ++i) 124 | { 125 | Marshal.StructureToPtr(_properties[i].Data, propertyPointer, false); 126 | propertyPointer = (IntPtr) (propertyPointer.ToInt64() + Marshal.SizeOf(typeof (UIAutomationPropertyInfo))); 127 | } 128 | } 129 | else 130 | { 131 | _data.pProperties = IntPtr.Zero; 132 | } 133 | 134 | // Build the list of events 135 | _data.cEvents = (uint) _events.Count; 136 | if (_data.cEvents > 0) 137 | { 138 | _data.pEvents = Marshal.AllocCoTaskMem((int) (_data.cEvents*Marshal.SizeOf(typeof (UIAutomationEventInfo)))); 139 | var eventPointer = _data.pEvents; 140 | for (var i = 0; i < _data.cEvents; ++i) 141 | { 142 | Marshal.StructureToPtr(_events[i].Data, eventPointer, false); 143 | eventPointer = (IntPtr) (eventPointer.ToInt64() + Marshal.SizeOf(typeof (UIAutomationEventInfo))); 144 | } 145 | } 146 | else 147 | { 148 | _data.pEvents = IntPtr.Zero; 149 | } 150 | 151 | _built = true; 152 | } 153 | } 154 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/Schema/UiaPropertyInfoHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Interop.UIAutomationCore; 3 | 4 | namespace ManagedUiaCustomizationCore 5 | { 6 | /// 7 | /// Helper class to gather data about a custom property 8 | /// Corresponds to UIAutomationPropertyInfo 9 | /// 10 | public class UiaPropertyInfoHelper : ISchemaMember 11 | { 12 | private readonly Guid _propertyGuid; 13 | private readonly string _programmaticName; 14 | private readonly UIAutomationType _propertyType; 15 | private readonly Func _getterFromProvider; 16 | private bool _built; 17 | private UIAutomationPropertyInfo _data; 18 | 19 | /// 20 | /// Suitable for standalone properties that do not require handlers, hence no need to use ISchemaMember.DispatchCallToProvider() ever. 21 | /// 22 | public UiaPropertyInfoHelper(Guid propertyGuid, string programmaticName, UIAutomationType propertyType) 23 | :this(propertyGuid, programmaticName, propertyType, null) 24 | { 25 | } 26 | 27 | /// 28 | /// Usable for general-purpose implementation that uses ISchemaMember.DispatchCallToProvider() 29 | /// 30 | /// Lambda for getting property value from pattern provider interface. It should be akin to 31 | /// (object p) => ((ISomePatternProvider)p).MyProperty. Or, same thing, 32 | /// TypeMember<ISomePatternProvider>.GetPropertyGetter(p => p.MyProperty). For standalone properties 33 | /// it can be null (it is used for pattern handler implementation only, which doesn't take part in getting standalone properties). 34 | public UiaPropertyInfoHelper(Guid propertyGuid, string programmaticName, UIAutomationType propertyType, Func getterFromProvider) 35 | { 36 | _programmaticName = programmaticName; 37 | _propertyGuid = propertyGuid; 38 | _propertyType = propertyType; 39 | _getterFromProvider = getterFromProvider; 40 | } 41 | 42 | /// 43 | /// Get a marshalled UIAutomationPropertyInfo struct for this Helper. 44 | /// 45 | public UIAutomationPropertyInfo Data 46 | { 47 | get 48 | { 49 | if (!_built) 50 | Build(); 51 | return _data; 52 | } 53 | } 54 | 55 | /// 56 | /// The UIA type of this property 57 | /// 58 | public UIAutomationType UiaType 59 | { 60 | get { return _propertyType; } 61 | } 62 | 63 | /// 64 | /// The unique identifier for this property 65 | /// 66 | public Guid Guid 67 | { 68 | get { return _propertyGuid; } 69 | } 70 | 71 | /// 72 | /// The index of this property, when it is used as part of a pattern 73 | /// 74 | public uint Index { get; set; } 75 | 76 | /// 77 | /// The property ID of this property, assigned after registration 78 | /// 79 | public int PropertyId { get; set; } 80 | 81 | private void Build() 82 | { 83 | _data = new UIAutomationPropertyInfo 84 | { 85 | pProgrammaticName = _programmaticName, 86 | guid = _propertyGuid, 87 | type = _propertyType 88 | }; 89 | _built = true; 90 | } 91 | 92 | public void DispatchCallToProvider(object provider, UiaParameterListHelper paramList) 93 | { 94 | if (_getterFromProvider == null) 95 | throw new InvalidOperationException("You have to provide getterFromProvider lambda argument to constructor in order to use this method"); 96 | if (paramList.Count != 1) 97 | throw new ArgumentException("For a property param list should contain only one out param"); 98 | paramList[0] = _getterFromProvider(provider); 99 | } 100 | 101 | public bool SupportsDispatch 102 | { 103 | get { return _getterFromProvider != null; } 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/UiaCallFailedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace ManagedUiaCustomizationCore 5 | { 6 | [Serializable] 7 | public class UiaCallFailedException : Exception 8 | { 9 | public UiaCallFailedException() 10 | { 11 | } 12 | 13 | public UiaCallFailedException(string message) : base(message) 14 | { 15 | } 16 | 17 | public UiaCallFailedException(string message, Exception inner) : base(message, inner) 18 | { 19 | } 20 | 21 | protected UiaCallFailedException( 22 | SerializationInfo info, 23 | StreamingContext context) : base(info, context) 24 | { 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /ManagedUiaCustomizationCore/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /UIAControls/BaseFragmentProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using Interop.UIAutomationCore; 3 | 4 | 5 | namespace UIAControls 6 | { 7 | /// 8 | /// A basic implementation of the Fragment provider. 9 | /// This adds the concept of a sub-window element to the Simple provider, 10 | /// and so includes work to report element aspects that the system 11 | /// would usually get for free from a window handle, like position and runtime ID. 12 | /// 13 | [ComVisible(true)] 14 | public abstract class BaseFragmentProvider : BaseSimpleProvider, IRawElementProviderFragment 15 | { 16 | protected IRawElementProviderFragment parent; 17 | protected IRawElementProviderFragmentRoot fragmentRoot; 18 | 19 | protected BaseFragmentProvider(IRawElementProviderFragment parent, IRawElementProviderFragmentRoot fragmentRoot) 20 | { 21 | this.parent = parent; 22 | this.fragmentRoot = fragmentRoot; 23 | } 24 | 25 | // Return a unique runtime ID to distinguish this from other elements. 26 | // This is required to implement. It is usually best to return an array 27 | // starting with the AppendRuntimeId so that it will be joined to the 28 | // fragment root's runtime -- then you just need to add a unique suffix. 29 | public abstract int[] GetRuntimeId(); 30 | 31 | // Return the bounding rectangle of the fragment. 32 | // This is required to implement. 33 | public abstract UiaRect get_BoundingRectangle(); 34 | 35 | // Return any fragment roots embedded within this fragment - uncommon 36 | // unless this is a fragment hosting another full HWND. 37 | public virtual IRawElementProviderFragmentRoot[] GetEmbeddedFragmentRoots() 38 | { 39 | return null; 40 | } 41 | 42 | // Set focus to this fragment, if it is keyboard focusable. 43 | public virtual void SetFocus() 44 | { 45 | } 46 | 47 | // Return the fragment root: the fragment that is tied to the window handle itself. 48 | // Don't override, since the constructor requires the fragment root already. 49 | public IRawElementProviderFragmentRoot FragmentRoot 50 | { 51 | get { return fragmentRoot; } 52 | } 53 | 54 | // Routing function for going to neighboring elements. We implemented 55 | // this to delegate to other virtual functions, so don't override it. 56 | public IRawElementProviderFragment Navigate(NavigateDirection direction) 57 | { 58 | switch (direction) 59 | { 60 | case NavigateDirection.NavigateDirection_Parent: return parent; 61 | case NavigateDirection.NavigateDirection_FirstChild: return GetFirstChild(); 62 | case NavigateDirection.NavigateDirection_LastChild: return GetLastChild(); 63 | case NavigateDirection.NavigateDirection_NextSibling: return GetNextSibling(); 64 | case NavigateDirection.NavigateDirection_PreviousSibling: return GetPreviousSibling(); 65 | } 66 | return null; 67 | } 68 | 69 | // Return the first child of this fragment. 70 | protected virtual IRawElementProviderFragment GetFirstChild() 71 | { 72 | return null; 73 | } 74 | 75 | // Return the last child of this fragment. 76 | protected virtual IRawElementProviderFragment GetLastChild() 77 | { 78 | return null; 79 | } 80 | 81 | // Return the next sibling of this fragment. 82 | protected virtual IRawElementProviderFragment GetNextSibling() 83 | { 84 | return null; 85 | } 86 | 87 | // Return the previous sibling of this fragment. 88 | protected virtual IRawElementProviderFragment GetPreviousSibling() 89 | { 90 | return null; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /UIAControls/BaseFragmentRootProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using Interop.UIAutomationCore; 3 | 4 | 5 | namespace UIAControls 6 | { 7 | /// 8 | /// A basic implementation of the FragmentRoot provider. This adds on to Fragment 9 | /// the power to route certain queries to the sub-window elements in this tree, 10 | /// so it is usually implemented by the fragment that corresponds to the window handle. 11 | /// 12 | [ComVisible(true)] 13 | public abstract class BaseFragmentRootProvider : BaseFragmentProvider, IRawElementProviderFragmentRoot 14 | { 15 | protected BaseFragmentRootProvider() 16 | : base(parent: null, fragmentRoot: null) 17 | { 18 | fragmentRoot = this; 19 | } 20 | 21 | // Perform hit testing and testing and return the element that contains this point. 22 | // Point is given in screen coordinates. Return null is the hit is on the fragment 23 | // root itself. 24 | public virtual IRawElementProviderFragment ElementProviderFromPoint(double x, double y) 25 | { 26 | return null; 27 | } 28 | 29 | // Return the fragment with keyboard focus, if there is one. 30 | public virtual IRawElementProviderFragment GetFocus() 31 | { 32 | return null; 33 | } 34 | 35 | // The fragment root usually has an HWND, so returning an empty bounding rect is OK. 36 | public override UiaRect get_BoundingRectangle() 37 | { 38 | return new UiaRect(); 39 | } 40 | 41 | // The fragment root usually has an HWND, so returning an empty runtime ID is OK. 42 | // The system will construct one for us. 43 | public override int[] GetRuntimeId() 44 | { 45 | return null; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /UIAControls/BaseSimpleProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.InteropServices; 4 | using ManagedUiaCustomizationCore; 5 | using UIAutomationClient; 6 | using IRawElementProviderSimple = Interop.UIAutomationCore.IRawElementProviderSimple; 7 | using ProviderOptions = Interop.UIAutomationCore.ProviderOptions; 8 | 9 | namespace UIAControls 10 | { 11 | /// 12 | /// A basic implementation of IRawElementSimpleProvider. 13 | /// Many customizations can be done by overriding virtual methods of this class, 14 | /// rather than having to implement the whole interface. 15 | /// 16 | [ComVisible(true)] 17 | public abstract class BaseSimpleProvider : IRawElementProviderSimple 18 | { 19 | private readonly Dictionary _staticProps = new Dictionary(); 20 | 21 | public virtual object GetPatternProvider(int patternId) 22 | { 23 | return null; 24 | } 25 | 26 | public virtual object GetPropertyValue(int propertyId) 27 | { 28 | // Check the static props list first 29 | if (_staticProps.ContainsKey(propertyId)) 30 | { 31 | return _staticProps[propertyId]; 32 | } 33 | 34 | // Switching construct to go get the right property from a virtual method. 35 | if (propertyId == UIA_PropertyIds.UIA_NamePropertyId) 36 | { 37 | return GetName(); 38 | } 39 | 40 | // Add further cases here to support more properties. 41 | // Do note that it may be more efficient to handle static properties 42 | // by adding them to the static props list instead of using methods. 43 | 44 | return null; 45 | } 46 | 47 | public IRawElementProviderSimple HostRawElementProvider 48 | { 49 | get 50 | { 51 | var hwnd = GetWindowHandle(); 52 | if (hwnd == IntPtr.Zero) return null; 53 | IRawElementProviderSimple hostProvider; 54 | NativeMethods.UiaHostProviderFromHwnd(GetWindowHandle(), out hostProvider); 55 | return hostProvider; 56 | } 57 | } 58 | 59 | public virtual ProviderOptions ProviderOptions 60 | { 61 | get { return ProviderOptions.ProviderOptions_ServerSideProvider; } 62 | } 63 | 64 | // Get the window handle for a provider that is a full HWND 65 | protected virtual IntPtr GetWindowHandle() 66 | { 67 | return IntPtr.Zero; 68 | } 69 | 70 | // Get the localized name for this control 71 | protected virtual string GetName() 72 | { 73 | return null; 74 | } 75 | 76 | protected void AddStaticProperty(int propertyId, object value) 77 | { 78 | _staticProps.Add(propertyId, value); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /UIAControls/ColorProviderClientInstance.cs: -------------------------------------------------------------------------------- 1 | using Interop.UIAutomationCore; 2 | using ManagedUiaCustomizationCore; 3 | 4 | namespace UIAControls 5 | { 6 | public class ColorProviderClientInstance : CustomClientInstanceBase, IColorPattern 7 | { 8 | public ColorProviderClientInstance(IUIAutomationPatternInstance patternInstance) 9 | : base(patternInstance) 10 | { 11 | } 12 | 13 | public int CurrentValueAsColor 14 | { 15 | get { return (int) GetCurrentPropertyValue(ColorSchema.GetInstance().ValueAsColorProperty); } 16 | } 17 | 18 | public int CachedValueAsColor 19 | { 20 | get { return (int) GetCachedPropertyValue(ColorSchema.GetInstance().ValueAsColorProperty); } 21 | } 22 | 23 | public void SetValueAsColor(int value) 24 | { 25 | CallMethod(ColorSchema.GetInstance().SetValueAsColorMethod, value); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /UIAControls/ColorProviderHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Interop.UIAutomationCore; 3 | using ManagedUiaCustomizationCore; 4 | 5 | namespace UIAControls 6 | { 7 | /// 8 | /// Pattern handler class: creates pattern instances on client side and dispatches 9 | /// calls on the provider side. 10 | /// 11 | public class ColorProviderHandler : IUIAutomationPatternHandler 12 | { 13 | public void CreateClientWrapper(IUIAutomationPatternInstance pPatternInstance, out object pClientWrapper) 14 | { 15 | pClientWrapper = new ColorProviderClientInstance(pPatternInstance); 16 | } 17 | 18 | public void Dispatch(object pTarget, uint index, UIAutomationParameter[] pParams, uint cParams) 19 | { 20 | // Parse the provider and parameter list 21 | var provider = (IColorProvider) pTarget; 22 | var paramList = new UiaParameterListHelper(pParams); 23 | 24 | // Dispatch the method/property calls 25 | if (index == ColorSchema.GetInstance().ValueAsColorProperty.Index) 26 | { 27 | paramList[0] = provider.ValueAsColor; 28 | } 29 | else if (index == ColorSchema.GetInstance().SetValueAsColorMethod.Index) 30 | { 31 | provider.SetValueAsColor((int) paramList[0]); 32 | } 33 | else 34 | { 35 | throw new InvalidOperationException(); 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /UIAControls/ColorSchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Interop.UIAutomationCore; 3 | using ManagedUiaCustomizationCore; 4 | 5 | // Color Pattern 6 | // Schema and implementation for the custom pattern for setting/retrieving a controls 7 | // value by RGB color. 8 | namespace UIAControls 9 | { 10 | // Declaration of the provider-side interface, which the control will implement. 11 | 12 | // Declaration of the client-side interface, for the client/test to use. 13 | 14 | /// 15 | /// Declaration of the pattern schema, with all of the information UIA needs 16 | /// about this property. 17 | /// 18 | public class ColorSchema : CustomPatternSchemaBase 19 | { 20 | private static readonly ColorSchema Instance = new ColorSchema(); 21 | 22 | public static ColorSchema GetInstance() 23 | { 24 | return Instance; 25 | } 26 | 27 | public readonly UiaPropertyInfoHelper ValueAsColorProperty = 28 | new UiaPropertyInfoHelper( 29 | new Guid("48F45D48-37A1-4480-B5A7-198315D2F2A0"), 30 | "ValueAsColor", 31 | UIAutomationType.UIAutomationType_Int, 32 | provider => ((IColorProvider)provider).ValueAsColor); 33 | 34 | public readonly UiaMethodInfoHelper SetValueAsColorMethod = 35 | new UiaMethodInfoHelper( 36 | "SetValueAsColor", 37 | true /* doSetFocus */, 38 | new[] {new UiaParameterDescription("value", UIAutomationType.UIAutomationType_Int)}); 39 | 40 | public override UiaPropertyInfoHelper[] Properties 41 | { 42 | get { return new[] {ValueAsColorProperty}; } 43 | } 44 | 45 | public override UiaMethodInfoHelper[] Methods 46 | { 47 | get { return new[] {SetValueAsColorMethod}; } 48 | } 49 | 50 | public override UiaEventInfoHelper[] Events 51 | { 52 | get { return new UiaEventInfoHelper[] {}; } 53 | } 54 | 55 | public override Guid PatternGuid 56 | { 57 | get { return new Guid("CDF2D932-6043-47ef-AB48-1CA756678B0C"); } 58 | } 59 | 60 | public override string PatternName 61 | { 62 | get { return "ColorPattern"; } 63 | } 64 | 65 | public override Type PatternProviderInterface 66 | { 67 | get { return typeof(IColorProvider); } 68 | } 69 | 70 | public override Type PatternClientInterface 71 | { 72 | get { return typeof(IColorPattern); } 73 | } 74 | 75 | public override IUIAutomationPatternHandler Handler 76 | { 77 | get { return new ColorProviderHandler(); } 78 | } 79 | } 80 | 81 | // Pattern instance class: wrap up a IUIAutomationPatternInstance and implement the 82 | // custom pattern interface on top of it. 83 | } -------------------------------------------------------------------------------- /UIAControls/Form1.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace UIAControls 2 | { 3 | partial class Form1 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.triColorControl1 = new UIAControls.TriColorControl(); 32 | this.SuspendLayout(); 33 | // 34 | // triColorControl1 35 | // 36 | this.triColorControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 37 | | System.Windows.Forms.AnchorStyles.Left) 38 | | System.Windows.Forms.AnchorStyles.Right))); 39 | this.triColorControl1.Location = new System.Drawing.Point(51, 37); 40 | this.triColorControl1.Name = "triColorControl1"; 41 | this.triColorControl1.Size = new System.Drawing.Size(150, 150); 42 | this.triColorControl1.TabIndex = 0; 43 | // 44 | // Form1 45 | // 46 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 47 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 48 | this.ClientSize = new System.Drawing.Size(284, 262); 49 | this.Controls.Add(this.triColorControl1); 50 | this.Name = "Form1"; 51 | this.Text = "Form1"; 52 | this.ResumeLayout(false); 53 | 54 | } 55 | 56 | #endregion 57 | 58 | private TriColorControl triColorControl1; 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /UIAControls/Form1.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | namespace UIAControls 4 | { 5 | public partial class Form1 : Form 6 | { 7 | public Form1() 8 | { 9 | InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /UIAControls/Form1.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 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 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /UIAControls/IColorPattern.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace UIAControls 4 | { 5 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 6 | [ComImport] 7 | [Guid("B98D615C-C7A2-4afd-AEC9-62FF4501AA30")] 8 | public interface IColorPattern 9 | { 10 | int CurrentValueAsColor { get; } 11 | int CachedValueAsColor { get; } 12 | void SetValueAsColor(int value); 13 | } 14 | } -------------------------------------------------------------------------------- /UIAControls/IColorProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace UIAControls 4 | { 5 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 6 | [ComImport] 7 | [Guid("49F2F4CD-FFB7-4b21-9C4F-58090CDD8BCE")] 8 | public interface IColorProvider 9 | { 10 | int ValueAsColor { get; } 11 | void SetValueAsColor(int value); 12 | } 13 | } -------------------------------------------------------------------------------- /UIAControls/ITestPattern.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using UIAutomationClient; 3 | 4 | namespace UIAControls 5 | { 6 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 7 | [ComImport] 8 | [Guid("82A9C7E7-9C87-497C-ABD2-054A6A7BACA2")] 9 | public interface ITestPattern 10 | { 11 | int CurrentIntValue { get; } 12 | string CurrentStringValue { get; } 13 | bool CurrentBoolValue { get; } 14 | double CurrentDoubleValue { get; } 15 | IUIAutomationElement CurrentElementValue { get; } 16 | 17 | int CachedIntValue { get; } 18 | string CachedStringValue { get; } 19 | bool CachedBoolValue { get; } 20 | double CachedDoubleValue { get; } 21 | IUIAutomationElement CachedElementValue { get; } 22 | 23 | void PassIntParam(int value, out int retVal); 24 | void PassStringParam(string value, out string retVal); 25 | void PassBoolParam(bool value, out bool retVal); 26 | void PassDoubleParam(double value, out double retVal); 27 | } 28 | } -------------------------------------------------------------------------------- /UIAControls/ITestProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using Interop.UIAutomationCore; 3 | 4 | namespace UIAControls 5 | { 6 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 7 | [ComImport] 8 | [Guid("E7C4D124-E430-46B8-B9CC-1DED8BBDA0F2")] 9 | public interface ITestProvider 10 | { 11 | int IntValue { get; } 12 | string StringValue { get; } 13 | bool BoolValue { get; } 14 | double DoubleValue { get; } 15 | IRawElementProviderSimple ElementValue { get; } 16 | 17 | void PassIntParam(int value, out int retVal); 18 | void PassStringParam(string value, out string retVal); 19 | void PassBoolParam(bool value, out bool retVal); 20 | void PassDoubleParam(double value, out double retVal); 21 | } 22 | } -------------------------------------------------------------------------------- /UIAControls/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace UIAControls 5 | { 6 | static class Program 7 | { 8 | /// 9 | /// The main entry point for the application. 10 | /// 11 | [STAThread] 12 | static void Main() 13 | { 14 | Application.EnableVisualStyles(); 15 | Application.SetCompatibleTextRenderingDefault(false); 16 | Application.Run(new Form1()); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /UIAControls/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("UIAControls")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Microsoft Corp.")] 11 | [assembly: AssemblyProduct("UIAControls")] 12 | [assembly: AssemblyCopyright("Copyright © Microsoft Corp. 2010")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("202adec3-a738-4908-8446-286672f420ae")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /UIAControls/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18213 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace UIAControls.Properties { 12 | /// 13 | /// A strongly-typed resource class, for looking up localized strings, etc. 14 | /// 15 | // This class was auto-generated by the StronglyTypedResourceBuilder 16 | // class via a tool like ResGen or Visual Studio. 17 | // To add or remove a member, edit your .ResX file then rerun ResGen 18 | // with the /str option, or rebuild your VS project. 19 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 20 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 21 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 22 | internal class Resources { 23 | 24 | private static global::System.Resources.ResourceManager resourceMan; 25 | 26 | private static global::System.Globalization.CultureInfo resourceCulture; 27 | 28 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 29 | internal Resources() { 30 | } 31 | 32 | /// 33 | /// Returns the cached ResourceManager instance used by this class. 34 | /// 35 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 36 | internal static global::System.Resources.ResourceManager ResourceManager { 37 | get { 38 | if (object.ReferenceEquals(resourceMan, null)) { 39 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("UIAControls.Properties.Resources", typeof(Resources).Assembly); 40 | resourceMan = temp; 41 | } 42 | return resourceMan; 43 | } 44 | } 45 | 46 | /// 47 | /// Overrides the current thread's CurrentUICulture property for all 48 | /// resource lookups using this strongly typed resource class. 49 | /// 50 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 51 | internal static global::System.Globalization.CultureInfo Culture { 52 | get { 53 | return resourceCulture; 54 | } 55 | set { 56 | resourceCulture = value; 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /UIAControls/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 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 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /UIAControls/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18213 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace UIAControls.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /UIAControls/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /UIAControls/ReadyStateSchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Interop.UIAutomationCore; 3 | using ManagedUiaCustomizationCore; 4 | 5 | // Ready State Property 6 | // Declaration of a simple custom property to represent the readiness of a control. 7 | 8 | namespace UIAControls 9 | { 10 | /// 11 | /// Declaration of the pattern schema, with all of the information UIA needs 12 | /// about this property. 13 | /// 14 | public class ReadyStateSchema 15 | { 16 | private bool _registered; 17 | 18 | private static readonly ReadyStateSchema Instance = new ReadyStateSchema(); 19 | 20 | public static ReadyStateSchema GetInstance() 21 | { 22 | return Instance; 23 | } 24 | 25 | public readonly UiaPropertyInfoHelper ReadyStateProperty = 26 | new UiaPropertyInfoHelper( 27 | new Guid("6E3383FB-96CF-485E-A796-FB6DE483B3DA"), 28 | "ReadyState", 29 | UIAutomationType.UIAutomationType_String, 30 | getterFromProvider: null /* it is standalone property, so we don't have to provide getter */); 31 | 32 | public void Register() 33 | { 34 | if (!_registered) 35 | { 36 | // Get our pointer to the registrar 37 | IUIAutomationRegistrar registrar = 38 | new CUIAutomationRegistrarClass(); 39 | 40 | // Set up the property struct 41 | var propertyInfo = ReadyStateProperty.Data; 42 | 43 | // Register it 44 | int propertyId; 45 | registrar.RegisterProperty( 46 | ref propertyInfo, 47 | out propertyId); 48 | 49 | // Write the property ID back 50 | ReadyStateProperty.PropertyId = propertyId; 51 | 52 | _registered = true; 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /UIAControls/TestPatternProvider.cs: -------------------------------------------------------------------------------- 1 | using Interop.UIAutomationCore; 2 | 3 | namespace UIAControls 4 | { 5 | /// 6 | /// A sample implementation of ITestProvider. 7 | /// This could be on the element provider itself, but it can also be separate, 8 | /// and keeping it separate keeps the main code cleaner, 9 | /// since this is pretty much just for testing. 10 | /// 11 | public class TestPatternProvider : ITestProvider 12 | { 13 | /// 14 | /// The host element of this pattern, from which the pattern was taken. 15 | /// 16 | private readonly IRawElementProviderSimple _hostElement; 17 | 18 | public TestPatternProvider(IRawElementProviderSimple hostElement) 19 | { 20 | _hostElement = hostElement; 21 | } 22 | 23 | public int IntValue 24 | { 25 | get { return 42; } 26 | } 27 | 28 | public string StringValue 29 | { 30 | get { return "TestString"; } 31 | } 32 | 33 | public bool BoolValue 34 | { 35 | get { return true; } 36 | } 37 | 38 | public double DoubleValue 39 | { 40 | get { return 3.1415; } 41 | } 42 | 43 | public IRawElementProviderSimple ElementValue 44 | { 45 | get { return _hostElement; } 46 | } 47 | 48 | public void PassIntParam(int value, out int retVal) 49 | { 50 | retVal = value; 51 | } 52 | 53 | public void PassStringParam(string value, out string retVal) 54 | { 55 | retVal = value; 56 | } 57 | 58 | public void PassBoolParam(bool value, out bool retVal) 59 | { 60 | retVal = value; 61 | } 62 | 63 | public void PassDoubleParam(double value, out double retVal) 64 | { 65 | retVal = value; 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /UIAControls/TestProviderClientInstance.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Interop.UIAutomationCore; 3 | using ManagedUiaCustomizationCore; 4 | using UIAutomationClient; 5 | 6 | namespace UIAControls 7 | { 8 | public class TestProviderClientInstance : CustomClientInstanceBase, ITestPattern 9 | { 10 | public TestProviderClientInstance(IUIAutomationPatternInstance patternInstance) 11 | : base(patternInstance) 12 | { 13 | } 14 | 15 | public int CurrentIntValue 16 | { 17 | get { return (int) GetCurrentPropertyValue(TestSchema.GetInstance().IntValueProperty); } 18 | } 19 | 20 | public string CurrentStringValue 21 | { 22 | get { return (string) GetCurrentPropertyValue(TestSchema.GetInstance().StringValueProperty); } 23 | } 24 | 25 | public bool CurrentBoolValue 26 | { 27 | get 28 | { 29 | // Get the current property value via method, to work around the 2-property 30 | // limitation in Win7 UIA 31 | return (bool) GetCurrentPropertyValueViaMethod(TestSchema.GetInstance().GetBoolValueMethod); 32 | } 33 | } 34 | 35 | public double CurrentDoubleValue 36 | { 37 | get 38 | { 39 | // Get the current property value via method, to work around the 2-property 40 | // limitation in Win7 UIA 41 | return (double) GetCurrentPropertyValueViaMethod(TestSchema.GetInstance().GetDoubleValueMethod); 42 | } 43 | } 44 | 45 | public IUIAutomationElement CurrentElementValue 46 | { 47 | get 48 | { 49 | // Get the current property value via method, to work around the 2-property 50 | // limitation in Win7 UIA 51 | return (IUIAutomationElement) GetCurrentPropertyValueViaMethod(TestSchema.GetInstance().GetElementValueMethod); 52 | } 53 | } 54 | 55 | public int CachedIntValue 56 | { 57 | get { return (int) GetCachedPropertyValue(TestSchema.GetInstance().IntValueProperty); } 58 | } 59 | 60 | public string CachedStringValue 61 | { 62 | get { return (string) GetCachedPropertyValue(TestSchema.GetInstance().StringValueProperty); } 63 | } 64 | 65 | public bool CachedBoolValue 66 | { 67 | get 68 | { 69 | // Not supported, since Win7 UIA will not support more than 2 pattern properties 70 | throw new NotImplementedException(); 71 | } 72 | } 73 | 74 | public double CachedDoubleValue 75 | { 76 | get 77 | { 78 | // Not supported, since Win7 UIA will not support more than 2 pattern properties 79 | throw new NotImplementedException(); 80 | } 81 | } 82 | 83 | public IUIAutomationElement CachedElementValue 84 | { 85 | get 86 | { 87 | // Not supported, since Win7 UIA will not support more than 2 pattern properties 88 | throw new NotImplementedException(); 89 | } 90 | } 91 | 92 | public void PassIntParam(int value, out int retVal) 93 | { 94 | // Create and init a parameter list 95 | // We can't just use the CallMethod helper because we have out-parameters 96 | var paramList = new UiaParameterListHelper(TestSchema.GetInstance().PassIntParamMethod); 97 | paramList[0] = value; 98 | 99 | // Call through 100 | PatternInstance.CallMethod(TestSchema.GetInstance().PassIntParamMethod.Index, paramList.Data, paramList.Count); 101 | 102 | // Get the out-parameter 103 | retVal = (int) paramList[1]; 104 | } 105 | 106 | public void PassStringParam(string value, out string retVal) 107 | { 108 | // Create and init a parameter list 109 | // We can't just use the CallMethod helper because we have out-parameters 110 | var paramList = new UiaParameterListHelper(TestSchema.GetInstance().PassStringParamMethod); 111 | paramList[0] = value; 112 | 113 | // Call through 114 | PatternInstance.CallMethod(TestSchema.GetInstance().PassStringParamMethod.Index, paramList.Data, paramList.Count); 115 | 116 | // Get the out-parameter 117 | retVal = (string) paramList[1]; 118 | } 119 | 120 | public void PassBoolParam(bool value, out bool retVal) 121 | { 122 | // Create and init a parameter list 123 | // We can't just use the CallMethod helper because we have out-parameters 124 | var paramList = new UiaParameterListHelper(TestSchema.GetInstance().PassBoolParamMethod); 125 | paramList[0] = value; 126 | 127 | // Call through 128 | PatternInstance.CallMethod(TestSchema.GetInstance().PassBoolParamMethod.Index, paramList.Data, paramList.Count); 129 | 130 | // Get the out-parameter 131 | retVal = (bool) paramList[1]; 132 | } 133 | 134 | public void PassDoubleParam(double value, out double retVal) 135 | { 136 | // Create and init a parameter list 137 | // We can't just use the CallMethod helper because we have out-parameters 138 | var paramList = new UiaParameterListHelper(TestSchema.GetInstance().PassDoubleParamMethod); 139 | paramList[0] = value; 140 | 141 | // Call through 142 | PatternInstance.CallMethod(TestSchema.GetInstance().PassDoubleParamMethod.Index, paramList.Data, paramList.Count); 143 | 144 | // Get the out-parameter 145 | retVal = (double) paramList[1]; 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /UIAControls/TestProviderHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Interop.UIAutomationCore; 3 | using ManagedUiaCustomizationCore; 4 | 5 | namespace UIAControls 6 | { 7 | /// 8 | /// Pattern handler class: creates pattern instances on client side and dispatches 9 | /// calls on the provider side. 10 | /// 11 | public class TestProviderHandler : IUIAutomationPatternHandler 12 | { 13 | public void CreateClientWrapper(IUIAutomationPatternInstance pPatternInstance, out object pClientWrapper) 14 | { 15 | pClientWrapper = new TestProviderClientInstance(pPatternInstance); 16 | } 17 | 18 | public void Dispatch(object pTarget, uint index, UIAutomationParameter[] pParams, uint cParams) 19 | { 20 | // Parse the provider and parameter list 21 | var provider = (ITestProvider) pTarget; 22 | var paramList = new UiaParameterListHelper(pParams); 23 | 24 | var member = TestSchema.GetInstance().GetMemberByIndex(index); 25 | if (member != null) 26 | { 27 | member.DispatchCallToProvider(provider, paramList); 28 | return; 29 | } 30 | 31 | // Dispatch the method/property calls 32 | if (index == TestSchema.GetInstance().GetBoolValueMethod.Index) 33 | { 34 | paramList[0] = provider.BoolValue; 35 | } 36 | else if (index == TestSchema.GetInstance().GetDoubleValueMethod.Index) 37 | { 38 | paramList[0] = provider.DoubleValue; 39 | } 40 | else if (index == TestSchema.GetInstance().GetElementValueMethod.Index) 41 | { 42 | paramList[0] = provider.ElementValue; 43 | } 44 | else 45 | { 46 | throw new InvalidOperationException(); 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /UIAControls/TestSchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Interop.UIAutomationCore; 3 | 4 | // Test Pattern 5 | // Schema and implementation for the custom pattern that demonstrates several 6 | // different supported parameter types 7 | using ManagedUiaCustomizationCore; 8 | 9 | namespace UIAControls 10 | { 11 | // Declaration of the provider-side interface, which the control will implement. 12 | 13 | // Declaration of the client-side interface, for the client/test to use. 14 | 15 | /// 16 | /// Declaration of the pattern schema, with all of the information UIA needs 17 | /// about this property. 18 | /// 19 | public class TestSchema : CustomPatternSchemaBase 20 | { 21 | private static readonly TestSchema Instance = new TestSchema(); 22 | 23 | private static readonly ITestProvider _dummyProvider = null; 24 | private static int _dummyInt = 0; 25 | private static string _dummyString = null; 26 | private static bool _dummyBool = false; 27 | private static double _dummyDouble = 0; 28 | 29 | public static TestSchema GetInstance() 30 | { 31 | return Instance; 32 | } 33 | 34 | public readonly UiaPropertyInfoHelper IntValueProperty = 35 | new UiaPropertyInfoHelper( 36 | new Guid("1898A775-726D-44AF-8F7B-A52814E46AC8"), 37 | "IntValue", 38 | UIAutomationType.UIAutomationType_Int, 39 | TypeMember.GetPropertyGetter(p => p.IntValue)); 40 | 41 | public readonly UiaPropertyInfoHelper StringValueProperty = 42 | new UiaPropertyInfoHelper( 43 | new Guid("83454F57-97C3-4740-B2CD-A5AA4FA40EA2"), 44 | "StringValue", 45 | UIAutomationType.UIAutomationType_String, 46 | TypeMember.GetPropertyGetter(p => p.StringValue)); 47 | 48 | // These function like properties, but are declared as methods 49 | // to work around the two-property limitation in Win7 UIA. 50 | // Win7 UIA does not seem to be able to process more than 51 | // two properties attached to a pattern. Standalone properties work fine. 52 | // And we can also work around this by creating methods that 53 | // have a single out-parameter, which is what we're doing here. 54 | 55 | public readonly UiaMethodInfoHelper GetBoolValueMethod = 56 | new UiaMethodInfoHelper( 57 | "get_BoolValue", 58 | false /* doSetFocus */, 59 | new[] 60 | { 61 | new UiaParameterDescription("retVal", UIAutomationType.UIAutomationType_OutBool) 62 | }); 63 | 64 | public readonly UiaMethodInfoHelper GetDoubleValueMethod = 65 | new UiaMethodInfoHelper( 66 | "get_DoubleValue", 67 | false /* doSetFocus */, 68 | new[] 69 | { 70 | new UiaParameterDescription("retVal", UIAutomationType.UIAutomationType_OutDouble) 71 | }); 72 | 73 | public readonly UiaMethodInfoHelper GetElementValueMethod = 74 | new UiaMethodInfoHelper( 75 | "get_ElementValue", 76 | false /* doSetFocus */, 77 | new[] 78 | { 79 | new UiaParameterDescription("retVal", UIAutomationType.UIAutomationType_OutElement) 80 | }); 81 | 82 | public readonly UiaMethodInfoHelper PassIntParamMethod = 83 | new UiaMethodInfoHelper( 84 | ReflectionUtils.GetMethodInfo(() => _dummyProvider.PassIntParam(0, out _dummyInt)), 85 | true /* doSetFocus */); 86 | 87 | public readonly UiaMethodInfoHelper PassStringParamMethod = 88 | new UiaMethodInfoHelper( 89 | ReflectionUtils.GetMethodInfo(() => _dummyProvider.PassStringParam(null, out _dummyString)), 90 | true /* doSetFocus */); 91 | 92 | public readonly UiaMethodInfoHelper PassBoolParamMethod = 93 | new UiaMethodInfoHelper( 94 | ReflectionUtils.GetMethodInfo(() => _dummyProvider.PassBoolParam(true, out _dummyBool)), 95 | true /* doSetFocus */); 96 | 97 | public readonly UiaMethodInfoHelper PassDoubleParamMethod = 98 | new UiaMethodInfoHelper( 99 | ReflectionUtils.GetMethodInfo(() => _dummyProvider.PassDoubleParam(0, out _dummyDouble)), 100 | true /* doSetFocus */); 101 | 102 | public readonly UiaEventInfoHelper Test1Event = 103 | new UiaEventInfoHelper( 104 | new Guid("FDACD325-D5AE-4D80-AE13-81FA7793645B"), 105 | "Test1"); 106 | 107 | public readonly UiaEventInfoHelper Test2Event = 108 | new UiaEventInfoHelper( 109 | new Guid("B7827175-069C-43D0-8D3A-843F42B846E1"), 110 | "Test2"); 111 | 112 | public override UiaPropertyInfoHelper[] Properties 113 | { 114 | get 115 | { 116 | return new[] 117 | { 118 | IntValueProperty, 119 | StringValueProperty, 120 | }; 121 | } 122 | } 123 | 124 | public override UiaMethodInfoHelper[] Methods 125 | { 126 | get 127 | { 128 | return new[] 129 | { 130 | GetBoolValueMethod, 131 | GetDoubleValueMethod, 132 | GetElementValueMethod, 133 | PassIntParamMethod, 134 | PassStringParamMethod, 135 | PassBoolParamMethod, 136 | PassDoubleParamMethod, 137 | }; 138 | } 139 | } 140 | 141 | public override UiaEventInfoHelper[] Events 142 | { 143 | get 144 | { 145 | return new[] 146 | { 147 | Test1Event, 148 | Test2Event 149 | }; 150 | } 151 | } 152 | 153 | public override Guid PatternGuid 154 | { 155 | get { return new Guid("AD93BC6E-8BEC-4C29-9F4D-E820138FF43F"); } 156 | } 157 | 158 | public override string PatternName 159 | { 160 | get { return "TestPattern"; } 161 | } 162 | 163 | public override Type PatternProviderInterface 164 | { 165 | get { return typeof(ITestProvider); } 166 | } 167 | 168 | public override Type PatternClientInterface 169 | { 170 | get { return typeof(ITestPattern); } 171 | } 172 | 173 | public override IUIAutomationPatternHandler Handler 174 | { 175 | get { return new TestProviderHandler(); } 176 | } 177 | }; 178 | } -------------------------------------------------------------------------------- /UIAControls/TriColorControl.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace UIAControls 2 | { 3 | partial class TriColorControl 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.SuspendLayout(); 32 | // 33 | // TriColorControl 34 | // 35 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 36 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 37 | this.Name = "TriColorControl"; 38 | this.ResumeLayout(false); 39 | 40 | } 41 | 42 | #endregion 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /UIAControls/TriColorControl.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 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 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /UIAControls/TriColorFragmentProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Automation.Providers; 3 | using Interop.UIAutomationCore; 4 | using UIAutomationClient; 5 | using IRawElementProviderFragment = Interop.UIAutomationCore.IRawElementProviderFragment; 6 | using IRawElementProviderFragmentRoot = Interop.UIAutomationCore.IRawElementProviderFragmentRoot; 7 | using IRawElementProviderSimple = Interop.UIAutomationCore.IRawElementProviderSimple; 8 | using ISelectionItemProvider = Interop.UIAutomationCore.ISelectionItemProvider; 9 | using ProviderOptions = Interop.UIAutomationCore.ProviderOptions; 10 | 11 | namespace UIAControls 12 | { 13 | /// 14 | /// Provider for the color-bar fragments within the TriColor control. 15 | /// 16 | public class TriColorFragmentProvider : BaseFragmentProvider, ISelectionItemProvider 17 | { 18 | private readonly TriColorControl _control; 19 | private readonly TriColorValue _value; 20 | 21 | public TriColorFragmentProvider(TriColorControl control, IRawElementProviderFragmentRoot root, TriColorValue value) 22 | : base((IRawElementProviderFragment) root /* parent */, root /* fragmentRoot */) 23 | { 24 | _control = control; 25 | _value = value; 26 | 27 | // Populate static properties 28 | // 29 | // In a production app, Name should be localized 30 | AddStaticProperty(UIA_PropertyIds.UIA_NamePropertyId, _value.ToString()); 31 | AddStaticProperty(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_CustomControlTypeId); 32 | // In a production app, LocalizedControlType should be localized 33 | AddStaticProperty(UIA_PropertyIds.UIA_LocalizedControlTypePropertyId, "tri-color item"); 34 | AddStaticProperty(UIA_PropertyIds.UIA_ProviderDescriptionPropertyId, "UIASamples: Tri-Color Fragment Provider"); 35 | AddStaticProperty(UIA_PropertyIds.UIA_AutomationIdPropertyId, _value.ToString()); 36 | AddStaticProperty(UIA_PropertyIds.UIA_IsKeyboardFocusablePropertyId, false); 37 | AddStaticProperty(UIA_PropertyIds.UIA_IsControlElementPropertyId, true); 38 | AddStaticProperty(UIA_PropertyIds.UIA_IsContentElementPropertyId, false); 39 | } 40 | 41 | public override ProviderOptions ProviderOptions 42 | { 43 | // Request COM threading style - all calls on main thread 44 | get 45 | { 46 | return (ProviderOptions) ((int) (ProviderOptions.ProviderOptions_ServerSideProvider | 47 | ProviderOptions.ProviderOptions_UseComThreading)); 48 | } 49 | } 50 | 51 | public override object GetPatternProvider(int patternId) 52 | { 53 | if (patternId == UIA_PatternIds.UIA_SelectionItemPatternId) 54 | { 55 | return this; 56 | } 57 | 58 | return base.GetPatternProvider(patternId); 59 | } 60 | 61 | // Create a runtime ID. Since there is only one fragment per value, 62 | // the value turned into an integer is a unique identifier that we 63 | // can use as the runtime ID. 64 | public override int[] GetRuntimeId() 65 | { 66 | var runtimeId = new int[2]; 67 | runtimeId[0] = AutomationInteropProvider.AppendRuntimeId; 68 | runtimeId[1] = (int) _value; 69 | return runtimeId; 70 | } 71 | 72 | // Get the bounding rect by consulting the control. 73 | public override UiaRect get_BoundingRectangle() 74 | { 75 | // Bounding rects must be in screen coordinates 76 | var screenRect = _control.RectangleToScreen( 77 | _control.RectFromValue(_value)); 78 | var result = new UiaRect 79 | { 80 | left = screenRect.Left, 81 | top = screenRect.Top, 82 | width = screenRect.Width, 83 | height = screenRect.Height 84 | }; 85 | return result; 86 | } 87 | 88 | // Return the fragment for the next value 89 | protected override IRawElementProviderFragment GetNextSibling() 90 | { 91 | if (!TriColorValueHelper.IsLast(_value)) 92 | { 93 | return new TriColorFragmentProvider( 94 | _control, 95 | fragmentRoot, 96 | TriColorValueHelper.NextValue(_value)); 97 | } 98 | return null; 99 | } 100 | 101 | // Return the fragment for the previous value 102 | protected override IRawElementProviderFragment GetPreviousSibling() 103 | { 104 | if (!TriColorValueHelper.IsFirst(_value)) 105 | { 106 | return new TriColorFragmentProvider( 107 | _control, 108 | fragmentRoot, 109 | TriColorValueHelper.PreviousValue(_value)); 110 | } 111 | return null; 112 | } 113 | 114 | // Select this item 115 | public void Select() 116 | { 117 | // Set the control's value to be the value of this fragment 118 | _control.Value = _value; 119 | } 120 | 121 | // Is this item selected? 122 | public int IsSelected 123 | { 124 | get 125 | { 126 | // This item is selected iff the control's value is the fragment's value 127 | return (_control.Value == _value) ? 1 : 0; 128 | } 129 | } 130 | 131 | // Adding is not valid for a single-select control 132 | public void AddToSelection() 133 | { 134 | throw new InvalidOperationException(); 135 | } 136 | 137 | // Removing is not valid for a single-select control 138 | public void RemoveFromSelection() 139 | { 140 | throw new InvalidOperationException(); 141 | } 142 | 143 | // The selection container is simply our fragment root 144 | public IRawElementProviderSimple SelectionContainer 145 | { 146 | get { return (IRawElementProviderSimple) fragmentRoot; } 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /UIAControls/TriColorValue.cs: -------------------------------------------------------------------------------- 1 | namespace UIAControls 2 | { 3 | /// 4 | /// A choice among three colors 5 | /// 6 | public enum TriColorValue 7 | { 8 | Red, 9 | Yellow, 10 | Green, 11 | }; 12 | } -------------------------------------------------------------------------------- /UIAControls/TriColorValueHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UIAControls 4 | { 5 | public static class TriColorValueHelper 6 | { 7 | public static bool IsFirst(TriColorValue value) 8 | { 9 | return (value == TriColorValue.Red); 10 | } 11 | 12 | public static bool IsLast(TriColorValue value) 13 | { 14 | return (value == TriColorValue.Green); 15 | } 16 | 17 | public static TriColorValue NextValue(TriColorValue value) 18 | { 19 | if (IsLast(value)) 20 | { 21 | throw new ArgumentOutOfRangeException(); 22 | } 23 | 24 | value++; 25 | return value; 26 | } 27 | 28 | public static TriColorValue PreviousValue(TriColorValue value) 29 | { 30 | if (IsFirst(value)) 31 | { 32 | throw new ArgumentOutOfRangeException(); 33 | } 34 | 35 | value--; 36 | return value; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /UIAControls/UIAControls.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.30729 7 | 2.0 8 | {3663F841-CE46-42F6-82A3-FF60E17C0593} 9 | WinExe 10 | Properties 11 | UIAControls 12 | UIAControls 13 | v4.0 14 | 512 15 | 16 | 17 | true 18 | bin\Debug\ 19 | DEBUG;TRACE 20 | full 21 | AnyCPU 22 | prompt 23 | MinimumRecommendedRules.ruleset 24 | 25 | 26 | bin\Release\ 27 | TRACE 28 | true 29 | pdbonly 30 | AnyCPU 31 | prompt 32 | MinimumRecommendedRules.ruleset 33 | 34 | 35 | 36 | False 37 | False 38 | ..\packages\UIAComWrapper.1.1.0.14\lib\net40\Interop.UIAutomationClient.dll 39 | 40 | 41 | False 42 | ..\UIACoreInterop\Build\Interop.UIAutomationCore.dll 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | ..\packages\UIAComWrapper.1.1.0.14\lib\net40\UIAComWrapper.dll 52 | True 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | Form 64 | 65 | 66 | Form1.cs 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | Form1.cs 81 | Designer 82 | 83 | 84 | ResXFileCodeGenerator 85 | Resources.Designer.cs 86 | Designer 87 | 88 | 89 | TriColorControl.cs 90 | Designer 91 | 92 | 93 | True 94 | Resources.resx 95 | True 96 | 97 | 98 | 99 | SettingsSingleFileGenerator 100 | Settings.Designer.cs 101 | 102 | 103 | True 104 | Settings.settings 105 | True 106 | 107 | 108 | 109 | UserControl 110 | 111 | 112 | TriColorControl.cs 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | {21db168c-e0ef-4e07-b24a-1e5bb64d2a17} 121 | ManagedUiaCustomizationCore 122 | 123 | 124 | 125 | 132 | -------------------------------------------------------------------------------- /UIAControls/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /UiaControlsTest/CustomPatternBaseTests.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using System.Windows.Automation; 3 | using ManagedUiaCustomizationCore; 4 | using NUnit.Framework; 5 | 6 | namespace UiaControlsTest 7 | { 8 | // here we'll test that registration info is placed correctly to properties and wpf augmentation is done 9 | [TestFixture] 10 | public class CustomPatternBaseTests 11 | { 12 | [Test] 13 | public void AfterInitializationRegistrationInfoFilledCorrectly() 14 | { 15 | CustomPatternBaseTestPattern.Initialize(); 16 | 17 | Assert.IsNotNull(CustomPatternBaseTestPattern.Pattern); 18 | Assert.IsNotNull(CustomPatternBaseTestPattern.SomeIntProperty); 19 | Assert.IsNotNull(CustomPatternBaseTestPattern.SomeStringProperty); 20 | Assert.IsNotNull(CustomPatternBaseTestPattern.StandaloneIntProperty); 21 | } 22 | 23 | #region Pattern definition 24 | 25 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 26 | [ComVisible(true)] 27 | [Guid("1800101C-5550-46F0-99FC-11C6868D4237")] 28 | [PatternGuid("8453E6B6-C1D7-4A0E-A4F9-85CFCE098C2F")] 29 | public interface ICustomPatternBaseTestProvider 30 | { 31 | [PatternProperty("2D86858D-737E-4BC1-A9BA-51978E86B6A4")] 32 | int SomeInt { get; } 33 | 34 | [PatternProperty("64FE6A20-CB27-402E-86A4-29876D0DF81A")] 35 | string SomeString { get; } 36 | } 37 | 38 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 39 | [ComVisible(true)] 40 | [Guid("09DB9892-BD12-4A55-B3CF-218154B8D77B")] 41 | public interface ICustomPatternBaseTestPattern 42 | { 43 | int CurrentSomeInt { get; } 44 | string CurrentSomeString { get; } 45 | int CachedSomeInt { get; } 46 | string CachedSomeString { get; } 47 | } 48 | 49 | public class CustomPatternBaseTestPattern : CustomPatternBase 50 | { 51 | private CustomPatternBaseTestPattern() 52 | : base(usedInWpf: true) 53 | { 54 | } 55 | 56 | public static void Initialize() 57 | { 58 | if (PatternSchema != null) return; 59 | PatternSchema = new CustomPatternBaseTestPattern(); 60 | } 61 | 62 | public static CustomPatternBaseTestPattern PatternSchema; 63 | 64 | public static AutomationPattern Pattern; 65 | public static AutomationProperty SomeIntProperty; 66 | public static AutomationProperty SomeStringProperty; 67 | 68 | [StandaloneProperty("B26C3D40-215A-478B-9C4D-6D91DFDAC3FF", typeof(int))] 69 | public static AutomationProperty StandaloneIntProperty; 70 | } 71 | 72 | #endregion 73 | } 74 | } -------------------------------------------------------------------------------- /UiaControlsTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("UiaControlsTest")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Microsoft Corp.")] 11 | [assembly: AssemblyProduct("UiaControlsTest")] 12 | [assembly: AssemblyCopyright("Copyright © Microsoft Corp. 2010")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM componenets. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("d28543e6-3cb5-4123-8ee2-c2a2153d2f13")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Revision and Build Numbers 32 | // by using the '*' as shown below: 33 | [assembly: AssemblyVersion("1.0.0.0")] 34 | [assembly: AssemblyFileVersion("1.0.0.0")] 35 | -------------------------------------------------------------------------------- /UiaControlsTest/UiaControlsTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.30729 7 | 2.0 8 | {B3C66956-B92B-411B-B7AA-D2DC8C93A801} 9 | Library 10 | Properties 11 | UiaControlsTest 12 | UiaControlsTest 13 | v4.0 14 | 512 15 | 16 | 17 | true 18 | bin\Debug\ 19 | DEBUG;TRACE 20 | full 21 | AnyCPU 22 | prompt 23 | MinimumRecommendedRules.ruleset 24 | 25 | 26 | bin\Release\ 27 | TRACE 28 | true 29 | pdbonly 30 | AnyCPU 31 | prompt 32 | MinimumRecommendedRules.ruleset 33 | 34 | 35 | 36 | False 37 | False 38 | ..\packages\UIAComWrapper.1.1.0.14\lib\net40\Interop.UIAutomationClient.dll 39 | 40 | 41 | False 42 | ..\UIACoreInterop\Build\Interop.UIAutomationCore.dll 43 | 44 | 45 | ..\packages\NSubstitute.1.7.2.0\lib\NET40\NSubstitute.dll 46 | 47 | 48 | ..\packages\NUnit.2.6.3\lib\nunit.framework.dll 49 | 50 | 51 | 52 | 53 | 54 | ..\packages\UIAComWrapper.1.1.0.14\lib\net40\UIAComWrapper.dll 55 | True 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | {21db168c-e0ef-4e07-b24a-1e5bb64d2a17} 70 | ManagedUiaCustomizationCore 71 | 72 | 73 | {3663F841-CE46-42F6-82A3-FF60E17C0593} 74 | UIAControls 75 | 76 | 77 | {b010a379-d2b1-474a-89f8-5a381d99183d} 78 | WpfAppWithAdvTextControl 79 | 80 | 81 | 82 | 83 | 84 | 85 | 92 | -------------------------------------------------------------------------------- /UiaControlsTest/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /UiaCustomPattersManaged.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TestStack.UiaCustomPattersManaged 5 | $version$ 6 | TestStack.UiaCustomPattersManaged 7 | UiaCustomPattersManaged allows to define and use custom UIA patterns from managed code. 8 | Custom patterns could be seen from UIAVerify tool (see TestStack's fork of it) and handy to use in WPF apps because pattern registration has some means to inject new pattern into existing AutomationPeer's structure. 9 | 10 | Also was tested to some extent with WinForms. 11 | Ivan Danilov 12 | Ivan Danilov 13 | https://github.com/TestStack/uia-custom-pattern-managed 14 | false 15 | UIAutomation Testing UIA WPF Win32 Automation 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /UiaCustomPattersManaged.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25123.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UIAControls", "UIAControls\UIAControls.csproj", "{3663F841-CE46-42F6-82A3-FF60E17C0593}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomizeUiaInterop", "CustomizeUiaInterop\CustomizeUiaInterop.csproj", "{12F27127-240F-4AAB-A233-D7C0A2BFC70B}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UiaControlsTest", "UiaControlsTest\UiaControlsTest.csproj", "{B3C66956-B92B-411B-B7AA-D2DC8C93A801}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfAppWithAdvTextControl", "WpfAppWithAdvTextControl\WpfAppWithAdvTextControl.csproj", "{B010A379-D2B1-474A-89F8-5A381D99183D}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManagedUiaCustomizationCore", "ManagedUiaCustomizationCore\ManagedUiaCustomizationCore.csproj", "{21DB168C-E0EF-4E07-B24A-1E5BB64D2A17}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {3663F841-CE46-42F6-82A3-FF60E17C0593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {3663F841-CE46-42F6-82A3-FF60E17C0593}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {3663F841-CE46-42F6-82A3-FF60E17C0593}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {3663F841-CE46-42F6-82A3-FF60E17C0593}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {12F27127-240F-4AAB-A233-D7C0A2BFC70B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {12F27127-240F-4AAB-A233-D7C0A2BFC70B}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {12F27127-240F-4AAB-A233-D7C0A2BFC70B}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {12F27127-240F-4AAB-A233-D7C0A2BFC70B}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {B3C66956-B92B-411B-B7AA-D2DC8C93A801}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {B3C66956-B92B-411B-B7AA-D2DC8C93A801}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {B3C66956-B92B-411B-B7AA-D2DC8C93A801}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {B3C66956-B92B-411B-B7AA-D2DC8C93A801}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {B010A379-D2B1-474A-89F8-5A381D99183D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {B010A379-D2B1-474A-89F8-5A381D99183D}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {B010A379-D2B1-474A-89F8-5A381D99183D}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {B010A379-D2B1-474A-89F8-5A381D99183D}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {21DB168C-E0EF-4E07-B24A-1E5BB64D2A17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {21DB168C-E0EF-4E07-B24A-1E5BB64D2A17}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {21DB168C-E0EF-4E07-B24A-1E5BB64D2A17}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {21DB168C-E0EF-4E07-B24A-1E5BB64D2A17}.Release|Any CPU.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | EndGlobal 47 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/AdvTextBox.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Automation.Peers; 2 | using System.Windows.Controls; 3 | 4 | namespace WpfAppWithAdvTextControl 5 | { 6 | public class AdvTextBox : TextBox 7 | { 8 | protected override AutomationPeer OnCreateAutomationPeer() 9 | { 10 | return new AdvTextBoxAutomationPeer(this); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/AdvTextBoxAutomationPeer.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Automation.Peers; 2 | 3 | namespace WpfAppWithAdvTextControl 4 | { 5 | public class AdvTextBoxAutomationPeer : TextBoxAutomationPeer, ICaretPositionProvider 6 | { 7 | public AdvTextBoxAutomationPeer(AdvTextBox owner) 8 | : base(owner) 9 | { 10 | CaretPositionPattern.Initialize(); 11 | } 12 | 13 | private new AdvTextBox Owner 14 | { 15 | get { return (AdvTextBox)base.Owner; } 16 | } 17 | 18 | protected override string GetClassNameCore() 19 | { 20 | return "AdvTextBox"; 21 | } 22 | 23 | public override object GetPattern(PatternInterface patternInterface) 24 | { 25 | if ((int)patternInterface == CaretPositionPattern.Pattern.Id) 26 | return this; 27 | return base.GetPattern(patternInterface); 28 | } 29 | 30 | public int SelectionStart 31 | { 32 | get { return Owner.SelectionStart; } 33 | } 34 | 35 | public int SelectionLength 36 | { 37 | get { return Owner.SelectionLength; } 38 | } 39 | 40 | public void SetSelectionStart(int value) 41 | { 42 | Owner.SelectionStart = value; 43 | } 44 | 45 | public void SetSelectionLength(int value) 46 | { 47 | Owner.SelectionLength = value; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace WpfAppWithAdvTextControl 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/AutomationElementRetievingPattern.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using System.Windows.Automation; 3 | using ManagedUiaCustomizationCore; 4 | using UIAutomationClient; 5 | using IRawElementProviderSimple = System.Windows.Automation.Provider.IRawElementProviderSimple; 6 | 7 | namespace WpfAppWithAdvTextControl 8 | { 9 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 10 | [ComImport] 11 | [Guid("DB7AAA20-B3F3-4A71-A0D1-F08EA667FC05")] 12 | [PatternGuid("7C776C94-2F54-4054-A8EB-B23E713C3F5E")] 13 | public interface IAutomationElementRetievingProvider 14 | { 15 | [PatternProperty("2C87DC26-B842-4E0D-ADD8-2DEFB8F7F360")] 16 | IRawElementProviderSimple NativeElement { get; } 17 | 18 | [PatternProperty("B5C46FFC-C638-4520-9CCF-6D73FA9A6DF7")] 19 | IRawElementProviderSimple WrappedElement { get; } 20 | 21 | [PatternMethod] 22 | IRawElementProviderSimple NativeGetCurrentElement(); 23 | 24 | [PatternMethod] 25 | IRawElementProviderSimple NativeGetNullElement(); 26 | 27 | [PatternMethod] 28 | void NativeGetCurrentElementWithOutParam(out IRawElementProviderSimple value); 29 | 30 | [PatternMethod] 31 | IRawElementProviderSimple WrappedGetCurrentElement(); 32 | 33 | [PatternMethod] 34 | IRawElementProviderSimple WrappedGetNullElement(); 35 | 36 | [PatternMethod] 37 | void WrappedGetCurrentElementWithOutParam(out IRawElementProviderSimple value); 38 | } 39 | 40 | public interface IAutomationElementRetievingPattern 41 | { 42 | IUIAutomationElement CurrentNativeElement { get; } 43 | IUIAutomationElement CachedNativeElement { get; } 44 | 45 | AutomationElement CurrentWrappedElement { get; } 46 | AutomationElement CachedWrappedElement { get; } 47 | 48 | IUIAutomationElement NativeGetCurrentElement(); 49 | IUIAutomationElement NativeGetNullElement(); 50 | void NativeGetCurrentElementWithOutParam(out IUIAutomationElement value); 51 | 52 | AutomationElement WrappedGetCurrentElement(); 53 | AutomationElement WrappedGetNullElement(); 54 | void WrappedGetCurrentElementWithOutParam(out AutomationElement value); 55 | } 56 | 57 | public class AutomationElementRetievingPattern : CustomPatternBase 58 | { 59 | private AutomationElementRetievingPattern() 60 | : base(usedInWpf: true) 61 | { 62 | } 63 | 64 | public static void Initialize() 65 | { 66 | if (PatternSchema != null) return; 67 | PatternSchema = new AutomationElementRetievingPattern(); 68 | } 69 | 70 | public static AutomationElementRetievingPattern PatternSchema; 71 | public static AutomationPattern Pattern; 72 | public static AutomationProperty NativeElementProperty; 73 | public static AutomationProperty WrappedElementProperty; 74 | } 75 | } -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/CaretPositionPattern.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Automation; 2 | using ManagedUiaCustomizationCore; 3 | 4 | namespace WpfAppWithAdvTextControl 5 | { 6 | public class CaretPositionPattern : CustomPatternBase 7 | { 8 | private CaretPositionPattern() 9 | : base(usedInWpf: true) 10 | { 11 | } 12 | 13 | public static void Initialize() 14 | { 15 | if (PatternSchema != null) return; 16 | PatternSchema = new CaretPositionPattern(); 17 | } 18 | 19 | public static CaretPositionPattern PatternSchema; 20 | 21 | // these will be set via reflection on Initialize() call 22 | public static AutomationPattern Pattern; 23 | public static AutomationProperty SelectionStartProperty; 24 | public static AutomationProperty SelectionLengthProperty; 25 | } 26 | } -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/ICaretPositionPattern.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace WpfAppWithAdvTextControl 4 | { 5 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 6 | [ComImport] 7 | [Guid("0FC33FD3-3874-4A32-A530-0EBE937D4419")] 8 | public interface ICaretPositionPattern 9 | { 10 | int CurrentSelectionStart { get; } 11 | int CurrentSelectionLength { get; } 12 | 13 | int CachedSelectionStart { get; } 14 | int CachedSelectionLength { get; } 15 | 16 | void SetSelectionStart(int value); 17 | void SetSelectionLength(int value); 18 | } 19 | } -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/ICaretPositionProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using ManagedUiaCustomizationCore; 3 | 4 | namespace WpfAppWithAdvTextControl 5 | { 6 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 7 | [ComImport] 8 | [Guid("0F268572-8746-4105-9188-080086FCC6E4")] 9 | [PatternGuid("B85FDDEA-D38F-44D6-AE42-0CA3CF0433F1")] 10 | public interface ICaretPositionProvider 11 | { 12 | [PatternProperty("6B55247F-6BAF-460C-9C3E-388E7161A7E9")] 13 | int SelectionStart { get; } 14 | 15 | [PatternProperty("F0CD6926-AA86-4EBF-BDCC-7345C5D98EC6")] 16 | int SelectionLength { get; } 17 | 18 | [PatternMethod] 19 | void SetSelectionStart(int value); 20 | 21 | [PatternMethod] 22 | void SetSelectionLength(int value); 23 | } 24 | } -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Test control for other patterns 14 | 15 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace WpfAppWithAdvTextControl 17 | { 18 | /// 19 | /// Interaction logic for MainWindow.xaml 20 | /// 21 | public partial class MainWindow : Window 22 | { 23 | public MainWindow() 24 | { 25 | InitializeComponent(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("WpfAppWithAdvTextControl")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("WpfAppWithAdvTextControl")] 15 | [assembly: AssemblyCopyright("Copyright © 2014")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18444 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace WpfAppWithAdvTextControl.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WpfAppWithAdvTextControl.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 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 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18444 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace WpfAppWithAdvTextControl.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/TestControl.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Automation.Peers; 2 | using System.Windows.Controls; 3 | 4 | namespace WpfAppWithAdvTextControl 5 | { 6 | public class TestControl : ContentControl 7 | { 8 | protected override AutomationPeer OnCreateAutomationPeer() 9 | { 10 | return new TestControlAutomationPeer(this); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/TestControlAutomationPeer.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Automation; 2 | using System.Windows.Automation.Peers; 3 | using System.Windows.Automation.Provider; 4 | using ManagedUiaCustomizationCore; 5 | 6 | namespace WpfAppWithAdvTextControl 7 | { 8 | public class TestControlAutomationPeer : FrameworkElementAutomationPeer, 9 | ITestOfMoreThanTwoPatternPropertiesProvider, 10 | IStandalonePropertyProvider, 11 | IAutomationElementRetievingProvider 12 | { 13 | public TestControlAutomationPeer(TestControl testControl) 14 | : base(testControl) 15 | { 16 | TestOfMoreThanTwoPatternPropertiesPattern.Initialize(); 17 | AutomationElementRetievingPattern.Initialize(); 18 | } 19 | 20 | protected override string GetClassNameCore() 21 | { 22 | return "TestControl"; 23 | } 24 | 25 | public override object GetPattern(PatternInterface patternInterface) 26 | { 27 | var patternId = (int)patternInterface; 28 | if (patternId == TestOfMoreThanTwoPatternPropertiesPattern.Pattern || 29 | patternId == AutomationElementRetievingPattern.Pattern.Id) 30 | return this; 31 | return base.GetPattern(patternInterface); 32 | } 33 | 34 | public int Property1 35 | { 36 | get { return 421; } 37 | } 38 | 39 | public int Property2 40 | { 41 | get { return 422; } 42 | } 43 | 44 | public int Property3 45 | { 46 | get { return 423; } 47 | } 48 | 49 | public TestEnum GetEnum() 50 | { 51 | return TestEnum.EnumValue42; 52 | } 53 | 54 | public object GetPropertyValue(AutomationProperty property) 55 | { 56 | if (TestOfMoreThanTwoPatternPropertiesPattern.Standalone1Property.Equals(property)) 57 | return 42; 58 | if (TestOfMoreThanTwoPatternPropertiesPattern.NullStringStandaloneProperty.Equals(property)) 59 | return null; 60 | return null; 61 | } 62 | 63 | public IRawElementProviderSimple NativeElement 64 | { 65 | get { return ProviderFromPeer(this); } 66 | } 67 | 68 | public IRawElementProviderSimple WrappedElement 69 | { 70 | get { return ProviderFromPeer(this); } 71 | } 72 | 73 | public IRawElementProviderSimple NativeGetCurrentElement() 74 | { 75 | return ProviderFromPeer(this); 76 | } 77 | 78 | public IRawElementProviderSimple NativeGetNullElement() 79 | { 80 | return null; 81 | } 82 | 83 | public void NativeGetCurrentElementWithOutParam(out IRawElementProviderSimple value) 84 | { 85 | value = ProviderFromPeer(this); 86 | } 87 | 88 | public IRawElementProviderSimple WrappedGetCurrentElement() 89 | { 90 | return ProviderFromPeer(this); 91 | } 92 | 93 | public IRawElementProviderSimple WrappedGetNullElement() 94 | { 95 | return null; 96 | } 97 | 98 | public void WrappedGetCurrentElementWithOutParam(out IRawElementProviderSimple value) 99 | { 100 | value = ProviderFromPeer(this); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/TestOfMoreThanTwoPatternPropertiesPattern.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using System.Windows.Automation; 3 | using ManagedUiaCustomizationCore; 4 | 5 | namespace WpfAppWithAdvTextControl 6 | { 7 | public enum TestEnum 8 | { 9 | EnumValue0 = 0, 10 | EnumValue42 = 42, 11 | EnumValue513 = 513, 12 | } 13 | 14 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 15 | [ComVisible(true)] 16 | [Guid("D645A984-99C8-4918-8E16-9C16B67EE9AE")] 17 | [PatternGuid("37799443-A693-461D-A84F-F3D4ED00CEF3")] 18 | public interface ITestOfMoreThanTwoPatternPropertiesProvider 19 | { 20 | [PatternProperty("71DAA00F-5179-43C7-B5E2-6F3CF7147356")] 21 | int Property1 { get; } 22 | 23 | [PatternProperty("896296D6-EC78-4E2B-A1B0-F80B6DC633D7")] 24 | int Property2 { get; } 25 | 26 | [PatternProperty("A6DD9558-B635-4C41-AE2F-93D57F68F107")] 27 | int Property3 { get; } 28 | 29 | [PatternMethod] 30 | TestEnum GetEnum(); 31 | } 32 | 33 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 34 | [ComVisible(true)] 35 | [Guid("20260BA6-6A89-4147-B00C-569915822332")] 36 | public interface ITestOfMoreThanTwoPatternPropertiesPattern 37 | { 38 | int CurrentProperty1 { get; } 39 | int CurrentProperty2 { get; } 40 | int CurrentProperty3 { get; } 41 | int CachedProperty1 { get; } 42 | int CachedProperty2 { get; } 43 | int CachedProperty3 { get; } 44 | 45 | TestEnum GetEnum(); 46 | } 47 | 48 | public class TestOfMoreThanTwoPatternPropertiesPattern : CustomPatternBase 49 | { 50 | private TestOfMoreThanTwoPatternPropertiesPattern() 51 | : base(usedInWpf: true) 52 | { 53 | } 54 | 55 | public static void Initialize() 56 | { 57 | if (PatternSchema != null) return; 58 | PatternSchema = new TestOfMoreThanTwoPatternPropertiesPattern(); 59 | } 60 | 61 | public static TestOfMoreThanTwoPatternPropertiesPattern PatternSchema; 62 | public static int Pattern; 63 | public static int Property1Property; 64 | public static int Property2Property; 65 | public static int Property3Property; 66 | 67 | [StandaloneProperty("36683304-3B8A-4035-A88C-B7384C7F057F", typeof(int))] 68 | public static AutomationProperty Standalone1Property; 69 | 70 | [StandaloneProperty("BC40E43E-9CBD-4D94-BF2C-C98727A6BCE1", typeof(string))] 71 | public static AutomationProperty NullStringStandaloneProperty; 72 | } 73 | } -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/WpfAppWithAdvTextControl.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | {B010A379-D2B1-474A-89F8-5A381D99183D} 7 | WinExe 8 | Properties 9 | WpfAppWithAdvTextControl 10 | WpfAppWithAdvTextControl 11 | v4.0 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | 16 | 17 | true 18 | bin\Debug\ 19 | DEBUG;TRACE 20 | full 21 | AnyCPU 22 | prompt 23 | MinimumRecommendedRules.ruleset 24 | false 25 | 26 | 27 | bin\Release\ 28 | TRACE 29 | true 30 | pdbonly 31 | AnyCPU 32 | prompt 33 | MinimumRecommendedRules.ruleset 34 | 35 | 36 | 37 | ..\packages\UIAComWrapper.1.1.0.14\lib\net40\Interop.UIAutomationClient.dll 38 | False 39 | 40 | 41 | ..\UIACoreInterop\Build\Interop.UIAutomationCore.dll 42 | False 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | ..\packages\UIAComWrapper.1.1.0.14\lib\net40\UIAComWrapper.dll 54 | True 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | MSBuild:Compile 64 | Designer 65 | 66 | 67 | MSBuild:Compile 68 | Designer 69 | 70 | 71 | 72 | 73 | App.xaml 74 | Code 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | MainWindow.xaml 85 | Code 86 | 87 | 88 | 89 | 90 | Code 91 | 92 | 93 | True 94 | True 95 | Resources.resx 96 | 97 | 98 | True 99 | Settings.settings 100 | True 101 | 102 | 103 | ResXFileCodeGenerator 104 | Resources.Designer.cs 105 | 106 | 107 | 108 | SettingsSingleFileGenerator 109 | Settings.Designer.cs 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | {21db168c-e0ef-4e07-b24a-1e5bb64d2a17} 119 | ManagedUiaCustomizationCore 120 | 121 | 122 | 123 | 130 | -------------------------------------------------------------------------------- /WpfAppWithAdvTextControl/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /build-and-publish.bat: -------------------------------------------------------------------------------- 1 | choco install nuget.commandline gitlink -y 2 | if errorlevel 1 goto somethingbad 3 | 4 | choco install gitversion.portable -pre -y 5 | if errorlevel 1 goto somethingbad 6 | 7 | rmdir /s /q UIACoreInterop 8 | 9 | call BuildUIACoreInterop.bat 10 | if errorlevel 1 goto somethingbad 11 | 12 | nuget restore UiaCustomPattersManaged.sln 13 | if errorlevel 1 goto somethingbad 14 | 15 | gitversion /l console 16 | if errorlevel 1 goto somethingbad 17 | 18 | for /f %%v in ('gitversion /showvariable NuGetVersion') do set GitVersion_NuGetVersion=%%v 19 | 20 | msbuild UiaCustomPattersManaged.sln "/p:Configuration=Release;Platform=Any CPU" 21 | if errorlevel 1 goto somethingbad 22 | 23 | GitLink . -u https://github.com/TestStack/uia-custom-pattern-managed -c Release -include ManagedUiaCustomizationCore 24 | if errorlevel 1 goto somethingbad 25 | 26 | echo nuget pack UiaCustomPattersManaged.nuspec -version "%GitVersion_NuGetVersion%" 27 | nuget pack UiaCustomPattersManaged.nuspec -version "%GitVersion_NuGetVersion%" -verbosity detailed -basepath . 28 | if errorlevel 1 goto somethingbad 29 | 30 | git tag v%GitVersion_NuGetVersion% 31 | if errorlevel 1 goto somethingbad 32 | 33 | git push --tags 34 | if errorlevel 1 goto somethingbad 35 | 36 | echo Finished successfully 37 | echo(--------------------- 38 | echo Remember to publish created nupkg file and update Changes section in Readme.md 39 | goto end 40 | 41 | :somethingbad 42 | echo Something Bad Happened. 43 | 44 | :end 45 | 46 | pause -------------------------------------------------------------------------------- /install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | $frameworkVersionString = $project.Properties.Item('TargetFrameworkMoniker').Value 4 | $frameworkVersionString -match 'Version=(v\d\.\d)' 5 | $frameworkVersion = $matches[1] 6 | $project.Save(); 7 | 8 | if ($frameworkVersion -ge 'v4.0') 9 | { 10 | $project.Object.References | Where-Object { $_.EmbedInteropTypes -eq $true -and $_.Name -eq "Interop.UIAutomationCore" } | ForEach-Object { $_.EmbedInteropTypes = $false } 11 | } 12 | 13 | $project.Save() -------------------------------------------------------------------------------- /packages/repositories.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | --------------------------------------------------------------------------------