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

7
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
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
nukebuild/numerge.config

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

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

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
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)" />

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

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

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

6
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)
{

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2
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

Loading…
Cancel
Save