From af0f73de934c9519e37e5fb591cb2c1bf3764af9 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Thu, 31 Oct 2024 11:03:29 +0000 Subject: [PATCH] `[GeneratedComInterface]` based Windows automation (#16543) * Move automation interfaces to the Avalonia.Win32.Automation with DisableRuntimeMarshalling and use [GeneratedComInterface] marshalling * Various fixes for the new windows accessibility * Numerge Avalonia.Win32.Automation into Avalonia.Win32 * Suppress Avalonia.Win32 API warnings, these interfaces never were part of the public API * Fix IRawElementProviderSimple2 definition on legacy COM interop * Some changes after review * More consistent COM method names * Fix folder hierarchy * Rewrite SafeArrayMarshaller to use arrays as managed type * Add ManagedObjectWrapper where's possible * Throw an exception for unsupported SafeArrayRef scenario --------- Co-authored-by: Julien Lebosquain --- Avalonia.sln | 7 + api/Avalonia.Win32.nupkg.xml | 214 +++++++++++ nukebuild/numerge.config | 12 + .../Avalonia/AvaloniaSingleProject.targets | 2 +- .../SafeAreaDemo.Desktop.csproj | 1 - .../Avalonia.Controls.csproj | 1 + .../AutomationNode.ExpandCollapse.cs | 6 +- .../AutomationNode.RangeValue.cs | 17 + .../AutomationNode.Scroll.cs | 30 ++ .../AutomationNode.Selection.cs | 27 +- .../AutomationNode.Toggle.cs | 4 +- .../AutomationNode.Value.cs | 6 +- .../AutomationNode.cs | 47 ++- .../Avalonia.Win32.Automation.csproj | 19 + .../Interop/IDockProvider.cs | 28 ++ .../Interop/IExpandCollapseProvider.cs | 19 + .../Interop/IGridItemProvider.cs | 20 + .../Interop/IGridProvider.cs | 18 + .../Interop/IInvokeProvider.cs | 20 + .../Interop/IMultipleViewProvider.cs | 25 ++ .../Interop/IRangeValueProvider.cs | 25 ++ .../IRawElementProviderAdviseEvents.cs | 28 ++ .../Interop/IRawElementProviderFragment.cs | 39 ++ .../IRawElementProviderFragmentRoot.cs | 17 + .../Interop/IRawElementProviderSimple.cs | 290 +++++++++++++++ .../Interop/IRawElementProviderSimple2.cs | 26 ++ .../Interop/IScrollItemProvider.cs | 16 + .../Interop/IScrollProvider.cs | 28 ++ .../Interop/ISelectionItemProvider.cs | 23 ++ .../Interop/ISelectionProvider.cs | 27 ++ .../Interop/ISynchronizedInputProvider.cs | 27 ++ .../Interop/ITableItemProvider.cs | 25 ++ .../Interop/ITableProvider.cs | 33 ++ .../Interop/ITextProvider.cs | 41 +++ .../Interop/ITextRangeProvider.cs | 79 ++++ .../Interop/IToggleProvider.cs | 18 + .../Interop/ITransformProvider.cs | 27 ++ .../Interop/IValueProvider.cs | 22 ++ .../Interop/IWindowProvider.cs | 52 +++ .../Interop}/UiaCoreProviderApi.cs | 45 ++- .../Interop/UiaCoreTypesApi.cs | 60 +++ .../InteropAutomationNode.cs | 28 +- .../Marshalling/ComVariant.cs | 282 ++++++++++++++ .../Marshalling/ComVariantMarshaller.cs | 16 + .../Marshalling/SafeArrayMarshaller.cs | 21 ++ .../Marshalling/SafeArrayRef.cs | 343 ++++++++++++++++++ .../RootAutomationNode.cs | 37 +- .../Automation/AutomationNode.RangeValue.cs | 17 - .../Automation/AutomationNode.Scroll.cs | 30 -- .../Avalonia.Win32/Avalonia.Win32.csproj | 8 + .../Interop/Automation/IDockProvider.cs | 26 -- .../Automation/IExpandCollapseProvider.cs | 16 - .../Interop/Automation/IGridItemProvider.cs | 17 - .../Interop/Automation/IGridProvider.cs | 14 - .../Interop/Automation/IInvokeProvider.cs | 19 - .../Automation/IMultipleViewProvider.cs | 16 - .../Interop/Automation/IRangeValueProvider.cs | 19 - .../IRawElementProviderAdviseEvents.cs | 15 - .../Automation/IRawElementProviderFragment.cs | 32 -- .../IRawElementProviderFragmentRoot.cs | 13 - .../Automation/IRawElementProviderSimple.cs | 283 --------------- .../Automation/IRawElementProviderSimple2.cs | 11 - .../Interop/Automation/IScrollItemProvider.cs | 13 - .../Interop/Automation/IScrollProvider.cs | 21 -- .../Automation/ISelectionItemProvider.cs | 16 - .../Interop/Automation/ISelectionProvider.cs | 15 - .../Automation/ISynchronizedInputProvider.cs | 26 -- .../Interop/Automation/ITableItemProvider.cs | 14 - .../Interop/Automation/ITableProvider.cs | 24 -- .../Interop/Automation/ITextProvider.cs | 30 -- .../Interop/Automation/ITextRangeProvider.cs | 48 --- .../Interop/Automation/IToggleProvider.cs | 15 - .../Interop/Automation/ITransformProvider.cs | 18 - .../Interop/Automation/IValueProvider.cs | 14 - .../Interop/Automation/IWindowProvider.cs | 42 --- .../Interop/Automation/UiaCoreTypesApi.cs | 79 ---- .../Avalonia.Win32/WindowImpl.AppWndProc.cs | 2 +- 77 files changed, 2134 insertions(+), 977 deletions(-) create mode 100644 api/Avalonia.Win32.nupkg.xml rename src/Windows/{Avalonia.Win32/Automation => Avalonia.Win32.Automation}/AutomationNode.ExpandCollapse.cs (71%) create mode 100644 src/Windows/Avalonia.Win32.Automation/AutomationNode.RangeValue.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/AutomationNode.Scroll.cs rename src/Windows/{Avalonia.Win32/Automation => Avalonia.Win32.Automation}/AutomationNode.Selection.cs (56%) rename src/Windows/{Avalonia.Win32/Automation => Avalonia.Win32.Automation}/AutomationNode.Toggle.cs (59%) rename src/Windows/{Avalonia.Win32/Automation => Avalonia.Win32.Automation}/AutomationNode.Value.cs (59%) rename src/Windows/{Avalonia.Win32/Automation => Avalonia.Win32.Automation}/AutomationNode.cs (92%) create mode 100644 src/Windows/Avalonia.Win32.Automation/Avalonia.Win32.Automation.csproj create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IDockProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IExpandCollapseProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IGridItemProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IGridProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IInvokeProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IMultipleViewProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IRangeValueProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderAdviseEvents.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderFragment.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderFragmentRoot.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple2.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IScrollItemProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IScrollProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/ISelectionItemProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/ISelectionProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/ISynchronizedInputProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/ITableItemProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/ITableProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/ITextProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/ITextRangeProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IToggleProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/ITransformProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IValueProvider.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/IWindowProvider.cs rename src/Windows/{Avalonia.Win32/Interop/Automation => Avalonia.Win32.Automation/Interop}/UiaCoreProviderApi.cs (53%) create mode 100644 src/Windows/Avalonia.Win32.Automation/Interop/UiaCoreTypesApi.cs rename src/Windows/{Avalonia.Win32/Automation => Avalonia.Win32.Automation}/InteropAutomationNode.cs (56%) create mode 100644 src/Windows/Avalonia.Win32.Automation/Marshalling/ComVariant.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Marshalling/ComVariantMarshaller.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayMarshaller.cs create mode 100644 src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayRef.cs rename src/Windows/{Avalonia.Win32/Automation => Avalonia.Win32.Automation}/RootAutomationNode.cs (63%) delete mode 100644 src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs delete mode 100644 src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IDockProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IExpandCollapseProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IGridItemProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IInvokeProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IMultipleViewProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IRangeValueProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderAdviseEvents.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IScrollItemProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IScrollProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/ISelectionProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/ISynchronizedInputProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/ITableItemProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/ITableProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/ITextProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/ITextRangeProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IToggleProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/ITransformProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/IWindowProvider.cs delete mode 100644 src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs diff --git a/Avalonia.sln b/Avalonia.sln index c9958883503..98436f68968 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -301,6 +301,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Vulkan", "src\Aval EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.RenderTests.WpfCompare", "tests\Avalonia.RenderTests.WpfCompare\Avalonia.RenderTests.WpfCompare.csproj", "{9AE1B827-21AC-4063-AB22-C8804B7F931E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32.Automation", "src\Windows\Avalonia.Win32.Automation\Avalonia.Win32.Automation.csproj", "{0097673D-DBCE-476E-82FE-E78A56E58AA2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -701,6 +703,10 @@ Global {9AE1B827-21AC-4063-AB22-C8804B7F931E}.Debug|Any CPU.Build.0 = Debug|Any CPU {9AE1B827-21AC-4063-AB22-C8804B7F931E}.Release|Any CPU.ActiveCfg = Release|Any CPU {9AE1B827-21AC-4063-AB22-C8804B7F931E}.Release|Any CPU.Build.0 = Release|Any CPU + {0097673D-DBCE-476E-82FE-E78A56E58AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0097673D-DBCE-476E-82FE-E78A56E58AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0097673D-DBCE-476E-82FE-E78A56E58AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0097673D-DBCE-476E-82FE-E78A56E58AA2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -788,6 +794,7 @@ Global {D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0} = {9CCA131B-DE95-4D44-8788-C3CAE28574CD} {DA5F1FF9-4259-4C54-B443-85CFA226EE6A} = {9CCA131B-DE95-4D44-8788-C3CAE28574CD} {9AE1B827-21AC-4063-AB22-C8804B7F931E} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {0097673D-DBCE-476E-82FE-E78A56E58AA2} = {B39A8919-9F95-48FE-AD7B-76E08B509888} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} diff --git a/api/Avalonia.Win32.nupkg.xml b/api/Avalonia.Win32.nupkg.xml new file mode 100644 index 00000000000..3ce897dedab --- /dev/null +++ b/api/Avalonia.Win32.nupkg.xml @@ -0,0 +1,214 @@ + + + + + CP0001 + T:Avalonia.Win32.Interop.Automation.DockPosition + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IDockProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IExpandCollapseProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IGridItemProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IGridProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IInvokeProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IMultipleViewProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IRangeValueProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IRawElementProviderAdviseEvents + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IRawElementProviderFragment + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IRawElementProviderFragmentRoot + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IRawElementProviderSimple + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IRawElementProviderSimple2 + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IScrollItemProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IScrollProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.ISelectionItemProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.ISelectionProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.ISynchronizedInputProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.ITableItemProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.ITableProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.ITextProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.ITextRangeProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IToggleProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.ITransformProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IValueProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.IWindowProvider + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.NavigateDirection + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.ProviderOptions + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.RowOrColumnMajor + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.SupportedTextSelection + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.SynchronizedInputType + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.TextPatternRangeEndpoint + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.TextUnit + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.WindowInteractionState + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + + CP0001 + T:Avalonia.Win32.Interop.Automation.WindowVisualState + baseline/netstandard2.0/Avalonia.Win32.dll + target/netstandard2.0/Avalonia.Win32.dll + + \ No newline at end of file diff --git a/nukebuild/numerge.config b/nukebuild/numerge.config index 71b77bee93c..8af0af7ff07 100644 --- a/nukebuild/numerge.config +++ b/nukebuild/numerge.config @@ -23,6 +23,18 @@ "DoNotMergeDependencies": true } ] + }, + { + "Id": "Avalonia.Win32", + "MergeAll": false, + "IncomingIncludeAssetsOverride": "", + "Merge": [ + { + "Id": "Avalonia.Win32.Automation", + "IgnoreMissingFrameworkBinaries": true, + "DoNotMergeDependencies": true + } + ] } ] } diff --git a/packages/Avalonia/AvaloniaSingleProject.targets b/packages/Avalonia/AvaloniaSingleProject.targets index 793f0e36eb1..17b456f1458 100644 --- a/packages/Avalonia/AvaloniaSingleProject.targets +++ b/packages/Avalonia/AvaloniaSingleProject.targets @@ -29,7 +29,7 @@ WinExe - true + true true diff --git a/samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj b/samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj index b3b48afcb95..fe8e9d45067 100644 --- a/samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj +++ b/samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj @@ -3,7 +3,6 @@ WinExe $(AvsCurrentTargetFramework) enable - true diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj index 0021d5bb751..09e94550824 100644 --- a/src/Avalonia.Controls/Avalonia.Controls.csproj +++ b/src/Avalonia.Controls/Avalonia.Controls.csproj @@ -25,6 +25,7 @@ + diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.ExpandCollapse.cs b/src/Windows/Avalonia.Win32.Automation/AutomationNode.ExpandCollapse.cs similarity index 71% rename from src/Windows/Avalonia.Win32/Automation/AutomationNode.ExpandCollapse.cs rename to src/Windows/Avalonia.Win32.Automation/AutomationNode.ExpandCollapse.cs index aaad9cb3ba1..c28d000f564 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.ExpandCollapse.cs +++ b/src/Windows/Avalonia.Win32.Automation/AutomationNode.ExpandCollapse.cs @@ -1,14 +1,14 @@ using Avalonia.Automation; using Avalonia.Automation.Provider; -using UIA = Avalonia.Win32.Interop.Automation; +using UIA = Avalonia.Win32.Automation.Interop; namespace Avalonia.Win32.Automation { internal partial class AutomationNode : UIA.IExpandCollapseProvider { - ExpandCollapseState UIA.IExpandCollapseProvider.ExpandCollapseState + ExpandCollapseState UIA.IExpandCollapseProvider.GetExpandCollapseState() { - get => InvokeSync(x => x.ExpandCollapseState); + return InvokeSync(x => x.ExpandCollapseState); } void UIA.IExpandCollapseProvider.Expand() => InvokeSync(x => x.Expand()); diff --git a/src/Windows/Avalonia.Win32.Automation/AutomationNode.RangeValue.cs b/src/Windows/Avalonia.Win32.Automation/AutomationNode.RangeValue.cs new file mode 100644 index 00000000000..47e80a85a29 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/AutomationNode.RangeValue.cs @@ -0,0 +1,17 @@ +using Avalonia.Automation.Provider; +using UIA = Avalonia.Win32.Automation.Interop; + +namespace Avalonia.Win32.Automation +{ + internal partial class AutomationNode : UIA.IRangeValueProvider + { + double UIA.IRangeValueProvider.GetValue() => InvokeSync(x => x.Value); + bool UIA.IRangeValueProvider.GetIsReadOnly() => InvokeSync(x => x.IsReadOnly); + double UIA.IRangeValueProvider.GetMaximum() => InvokeSync(x => x.Maximum); + double UIA.IRangeValueProvider.GetMinimum() => InvokeSync(x => x.Minimum); + double UIA.IRangeValueProvider.GetLargeChange() => 1; + double UIA.IRangeValueProvider.GetSmallChange() => 1; + + public void SetValue(double value) => InvokeSync(x => x.SetValue(value)); + } +} diff --git a/src/Windows/Avalonia.Win32.Automation/AutomationNode.Scroll.cs b/src/Windows/Avalonia.Win32.Automation/AutomationNode.Scroll.cs new file mode 100644 index 00000000000..3b54c4bdfff --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/AutomationNode.Scroll.cs @@ -0,0 +1,30 @@ +using Avalonia.Automation.Provider; +using UIA = Avalonia.Win32.Automation.Interop; + +namespace Avalonia.Win32.Automation +{ + internal partial class AutomationNode : UIA.IScrollProvider, UIA.IScrollItemProvider + { + bool UIA.IScrollProvider.GetHorizontallyScrollable() => InvokeSync(x => x.HorizontallyScrollable); + double UIA.IScrollProvider.GetHorizontalScrollPercent() => InvokeSync(x => x.HorizontalScrollPercent); + double UIA.IScrollProvider.GetHorizontalViewSize() => InvokeSync(x => x.HorizontalViewSize); + bool UIA.IScrollProvider.GetVerticallyScrollable() => InvokeSync(x => x.VerticallyScrollable); + double UIA.IScrollProvider.GetVerticalScrollPercent() => InvokeSync(x => x.VerticalScrollPercent); + double UIA.IScrollProvider.GetVerticalViewSize() => InvokeSync(x => x.VerticalViewSize); + + void UIA.IScrollProvider.Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount) + { + InvokeSync(x => x.Scroll(horizontalAmount, verticalAmount)); + } + + void UIA.IScrollProvider.SetScrollPercent(double horizontalPercent, double verticalPercent) + { + InvokeSync(x => x.SetScrollPercent(horizontalPercent, verticalPercent)); + } + + void UIA.IScrollItemProvider.ScrollIntoView() + { + InvokeSync(() => Peer.BringIntoView()); + } + } +} diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Selection.cs b/src/Windows/Avalonia.Win32.Automation/AutomationNode.Selection.cs similarity index 56% rename from src/Windows/Avalonia.Win32/Automation/AutomationNode.Selection.cs rename to src/Windows/Avalonia.Win32.Automation/AutomationNode.Selection.cs index 3751bb6476a..0f40bea5b99 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Selection.cs +++ b/src/Windows/Avalonia.Win32.Automation/AutomationNode.Selection.cs @@ -2,23 +2,23 @@ using System.Linq; using Avalonia.Automation.Peers; using Avalonia.Automation.Provider; -using UIA = Avalonia.Win32.Interop.Automation; +using UIA = Avalonia.Win32.Automation.Interop; namespace Avalonia.Win32.Automation { internal partial class AutomationNode : UIA.ISelectionProvider, UIA.ISelectionItemProvider { - bool UIA.ISelectionProvider.CanSelectMultiple => InvokeSync(x => x.CanSelectMultiple); - bool UIA.ISelectionProvider.IsSelectionRequired => InvokeSync(x => x.IsSelectionRequired); - bool UIA.ISelectionItemProvider.IsSelected => InvokeSync(x => x.IsSelected); - - UIA.IRawElementProviderSimple? UIA.ISelectionItemProvider.SelectionContainer + bool UIA.ISelectionProvider.CanSelectMultiple() => InvokeSync(x => x.CanSelectMultiple); + + bool UIA.ISelectionProvider.IsSelectionRequired() => + InvokeSync(x => x.IsSelectionRequired); + + bool UIA.ISelectionItemProvider.GetIsSelected() => InvokeSync(x => x.IsSelected); + + UIA.IRawElementProviderSimple? UIA.ISelectionItemProvider.GetSelectionContainer() { - get - { - var peer = InvokeSync(x => x.SelectionContainer); - return GetOrCreate(peer as AutomationPeer); - } + var peer = InvokeSync(x => x.SelectionContainer); + return GetOrCreate(peer as AutomationPeer); } UIA.IRawElementProviderSimple[] UIA.ISelectionProvider.GetSelection() @@ -28,7 +28,10 @@ UIA.IRawElementProviderSimple[] UIA.ISelectionProvider.GetSelection() } void UIA.ISelectionItemProvider.AddToSelection() => InvokeSync(x => x.AddToSelection()); - void UIA.ISelectionItemProvider.RemoveFromSelection() => InvokeSync(x => x.RemoveFromSelection()); + + void UIA.ISelectionItemProvider.RemoveFromSelection() => + InvokeSync(x => x.RemoveFromSelection()); + void UIA.ISelectionItemProvider.Select() => InvokeSync(x => x.Select()); } } diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Toggle.cs b/src/Windows/Avalonia.Win32.Automation/AutomationNode.Toggle.cs similarity index 59% rename from src/Windows/Avalonia.Win32/Automation/AutomationNode.Toggle.cs rename to src/Windows/Avalonia.Win32.Automation/AutomationNode.Toggle.cs index 08f4b62d838..ef302fec259 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Toggle.cs +++ b/src/Windows/Avalonia.Win32.Automation/AutomationNode.Toggle.cs @@ -1,11 +1,11 @@ using Avalonia.Automation.Provider; -using UIA = Avalonia.Win32.Interop.Automation; +using UIA = Avalonia.Win32.Automation.Interop; namespace Avalonia.Win32.Automation { internal partial class AutomationNode : UIA.IToggleProvider { - ToggleState UIA.IToggleProvider.ToggleState => InvokeSync(x => x.ToggleState); + ToggleState UIA.IToggleProvider.GetToggleState() => InvokeSync(x => x.ToggleState); void UIA.IToggleProvider.Toggle() => InvokeSync(x => x.Toggle()); } } diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Value.cs b/src/Windows/Avalonia.Win32.Automation/AutomationNode.Value.cs similarity index 59% rename from src/Windows/Avalonia.Win32/Automation/AutomationNode.Value.cs rename to src/Windows/Avalonia.Win32.Automation/AutomationNode.Value.cs index 204e1590490..a4fcb03ed94 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Value.cs +++ b/src/Windows/Avalonia.Win32.Automation/AutomationNode.Value.cs @@ -1,13 +1,13 @@ using System.Runtime.InteropServices; using Avalonia.Automation.Provider; -using UIA = Avalonia.Win32.Interop.Automation; +using UIA = Avalonia.Win32.Automation.Interop; namespace Avalonia.Win32.Automation { internal partial class AutomationNode : UIA.IValueProvider { - bool UIA.IValueProvider.IsReadOnly => InvokeSync(x => x.IsReadOnly); - string? UIA.IValueProvider.Value => InvokeSync(x => x.Value); + bool UIA.IValueProvider.GetIsReadOnly() => InvokeSync(x => x.IsReadOnly); + string? UIA.IValueProvider.GetValue() => InvokeSync(x => x.Value); void UIA.IValueProvider.SetValue([MarshalAs(UnmanagedType.LPWStr)] string? value) { diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs b/src/Windows/Avalonia.Win32.Automation/AutomationNode.cs similarity index 92% rename from src/Windows/Avalonia.Win32/Automation/AutomationNode.cs rename to src/Windows/Avalonia.Win32.Automation/AutomationNode.cs index 00b4f179c7a..e3c58c66738 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs +++ b/src/Windows/Avalonia.Win32.Automation/AutomationNode.cs @@ -6,18 +6,26 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; using Avalonia.Automation; using Avalonia.Automation.Peers; using Avalonia.Controls.Automation.Peers; using Avalonia.Threading; -using Avalonia.Win32.Interop.Automation; +using Avalonia.Win32.Automation.Interop; using AAP = Avalonia.Automation.Provider; +using UIA = Avalonia.Win32.Automation.Interop; namespace Avalonia.Win32.Automation { - [ComVisible(true)] +#if NET8_0_OR_GREATER + [GeneratedComClass] + internal partial class AutomationNode : +#else +#if NET6_0_OR_GREATER [RequiresUnreferencedCode("Requires .NET COM interop")] +#endif internal partial class AutomationNode : MarshalByRefObject, +#endif IRawElementProviderSimple, IRawElementProviderSimple2, IRawElementProviderFragment, @@ -44,7 +52,10 @@ internal partial class AutomationNode : MarshalByRefObject, { SelectionPatternIdentifiers.IsSelectionRequiredProperty, UiaPropertyId.SelectionIsSelectionRequired }, { SelectionPatternIdentifiers.SelectionProperty, UiaPropertyId.SelectionSelection }, { SelectionItemPatternIdentifiers.IsSelectedProperty, UiaPropertyId.SelectionItemIsSelected }, - { SelectionItemPatternIdentifiers.SelectionContainerProperty, UiaPropertyId.SelectionItemSelectionContainer } + { + SelectionItemPatternIdentifiers.SelectionContainerProperty, + UiaPropertyId.SelectionItemSelectionContainer + } }; private static ConditionalWeakTable s_nodes = new(); @@ -65,9 +76,9 @@ public AutomationNode(AutomationPeer peer) public AutomationPeer Peer { get; protected set; } - public virtual Rect BoundingRectangle + public virtual Rect GetBoundingRectangle() { - get => InvokeSync(() => + return InvokeSync(() => { if (GetRoot() is RootAutomationNode root) return root.ToScreen(Peer.GetBoundingRectangle()); @@ -75,15 +86,14 @@ public virtual Rect BoundingRectangle }); } - public virtual IRawElementProviderFragmentRoot? FragmentRoot + public virtual IRawElementProviderFragmentRoot? GetFragmentRoot() { - get => InvokeSync(() => GetRoot()); + return InvokeSync(() => GetRoot()); } - public virtual IRawElementProviderSimple? HostRawElementProvider => null; - public virtual ProviderOptions ProviderOptions => ProviderOptions.ServerSideProvider; + public virtual IRawElementProviderSimple? GetHostRawElementProvider() => null; + public virtual ProviderOptions GetProviderOptions() => ProviderOptions.ServerSideProvider; - [return: MarshalAs(UnmanagedType.IUnknown)] public virtual object? GetPatternProvider(int patternId) { AutomationNode? ThisIfPeerImplementsProvider() => Peer.GetProvider() is object ? this : null; @@ -105,13 +115,15 @@ public virtual IRawElementProviderFragmentRoot? FragmentRoot public virtual object? GetPropertyValue(int propertyId) { - return (UiaPropertyId)propertyId switch + object? value = (UiaPropertyId)propertyId switch { UiaPropertyId.AcceleratorKey => InvokeSync(() => Peer.GetAcceleratorKey()), UiaPropertyId.AccessKey => InvokeSync(() => Peer.GetAccessKey()), UiaPropertyId.AutomationId => InvokeSync(() => Peer.GetAutomationId()), UiaPropertyId.ClassName => InvokeSync(() => Peer.GetClassName()), - UiaPropertyId.ClickablePoint => new[] { BoundingRectangle.Center.X, BoundingRectangle.Center.Y }, + UiaPropertyId.ClickablePoint => GetBoundingRectangle() is var rect ? + new[] { rect.Center.X, rect.Center.Y } : + default, UiaPropertyId.ControlType => InvokeSync(() => ToUiaControlType(Peer.GetAutomationControlType())), UiaPropertyId.Culture => CultureInfo.CurrentCulture.LCID, UiaPropertyId.FrameworkId => "Avalonia", @@ -128,9 +140,16 @@ public virtual IRawElementProviderFragmentRoot? FragmentRoot UiaPropertyId.RuntimeId => _runtimeId, _ => null, }; + + if (value?.GetType().IsEnum == true) + { + return Convert.ToInt32(value!); + } + + return value; } - public int[]? GetRuntimeId() => _runtimeId; + public int[] GetRuntimeId() => _runtimeId; public virtual IRawElementProviderFragment? Navigate(NavigateDirection direction) { @@ -167,7 +186,9 @@ public virtual IRawElementProviderFragmentRoot? FragmentRoot public void SetFocus() => InvokeSync(() => Peer.SetFocus()); +#if NET6_0_OR_GREATER [return: NotNullIfNotNull(nameof(peer))] +#endif public static AutomationNode? GetOrCreate(AutomationPeer? peer) { return peer is null ? null : s_nodes.GetValue(peer, Create); diff --git a/src/Windows/Avalonia.Win32.Automation/Avalonia.Win32.Automation.csproj b/src/Windows/Avalonia.Win32.Automation/Avalonia.Win32.Automation.csproj new file mode 100644 index 00000000000..e64233afa5c --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Avalonia.Win32.Automation.csproj @@ -0,0 +1,19 @@ + + + + $(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0 + true + true + + + + + + + + + + + + + diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IDockProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IDockProvider.cs new file mode 100644 index 00000000000..c65e76366a7 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IDockProvider.cs @@ -0,0 +1,28 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +[Guid("70d46e77-e3a8-449d-913c-e30eb2afecdb")] +internal enum DockPosition +{ + Top, + Left, + Bottom, + Right, + Fill, + None +} + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("159bc72c-4ad3-485e-9637-d7052edf0146")] +internal partial interface IDockProvider +{ + void SetDockPosition(DockPosition dockPosition); + DockPosition GetDockPosition(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IExpandCollapseProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IExpandCollapseProvider.cs new file mode 100644 index 00000000000..ee04a24ce7a --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IExpandCollapseProvider.cs @@ -0,0 +1,19 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Avalonia.Automation; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("d847d3a5-cab0-4a98-8c32-ecb45c59ad24")] +internal partial interface IExpandCollapseProvider +{ + void Expand(); + void Collapse(); + ExpandCollapseState GetExpandCollapseState(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IGridItemProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IGridItemProvider.cs new file mode 100644 index 00000000000..f7644274176 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IGridItemProvider.cs @@ -0,0 +1,20 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("d02541f1-fb81-4d64-ae32-f520f8a6dbd1")] +internal partial interface IGridItemProvider +{ + int GetRow(); + int GetColumn(); + int GetRowSpan(); + int GetColumnSpan(); + IRawElementProviderSimple GetContainingGrid(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IGridProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IGridProvider.cs new file mode 100644 index 00000000000..cfc295fa7db --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IGridProvider.cs @@ -0,0 +1,18 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("b17d6187-0907-464b-a168-0ef17a1572b1")] +internal partial interface IGridProvider +{ + IRawElementProviderSimple? GetItem(int row, int column); + int GetRowCount(); + int GetColumnCount(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IInvokeProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IInvokeProvider.cs new file mode 100644 index 00000000000..7737a1bb744 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IInvokeProvider.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("54fcb24b-e18e-47a2-b4d3-eccbe77599a2")] +internal partial interface IInvokeProvider +{ + void Invoke(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IMultipleViewProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IMultipleViewProvider.cs new file mode 100644 index 00000000000..dcd0d35e748 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IMultipleViewProvider.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Avalonia.Win32.Automation.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("6278cab1-b556-4a1a-b4e0-418acc523201")] +internal partial interface IMultipleViewProvider +{ + [return: MarshalAs(UnmanagedType.BStr)] + string GetViewName(int viewId); + void SetCurrentView(int viewId); + int GetCurrentView(); +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + int[] GetSupportedViews(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IRangeValueProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IRangeValueProvider.cs new file mode 100644 index 00000000000..a8f921fa265 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IRangeValueProvider.cs @@ -0,0 +1,25 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("36dc7aef-33e6-4691-afe1-2be7274b3d33")] +internal partial interface IRangeValueProvider +{ + void SetValue(double value); + double GetValue(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool GetIsReadOnly(); + + double GetMaximum(); + double GetMinimum(); + double GetLargeChange(); + double GetSmallChange(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderAdviseEvents.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderAdviseEvents.cs new file mode 100644 index 00000000000..9d2e16ab940 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderAdviseEvents.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Avalonia.Win32.Automation.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("a407b27b-0f6d-4427-9292-473c7bf93258")] +internal partial interface IRawElementProviderAdviseEvents +{ + void AdviseEventAdded(int eventId, +#if NET8_0_OR_GREATER + [MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + int[] properties); + + void AdviseEventRemoved(int eventId, +#if NET8_0_OR_GREATER + [MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + int[] properties); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderFragment.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderFragment.cs new file mode 100644 index 00000000000..0bb56c8b689 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderFragment.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Avalonia.Win32.Automation.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +[Guid("670c3006-bf4c-428b-8534-e1848f645122")] +internal enum NavigateDirection +{ + Parent, + NextSibling, + PreviousSibling, + FirstChild, + LastChild, +} + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("f7063da8-8359-439c-9297-bbc5299a7d87")] +internal partial interface IRawElementProviderFragment +{ + IRawElementProviderFragment? Navigate(NavigateDirection direction); +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + int[]? GetRuntimeId(); + Rect GetBoundingRectangle(); +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + IRawElementProviderSimple[]? GetEmbeddedFragmentRoots(); + void SetFocus(); + IRawElementProviderFragmentRoot? GetFragmentRoot(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderFragmentRoot.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderFragmentRoot.cs new file mode 100644 index 00000000000..349e58b7b34 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderFragmentRoot.cs @@ -0,0 +1,17 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("620ce2a5-ab8f-40a9-86cb-de3c75599b58")] +internal partial interface IRawElementProviderFragmentRoot +{ + IRawElementProviderFragment? ElementProviderFromPoint(double x, double y); + IRawElementProviderFragment? GetFocus(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple.cs new file mode 100644 index 00000000000..c8c5d1ceee2 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple.cs @@ -0,0 +1,290 @@ +using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +[Flags] +internal enum ProviderOptions +{ + ClientSideProvider = 0x0001, + ServerSideProvider = 0x0002, + NonClientAreaProvider = 0x0004, + OverrideProvider = 0x0008, + ProviderOwnsSetFocus = 0x0010, + UseComThreading = 0x0020 +} + +internal enum UiaPropertyId +{ + RuntimeId = 30000, + BoundingRectangle, + ProcessId, + ControlType, + LocalizedControlType, + Name, + AcceleratorKey, + AccessKey, + HasKeyboardFocus, + IsKeyboardFocusable, + IsEnabled, + AutomationId, + ClassName, + HelpText, + ClickablePoint, + Culture, + IsControlElement, + IsContentElement, + LabeledBy, + IsPassword, + NativeWindowHandle, + ItemType, + IsOffscreen, + Orientation, + FrameworkId, + IsRequiredForForm, + ItemStatus, + IsDockPatternAvailable, + IsExpandCollapsePatternAvailable, + IsGridItemPatternAvailable, + IsGridPatternAvailable, + IsInvokePatternAvailable, + IsMultipleViewPatternAvailable, + IsRangeValuePatternAvailable, + IsScrollPatternAvailable, + IsScrollItemPatternAvailable, + IsSelectionItemPatternAvailable, + IsSelectionPatternAvailable, + IsTablePatternAvailable, + IsTableItemPatternAvailable, + IsTextPatternAvailable, + IsTogglePatternAvailable, + IsTransformPatternAvailable, + IsValuePatternAvailable, + IsWindowPatternAvailable, + ValueValue, + ValueIsReadOnly, + RangeValueValue, + RangeValueIsReadOnly, + RangeValueMinimum, + RangeValueMaximum, + RangeValueLargeChange, + RangeValueSmallChange, + ScrollHorizontalScrollPercent, + ScrollHorizontalViewSize, + ScrollVerticalScrollPercent, + ScrollVerticalViewSize, + ScrollHorizontallyScrollable, + ScrollVerticallyScrollable, + SelectionSelection, + SelectionCanSelectMultiple, + SelectionIsSelectionRequired, + GridRowCount, + GridColumnCount, + GridItemRow, + GridItemColumn, + GridItemRowSpan, + GridItemColumnSpan, + GridItemContainingGrid, + DockDockPosition, + ExpandCollapseExpandCollapseState, + MultipleViewCurrentView, + MultipleViewSupportedViews, + WindowCanMaximize, + WindowCanMinimize, + WindowWindowVisualState, + WindowWindowInteractionState, + WindowIsModal, + WindowIsTopmost, + SelectionItemIsSelected, + SelectionItemSelectionContainer, + TableRowHeaders, + TableColumnHeaders, + TableRowOrColumnMajor, + TableItemRowHeaderItems, + TableItemColumnHeaderItems, + ToggleToggleState, + TransformCanMove, + TransformCanResize, + TransformCanRotate, + IsLegacyIAccessiblePatternAvailable, + LegacyIAccessibleChildId, + LegacyIAccessibleName, + LegacyIAccessibleValue, + LegacyIAccessibleDescription, + LegacyIAccessibleRole, + LegacyIAccessibleState, + LegacyIAccessibleHelp, + LegacyIAccessibleKeyboardShortcut, + LegacyIAccessibleSelection, + LegacyIAccessibleDefaultAction, + AriaRole, + AriaProperties, + IsDataValidForForm, + ControllerFor, + DescribedBy, + FlowsTo, + ProviderDescription, + IsItemContainerPatternAvailable, + IsVirtualizedItemPatternAvailable, + IsSynchronizedInputPatternAvailable, + OptimizeForVisualContent, + IsObjectModelPatternAvailable, + AnnotationAnnotationTypeId, + AnnotationAnnotationTypeName, + AnnotationAuthor, + AnnotationDateTime, + AnnotationTarget, + IsAnnotationPatternAvailable, + IsTextPattern2Available, + StylesStyleId, + StylesStyleName, + StylesFillColor, + StylesFillPatternStyle, + StylesShape, + StylesFillPatternColor, + StylesExtendedProperties, + IsStylesPatternAvailable, + IsSpreadsheetPatternAvailable, + SpreadsheetItemFormula, + SpreadsheetItemAnnotationObjects, + SpreadsheetItemAnnotationTypes, + IsSpreadsheetItemPatternAvailable, + Transform2CanZoom, + IsTransformPattern2Available, + LiveSetting, + IsTextChildPatternAvailable, + IsDragPatternAvailable, + DragIsGrabbed, + DragDropEffect, + DragDropEffects, + IsDropTargetPatternAvailable, + DropTargetDropTargetEffect, + DropTargetDropTargetEffects, + DragGrabbedItems, + Transform2ZoomLevel, + Transform2ZoomMinimum, + Transform2ZoomMaximum, + FlowsFrom, + IsTextEditPatternAvailable, + IsPeripheral, + IsCustomNavigationPatternAvailable, + PositionInSet, + SizeOfSet, + Level, + AnnotationTypes, + AnnotationObjects, + LandmarkType, + LocalizedLandmarkType, + FullDescription, + FillColor, + OutlineColor, + FillType, + VisualEffects, + OutlineThickness, + CenterPoint, + Rotatation, + Size +} + +internal enum UiaPatternId +{ + Invoke = 10000, + Selection, + Value, + RangeValue, + Scroll, + ExpandCollapse, + Grid, + GridItem, + MultipleView, + Window, + SelectionItem, + Dock, + Table, + TableItem, + Text, + Toggle, + Transform, + ScrollItem, + LegacyIAccessible, + ItemContainer, + VirtualizedItem, + SynchronizedInput, + ObjectModel, + Annotation, + Text2, + Styles, + Spreadsheet, + SpreadsheetItem, + Transform2, + TextChild, + Drag, + DropTarget, + TextEdit, + CustomNavigation +}; + +internal enum UiaControlTypeId +{ + Button = 50000, + Calendar, + CheckBox, + ComboBox, + Edit, + Hyperlink, + Image, + ListItem, + List, + Menu, + MenuBar, + MenuItem, + ProgressBar, + RadioButton, + ScrollBar, + Slider, + Spinner, + StatusBar, + Tab, + TabItem, + Text, + ToolBar, + ToolTip, + Tree, + TreeItem, + Custom, + Group, + Thumb, + DataGrid, + DataItem, + Document, + SplitButton, + Window, + Pane, + Header, + HeaderItem, + Table, + TitleBar, + Separator, + SemanticZoom, + AppBar +}; + +#if NET8_0_OR_GREATER +[GeneratedComInterface] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("d6dd68d1-86fd-4332-8666-9abedea2d24c")] +internal partial interface IRawElementProviderSimple +{ + ProviderOptions GetProviderOptions(); + [return: MarshalAs(UnmanagedType.Interface)] + object? GetPatternProvider(int patternId); +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(ComVariantMarshaller))] +#endif + object? GetPropertyValue(int propertyId); + IRawElementProviderSimple? GetHostRawElementProvider(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple2.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple2.cs new file mode 100644 index 00000000000..7bd48f4e78e --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple2.cs @@ -0,0 +1,26 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("a0a839a9-8da1-4a82-806a-8e0d44e79f56")] +internal partial interface IRawElementProviderSimple2 : IRawElementProviderSimple +{ +#if !NET8_0_OR_GREATER + // Hack for the legacy COM interop + // See https://learn.microsoft.com/en-us/dotnet/standard/native-interop/comwrappers-source-generation#derived-interfaces + new ProviderOptions GetProviderOptions(); + [return: MarshalAs(UnmanagedType.Interface)] + new object? GetPatternProvider(int patternId); + [return: MarshalAs(UnmanagedType.Struct)] + new object? GetPropertyValue(int propertyId); + new IRawElementProviderSimple? GetHostRawElementProvider(); +#endif + void ShowContextMenu(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IScrollItemProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IScrollItemProvider.cs new file mode 100644 index 00000000000..8e022c988d6 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IScrollItemProvider.cs @@ -0,0 +1,16 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("2360c714-4bf1-4b26-ba65-9b21316127eb")] +internal partial interface IScrollItemProvider +{ + void ScrollIntoView(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IScrollProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IScrollProvider.cs new file mode 100644 index 00000000000..1113685592f --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IScrollProvider.cs @@ -0,0 +1,28 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Avalonia.Automation.Provider; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("b38b8077-1fc3-42a5-8cae-d40c2215055a")] +internal partial interface IScrollProvider +{ + void Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount); + void SetScrollPercent(double horizontalPercent, double verticalPercent); + double GetHorizontalScrollPercent(); + double GetVerticalScrollPercent(); + double GetHorizontalViewSize(); + double GetVerticalViewSize(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool GetHorizontallyScrollable(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool GetVerticallyScrollable(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/ISelectionItemProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/ISelectionItemProvider.cs new file mode 100644 index 00000000000..a4f4d56e542 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/ISelectionItemProvider.cs @@ -0,0 +1,23 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("2acad808-b2d4-452d-a407-91ff1ad167b2")] +internal partial interface ISelectionItemProvider +{ + void Select(); + void AddToSelection(); + void RemoveFromSelection(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool GetIsSelected(); + + IRawElementProviderSimple? GetSelectionContainer(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/ISelectionProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/ISelectionProvider.cs new file mode 100644 index 00000000000..2a30c97f188 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/ISelectionProvider.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Avalonia.Win32.Automation.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("fb8b03af-3bdf-48d4-bd36-1a65793be168")] +internal partial interface ISelectionProvider +{ +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + IRawElementProviderSimple[] GetSelection(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool CanSelectMultiple(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool IsSelectionRequired(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/ISynchronizedInputProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/ISynchronizedInputProvider.cs new file mode 100644 index 00000000000..75850461c37 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/ISynchronizedInputProvider.cs @@ -0,0 +1,27 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +[Guid("fdc8f176-aed2-477a-8c89-5604c66f278d")] +internal enum SynchronizedInputType +{ + KeyUp = 0x01, + KeyDown = 0x02, + MouseLeftButtonUp = 0x04, + MouseLeftButtonDown = 0x08, + MouseRightButtonUp = 0x10, + MouseRightButtonDown = 0x20 +} +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("29db1a06-02ce-4cf7-9b42-565d4fab20ee")] +internal partial interface ISynchronizedInputProvider +{ + void StartListening(SynchronizedInputType inputType); + void Cancel(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/ITableItemProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/ITableItemProvider.cs new file mode 100644 index 00000000000..75bdf48bb87 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/ITableItemProvider.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Avalonia.Win32.Automation.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("b9734fa6-771f-4d78-9c90-2517999349cd")] +internal partial interface ITableItemProvider +{ +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + IRawElementProviderSimple[] GetRowHeaderItems(); +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + IRawElementProviderSimple[] GetColumnHeaderItems(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/ITableProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/ITableProvider.cs new file mode 100644 index 00000000000..6acacbdf5d8 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/ITableProvider.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Avalonia.Win32.Automation.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +[Guid("15fdf2e2-9847-41cd-95dd-510612a025ea")] +internal enum RowOrColumnMajor +{ + RowMajor, + ColumnMajor, + Indeterminate, +} +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("9c860395-97b3-490a-b52a-858cc22af166")] +internal partial interface ITableProvider +{ +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + IRawElementProviderSimple[] GetRowHeaders(); +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + IRawElementProviderSimple[] GetColumnHeaders(); + RowOrColumnMajor GetRowOrColumnMajor(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/ITextProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/ITextProvider.cs new file mode 100644 index 00000000000..63a92ce547d --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/ITextProvider.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Avalonia.Win32.Automation.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +[Flags] +[Guid("3d9e3d8f-bfb0-484f-84ab-93ff4280cbc4")] +internal enum SupportedTextSelection +{ + None, + Single, + Multiple, +} + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("3589c92c-63f3-4367-99bb-ada653b77cf2")] +internal partial interface ITextProvider +{ +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + ITextRangeProvider[] GetSelection(); +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + ITextRangeProvider[] GetVisibleRanges(); + ITextRangeProvider RangeFromChild(IRawElementProviderSimple childElement); + + ITextRangeProvider RangeFromPoint(double X, double Y); + + ITextRangeProvider GetDocumentRange(); + SupportedTextSelection GetSupportedTextSelection(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/ITextRangeProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/ITextRangeProvider.cs new file mode 100644 index 00000000000..18f167a87aa --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/ITextRangeProvider.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Avalonia.Win32.Automation.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +internal enum TextPatternRangeEndpoint +{ + Start = 0, + End = 1, +} + +internal enum TextUnit +{ + Character = 0, + Format = 1, + Word = 2, + Line = 3, + Paragraph = 4, + Page = 5, + Document = 6, +} + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("5347ad7b-c355-46f8-aff5-909033582f63")] +internal partial interface ITextRangeProvider +{ + ITextRangeProvider Clone(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool Compare(ITextRangeProvider range); + + int CompareEndpoints(TextPatternRangeEndpoint endpoint, ITextRangeProvider targetRange, + TextPatternRangeEndpoint targetEndpoint); + + void ExpandToEnclosingUnit(TextUnit unit); + + ITextRangeProvider FindAttribute(int attribute, +#if NET8_0_OR_GREATER + [MarshalUsing(typeof(ComVariantMarshaller))] +#endif + object value, [MarshalAs(UnmanagedType.Bool)] bool backward); + + ITextRangeProvider FindText( + [MarshalAs(UnmanagedType.BStr)] string text, + [MarshalAs(UnmanagedType.Bool)] bool backward, + [MarshalAs(UnmanagedType.Bool)] bool ignoreCase); +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(ComVariantMarshaller))] +#endif + object GetAttributeValue(int attribute); +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + double[] GetBoundingRectangles(); + IRawElementProviderSimple GetEnclosingElement(); + [return: MarshalAs(UnmanagedType.BStr)] + string GetText(int maxLength); + int Move(TextUnit unit, int count); + int MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, TextUnit unit, int count); + + void MoveEndpointByRange(TextPatternRangeEndpoint endpoint, ITextRangeProvider targetRange, + TextPatternRangeEndpoint targetEndpoint); + + void Select(); + void AddToSelection(); + void RemoveFromSelection(); + void ScrollIntoView([MarshalAs(UnmanagedType.Bool)] bool alignToTop); +#if NET8_0_OR_GREATER + [return: MarshalUsing(typeof(SafeArrayMarshaller))] +#endif + IRawElementProviderSimple[] GetChildren(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IToggleProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IToggleProvider.cs new file mode 100644 index 00000000000..85dd3c0f977 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IToggleProvider.cs @@ -0,0 +1,18 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Avalonia.Automation.Provider; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("56d00bd0-c4f4-433c-a836-1a52a57e0892")] +internal partial interface IToggleProvider +{ + void Toggle(); + ToggleState GetToggleState(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/ITransformProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/ITransformProvider.cs new file mode 100644 index 00000000000..baabaf36640 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/ITransformProvider.cs @@ -0,0 +1,27 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("6829ddc4-4f91-4ffa-b86f-bd3e2987cb4c")] +internal partial interface ITransformProvider +{ + void Move(double x, double y); + void Resize(double width, double height); + void Rotate(double degrees); + + [return: MarshalAs(UnmanagedType.Bool)] + bool GetCanMove(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool GetCanResize(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool GetCanRotate(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IValueProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IValueProvider.cs new file mode 100644 index 00000000000..6d7526c0549 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IValueProvider.cs @@ -0,0 +1,22 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("c7935180-6fb3-4201-b174-7df73adbf64a")] +internal partial interface IValueProvider +{ + void SetValue([MarshalAs(UnmanagedType.LPWStr)] string? value); + + [return: MarshalAs(UnmanagedType.BStr)] + string? GetValue(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool GetIsReadOnly(); +} diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/IWindowProvider.cs b/src/Windows/Avalonia.Win32.Automation/Interop/IWindowProvider.cs new file mode 100644 index 00000000000..65cec9a1f51 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/IWindowProvider.cs @@ -0,0 +1,52 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Interop; + +[Guid("fdc8f176-aed2-477a-8c89-ea04cc5f278d")] +internal enum WindowVisualState +{ + Normal, + Maximized, + Minimized +} + +[Guid("65101cc7-7904-408e-87a7-8c6dbd83a18b")] +internal enum WindowInteractionState +{ + Running, + Closing, + ReadyForUserInteraction, + BlockedByModalWindow, + NotResponding +} +#if NET8_0_OR_GREATER +[GeneratedComInterface(Options = ComInterfaceOptions.ManagedObjectWrapper)] +#else +[ComImport()] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +#endif +[Guid("987df77b-db06-4d77-8f8a-86a9c3bb90b9")] +internal partial interface IWindowProvider +{ + void SetVisualState(WindowVisualState state); + void Close(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool WaitForInputIdle(int milliseconds); + + [return: MarshalAs(UnmanagedType.Bool)] + bool GetMaximizable(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool GetMinimizable(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool GetIsModal(); + + WindowVisualState GetVisualState(); + WindowInteractionState GetInteractionState(); + + [return: MarshalAs(UnmanagedType.Bool)] + bool GetIsTopmost(); +} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreProviderApi.cs b/src/Windows/Avalonia.Win32.Automation/Interop/UiaCoreProviderApi.cs similarity index 53% rename from src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreProviderApi.cs rename to src/Windows/Avalonia.Win32.Automation/Interop/UiaCoreProviderApi.cs index bd939c56b70..36e69028464 100644 --- a/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreProviderApi.cs +++ b/src/Windows/Avalonia.Win32.Automation/Interop/UiaCoreProviderApi.cs @@ -1,9 +1,9 @@ using System; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; -namespace Avalonia.Win32.Interop.Automation +namespace Avalonia.Win32.Automation.Interop { - [ComVisible(true)] [Guid("d8e55844-7043-4edc-979d-593cc6b4775e")] internal enum AsyncContentLoadedState { @@ -12,7 +12,6 @@ internal enum AsyncContentLoadedState Completed, } - [ComVisible(true)] [Guid("e4cfef41-071d-472c-a65c-c14f59ea81eb")] internal enum StructureChangeType { @@ -63,29 +62,57 @@ internal enum UiaEventId Changes }; - internal static class UiaCoreProviderApi + internal static partial class UiaCoreProviderApi { public const int UIA_E_ELEMENTNOTENABLED = unchecked((int)0x80040200); +#if NET7_0_OR_GREATER + [LibraryImport("UIAutomationCore.dll", StringMarshalling = StringMarshalling.Utf8)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool UiaClientsAreListening(); + + [LibraryImport("UIAutomationCore.dll", StringMarshalling = StringMarshalling.Utf8)] + public static partial IntPtr UiaReturnRawElementProvider(IntPtr hwnd, IntPtr wParam, IntPtr lParam, IRawElementProviderSimple? el); + + [LibraryImport("UIAutomationCore.dll", StringMarshalling = StringMarshalling.Utf8)] + public static partial int UiaHostProviderFromHwnd(IntPtr hwnd, [MarshalAs(UnmanagedType.Interface)] out IRawElementProviderSimple provider); + + [LibraryImport("UIAutomationCore.dll", StringMarshalling = StringMarshalling.Utf8)] + public static partial int UiaRaiseAutomationEvent(IRawElementProviderSimple? provider, int id); + + [LibraryImport("UIAutomationCore.dll", StringMarshalling = StringMarshalling.Utf8)] + public static partial int UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple? provider, int id, [MarshalUsing(typeof(ComVariantMarshaller))] object? oldValue, [MarshalUsing(typeof(ComVariantMarshaller))] object? newValue); + + [LibraryImport("UIAutomationCore.dll", StringMarshalling = StringMarshalling.Utf8)] + public static partial int UiaRaiseStructureChangedEvent(IRawElementProviderSimple? provider, StructureChangeType structureChangeType, int[]? runtimeId, int runtimeIdLen); + + [LibraryImport("UIAutomationCore.dll", StringMarshalling = StringMarshalling.Utf8)] + public static partial int UiaDisconnectProvider(IRawElementProviderSimple? provider); +#else [DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)] public static extern bool UiaClientsAreListening(); - + [DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)] - public static extern IntPtr UiaReturnRawElementProvider(IntPtr hwnd, IntPtr wParam, IntPtr lParam, IRawElementProviderSimple? el); + public static extern IntPtr UiaReturnRawElementProvider(IntPtr hwnd, IntPtr wParam, IntPtr lParam, + IRawElementProviderSimple? el); [DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)] - public static extern int UiaHostProviderFromHwnd(IntPtr hwnd, [MarshalAs(UnmanagedType.Interface)] out IRawElementProviderSimple provider); + public static extern int UiaHostProviderFromHwnd(IntPtr hwnd, + [MarshalAs(UnmanagedType.Interface)] out IRawElementProviderSimple provider); [DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)] public static extern int UiaRaiseAutomationEvent(IRawElementProviderSimple? provider, int id); [DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)] - public static extern int UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple? provider, int id, object? oldValue, object? newValue); + public static extern int UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple? provider, int id, + object? oldValue, object? newValue); [DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)] - public static extern int UiaRaiseStructureChangedEvent(IRawElementProviderSimple? provider, StructureChangeType structureChangeType, int[]? runtimeId, int runtimeIdLen); + public static extern int UiaRaiseStructureChangedEvent(IRawElementProviderSimple? provider, + StructureChangeType structureChangeType, int[]? runtimeId, int runtimeIdLen); [DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)] public static extern int UiaDisconnectProvider(IRawElementProviderSimple? provider); +#endif } } diff --git a/src/Windows/Avalonia.Win32.Automation/Interop/UiaCoreTypesApi.cs b/src/Windows/Avalonia.Win32.Automation/Interop/UiaCoreTypesApi.cs new file mode 100644 index 00000000000..a8a83dfd578 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Interop/UiaCoreTypesApi.cs @@ -0,0 +1,60 @@ +using System; +using System.Runtime.InteropServices; + +// Just to keep "netstandard2.0" build happy +namespace System.Runtime.InteropServices.Marshalling +{ +} + +namespace Avalonia.Win32.Automation.Interop +{ + internal static partial class UiaCoreTypesApi + { + internal enum AutomationIdType + { + Property, + Pattern, + Event, + ControlType, + TextAttribute + } + + internal const int UIA_E_ELEMENTNOTENABLED = unchecked((int)0x80040200); + internal const int UIA_E_ELEMENTNOTAVAILABLE = unchecked((int)0x80040201); + internal const int UIA_E_NOCLICKABLEPOINT = unchecked((int)0x80040202); + internal const int UIA_E_PROXYASSEMBLYNOTLOADED = unchecked((int)0x80040203); + + internal static bool IsNetComInteropAvailable + { + get + { +#if NET8_0_OR_GREATER + return true; +#else +#if NET6_0_OR_GREATER + if (!System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported) + { + return false; + } +#endif + var comConfig = + AppContext.GetData("System.Runtime.InteropServices.BuiltInComInterop.IsSupported") as string; + return comConfig == null || bool.Parse(comConfig); +#endif + } + } + + internal static int UiaLookupId(AutomationIdType type, ref Guid guid) + { + return RawUiaLookupId(type, ref guid); + } + +#if NET7_0_OR_GREATER + [LibraryImport("UIAutomationCore.dll", EntryPoint = "UiaLookupId", StringMarshalling = StringMarshalling.Utf8)] + private static partial int RawUiaLookupId(AutomationIdType type, ref Guid guid); +#else + [DllImport("UIAutomationCore.dll", EntryPoint = "UiaLookupId", CharSet = CharSet.Unicode)] + private static extern int RawUiaLookupId(AutomationIdType type, ref Guid guid); +#endif + } +} diff --git a/src/Windows/Avalonia.Win32/Automation/InteropAutomationNode.cs b/src/Windows/Avalonia.Win32.Automation/InteropAutomationNode.cs similarity index 56% rename from src/Windows/Avalonia.Win32/Automation/InteropAutomationNode.cs rename to src/Windows/Avalonia.Win32.Automation/InteropAutomationNode.cs index 9ef8b79cfe1..d6f698513c5 100644 --- a/src/Windows/Avalonia.Win32/Automation/InteropAutomationNode.cs +++ b/src/Windows/Avalonia.Win32.Automation/InteropAutomationNode.cs @@ -1,16 +1,21 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; using Avalonia.Controls.Automation.Peers; -using Avalonia.Win32.Interop.Automation; +using Avalonia.Win32.Automation.Interop; namespace Avalonia.Win32.Automation; /// /// An automation node which serves as the root of an embedded native control automation tree. /// -[RequiresUnreferencedCode("Requires .NET COM interop")] -internal class InteropAutomationNode : AutomationNode, IRawElementProviderFragmentRoot +#if NET8_0_OR_GREATER + [GeneratedComClass] +#elif NET6_0_OR_GREATER + [RequiresUnreferencedCode("Requires .NET COM interop")] +#endif +internal partial class InteropAutomationNode : AutomationNode, IRawElementProviderFragmentRoot { private readonly IntPtr _handle; @@ -20,21 +25,18 @@ public InteropAutomationNode(InteropAutomationPeer peer) _handle = peer.NativeControlHandle.Handle; } - public override Rect BoundingRectangle => default; - public override IRawElementProviderFragmentRoot? FragmentRoot => null; - public override ProviderOptions ProviderOptions => ProviderOptions.ServerSideProvider | ProviderOptions.OverrideProvider; + public override Rect GetBoundingRectangle() => default; + public override IRawElementProviderFragmentRoot? GetFragmentRoot() => null; + public override ProviderOptions GetProviderOptions() => ProviderOptions.ServerSideProvider | ProviderOptions.OverrideProvider; public override object? GetPatternProvider(int patternId) => null; public override object? GetPropertyValue(int propertyId) => null; - public override IRawElementProviderSimple? HostRawElementProvider + public override IRawElementProviderSimple? GetHostRawElementProvider() { - get - { - var hr = UiaCoreProviderApi.UiaHostProviderFromHwnd(_handle, out var result); - Marshal.ThrowExceptionForHR(hr); - return result; - } + var hr = UiaCoreProviderApi.UiaHostProviderFromHwnd(_handle, out var result); + Marshal.ThrowExceptionForHR(hr); + return result; } public override IRawElementProviderFragment? Navigate(NavigateDirection direction) diff --git a/src/Windows/Avalonia.Win32.Automation/Marshalling/ComVariant.cs b/src/Windows/Avalonia.Win32.Automation/Marshalling/ComVariant.cs new file mode 100644 index 00000000000..d5da462f8c9 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Marshalling/ComVariant.cs @@ -0,0 +1,282 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Avalonia.Win32.Automation.Marshalling; + +#if NET7_0_OR_GREATER +// Oversimplified ComVariant implementation based on https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ComVariant.cs +// Available +[StructLayout(LayoutKind.Explicit)] +internal struct ComVariant : IDisposable +{ + // VARIANT_BOOL constants. + internal const short VARIANT_TRUE = -1; + internal const short VARIANT_FALSE = 0; + + // Most of the data types in the Variant are carried in _typeUnion + [FieldOffset(0)] private TypeUnion _typeUnion; + + [StructLayout(LayoutKind.Sequential)] + private struct TypeUnion + { + public ushort _vt; + public ushort _wReserved1; + public ushort _wReserved2; + public ushort _wReserved3; + + public UnionTypes _unionTypes; + } + + [StructLayout(LayoutKind.Explicit)] + private unsafe struct UnionTypes + { + [FieldOffset(0)] public sbyte _i1; + [FieldOffset(0)] public short _i2; + [FieldOffset(0)] public int _i4; + [FieldOffset(0)] public long _i8; + [FieldOffset(0)] public byte _ui1; + [FieldOffset(0)] public ushort _ui2; + [FieldOffset(0)] public uint _ui4; + [FieldOffset(0)] public ulong _ui8; + [FieldOffset(0)] public int _int; + [FieldOffset(0)] public uint _uint; + [FieldOffset(0)] public short _bool; + [FieldOffset(0)] public int _error; + [FieldOffset(0)] public float _r4; + [FieldOffset(0)] public double _r8; + [FieldOffset(0)] public long _cy; + [FieldOffset(0)] public double _date; + [FieldOffset(0)] public IntPtr _bstr; + [FieldOffset(0)] public IntPtr _unknown; + [FieldOffset(0)] public IntPtr _dispatch; + [FieldOffset(0)] public IntPtr _pvarVal; + [FieldOffset(0)] public IntPtr _byref; + [FieldOffset(0)] public SafeArrayRef parray; + [FieldOffset(0)] public SafeArrayRef*pparray; + } + + /// + /// Release resources owned by this instance. + /// + public void Dispose() + { + // Re-implement the same clearing semantics as PropVariantClear manually for non-Windows platforms. + if (VarType == VarEnum.VT_BSTR) + { + Marshal.FreeBSTR(_typeUnion._unionTypes._bstr); + } + else if (VarType.HasFlag(VarEnum.VT_ARRAY)) + { + _typeUnion._unionTypes.parray.Destroy(); + } + else if (VarType == VarEnum.VT_UNKNOWN || VarType == VarEnum.VT_DISPATCH) + { + if (_typeUnion._unionTypes._unknown != IntPtr.Zero) + { + Marshal.Release(_typeUnion._unionTypes._unknown); + } + } + else if (VarType == VarEnum.VT_LPSTR || VarType == VarEnum.VT_LPWSTR || VarType == VarEnum.VT_CLSID) + { + Marshal.FreeCoTaskMem(_typeUnion._unionTypes._byref); + } + else if (VarType == VarEnum.VT_STREAM || VarType == VarEnum.VT_STREAMED_OBJECT || + VarType == VarEnum.VT_STORAGE || VarType == VarEnum.VT_STORED_OBJECT) + { + if (_typeUnion._unionTypes._unknown != IntPtr.Zero) + { + Marshal.Release(_typeUnion._unionTypes._unknown); + } + } + + // Clear out this ComVariant instance. + this = default; + } + + /// + /// Create an instance from the specified value. + /// + /// The value to wrap in an . + /// An that contains the provided value. + public static unsafe ComVariant Create(object? value) + { + if (value is null) return Null; + + Unsafe.SkipInit(out ComVariant variant); + + if (value.GetType().IsEnum) + { + var underlyingType = Enum.GetUnderlyingType(value.GetType()); + value = Convert.ChangeType(value, underlyingType); + } + + if (value is short) + { + variant.VarType = VarEnum.VT_I2; + variant._typeUnion._unionTypes._i2 = (short)value; + } + else if (value is int) + { + variant.VarType = VarEnum.VT_I4; + variant._typeUnion._unionTypes._i4 = (int)value; + } + else if (value is float) + { + variant.VarType = VarEnum.VT_R4; + variant._typeUnion._unionTypes._r4 = (float)value; + } + else if (value is double) + { + variant.VarType = VarEnum.VT_R8; + variant._typeUnion._unionTypes._r8 = (double)value; + } + else if (value is DateTime) + { + variant.VarType = VarEnum.VT_DATE; + variant._typeUnion._unionTypes._date = ((DateTime)value).ToOADate(); + } + else if (value is string) + { + variant.VarType = VarEnum.VT_BSTR; + variant._typeUnion._unionTypes._bstr = Marshal.StringToBSTR((string)value); + } + else if (value is bool) + { + // bool values in OLE VARIANTs are VARIANT_BOOL values. + variant.VarType = VarEnum.VT_BOOL; + variant._typeUnion._unionTypes._bool = ((bool)value) ? VARIANT_TRUE : VARIANT_FALSE; + } + else if (value is sbyte) + { + variant.VarType = VarEnum.VT_I1; + variant._typeUnion._unionTypes._i1 = (sbyte)value; + } + else if (value is byte) + { + variant.VarType = VarEnum.VT_UI1; + variant._typeUnion._unionTypes._ui1 = (byte)value; + } + else if (value is ushort) + { + variant.VarType = VarEnum.VT_UI2; + variant._typeUnion._unionTypes._ui2 = (ushort)value; + } + else if (value is uint) + { + variant.VarType = VarEnum.VT_UI4; + variant._typeUnion._unionTypes._ui4 = (uint)value; + } + else if (value is long) + { + variant.VarType = VarEnum.VT_I8; + variant._typeUnion._unionTypes._i8 = (long)value; + } + else if (value is ulong) + { + variant.VarType = VarEnum.VT_UI8; + variant._typeUnion._unionTypes._ui8 = (ulong)value; + } + else if (value is IEnumerable list && SafeArrayRef.TryCreate(list, out var array, out var arrayEnum)) + { + variant.VarType = arrayEnum | VarEnum.VT_ARRAY; + variant._typeUnion._unionTypes.parray = array.Value; + } + else if (ComWrappers.TryGetComInstance(value, out var unknown)) + { + variant.VarType = VarEnum.VT_UNKNOWN; + variant._typeUnion._unionTypes._unknown = unknown; + } + else + { + throw new ArgumentException("UnsupportedType", value.GetType().Name); + } + + return variant; + } + + /// + /// A instance that represents a null value with type. + /// + public static ComVariant Null { get; } = new() { VarType = VarEnum.VT_NULL }; + + /// + /// Create a managed value based on the value in the instance. + /// + /// The managed value contained in this variant. + public readonly unsafe object? AsObject() + { + if (VarType == VarEnum.VT_EMPTY) + { + return null; + } + + return VarType switch + { + VarEnum.VT_NULL => null, + // integer + VarEnum.VT_I1 => _typeUnion._unionTypes._i1, + VarEnum.VT_I2 => _typeUnion._unionTypes._i2, + VarEnum.VT_I4 => _typeUnion._unionTypes._i4, + VarEnum.VT_I8 => _typeUnion._unionTypes._i8, + VarEnum.VT_INT => _typeUnion._unionTypes._i4, + VarEnum.VT_ERROR => _typeUnion._unionTypes._i4, + // unsigned integer + VarEnum.VT_UI1 => _typeUnion._unionTypes._ui1, + VarEnum.VT_UI2 => _typeUnion._unionTypes._ui2, + VarEnum.VT_UI4 => _typeUnion._unionTypes._ui4, + VarEnum.VT_UI8 => _typeUnion._unionTypes._ui8, + VarEnum.VT_UINT => _typeUnion._unionTypes._ui4, + // floating + VarEnum.VT_R4 => _typeUnion._unionTypes._r4, + VarEnum.VT_R8 => _typeUnion._unionTypes._r8, + // date + VarEnum.VT_DATE => DateTime.FromOADate(_typeUnion._unionTypes._date), + // string + VarEnum.VT_BSTR => Marshal.PtrToStringBSTR(_typeUnion._unionTypes._bstr), + // bool + VarEnum.VT_BOOL => _typeUnion._unionTypes._bool != VARIANT_FALSE, + // unknown + VarEnum.VT_UNKNOWN => ComWrappers.TryGetObject(_typeUnion._unionTypes._unknown, out var obj) ? obj : null, + // array + { } varEnum when varEnum.HasFlag(VarEnum.VT_ARRAY) => (varEnum ^ VarEnum.VT_ARRAY) switch + { + // integer + VarEnum.VT_I1 => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + VarEnum.VT_I2 => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + VarEnum.VT_I4 => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + VarEnum.VT_I8 => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + VarEnum.VT_INT => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + // unsigned integer + VarEnum.VT_UI1 => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + VarEnum.VT_UI2 => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + VarEnum.VT_UI4 => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + VarEnum.VT_UI8 => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + VarEnum.VT_UINT => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + // floating + VarEnum.VT_R4 => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + VarEnum.VT_R8 => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + // string + VarEnum.VT_BSTR => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + // variant + VarEnum.VT_UNKNOWN => SafeArrayRef.ToArray(_typeUnion._unionTypes.parray), + _ => throw new ArgumentException($"Unknown variant type: {varEnum}") + }, + _ => throw new ArgumentException($"Unknown variant type: {VarType}") + }; + } + + /// + /// The type of the data stored in this . + /// + public VarEnum VarType + { + readonly get => (VarEnum)_typeUnion._vt; + private set => _typeUnion._vt = (ushort)value; + } +} +#endif diff --git a/src/Windows/Avalonia.Win32.Automation/Marshalling/ComVariantMarshaller.cs b/src/Windows/Avalonia.Win32.Automation/Marshalling/ComVariantMarshaller.cs new file mode 100644 index 00000000000..02ae8eca284 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Marshalling/ComVariantMarshaller.cs @@ -0,0 +1,16 @@ +#if NET7_0_OR_GREATER +global using ComVariantMarshaller = Avalonia.Win32.Automation.Marshalling.ComVariantMarshaller; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Marshalling; + +[CustomMarshaller(typeof(object), MarshalMode.Default, typeof(ComVariantMarshaller))] +internal static class ComVariantMarshaller +{ + public static ComVariant ConvertToUnmanaged(object? managed) => ComVariant.Create(managed); + + public static object? ConvertToManaged(ComVariant unmanaged) => unmanaged.AsObject(); + + public static void Free(ComVariant unmanaged) => unmanaged.Dispose(); +} +#endif diff --git a/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayMarshaller.cs b/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayMarshaller.cs new file mode 100644 index 00000000000..fe7fe549767 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayMarshaller.cs @@ -0,0 +1,21 @@ +#if NET7_0_OR_GREATER +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices.Marshalling; + +namespace Avalonia.Win32.Automation.Marshalling; + +[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.Default, typeof(SafeArrayMarshaller<>))] +internal static class SafeArrayMarshaller where T : notnull +{ + public static SafeArrayRef ConvertToUnmanaged(T[]? managed) => + managed is null ? new SafeArrayRef() + : SafeArrayRef.TryCreate(managed, out var result, out _) ? result.Value + : throw new NotImplementedException($"SafeArray marshalling for '{managed?.GetType().Name}' is not implemented."); + + public static T[]? ConvertToManaged(SafeArrayRef unmanaged) => SafeArrayRef.ToArray(unmanaged); + + public static void Free(SafeArrayRef unmanaged) => unmanaged.Destroy(); +} +#endif diff --git a/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayRef.cs b/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayRef.cs new file mode 100644 index 00000000000..14158c4ee30 --- /dev/null +++ b/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayRef.cs @@ -0,0 +1,343 @@ +using System; +using System.Buffers; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Avalonia.Controls.Documents; +// ReSharper disable InconsistentNaming + +namespace Avalonia.Win32.Automation.Marshalling; + +#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value +#if NET7_0_OR_GREATER +internal unsafe partial struct SafeArrayRef +{ + private SAFEARRAY* _ptr; + + internal struct SAFEARRAY + { + /// The number of dimensions. + internal ushort cDims; + + /// + /// Flags. + /// This doc was truncated. + /// Read more on docs.microsoft.com. + /// + internal ADVANCED_FEATURE_FLAGS fFeatures; + + /// The size of an array element. + internal uint cbElements; + + /// The number of times the array has been locked without a corresponding unlock. + internal uint cLocks; + + /// The data. + internal void* pvData; + + /// One bound for each dimension. + internal VariableLengthInlineArray rgsabound; + } + internal struct SAFEARRAYBOUND + { + /// The number of elements in the dimension. + internal uint cElements; + + /// The lower bound of the dimension. + internal int lLbound; + } + + internal struct VariableLengthInlineArray + where T : unmanaged + { + internal T e0; + + internal ref T this[int index] + { + [UnscopedRef] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref Unsafe.Add(ref this.e0, index); + } + + [UnscopedRef] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Span AsSpan(int length) + { + return MemoryMarshal.CreateSpan(ref this.e0, length); + } + } + + [Flags] + internal enum ADVANCED_FEATURE_FLAGS : ushort + { + FADF_AUTO = 0x0001, + FADF_STATIC = 0x0002, + FADF_EMBEDDED = 0x0004, + FADF_FIXEDSIZE = 0x0010, + FADF_RECORD = 0x0020, + FADF_HAVEIID = 0x0040, + FADF_HAVEVARTYPE = 0x0080, + FADF_BSTR = 0x0100, + FADF_UNKNOWN = 0x0200, + FADF_DISPATCH = 0x0400, + FADF_VARIANT = 0x0800, + FADF_RESERVED = 0xF008, + } + + public void Destroy() + { + if (_ptr != default) + { + SafeArrayDestroy(_ptr); + } + } + + public static T[]? ToArray(SafeArrayRef? safearray) + { + if (safearray is null) return null; + + return AccessData(safearray.Value, static (data, length) => + { + var array = new T[length]; + if (typeof(T) == typeof(sbyte)) + Marshal.Copy(data, (byte[])(object)array, 0, length); + else if (typeof(T) == typeof(short)) + Marshal.Copy(data, (short[])(object)array, 0, length); + else if (typeof(T) == typeof(int)) + Marshal.Copy(data, (int[])(object)array, 0, length); + else if (typeof(T) == typeof(long)) + Marshal.Copy(data, (long[])(object)array, 0, length); + else if (typeof(T) == typeof(byte)) + Marshal.Copy(data, (byte[])(object)array, 0, length); + else if (typeof(T) == typeof(ushort)) + Marshal.Copy(data, (short[])(object)array, 0, length); + else if (typeof(T) == typeof(uint)) + Marshal.Copy(data, (int[])(object)array, 0, length); + else if (typeof(T) == typeof(ulong)) + Marshal.Copy(data, (long[])(object)array, 0, length); + else if (typeof(T) == typeof(float)) + Marshal.Copy(data, (float[])(object)array, 0, length); + else if (typeof(T) == typeof(double)) + Marshal.Copy(data, (double[])(object)array, 0, length); + else if (typeof(T) == typeof(nint)) + Marshal.Copy(data, (nint[])(object)array, 0, length); + else if (typeof(T) == typeof(nuint)) + Marshal.Copy(data, (nint[])(object)array, 0, length); + else if (typeof(T) == typeof(string)) + { + var pointers = new IntPtr[length]; + Marshal.Copy(data, pointers, 0, array.Length); + for (var i = 0; i < length; i++) + { + array[i] = (T)(object)Marshal.PtrToStringBSTR(pointers[i]); + } + } + else if (typeof(T).IsInterface) + { + var pointers = new IntPtr[length]; + Marshal.Copy(data, pointers, 0, array.Length); + for (int i = 0; i < pointers.Length; i++) + { + if (ComWrappers.TryGetObject(pointers[i], out var instance)) + { + array[i] = (T)instance; + } + else + { + throw new NotImplementedException("COM items not owned by managed code can't be unwrapped from SafeArray."); + } + } + } + else + { + throw new NotImplementedException(); + } + + return array; + }); + } + + public static bool TryCreate(IEnumerable? managed, [NotNullWhen(true)] out SafeArrayRef? safearray, out VarEnum varEnum) + { + safearray = default; + varEnum = default; + + if (managed is null) + { + return false; + } + + static SafeArrayRef CreateFromCollection(IReadOnlyCollection collection, VarEnum varEnum) + { + var collectionSpan = collection switch + { + T[] array => array, + List list => CollectionsMarshal.AsSpan(list), + _ => collection.ToArray() + }; + return CreateFromSpan(collectionSpan, varEnum); + } + + static SafeArrayRef CreateFromSpan(ReadOnlySpan span, VarEnum varEnum) + { + var bound = new SAFEARRAYBOUND { cElements = (uint)span.Length, lLbound = 0 }; + var safearray = SafeArrayCreate(varEnum, 1, bound); + if (span.Length == 0) + { + return new SafeArrayRef + { + _ptr = safearray + }; + } + + var lockResult = SafeArrayLock(safearray); + if (lockResult != 0) throw new Win32Exception(lockResult); + + try + { + // We assume it has the same length. + var output = new Span(safearray->pvData, (int)safearray->rgsabound[0].cElements); + span.CopyTo(output); + } + finally + { + SafeArrayUnlock(safearray); + } + + return new SafeArrayRef + { + _ptr = safearray + }; + } + + static SafeArrayRef CreateFromStrings(IReadOnlyList strings, VarEnum varEnum) + { + Debug.Assert(varEnum == VarEnum.VT_BSTR); // other types not supported yet + var pointers = ArrayPool.Shared.Rent(strings.Count); + try + { + for (int i = 0; i < strings.Count; i++) + { + pointers[i] = Marshal.StringToBSTR(strings[i]); + } + + return CreateFromSpan(pointers.AsSpan(0, strings.Count), varEnum); + } + finally + { + ArrayPool.Shared.Return(pointers); + } + } + + static SafeArrayRef CreateFromBools(IReadOnlyList bools, VarEnum varEnum) + { + Debug.Assert(varEnum == VarEnum.VT_BOOL); // other types not supported + var shorts = ArrayPool.Shared.Rent(bools.Count); + try + { + for (int i = 0; i < bools.Count; i++) + { + shorts[i] = bools[i] ? ComVariant.VARIANT_TRUE : ComVariant.VARIANT_FALSE; + } + + return CreateFromSpan(shorts.AsSpan(0, bools.Count), varEnum); + } + finally + { + ArrayPool.Shared.Return(shorts); + } + } + + static SafeArrayRef CreateFromObjects(IReadOnlyList objects, VarEnum varEnum) + { + Debug.Assert(varEnum == VarEnum.VT_UNKNOWN); // other types not supported yet + var pointers = ArrayPool.Shared.Rent(objects.Count); + try + { + for (int i = 0; i < objects.Count; i++) + { + if (ComWrappers.TryGetComInstance(objects[i], out var pointer)) + { + pointers[i] = pointer; + } + } + + return CreateFromSpan(pointers, varEnum); + } + finally + { + ArrayPool.Shared.Return(pointers); + } + } + + safearray = managed switch + { + IReadOnlyCollection ints => CreateFromCollection(ints, varEnum = VarEnum.VT_I1), + IReadOnlyCollection ints => CreateFromCollection(ints, varEnum = VarEnum.VT_I2), + IReadOnlyCollection ints => CreateFromCollection(ints, varEnum = VarEnum.VT_I4), + IReadOnlyCollection ints => CreateFromCollection(ints, varEnum = VarEnum.VT_I8), + + IReadOnlyCollection ints => CreateFromCollection(ints, varEnum = VarEnum.VT_UI1), + IReadOnlyCollection ints => CreateFromCollection(ints, varEnum = VarEnum.VT_UI2), + IReadOnlyCollection ints => CreateFromCollection(ints, varEnum = VarEnum.VT_UI4), + IReadOnlyCollection ints => CreateFromCollection(ints, varEnum = VarEnum.VT_UI8), + + IReadOnlyCollection ints => CreateFromCollection(ints, varEnum = VarEnum.VT_R4), + IReadOnlyCollection ints => CreateFromCollection(ints, varEnum = VarEnum.VT_R8), + + IReadOnlyCollection ints => CreateFromCollection(ints, varEnum = VarEnum.VT_INT), + IReadOnlyCollection ints => CreateFromCollection(ints, varEnum = VarEnum.VT_UINT), + + IReadOnlyList bools => CreateFromBools(bools, varEnum = VarEnum.VT_BOOL), + + IReadOnlyList strings => CreateFromStrings(strings, varEnum = VarEnum.VT_BSTR), + + IReadOnlyList objects => CreateFromObjects(objects, varEnum = VarEnum.VT_UNKNOWN), + + _ => null + }; + + return safearray is not null; + } + + [LibraryImport("oleaut32.dll")] + private static unsafe partial SAFEARRAY* SafeArrayCreate(VarEnum vt, uint cDims, in SAFEARRAYBOUND rgsabound); + + [LibraryImport("oleaut32.dll")] + private static unsafe partial void SafeArrayDestroy(SAFEARRAY* array); + + [LibraryImport("oleaut32.dll")] + [PreserveSig] + private static unsafe partial int SafeArrayLock(SAFEARRAY* array); + + [LibraryImport("oleaut32.dll")] + private static unsafe partial void SafeArrayUnlock(SAFEARRAY* array); + + private static TRes AccessData(SafeArrayRef safearray, Func accessor) + { + var lockResult = SafeArrayLock(safearray._ptr); + if (lockResult != 0) + { + throw new Win32Exception(lockResult); + } + + Debug.Assert(safearray._ptr->cDims == 1); + + try + { + var data = safearray._ptr->pvData; + var length= safearray._ptr->rgsabound[0].cElements; + return accessor(new IntPtr(data), (int)length); + } + finally + { + SafeArrayUnlock(safearray._ptr); + } + } +} +#endif diff --git a/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs b/src/Windows/Avalonia.Win32.Automation/RootAutomationNode.cs similarity index 63% rename from src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs rename to src/Windows/Avalonia.Win32.Automation/RootAutomationNode.cs index 8824a0a7207..e2f81fdb11e 100644 --- a/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs +++ b/src/Windows/Avalonia.Win32.Automation/RootAutomationNode.cs @@ -1,15 +1,23 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; using Avalonia.Automation.Peers; using Avalonia.Automation.Provider; using Avalonia.Platform; -using Avalonia.Win32.Interop.Automation; +using Avalonia.Win32.Automation.Interop; namespace Avalonia.Win32.Automation { +#if NET8_0_OR_GREATER + [GeneratedComClass] + internal partial class RootAutomationNode : AutomationNode, IRawElementProviderFragmentRoot +#else +#if NET6_0_OR_GREATER [RequiresUnreferencedCode("Requires .NET COM interop")] - internal class RootAutomationNode : AutomationNode, IRawElementProviderFragmentRoot +#endif + internal partial class RootAutomationNode : AutomationNode, IRawElementProviderFragmentRoot +#endif { public RootAutomationNode(AutomationPeer peer) : base(peer) @@ -19,7 +27,7 @@ public RootAutomationNode(AutomationPeer peer) Peer.FocusChanged += OnRootFocusChanged; } - public override IRawElementProviderFragmentRoot? FragmentRoot => this; + public override IRawElementProviderFragmentRoot? GetFragmentRoot() => this; public new IRootProvider Peer { get; } public IWindowBaseImpl? WindowImpl => Peer.PlatformImpl as IWindowBaseImpl; @@ -45,22 +53,19 @@ public Rect ToScreen(Rect rect) if (WindowImpl is null) return default; return new PixelRect( - WindowImpl.PointToScreen(rect.TopLeft), - WindowImpl.PointToScreen(rect.BottomRight)) - .ToRect(1); + WindowImpl.PointToScreen(rect.TopLeft), + WindowImpl.PointToScreen(rect.BottomRight)) + .ToRect(1); } - public override IRawElementProviderSimple? HostRawElementProvider + public override IRawElementProviderSimple? GetHostRawElementProvider() { - get - { - var handle = WindowImpl?.Handle?.Handle ?? IntPtr.Zero; - if (handle == IntPtr.Zero) - return null; - var hr = UiaCoreProviderApi.UiaHostProviderFromHwnd(handle, out var result); - Marshal.ThrowExceptionForHR(hr); - return result; - } + var handle = WindowImpl?.Handle?.Handle ?? IntPtr.Zero; + if (handle == IntPtr.Zero) + return null; + var hr = UiaCoreProviderApi.UiaHostProviderFromHwnd(handle, out var result); + Marshal.ThrowExceptionForHR(hr); + return result; } private void OnRootFocusChanged(object? sender, EventArgs e) diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs deleted file mode 100644 index 518c945aa9d..00000000000 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Avalonia.Automation.Provider; -using UIA = Avalonia.Win32.Interop.Automation; - -namespace Avalonia.Win32.Automation -{ - internal partial class AutomationNode : UIA.IRangeValueProvider - { - double UIA.IRangeValueProvider.Value => InvokeSync(x => x.Value); - bool UIA.IRangeValueProvider.IsReadOnly => InvokeSync(x => x.IsReadOnly); - double UIA.IRangeValueProvider.Maximum => InvokeSync(x => x.Maximum); - double UIA.IRangeValueProvider.Minimum => InvokeSync(x => x.Minimum); - double UIA.IRangeValueProvider.LargeChange => 1; - double UIA.IRangeValueProvider.SmallChange => 1; - - public void SetValue(double value) => InvokeSync(x => x.SetValue(value)); - } -} diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs deleted file mode 100644 index 0248a8d6a72..00000000000 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Avalonia.Automation.Provider; -using UIA = Avalonia.Win32.Interop.Automation; - -namespace Avalonia.Win32.Automation -{ - internal partial class AutomationNode : UIA.IScrollProvider, UIA.IScrollItemProvider - { - bool UIA.IScrollProvider.HorizontallyScrollable => InvokeSync(x => x.HorizontallyScrollable); - double UIA.IScrollProvider.HorizontalScrollPercent => InvokeSync(x => x.HorizontalScrollPercent); - double UIA.IScrollProvider.HorizontalViewSize => InvokeSync(x => x.HorizontalViewSize); - bool UIA.IScrollProvider.VerticallyScrollable => InvokeSync(x => x.VerticallyScrollable); - double UIA.IScrollProvider.VerticalScrollPercent => InvokeSync(x => x.VerticalScrollPercent); - double UIA.IScrollProvider.VerticalViewSize => InvokeSync(x => x.VerticalViewSize); - - void UIA.IScrollProvider.Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount) - { - InvokeSync(x => x.Scroll(horizontalAmount, verticalAmount)); - } - - void UIA.IScrollProvider.SetScrollPercent(double horizontalPercent, double verticalPercent) - { - InvokeSync(x => x.SetScrollPercent(horizontalPercent, verticalPercent)); - } - - void UIA.IScrollItemProvider.ScrollIntoView() - { - InvokeSync(() => Peer.BringIntoView()); - } - } -} diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj index c299bcba4ef..e26a4cd69f2 100644 --- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj +++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj @@ -24,6 +24,7 @@ + @@ -39,4 +40,11 @@ + + + + + + + diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IDockProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IDockProvider.cs deleted file mode 100644 index 2787434d266..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IDockProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("70d46e77-e3a8-449d-913c-e30eb2afecdb")] - public enum DockPosition - { - Top, - Left, - Bottom, - Right, - Fill, - None - } - - [ComVisible(true)] - [Guid("159bc72c-4ad3-485e-9637-d7052edf0146")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IDockProvider - { - void SetDockPosition(DockPosition dockPosition); - DockPosition DockPosition { get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IExpandCollapseProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IExpandCollapseProvider.cs deleted file mode 100644 index 67be1e6c717..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IExpandCollapseProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using Avalonia.Automation; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("d847d3a5-cab0-4a98-8c32-ecb45c59ad24")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IExpandCollapseProvider - { - void Expand(); - void Collapse(); - ExpandCollapseState ExpandCollapseState { get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IGridItemProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IGridItemProvider.cs deleted file mode 100644 index f911c384722..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IGridItemProvider.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("d02541f1-fb81-4d64-ae32-f520f8a6dbd1")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IGridItemProvider - { - int Row { get; } - int Column { get; } - int RowSpan { get; } - int ColumnSpan { get; } - IRawElementProviderSimple ContainingGrid { get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs deleted file mode 100644 index be8b998a9ec..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("b17d6187-0907-464b-a168-0ef17a1572b1")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IGridProvider - { - IRawElementProviderSimple? GetItem(int row, int column); - int RowCount { get; } - int ColumnCount { get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IInvokeProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IInvokeProvider.cs deleted file mode 100644 index f35646d4561..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IInvokeProvider.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// Description: Invoke pattern provider interface - -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("54fcb24b-e18e-47a2-b4d3-eccbe77599a2")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IInvokeProvider - { - void Invoke(); - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IMultipleViewProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IMultipleViewProvider.cs deleted file mode 100644 index c487a0f5df0..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IMultipleViewProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("6278cab1-b556-4a1a-b4e0-418acc523201")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IMultipleViewProvider - { - string GetViewName(int viewId); - void SetCurrentView(int viewId); - int CurrentView { get; } - int[] GetSupportedViews(); - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRangeValueProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRangeValueProvider.cs deleted file mode 100644 index 558f38a2cc6..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IRangeValueProvider.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("36dc7aef-33e6-4691-afe1-2be7274b3d33")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IRangeValueProvider - { - void SetValue(double value); - double Value { get; } - bool IsReadOnly { [return: MarshalAs(UnmanagedType.Bool)] get; } - double Maximum { get; } - double Minimum { get; } - double LargeChange { get; } - double SmallChange { get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderAdviseEvents.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderAdviseEvents.cs deleted file mode 100644 index 1e799e05a22..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderAdviseEvents.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Runtime.InteropServices; - - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("a407b27b-0f6d-4427-9292-473c7bf93258")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IRawElementProviderAdviseEvents : IRawElementProviderSimple - { - void AdviseEventAdded(int eventId, int [] properties); - void AdviseEventRemoved(int eventId, int [] properties); - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs deleted file mode 100644 index 46d8dc6cdb5..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("670c3006-bf4c-428b-8534-e1848f645122")] - public enum NavigateDirection - { - Parent, - NextSibling, - PreviousSibling, - FirstChild, - LastChild, - } - - // NOTE: This interface needs to be public otherwise Navigate is never called. I have no idea - // why given that IRawElementProviderSimple and IRawElementProviderFragmentRoot seem to get - // called fine when they're internal, but I lost a couple of days to this. - [ComVisible(true)] - [Guid("f7063da8-8359-439c-9297-bbc5299a7d87")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IRawElementProviderFragment : IRawElementProviderSimple - { - IRawElementProviderFragment? Navigate(NavigateDirection direction); - int[]? GetRuntimeId(); - Rect BoundingRectangle { get; } - IRawElementProviderSimple[]? GetEmbeddedFragmentRoots(); - void SetFocus(); - IRawElementProviderFragmentRoot? FragmentRoot { get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs deleted file mode 100644 index 1fd0cb13baf..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("620ce2a5-ab8f-40a9-86cb-de3c75599b58")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IRawElementProviderFragmentRoot : IRawElementProviderFragment - { - IRawElementProviderFragment? ElementProviderFromPoint(double x, double y); - IRawElementProviderFragment? GetFocus(); - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs deleted file mode 100644 index 5b67d10206b..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs +++ /dev/null @@ -1,283 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [Flags] - public enum ProviderOptions - { - ClientSideProvider = 0x0001, - ServerSideProvider = 0x0002, - NonClientAreaProvider = 0x0004, - OverrideProvider = 0x0008, - ProviderOwnsSetFocus = 0x0010, - UseComThreading = 0x0020 - } - - internal enum UiaPropertyId - { - RuntimeId = 30000, - BoundingRectangle, - ProcessId, - ControlType, - LocalizedControlType, - Name, - AcceleratorKey, - AccessKey, - HasKeyboardFocus, - IsKeyboardFocusable, - IsEnabled, - AutomationId, - ClassName, - HelpText, - ClickablePoint, - Culture, - IsControlElement, - IsContentElement, - LabeledBy, - IsPassword, - NativeWindowHandle, - ItemType, - IsOffscreen, - Orientation, - FrameworkId, - IsRequiredForForm, - ItemStatus, - IsDockPatternAvailable, - IsExpandCollapsePatternAvailable, - IsGridItemPatternAvailable, - IsGridPatternAvailable, - IsInvokePatternAvailable, - IsMultipleViewPatternAvailable, - IsRangeValuePatternAvailable, - IsScrollPatternAvailable, - IsScrollItemPatternAvailable, - IsSelectionItemPatternAvailable, - IsSelectionPatternAvailable, - IsTablePatternAvailable, - IsTableItemPatternAvailable, - IsTextPatternAvailable, - IsTogglePatternAvailable, - IsTransformPatternAvailable, - IsValuePatternAvailable, - IsWindowPatternAvailable, - ValueValue, - ValueIsReadOnly, - RangeValueValue, - RangeValueIsReadOnly, - RangeValueMinimum, - RangeValueMaximum, - RangeValueLargeChange, - RangeValueSmallChange, - ScrollHorizontalScrollPercent, - ScrollHorizontalViewSize, - ScrollVerticalScrollPercent, - ScrollVerticalViewSize, - ScrollHorizontallyScrollable, - ScrollVerticallyScrollable, - SelectionSelection, - SelectionCanSelectMultiple, - SelectionIsSelectionRequired, - GridRowCount, - GridColumnCount, - GridItemRow, - GridItemColumn, - GridItemRowSpan, - GridItemColumnSpan, - GridItemContainingGrid, - DockDockPosition, - ExpandCollapseExpandCollapseState, - MultipleViewCurrentView, - MultipleViewSupportedViews, - WindowCanMaximize, - WindowCanMinimize, - WindowWindowVisualState, - WindowWindowInteractionState, - WindowIsModal, - WindowIsTopmost, - SelectionItemIsSelected, - SelectionItemSelectionContainer, - TableRowHeaders, - TableColumnHeaders, - TableRowOrColumnMajor, - TableItemRowHeaderItems, - TableItemColumnHeaderItems, - ToggleToggleState, - TransformCanMove, - TransformCanResize, - TransformCanRotate, - IsLegacyIAccessiblePatternAvailable, - LegacyIAccessibleChildId, - LegacyIAccessibleName, - LegacyIAccessibleValue, - LegacyIAccessibleDescription, - LegacyIAccessibleRole, - LegacyIAccessibleState, - LegacyIAccessibleHelp, - LegacyIAccessibleKeyboardShortcut, - LegacyIAccessibleSelection, - LegacyIAccessibleDefaultAction, - AriaRole, - AriaProperties, - IsDataValidForForm, - ControllerFor, - DescribedBy, - FlowsTo, - ProviderDescription, - IsItemContainerPatternAvailable, - IsVirtualizedItemPatternAvailable, - IsSynchronizedInputPatternAvailable, - OptimizeForVisualContent, - IsObjectModelPatternAvailable, - AnnotationAnnotationTypeId, - AnnotationAnnotationTypeName, - AnnotationAuthor, - AnnotationDateTime, - AnnotationTarget, - IsAnnotationPatternAvailable, - IsTextPattern2Available, - StylesStyleId, - StylesStyleName, - StylesFillColor, - StylesFillPatternStyle, - StylesShape, - StylesFillPatternColor, - StylesExtendedProperties, - IsStylesPatternAvailable, - IsSpreadsheetPatternAvailable, - SpreadsheetItemFormula, - SpreadsheetItemAnnotationObjects, - SpreadsheetItemAnnotationTypes, - IsSpreadsheetItemPatternAvailable, - Transform2CanZoom, - IsTransformPattern2Available, - LiveSetting, - IsTextChildPatternAvailable, - IsDragPatternAvailable, - DragIsGrabbed, - DragDropEffect, - DragDropEffects, - IsDropTargetPatternAvailable, - DropTargetDropTargetEffect, - DropTargetDropTargetEffects, - DragGrabbedItems, - Transform2ZoomLevel, - Transform2ZoomMinimum, - Transform2ZoomMaximum, - FlowsFrom, - IsTextEditPatternAvailable, - IsPeripheral, - IsCustomNavigationPatternAvailable, - PositionInSet, - SizeOfSet, - Level, - AnnotationTypes, - AnnotationObjects, - LandmarkType, - LocalizedLandmarkType, - FullDescription, - FillColor, - OutlineColor, - FillType, - VisualEffects, - OutlineThickness, - CenterPoint, - Rotatation, - Size - } - - internal enum UiaPatternId - { - Invoke = 10000, - Selection, - Value, - RangeValue, - Scroll, - ExpandCollapse, - Grid, - GridItem, - MultipleView, - Window, - SelectionItem, - Dock, - Table, - TableItem, - Text, - Toggle, - Transform, - ScrollItem, - LegacyIAccessible, - ItemContainer, - VirtualizedItem, - SynchronizedInput, - ObjectModel, - Annotation, - Text2, - Styles, - Spreadsheet, - SpreadsheetItem, - Transform2, - TextChild, - Drag, - DropTarget, - TextEdit, - CustomNavigation - }; - - internal enum UiaControlTypeId - { - Button = 50000, - Calendar, - CheckBox, - ComboBox, - Edit, - Hyperlink, - Image, - ListItem, - List, - Menu, - MenuBar, - MenuItem, - ProgressBar, - RadioButton, - ScrollBar, - Slider, - Spinner, - StatusBar, - Tab, - TabItem, - Text, - ToolBar, - ToolTip, - Tree, - TreeItem, - Custom, - Group, - Thumb, - DataGrid, - DataItem, - Document, - SplitButton, - Window, - Pane, - Header, - HeaderItem, - Table, - TitleBar, - Separator, - SemanticZoom, - AppBar - }; - - [ComVisible(true)] - [Guid("d6dd68d1-86fd-4332-8666-9abedea2d24c")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IRawElementProviderSimple - { - ProviderOptions ProviderOptions { get; } - [return: MarshalAs(UnmanagedType.IUnknown)] - object? GetPatternProvider(int patternId); - object? GetPropertyValue(int propertyId); - IRawElementProviderSimple? HostRawElementProvider { get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs deleted file mode 100644 index c2e8a42f87a..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("a0a839a9-8da1-4a82-806a-8e0d44e79f56")] - public interface IRawElementProviderSimple2 - { - void ShowContextMenu(); - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IScrollItemProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IScrollItemProvider.cs deleted file mode 100644 index c34c8667ef8..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IScrollItemProvider.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("2360c714-4bf1-4b26-ba65-9b21316127eb")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IScrollItemProvider - { - void ScrollIntoView(); - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IScrollProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IScrollProvider.cs deleted file mode 100644 index 154d52c6af6..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IScrollProvider.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using Avalonia.Automation.Provider; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("b38b8077-1fc3-42a5-8cae-d40c2215055a")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IScrollProvider - { - void Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount); - void SetScrollPercent(double horizontalPercent, double verticalPercent); - double HorizontalScrollPercent { get; } - double VerticalScrollPercent { get; } - double HorizontalViewSize { get; } - double VerticalViewSize { get; } - bool HorizontallyScrollable { [return: MarshalAs(UnmanagedType.Bool)] get; } - bool VerticallyScrollable { [return: MarshalAs(UnmanagedType.Bool)] get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs deleted file mode 100644 index 072e210027c..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("2acad808-b2d4-452d-a407-91ff1ad167b2")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ISelectionItemProvider - { - void Select(); - void AddToSelection(); - void RemoveFromSelection(); - bool IsSelected { [return: MarshalAs(UnmanagedType.Bool)] get; } - IRawElementProviderSimple? SelectionContainer { get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionProvider.cs deleted file mode 100644 index 8a5924126dc..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionProvider.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("fb8b03af-3bdf-48d4-bd36-1a65793be168")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ISelectionProvider - { - IRawElementProviderSimple [] GetSelection(); - bool CanSelectMultiple { [return: MarshalAs(UnmanagedType.Bool)] get; } - bool IsSelectionRequired { [return: MarshalAs(UnmanagedType.Bool)] get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/ISynchronizedInputProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/ISynchronizedInputProvider.cs deleted file mode 100644 index def1bbd4b96..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/ISynchronizedInputProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("fdc8f176-aed2-477a-8c89-5604c66f278d")] - public enum SynchronizedInputType - { - KeyUp = 0x01, - KeyDown = 0x02, - MouseLeftButtonUp = 0x04, - MouseLeftButtonDown = 0x08, - MouseRightButtonUp = 0x10, - MouseRightButtonDown = 0x20 - } - - [ComVisible(true)] - [Guid("29db1a06-02ce-4cf7-9b42-565d4fab20ee")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ISynchronizedInputProvider - { - void StartListening(SynchronizedInputType inputType); - void Cancel(); - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/ITableItemProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/ITableItemProvider.cs deleted file mode 100644 index 36751122d14..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/ITableItemProvider.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("b9734fa6-771f-4d78-9c90-2517999349cd")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ITableItemProvider : IGridItemProvider - { - IRawElementProviderSimple [] GetRowHeaderItems(); - IRawElementProviderSimple [] GetColumnHeaderItems(); - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/ITableProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/ITableProvider.cs deleted file mode 100644 index e82bda3272c..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/ITableProvider.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("15fdf2e2-9847-41cd-95dd-510612a025ea")] - public enum RowOrColumnMajor - { - RowMajor, - ColumnMajor, - Indeterminate, - } - - [ComVisible(true)] - [Guid("9c860395-97b3-490a-b52a-858cc22af166")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ITableProvider : IGridProvider - { - IRawElementProviderSimple [] GetRowHeaders(); - IRawElementProviderSimple [] GetColumnHeaders(); - RowOrColumnMajor RowOrColumnMajor { get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/ITextProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/ITextProvider.cs deleted file mode 100644 index 3f8fbc80c74..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/ITextProvider.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [Flags] - [ComVisible(true)] - [Guid("3d9e3d8f-bfb0-484f-84ab-93ff4280cbc4")] - public enum SupportedTextSelection - { - None, - Single, - Multiple, - } - - [ComVisible(true)] - [Guid("3589c92c-63f3-4367-99bb-ada653b77cf2")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ITextProvider - { - ITextRangeProvider [] GetSelection(); - ITextRangeProvider [] GetVisibleRanges(); - ITextRangeProvider RangeFromChild(IRawElementProviderSimple childElement); - ITextRangeProvider RangeFromPoint(Point screenLocation); - ITextRangeProvider DocumentRange { get; } - SupportedTextSelection SupportedTextSelection { get; } - } -} - - diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/ITextRangeProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/ITextRangeProvider.cs deleted file mode 100644 index 9ebb4c9f497..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/ITextRangeProvider.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - public enum TextPatternRangeEndpoint - { - Start = 0, - End = 1, - } - - public enum TextUnit - { - Character = 0, - Format = 1, - Word = 2, - Line = 3, - Paragraph = 4, - Page = 5, - Document = 6, - } - - [ComVisible(true)] - [Guid("5347ad7b-c355-46f8-aff5-909033582f63")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ITextRangeProvider - - { - ITextRangeProvider Clone(); - [return: MarshalAs(UnmanagedType.Bool)] - bool Compare(ITextRangeProvider range); - int CompareEndpoints(TextPatternRangeEndpoint endpoint, ITextRangeProvider targetRange, TextPatternRangeEndpoint targetEndpoint); - void ExpandToEnclosingUnit(TextUnit unit); - ITextRangeProvider FindAttribute(int attribute, object value, [MarshalAs(UnmanagedType.Bool)] bool backward); - ITextRangeProvider FindText(string text, [MarshalAs(UnmanagedType.Bool)] bool backward, [MarshalAs(UnmanagedType.Bool)] bool ignoreCase); - object GetAttributeValue(int attribute); - double [] GetBoundingRectangles(); - IRawElementProviderSimple GetEnclosingElement(); - string GetText(int maxLength); - int Move(TextUnit unit, int count); - int MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, TextUnit unit, int count); - void MoveEndpointByRange(TextPatternRangeEndpoint endpoint, ITextRangeProvider targetRange, TextPatternRangeEndpoint targetEndpoint); - void Select(); - void AddToSelection(); - void RemoveFromSelection(); - void ScrollIntoView([MarshalAs(UnmanagedType.Bool)] bool alignToTop); - IRawElementProviderSimple[] GetChildren(); - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IToggleProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IToggleProvider.cs deleted file mode 100644 index e4072a12506..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IToggleProvider.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using Avalonia.Automation.Provider; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("56d00bd0-c4f4-433c-a836-1a52a57e0892")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IToggleProvider - { - void Toggle( ); - ToggleState ToggleState { get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/ITransformProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/ITransformProvider.cs deleted file mode 100644 index 4859f2d0781..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/ITransformProvider.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("6829ddc4-4f91-4ffa-b86f-bd3e2987cb4c")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ITransformProvider - { - void Move( double x, double y ); - void Resize( double width, double height ); - void Rotate( double degrees ); - bool CanMove { [return: MarshalAs(UnmanagedType.Bool)] get; } - bool CanResize { [return: MarshalAs(UnmanagedType.Bool)] get; } - bool CanRotate { [return: MarshalAs(UnmanagedType.Bool)] get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs deleted file mode 100644 index 0356f93ab88..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("c7935180-6fb3-4201-b174-7df73adbf64a")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IValueProvider - { - void SetValue([MarshalAs(UnmanagedType.LPWStr)] string? value); - string? Value { get; } - bool IsReadOnly { [return: MarshalAs(UnmanagedType.Bool)] get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IWindowProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IWindowProvider.cs deleted file mode 100644 index d915beb601e..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IWindowProvider.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - [ComVisible(true)] - [Guid("fdc8f176-aed2-477a-8c89-ea04cc5f278d")] - public enum WindowVisualState - { - Normal, - Maximized, - Minimized - } - - [ComVisible(true)] - [Guid("65101cc7-7904-408e-87a7-8c6dbd83a18b")] - public enum WindowInteractionState - { - Running, - Closing, - ReadyForUserInteraction, - BlockedByModalWindow, - NotResponding - } - - [ComVisible(true)] - [Guid("987df77b-db06-4d77-8f8a-86a9c3bb90b9")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IWindowProvider - { - void SetVisualState(WindowVisualState state); - void Close(); - [return: MarshalAs(UnmanagedType.Bool)] - bool WaitForInputIdle(int milliseconds); - bool Maximizable { [return: MarshalAs(UnmanagedType.Bool)] get; } - bool Minimizable { [return: MarshalAs(UnmanagedType.Bool)] get; } - bool IsModal { [return: MarshalAs(UnmanagedType.Bool)] get; } - WindowVisualState VisualState { get; } - WindowInteractionState InteractionState { get; } - bool IsTopmost { [return: MarshalAs(UnmanagedType.Bool)] get; } - } -} diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs b/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs deleted file mode 100644 index b6b069ac37a..00000000000 --- a/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; - -namespace Avalonia.Win32.Interop.Automation -{ - internal static class UiaCoreTypesApi - { - internal enum AutomationIdType - { - Property, - Pattern, - Event, - ControlType, - TextAttribute - } - - internal const int UIA_E_ELEMENTNOTENABLED = unchecked((int)0x80040200); - internal const int UIA_E_ELEMENTNOTAVAILABLE = unchecked((int)0x80040201); - internal const int UIA_E_NOCLICKABLEPOINT = unchecked((int)0x80040202); - internal const int UIA_E_PROXYASSEMBLYNOTLOADED = unchecked((int)0x80040203); - - private static bool? s_isNetComInteropAvailable; - internal static bool IsNetComInteropAvailable => s_isNetComInteropAvailable ??= GetIsNetComInteropAvailable(); - - internal static int UiaLookupId(AutomationIdType type, ref Guid guid) - { - return RawUiaLookupId( type, ref guid ); - } - - [RequiresUnreferencedCode("Requires .NET COM interop")] - internal static object UiaGetReservedNotSupportedValue() - { - object notSupportedValue; - CheckError(RawUiaGetReservedNotSupportedValue(out notSupportedValue)); - return notSupportedValue; - } - - [RequiresUnreferencedCode("Requires .NET COM interop")] - internal static object UiaGetReservedMixedAttributeValue() - { - object mixedAttributeValue; - CheckError(RawUiaGetReservedMixedAttributeValue(out mixedAttributeValue)); - return mixedAttributeValue; - } - - private static void CheckError(int hr) - { - if (hr >= 0) - { - return; - } - - Marshal.ThrowExceptionForHR(hr, (IntPtr)(-1)); - } - - private static bool GetIsNetComInteropAvailable() - { -#if NET6_0_OR_GREATER - if (!System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported) - { - return false; - } -#endif - - var comConfig = AppContext.GetData("System.Runtime.InteropServices.BuiltInComInterop.IsSupported") as string; - return comConfig == null || bool.Parse(comConfig); - } - - [DllImport("UIAutomationCore.dll", EntryPoint = "UiaLookupId", CharSet = CharSet.Unicode)] - private static extern int RawUiaLookupId(AutomationIdType type, ref Guid guid); - - [DllImport("UIAutomationCore.dll", EntryPoint = "UiaGetReservedNotSupportedValue", CharSet = CharSet.Unicode)] - private static extern int RawUiaGetReservedNotSupportedValue([MarshalAs(UnmanagedType.IUnknown)] out object notSupportedValue); - - [DllImport("UIAutomationCore.dll", EntryPoint = "UiaGetReservedMixedAttributeValue", CharSet = CharSet.Unicode)] - private static extern int RawUiaGetReservedMixedAttributeValue([MarshalAs(UnmanagedType.IUnknown)] out object mixedAttributeValue); - } -} diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index b33d6399555..70f2c1a4c5d 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -8,8 +8,8 @@ using Avalonia.Input.Raw; using Avalonia.Threading; using Avalonia.Win32.Automation; +using Avalonia.Win32.Automation.Interop; using Avalonia.Win32.Input; -using Avalonia.Win32.Interop.Automation; using static Avalonia.Win32.Interop.UnmanagedMethods; namespace Avalonia.Win32