Browse Source

`[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 <[email protected]>
Max Katz 1 year ago
parent
commit
af0f73de93
77 changed files with 2134 additions and 977 deletions
  1. 7 0
      Avalonia.sln
  2. 214 0
      api/Avalonia.Win32.nupkg.xml
  3. 12 0
      nukebuild/numerge.config
  4. 1 1
      packages/Avalonia/AvaloniaSingleProject.targets
  5. 0 1
      samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj
  6. 1 0
      src/Avalonia.Controls/Avalonia.Controls.csproj
  7. 3 3
      src/Windows/Avalonia.Win32.Automation/AutomationNode.ExpandCollapse.cs
  8. 17 0
      src/Windows/Avalonia.Win32.Automation/AutomationNode.RangeValue.cs
  9. 30 0
      src/Windows/Avalonia.Win32.Automation/AutomationNode.Scroll.cs
  10. 15 12
      src/Windows/Avalonia.Win32.Automation/AutomationNode.Selection.cs
  11. 2 2
      src/Windows/Avalonia.Win32.Automation/AutomationNode.Toggle.cs
  12. 3 3
      src/Windows/Avalonia.Win32.Automation/AutomationNode.Value.cs
  13. 34 13
      src/Windows/Avalonia.Win32.Automation/AutomationNode.cs
  14. 19 0
      src/Windows/Avalonia.Win32.Automation/Avalonia.Win32.Automation.csproj
  15. 28 0
      src/Windows/Avalonia.Win32.Automation/Interop/IDockProvider.cs
  16. 19 0
      src/Windows/Avalonia.Win32.Automation/Interop/IExpandCollapseProvider.cs
  17. 20 0
      src/Windows/Avalonia.Win32.Automation/Interop/IGridItemProvider.cs
  18. 18 0
      src/Windows/Avalonia.Win32.Automation/Interop/IGridProvider.cs
  19. 20 0
      src/Windows/Avalonia.Win32.Automation/Interop/IInvokeProvider.cs
  20. 25 0
      src/Windows/Avalonia.Win32.Automation/Interop/IMultipleViewProvider.cs
  21. 25 0
      src/Windows/Avalonia.Win32.Automation/Interop/IRangeValueProvider.cs
  22. 28 0
      src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderAdviseEvents.cs
  23. 39 0
      src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderFragment.cs
  24. 17 0
      src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderFragmentRoot.cs
  25. 290 0
      src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple.cs
  26. 26 0
      src/Windows/Avalonia.Win32.Automation/Interop/IRawElementProviderSimple2.cs
  27. 16 0
      src/Windows/Avalonia.Win32.Automation/Interop/IScrollItemProvider.cs
  28. 28 0
      src/Windows/Avalonia.Win32.Automation/Interop/IScrollProvider.cs
  29. 23 0
      src/Windows/Avalonia.Win32.Automation/Interop/ISelectionItemProvider.cs
  30. 27 0
      src/Windows/Avalonia.Win32.Automation/Interop/ISelectionProvider.cs
  31. 27 0
      src/Windows/Avalonia.Win32.Automation/Interop/ISynchronizedInputProvider.cs
  32. 25 0
      src/Windows/Avalonia.Win32.Automation/Interop/ITableItemProvider.cs
  33. 33 0
      src/Windows/Avalonia.Win32.Automation/Interop/ITableProvider.cs
  34. 41 0
      src/Windows/Avalonia.Win32.Automation/Interop/ITextProvider.cs
  35. 79 0
      src/Windows/Avalonia.Win32.Automation/Interop/ITextRangeProvider.cs
  36. 18 0
      src/Windows/Avalonia.Win32.Automation/Interop/IToggleProvider.cs
  37. 27 0
      src/Windows/Avalonia.Win32.Automation/Interop/ITransformProvider.cs
  38. 22 0
      src/Windows/Avalonia.Win32.Automation/Interop/IValueProvider.cs
  39. 52 0
      src/Windows/Avalonia.Win32.Automation/Interop/IWindowProvider.cs
  40. 36 9
      src/Windows/Avalonia.Win32.Automation/Interop/UiaCoreProviderApi.cs
  41. 60 0
      src/Windows/Avalonia.Win32.Automation/Interop/UiaCoreTypesApi.cs
  42. 15 13
      src/Windows/Avalonia.Win32.Automation/InteropAutomationNode.cs
  43. 282 0
      src/Windows/Avalonia.Win32.Automation/Marshalling/ComVariant.cs
  44. 16 0
      src/Windows/Avalonia.Win32.Automation/Marshalling/ComVariantMarshaller.cs
  45. 21 0
      src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayMarshaller.cs
  46. 343 0
      src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayRef.cs
  47. 21 16
      src/Windows/Avalonia.Win32.Automation/RootAutomationNode.cs
  48. 0 17
      src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs
  49. 0 30
      src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs
  50. 8 0
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  51. 0 26
      src/Windows/Avalonia.Win32/Interop/Automation/IDockProvider.cs
  52. 0 16
      src/Windows/Avalonia.Win32/Interop/Automation/IExpandCollapseProvider.cs
  53. 0 17
      src/Windows/Avalonia.Win32/Interop/Automation/IGridItemProvider.cs
  54. 0 14
      src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs
  55. 0 19
      src/Windows/Avalonia.Win32/Interop/Automation/IInvokeProvider.cs
  56. 0 16
      src/Windows/Avalonia.Win32/Interop/Automation/IMultipleViewProvider.cs
  57. 0 19
      src/Windows/Avalonia.Win32/Interop/Automation/IRangeValueProvider.cs
  58. 0 15
      src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderAdviseEvents.cs
  59. 0 32
      src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs
  60. 0 13
      src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs
  61. 0 283
      src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs
  62. 0 11
      src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs
  63. 0 13
      src/Windows/Avalonia.Win32/Interop/Automation/IScrollItemProvider.cs
  64. 0 21
      src/Windows/Avalonia.Win32/Interop/Automation/IScrollProvider.cs
  65. 0 16
      src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs
  66. 0 15
      src/Windows/Avalonia.Win32/Interop/Automation/ISelectionProvider.cs
  67. 0 26
      src/Windows/Avalonia.Win32/Interop/Automation/ISynchronizedInputProvider.cs
  68. 0 14
      src/Windows/Avalonia.Win32/Interop/Automation/ITableItemProvider.cs
  69. 0 24
      src/Windows/Avalonia.Win32/Interop/Automation/ITableProvider.cs
  70. 0 30
      src/Windows/Avalonia.Win32/Interop/Automation/ITextProvider.cs
  71. 0 48
      src/Windows/Avalonia.Win32/Interop/Automation/ITextRangeProvider.cs
  72. 0 15
      src/Windows/Avalonia.Win32/Interop/Automation/IToggleProvider.cs
  73. 0 18
      src/Windows/Avalonia.Win32/Interop/Automation/ITransformProvider.cs
  74. 0 14
      src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs
  75. 0 42
      src/Windows/Avalonia.Win32/Interop/Automation/IWindowProvider.cs
  76. 0 79
      src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs
  77. 1 1
      src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs

+ 7 - 0
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}

+ 214 - 0
api/Avalonia.Win32.nupkg.xml

@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- https://learn.microsoft.com/en-us/dotnet/fundamentals/package-validation/diagnostic-ids -->
+<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.DockPosition</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IDockProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IExpandCollapseProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IGridItemProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IGridProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IInvokeProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IMultipleViewProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IRangeValueProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IRawElementProviderAdviseEvents</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IRawElementProviderFragment</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IRawElementProviderFragmentRoot</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IRawElementProviderSimple</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IRawElementProviderSimple2</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IScrollItemProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IScrollProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.ISelectionItemProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.ISelectionProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.ISynchronizedInputProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.ITableItemProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.ITableProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.ITextProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.ITextRangeProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IToggleProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.ITransformProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IValueProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.IWindowProvider</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.NavigateDirection</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.ProviderOptions</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.RowOrColumnMajor</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.SupportedTextSelection</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.SynchronizedInputType</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.TextPatternRangeEndpoint</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.TextUnit</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.WindowInteractionState</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:Avalonia.Win32.Interop.Automation.WindowVisualState</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Win32.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Win32.dll</Right>
+  </Suppression>
+</Suppressions>

+ 12 - 0
nukebuild/numerge.config

@@ -23,6 +23,18 @@
           "DoNotMergeDependencies": true
         }
       ]
+    },
+    {
+      "Id": "Avalonia.Win32",
+      "MergeAll": false,
+      "IncomingIncludeAssetsOverride": "",
+      "Merge": [
+        {
+          "Id": "Avalonia.Win32.Automation",
+          "IgnoreMissingFrameworkBinaries": true,
+          "DoNotMergeDependencies": true
+        }
+      ]
     }
   ]
 }

+ 1 - 1
packages/Avalonia/AvaloniaSingleProject.targets

@@ -29,7 +29,7 @@
 
   <PropertyGroup Condition=" '$(_AvaloniaWindowsTarget)' == 'true' ">
     <OutputType Condition="'$(OutputType)' == 'Exe'">WinExe</OutputType>
-    <BuiltInComInteropSupport>true</BuiltInComInteropSupport>
+    <BuiltInComInteropSupport Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">true</BuiltInComInteropSupport>
     <EnableWindowsTargeting>true</EnableWindowsTargeting>
   </PropertyGroup>
 

+ 0 - 1
samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj

@@ -3,7 +3,6 @@
     <OutputType>WinExe</OutputType>
     <TargetFramework>$(AvsCurrentTargetFramework)</TargetFramework>
     <Nullable>enable</Nullable>
-    <BuiltInComInteropSupport>true</BuiltInComInteropSupport>
   </PropertyGroup>
 
   <PropertyGroup>

+ 1 - 0
src/Avalonia.Controls/Avalonia.Controls.csproj

@@ -25,6 +25,7 @@
     <InternalsVisibleTo Include="Avalonia.Headless, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="Avalonia.Native, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="Avalonia.Win32, PublicKey=$(AvaloniaPublicKey)" />
+    <InternalsVisibleTo Include="Avalonia.Win32.Automation, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="Avalonia.X11, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="Avalonia.LinuxFramebuffer, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="Avalonia.DesignerSupport.Remote, PublicKey=$(AvaloniaPublicKey)" />

+ 3 - 3
src/Windows/Avalonia.Win32/Automation/AutomationNode.ExpandCollapse.cs → 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<IExpandCollapseProvider, ExpandCollapseState>(x => x.ExpandCollapseState);
+            return InvokeSync<IExpandCollapseProvider, ExpandCollapseState>(x => x.ExpandCollapseState);
         }
 
         void UIA.IExpandCollapseProvider.Expand() => InvokeSync<IExpandCollapseProvider>(x => x.Expand());

+ 17 - 0
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<IRangeValueProvider, double>(x => x.Value);
+        bool UIA.IRangeValueProvider.GetIsReadOnly() => InvokeSync<IRangeValueProvider, bool>(x => x.IsReadOnly);
+        double UIA.IRangeValueProvider.GetMaximum() => InvokeSync<IRangeValueProvider, double>(x => x.Maximum);
+        double UIA.IRangeValueProvider.GetMinimum() => InvokeSync<IRangeValueProvider, double>(x => x.Minimum);
+        double UIA.IRangeValueProvider.GetLargeChange() => 1;
+        double UIA.IRangeValueProvider.GetSmallChange() => 1;
+
+        public void SetValue(double value) => InvokeSync<IRangeValueProvider>(x => x.SetValue(value));
+    }
+}

+ 30 - 0
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<IScrollProvider, bool>(x => x.HorizontallyScrollable);
+        double UIA.IScrollProvider.GetHorizontalScrollPercent() => InvokeSync<IScrollProvider, double>(x => x.HorizontalScrollPercent);
+        double UIA.IScrollProvider.GetHorizontalViewSize() => InvokeSync<IScrollProvider, double>(x => x.HorizontalViewSize);
+        bool UIA.IScrollProvider.GetVerticallyScrollable() => InvokeSync<IScrollProvider, bool>(x => x.VerticallyScrollable);
+        double UIA.IScrollProvider.GetVerticalScrollPercent() => InvokeSync<IScrollProvider, double>(x => x.VerticalScrollPercent);
+        double UIA.IScrollProvider.GetVerticalViewSize() => InvokeSync<IScrollProvider, double>(x => x.VerticalViewSize);
+
+        void UIA.IScrollProvider.Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount)
+        {
+            InvokeSync<IScrollProvider>(x => x.Scroll(horizontalAmount, verticalAmount));
+        }
+
+        void UIA.IScrollProvider.SetScrollPercent(double horizontalPercent, double verticalPercent)
+        {
+            InvokeSync<IScrollProvider>(x => x.SetScrollPercent(horizontalPercent, verticalPercent));
+        }
+
+        void UIA.IScrollItemProvider.ScrollIntoView()
+        {
+            InvokeSync(() => Peer.BringIntoView());
+        }
+    }
+}

+ 15 - 12
src/Windows/Avalonia.Win32/Automation/AutomationNode.Selection.cs → 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<ISelectionProvider, bool>(x => x.CanSelectMultiple);
-        bool UIA.ISelectionProvider.IsSelectionRequired => InvokeSync<ISelectionProvider, bool>(x => x.IsSelectionRequired);
-        bool UIA.ISelectionItemProvider.IsSelected => InvokeSync<ISelectionItemProvider, bool>(x => x.IsSelected);
-        
-        UIA.IRawElementProviderSimple? UIA.ISelectionItemProvider.SelectionContainer
+        bool UIA.ISelectionProvider.CanSelectMultiple() => InvokeSync<ISelectionProvider, bool>(x => x.CanSelectMultiple);
+
+        bool UIA.ISelectionProvider.IsSelectionRequired() =>
+            InvokeSync<ISelectionProvider, bool>(x => x.IsSelectionRequired);
+
+        bool UIA.ISelectionItemProvider.GetIsSelected() => InvokeSync<ISelectionItemProvider, bool>(x => x.IsSelected);
+
+        UIA.IRawElementProviderSimple? UIA.ISelectionItemProvider.GetSelectionContainer()
         {
-            get
-            {
-                var peer = InvokeSync<ISelectionItemProvider, ISelectionProvider?>(x => x.SelectionContainer);
-                return GetOrCreate(peer as AutomationPeer);
-            }
+            var peer = InvokeSync<ISelectionItemProvider, ISelectionProvider?>(x => x.SelectionContainer);
+            return GetOrCreate(peer as AutomationPeer);
         }
 
         UIA.IRawElementProviderSimple[] UIA.ISelectionProvider.GetSelection()
@@ -28,7 +28,10 @@ namespace Avalonia.Win32.Automation
         }
 
         void UIA.ISelectionItemProvider.AddToSelection() => InvokeSync<ISelectionItemProvider>(x => x.AddToSelection());
-        void UIA.ISelectionItemProvider.RemoveFromSelection() => InvokeSync<ISelectionItemProvider>(x => x.RemoveFromSelection());
+
+        void UIA.ISelectionItemProvider.RemoveFromSelection() =>
+            InvokeSync<ISelectionItemProvider>(x => x.RemoveFromSelection());
+
         void UIA.ISelectionItemProvider.Select() => InvokeSync<ISelectionItemProvider>(x => x.Select());
     }
 }

+ 2 - 2
src/Windows/Avalonia.Win32/Automation/AutomationNode.Toggle.cs → 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<IToggleProvider, ToggleState>(x => x.ToggleState);
+        ToggleState UIA.IToggleProvider.GetToggleState() => InvokeSync<IToggleProvider, ToggleState>(x => x.ToggleState);
         void UIA.IToggleProvider.Toggle() => InvokeSync<IToggleProvider>(x => x.Toggle());
     }
 }

+ 3 - 3
src/Windows/Avalonia.Win32/Automation/AutomationNode.Value.cs → 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<IValueProvider, bool>(x => x.IsReadOnly);
-        string? UIA.IValueProvider.Value => InvokeSync<IValueProvider, string?>(x => x.Value);
+        bool UIA.IValueProvider.GetIsReadOnly() => InvokeSync<IValueProvider, bool>(x => x.IsReadOnly);
+        string? UIA.IValueProvider.GetValue() => InvokeSync<IValueProvider, string?>(x => x.Value);
 
         void UIA.IValueProvider.SetValue([MarshalAs(UnmanagedType.LPWStr)] string? value)
         {

+ 34 - 13
src/Windows/Avalonia.Win32/Automation/AutomationNode.cs → src/Windows/Avalonia.Win32.Automation/AutomationNode.cs

@@ -6,18 +6,26 @@ using System.Globalization;
 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 @@ namespace Avalonia.Win32.Automation
             { SelectionPatternIdentifiers.IsSelectionRequiredProperty, UiaPropertyId.SelectionIsSelectionRequired },
             { SelectionPatternIdentifiers.SelectionProperty, UiaPropertyId.SelectionSelection },
             { SelectionItemPatternIdentifiers.IsSelectedProperty, UiaPropertyId.SelectionItemIsSelected },
-            { SelectionItemPatternIdentifiers.SelectionContainerProperty, UiaPropertyId.SelectionItemSelectionContainer }
+            {
+                SelectionItemPatternIdentifiers.SelectionContainerProperty,
+                UiaPropertyId.SelectionItemSelectionContainer
+            }
         };
 
         private static ConditionalWeakTable<AutomationPeer, AutomationNode> s_nodes = new();
@@ -65,9 +76,9 @@ namespace Avalonia.Win32.Automation
 
         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 @@ namespace Avalonia.Win32.Automation
             });
         }
 
-        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<T>() => Peer.GetProvider<T>() is object ? this : null;
@@ -105,13 +115,15 @@ namespace Avalonia.Win32.Automation
 
         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 @@ namespace Avalonia.Win32.Automation
                 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 @@ namespace Avalonia.Win32.Automation
 
         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);

+ 19 - 0
src/Windows/Avalonia.Win32.Automation/Avalonia.Win32.Automation.csproj

@@ -0,0 +1,19 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <BuiltInComInteropSupport Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">true</BuiltInComInteropSupport>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj"/>
+  </ItemGroup>
+  <Import Project="..\..\..\build\NullableEnable.props"/>
+  <Import Project="..\..\..\build\DevAnalyzers.props"/>
+  <Import Project="..\..\..\build\TrimmingEnable.props"/>
+
+  <ItemGroup>
+    <InternalsVisibleTo Include="Avalonia.Win32, PublicKey=$(AvaloniaPublicKey)"/>
+  </ItemGroup>
+</Project>

+ 28 - 0
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();
+}

+ 19 - 0
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();
+}

+ 20 - 0
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();
+}

+ 18 - 0
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();
+}

+ 20 - 0
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();
+}

+ 25 - 0
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<int>))]
+#endif
+    int[] GetSupportedViews();
+}

+ 25 - 0
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();
+}

+ 28 - 0
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<int>))]
+#endif
+        int[] properties);
+
+    void AdviseEventRemoved(int eventId,
+#if NET8_0_OR_GREATER
+        [MarshalUsing(typeof(SafeArrayMarshaller<int>))]
+#endif
+        int[] properties);
+}

+ 39 - 0
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<int>))]
+#endif
+    int[]? GetRuntimeId();
+    Rect GetBoundingRectangle();
+#if NET8_0_OR_GREATER
+    [return: MarshalUsing(typeof(SafeArrayMarshaller<IRawElementProviderSimple>))]
+#endif
+    IRawElementProviderSimple[]? GetEmbeddedFragmentRoots();
+    void SetFocus();
+    IRawElementProviderFragmentRoot? GetFragmentRoot();
+}

+ 17 - 0
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();
+}

+ 290 - 0
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();
+}

+ 26 - 0
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();
+}

+ 16 - 0
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();
+}

+ 28 - 0
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();
+}

+ 23 - 0
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();
+}

+ 27 - 0
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<IRawElementProviderSimple>))]
+#endif
+    IRawElementProviderSimple[] GetSelection();
+
+    [return: MarshalAs(UnmanagedType.Bool)]
+    bool CanSelectMultiple();
+
+    [return: MarshalAs(UnmanagedType.Bool)]
+    bool IsSelectionRequired();
+}

+ 27 - 0
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();
+}

+ 25 - 0
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<IRawElementProviderSimple>))]
+#endif
+    IRawElementProviderSimple[] GetRowHeaderItems();
+#if NET8_0_OR_GREATER
+    [return: MarshalUsing(typeof(SafeArrayMarshaller<IRawElementProviderSimple>))]
+#endif
+    IRawElementProviderSimple[] GetColumnHeaderItems();
+}

+ 33 - 0
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<IRawElementProviderSimple>))]
+#endif
+    IRawElementProviderSimple[] GetRowHeaders();
+#if NET8_0_OR_GREATER
+    [return: MarshalUsing(typeof(SafeArrayMarshaller<IRawElementProviderSimple>))]
+#endif
+    IRawElementProviderSimple[] GetColumnHeaders();
+    RowOrColumnMajor GetRowOrColumnMajor();
+}

+ 41 - 0
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<ITextRangeProvider>))]
+#endif
+    ITextRangeProvider[] GetSelection();
+#if NET8_0_OR_GREATER
+    [return: MarshalUsing(typeof(SafeArrayMarshaller<ITextRangeProvider>))]
+#endif
+    ITextRangeProvider[] GetVisibleRanges();
+    ITextRangeProvider RangeFromChild(IRawElementProviderSimple childElement);
+
+    ITextRangeProvider RangeFromPoint(double X, double Y);
+
+    ITextRangeProvider GetDocumentRange();
+    SupportedTextSelection GetSupportedTextSelection();
+}

+ 79 - 0
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<double>))]
+#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<IRawElementProviderSimple>))]
+#endif
+    IRawElementProviderSimple[] GetChildren();
+}

+ 18 - 0
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();
+}

+ 27 - 0
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();
+}

+ 22 - 0
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();
+}

+ 52 - 0
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();
+}

+ 36 - 9
src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreProviderApi.cs → 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 @@ namespace Avalonia.Win32.Interop.Automation
         Completed,
     }
 
-    [ComVisible(true)]
     [Guid("e4cfef41-071d-472c-a65c-c14f59ea81eb")]
     internal enum StructureChangeType
     {
@@ -63,29 +62,57 @@ namespace Avalonia.Win32.Interop.Automation
         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
     }
 }

+ 60 - 0
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
+    }
+}

+ 15 - 13
src/Windows/Avalonia.Win32/Automation/InteropAutomationNode.cs → 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;
 
 /// <summary>
 /// An automation node which serves as the root of an embedded native control automation tree.
 /// </summary>
-[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 @@ internal class InteropAutomationNode : AutomationNode, IRawElementProviderFragme
         _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)

+ 282 - 0
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;
+    }
+
+    /// <summary>
+    /// Release resources owned by this <see cref="ComVariant"/> instance.
+    /// </summary>
+    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;
+    }
+
+    /// <summary>
+    /// Create an <see cref="ComVariant"/> instance from the specified value.
+    /// </summary>
+    /// <param name="value">The value to wrap in an <see cref="ComVariant"/>.</param>
+    /// <returns>An <see cref="ComVariant"/> that contains the provided value.</returns>
+    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;
+    }
+
+    /// <summary>
+    /// A <see cref="ComVariant"/> instance that represents a null value with <see cref="VarEnum.VT_NULL"/> type.
+    /// </summary>
+    public static ComVariant Null { get; } = new() { VarType = VarEnum.VT_NULL };
+
+    /// <summary>
+    /// Create a managed value based on the value in the <see cref="ComVariant"/> instance.
+    /// </summary>
+    /// <returns>The managed value contained in this variant.</returns>
+    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<sbyte>(_typeUnion._unionTypes.parray),
+                VarEnum.VT_I2 => SafeArrayRef.ToArray<short>(_typeUnion._unionTypes.parray),
+                VarEnum.VT_I4 => SafeArrayRef.ToArray<int>(_typeUnion._unionTypes.parray),
+                VarEnum.VT_I8 => SafeArrayRef.ToArray<long>(_typeUnion._unionTypes.parray),
+                VarEnum.VT_INT => SafeArrayRef.ToArray<int>(_typeUnion._unionTypes.parray),
+                // unsigned integer
+                VarEnum.VT_UI1 => SafeArrayRef.ToArray<byte>(_typeUnion._unionTypes.parray),
+                VarEnum.VT_UI2 => SafeArrayRef.ToArray<ushort>(_typeUnion._unionTypes.parray),
+                VarEnum.VT_UI4 => SafeArrayRef.ToArray<uint>(_typeUnion._unionTypes.parray),
+                VarEnum.VT_UI8 => SafeArrayRef.ToArray<ulong>(_typeUnion._unionTypes.parray),
+                VarEnum.VT_UINT => SafeArrayRef.ToArray<uint>(_typeUnion._unionTypes.parray),
+                // floating
+                VarEnum.VT_R4 => SafeArrayRef.ToArray<float>(_typeUnion._unionTypes.parray),
+                VarEnum.VT_R8 => SafeArrayRef.ToArray<double>(_typeUnion._unionTypes.parray),
+                // string
+                VarEnum.VT_BSTR => SafeArrayRef.ToArray<string>(_typeUnion._unionTypes.parray),
+                // variant
+                VarEnum.VT_UNKNOWN => SafeArrayRef.ToArray<IntPtr>(_typeUnion._unionTypes.parray),
+                _ => throw new ArgumentException($"Unknown variant type: {varEnum}")
+            },
+            _ => throw new ArgumentException($"Unknown variant type: {VarType}")
+        };
+    }
+
+    /// <summary>
+    /// The type of the data stored in this <see cref="ComVariant"/>.
+    /// </summary>
+    public VarEnum VarType
+    {
+        readonly get => (VarEnum)_typeUnion._vt;
+        private set => _typeUnion._vt = (ushort)value;
+    }
+}
+#endif

+ 16 - 0
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

+ 21 - 0
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<T> 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<T>(unmanaged);
+
+    public static void Free(SafeArrayRef unmanaged) => unmanaged.Destroy();
+}
+#endif

+ 343 - 0
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
+    {
+        /// <summary>The number of dimensions.</summary>
+        internal ushort cDims;
+
+        /// <summary>
+        /// <para>Flags. </para>
+        /// <para>This doc was truncated.</para>
+        /// <para><see href="https://learn.microsoft.com/windows/win32/api/oaidl/ns-oaidl-safearray#members">Read more on docs.microsoft.com</see>.</para>
+        /// </summary>
+        internal ADVANCED_FEATURE_FLAGS fFeatures;
+
+        /// <summary>The size of an array element.</summary>
+        internal uint cbElements;
+
+        /// <summary>The number of times the array has been locked without a corresponding unlock.</summary>
+        internal uint cLocks;
+
+        /// <summary>The data.</summary>
+        internal void* pvData;
+
+        /// <summary>One bound for each dimension.</summary>
+        internal VariableLengthInlineArray<SAFEARRAYBOUND> rgsabound;
+    }
+    internal struct SAFEARRAYBOUND
+    {
+        /// <summary>The number of elements in the dimension.</summary>
+        internal uint cElements;
+
+        /// <summary>The lower bound of the dimension.</summary>
+        internal int lLbound;
+    }
+
+    internal struct VariableLengthInlineArray<T>
+        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<T> 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<T>(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<T>(IReadOnlyCollection<T> collection, VarEnum varEnum)
+        {
+            var collectionSpan = collection switch
+            {
+                T[] array => array,
+                List<T> list => CollectionsMarshal.AsSpan(list),
+                _ => collection.ToArray()
+            };
+            return CreateFromSpan<T>(collectionSpan, varEnum);
+        }
+
+        static SafeArrayRef CreateFromSpan<T>(ReadOnlySpan<T> 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<T>(safearray->pvData, (int)safearray->rgsabound[0].cElements);
+                span.CopyTo(output);
+            }
+            finally
+            {
+                SafeArrayUnlock(safearray);
+            }
+
+            return new SafeArrayRef
+            {
+                _ptr = safearray
+            };
+        }
+
+        static SafeArrayRef CreateFromStrings(IReadOnlyList<string> strings, VarEnum varEnum)
+        {
+            Debug.Assert(varEnum == VarEnum.VT_BSTR); // other types not supported yet
+            var pointers = ArrayPool<IntPtr>.Shared.Rent(strings.Count);
+            try
+            {
+                for (int i = 0; i < strings.Count; i++)
+                {
+                    pointers[i] = Marshal.StringToBSTR(strings[i]);
+                }
+
+                return CreateFromSpan<IntPtr>(pointers.AsSpan(0, strings.Count), varEnum);
+            }
+            finally
+            {
+                ArrayPool<IntPtr>.Shared.Return(pointers);
+            }
+        }
+
+        static SafeArrayRef CreateFromBools(IReadOnlyList<bool> bools, VarEnum varEnum)
+        {
+            Debug.Assert(varEnum == VarEnum.VT_BOOL); // other types not supported
+            var shorts = ArrayPool<short>.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<short>(shorts.AsSpan(0, bools.Count), varEnum);
+            }
+            finally
+            {
+                ArrayPool<short>.Shared.Return(shorts);
+            }
+        }
+
+        static SafeArrayRef CreateFromObjects(IReadOnlyList<object> objects, VarEnum varEnum)
+        {
+            Debug.Assert(varEnum == VarEnum.VT_UNKNOWN); // other types not supported yet
+            var pointers = ArrayPool<IntPtr>.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<IntPtr>(pointers, varEnum);
+            }
+            finally
+            {
+                ArrayPool<IntPtr>.Shared.Return(pointers);
+            }
+        }
+
+        safearray = managed switch
+        {
+            IReadOnlyCollection<sbyte> ints => CreateFromCollection(ints, varEnum = VarEnum.VT_I1),
+            IReadOnlyCollection<short> ints => CreateFromCollection(ints, varEnum = VarEnum.VT_I2),
+            IReadOnlyCollection<int> ints => CreateFromCollection(ints, varEnum = VarEnum.VT_I4),
+            IReadOnlyCollection<long> ints => CreateFromCollection(ints, varEnum = VarEnum.VT_I8),
+
+            IReadOnlyCollection<byte> ints => CreateFromCollection(ints, varEnum = VarEnum.VT_UI1),
+            IReadOnlyCollection<ushort> ints => CreateFromCollection(ints, varEnum = VarEnum.VT_UI2),
+            IReadOnlyCollection<uint> ints => CreateFromCollection(ints, varEnum = VarEnum.VT_UI4),
+            IReadOnlyCollection<ulong> ints => CreateFromCollection(ints, varEnum = VarEnum.VT_UI8),
+
+            IReadOnlyCollection<float> ints => CreateFromCollection(ints, varEnum = VarEnum.VT_R4),
+            IReadOnlyCollection<double> ints => CreateFromCollection(ints, varEnum = VarEnum.VT_R8),
+
+            IReadOnlyCollection<nint> ints => CreateFromCollection(ints, varEnum = VarEnum.VT_INT),
+            IReadOnlyCollection<nuint> ints => CreateFromCollection(ints, varEnum = VarEnum.VT_UINT),
+
+            IReadOnlyList<bool> bools => CreateFromBools(bools, varEnum = VarEnum.VT_BOOL),
+
+            IReadOnlyList<string> strings => CreateFromStrings(strings, varEnum = VarEnum.VT_BSTR),
+
+            IReadOnlyList<object> 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<TRes>(SafeArrayRef safearray, Func<IntPtr, int, TRes> 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

+ 21 - 16
src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs → 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 @@ namespace Avalonia.Win32.Automation
             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 @@ namespace Avalonia.Win32.Automation
             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)

+ 0 - 17
src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs

@@ -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<IRangeValueProvider, double>(x => x.Value);
-        bool UIA.IRangeValueProvider.IsReadOnly => InvokeSync<IRangeValueProvider, bool>(x => x.IsReadOnly);
-        double UIA.IRangeValueProvider.Maximum => InvokeSync<IRangeValueProvider, double>(x => x.Maximum);
-        double UIA.IRangeValueProvider.Minimum => InvokeSync<IRangeValueProvider, double>(x => x.Minimum);
-        double UIA.IRangeValueProvider.LargeChange => 1;
-        double UIA.IRangeValueProvider.SmallChange => 1;
-
-        public void SetValue(double value) => InvokeSync<IRangeValueProvider>(x => x.SetValue(value));
-    }
-}

+ 0 - 30
src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs

@@ -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<IScrollProvider, bool>(x => x.HorizontallyScrollable);
-        double UIA.IScrollProvider.HorizontalScrollPercent => InvokeSync<IScrollProvider, double>(x => x.HorizontalScrollPercent);
-        double UIA.IScrollProvider.HorizontalViewSize => InvokeSync<IScrollProvider, double>(x => x.HorizontalViewSize);
-        bool UIA.IScrollProvider.VerticallyScrollable => InvokeSync<IScrollProvider, bool>(x => x.VerticallyScrollable);
-        double UIA.IScrollProvider.VerticalScrollPercent => InvokeSync<IScrollProvider, double>(x => x.VerticalScrollPercent);
-        double UIA.IScrollProvider.VerticalViewSize => InvokeSync<IScrollProvider, double>(x => x.VerticalViewSize);
-
-        void UIA.IScrollProvider.Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount)
-        {
-            InvokeSync<IScrollProvider>(x => x.Scroll(horizontalAmount, verticalAmount));
-        }
-
-        void UIA.IScrollProvider.SetScrollPercent(double horizontalPercent, double verticalPercent)
-        {
-            InvokeSync<IScrollProvider>(x => x.SetScrollPercent(horizontalPercent, verticalPercent));
-        }
-
-        void UIA.IScrollItemProvider.ScrollIntoView()
-        {
-            InvokeSync(() => Peer.BringIntoView());
-        }
-    }
-}

+ 8 - 0
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@@ -24,6 +24,7 @@
     <MicroComIdl Include="Win32Com\win32.idl" CSharpInteropPath="Win32Com\Win32.Generated.cs" />
     <MicroComIdl Include="DirectX\directx.idl" CSharpInteropPath="DirectX\directx.Generated.cs" />
     <MicroComIdl Include="DComposition\dcomp.idl" CSharpInteropPath="DComposition\DComp.Generated.cs" />
+    <ProjectReference Include="..\Avalonia.Win32.Automation\Avalonia.Win32.Automation.csproj" />
   </ItemGroup>
   <Import Project="..\..\..\build\NullableEnable.props" />
   <Import Project="..\..\..\build\DevAnalyzers.props" />
@@ -39,4 +40,11 @@
     <InternalsVisibleTo Include="Avalonia.Win32.Interoperability, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="Avalonia.Direct2D1, PublicKey=$(AvaloniaPublicKey)" />
   </ItemGroup>
+  <ItemGroup>
+    <!-- By default, any projects supports Windows, Linux, MacOS platforms. -->
+    <!-- To properly support analyzers, we need to re-set this value -->
+    <!-- https://github.com/dotnet/sdk/blob/v8.0.403/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.SupportedPlatforms.props -->
+    <SupportedPlatform Remove="@(SupportedPlatform)" />
+    <SupportedPlatform Include="Windows" />
+  </ItemGroup>
 </Project>

+ 0 - 26
src/Windows/Avalonia.Win32/Interop/Automation/IDockProvider.cs

@@ -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; }
-    }
-}

+ 0 - 16
src/Windows/Avalonia.Win32/Interop/Automation/IExpandCollapseProvider.cs

@@ -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; }
-    }
-}

+ 0 - 17
src/Windows/Avalonia.Win32/Interop/Automation/IGridItemProvider.cs

@@ -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; }
-    }
-}

+ 0 - 14
src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs

@@ -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; }
-    }
-}

+ 0 - 19
src/Windows/Avalonia.Win32/Interop/Automation/IInvokeProvider.cs

@@ -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();
-    }
-}

+ 0 - 16
src/Windows/Avalonia.Win32/Interop/Automation/IMultipleViewProvider.cs

@@ -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();
-    }
-}

+ 0 - 19
src/Windows/Avalonia.Win32/Interop/Automation/IRangeValueProvider.cs

@@ -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; }
-    }
-}

+ 0 - 15
src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderAdviseEvents.cs

@@ -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);
-    }
-}

+ 0 - 32
src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs

@@ -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; }
-    }
-}

+ 0 - 13
src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs

@@ -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();
-    }
-}

+ 0 - 283
src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs

@@ -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; }
-    }
-}

+ 0 - 11
src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs

@@ -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();
-    }
-}

+ 0 - 13
src/Windows/Avalonia.Win32/Interop/Automation/IScrollItemProvider.cs

@@ -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();
-    }
-}

+ 0 - 21
src/Windows/Avalonia.Win32/Interop/Automation/IScrollProvider.cs

@@ -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; }
-    }
-}

+ 0 - 16
src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs

@@ -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; }
-    }
-}

+ 0 - 15
src/Windows/Avalonia.Win32/Interop/Automation/ISelectionProvider.cs

@@ -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; }
-    }
-}

+ 0 - 26
src/Windows/Avalonia.Win32/Interop/Automation/ISynchronizedInputProvider.cs

@@ -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();
-    }
-}

+ 0 - 14
src/Windows/Avalonia.Win32/Interop/Automation/ITableItemProvider.cs

@@ -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();
-    }
-}

+ 0 - 24
src/Windows/Avalonia.Win32/Interop/Automation/ITableProvider.cs

@@ -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; }
-    }
-}

+ 0 - 30
src/Windows/Avalonia.Win32/Interop/Automation/ITextProvider.cs

@@ -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; }
-    }
-}
-
-

+ 0 - 48
src/Windows/Avalonia.Win32/Interop/Automation/ITextRangeProvider.cs

@@ -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();
-    }
-}

+ 0 - 15
src/Windows/Avalonia.Win32/Interop/Automation/IToggleProvider.cs

@@ -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; }
-    }
-}

+ 0 - 18
src/Windows/Avalonia.Win32/Interop/Automation/ITransformProvider.cs

@@ -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; }
-    }
-}

+ 0 - 14
src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs

@@ -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; }
-    }
-}

+ 0 - 42
src/Windows/Avalonia.Win32/Interop/Automation/IWindowProvider.cs

@@ -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; }
-    }
-}

+ 0 - 79
src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs

@@ -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);
-    }
-}

+ 1 - 1
src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs

@@ -8,8 +8,8 @@ using Avalonia.Input;
 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