Browse Source

Implement ApiInformation checks (#14090)

* Create wrapper for IApiInformationStatics

* Use ApiInformation APIs to get if WinRT types are supported

* Add some docs
pull/14140/head
Max Katz 2 years ago
committed by GitHub
parent
commit
00e9a3da34
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      src/Windows/Avalonia.Win32/Input/WindowsInputPane.cs
  2. 6
      src/Windows/Avalonia.Win32/Win32PlatformSettings.cs
  3. 160
      src/Windows/Avalonia.Win32/WinRT/WinRTApiInformation.cs
  4. 14
      src/Windows/Avalonia.Win32/WinRT/winrt.idl
  5. 2
      src/Windows/Avalonia.Win32/WindowImpl.cs

17
src/Windows/Avalonia.Win32/Input/WindowsInputPane.cs

@ -3,11 +3,15 @@ using Avalonia.Controls.Platform;
using Avalonia.MicroCom;
using Avalonia.Win32.Interop;
using Avalonia.Win32.Win32Com;
using Avalonia.Win32.WinRT;
namespace Avalonia.Win32.Input;
internal unsafe class WindowsInputPane : IInputPane, IDisposable
{
private static readonly Lazy<bool> s_inputPaneSupported = new(() =>
WinRTApiInformation.IsTypePresent("Windows.UI.ViewManagement.InputPane"));
// GUID: D5120AA3-46BA-44C5-822D-CA8092C1FC72
private static readonly Guid CLSID_FrameworkInputPane = new(0xD5120AA3, 0x46BA, 0x44C5, 0x82, 0x2D, 0xCA, 0x80, 0x92, 0xC1, 0xFC, 0x72);
// GUID: 5752238B-24F0-495A-82F1-2FD593056796
@ -17,7 +21,7 @@ internal unsafe class WindowsInputPane : IInputPane, IDisposable
private readonly IFrameworkInputPane _inputPane;
private readonly uint _cookie;
public WindowsInputPane(WindowImpl windowImpl)
private WindowsInputPane(WindowImpl windowImpl)
{
_windowImpl = windowImpl;
_inputPane = UnmanagedMethods.CreateInstance<IFrameworkInputPane>(in CLSID_FrameworkInputPane, in SID_IFrameworkInputPane);
@ -29,6 +33,17 @@ internal unsafe class WindowsInputPane : IInputPane, IDisposable
_cookie = cookie;
}
}
public static WindowsInputPane? TryCreate(WindowImpl windowImpl)
{
if (s_inputPaneSupported.Value)
{
return new WindowsInputPane(windowImpl);
}
return null;
}
public InputPaneState State { get; private set; }
public Rect OccludedRect { get; private set; }

6
src/Windows/Avalonia.Win32/Win32PlatformSettings.cs

@ -8,6 +8,10 @@ namespace Avalonia.Win32;
internal class Win32PlatformSettings : DefaultPlatformSettings
{
private static readonly Lazy<bool> s_uiSettingsSupported = new(() =>
WinRTApiInformation.IsTypePresent("Windows.UI.ViewManagement.UISettings")
&& WinRTApiInformation.IsTypePresent("Windows.UI.ViewManagement.AccessibilitySettings"));
private PlatformColorValues? _lastColorValues;
public override Size GetTapSize(PointerType type)
@ -32,7 +36,7 @@ internal class Win32PlatformSettings : DefaultPlatformSettings
public override PlatformColorValues GetColorValues()
{
if (Win32Platform.WindowsVersion.Major < 10)
if (!s_uiSettingsSupported.Value)
{
return base.GetColorValues();
}

160
src/Windows/Avalonia.Win32/WinRT/WinRTApiInformation.cs

@ -0,0 +1,160 @@
using System;
using Avalonia.Logging;
using MicroCom.Runtime;
namespace Avalonia.Win32.WinRT;
/// <summary>
/// Any WinRT API might not be available even if Windows version is supposed to support them (Win PE, Xbox...).
/// Using ApiInformation is a typical solution in UWP/WinUI apps, so we should do as well.
/// </summary>
internal static unsafe class WinRTApiInformation
{
private static readonly Lazy<IApiInformationStatics?> s_statics = new(() =>
{
if (Win32Platform.WindowsVersion.Major < 10)
{
return null;
}
try
{
using var apiStatics = NativeWinRTMethods.CreateActivationFactory<IApiInformationStatics>(
"Windows.Foundation.Metadata.ApiInformation");
return apiStatics.CloneReference();
}
catch (Exception ex)
{
Logger.TryGet(LogEventLevel.Warning, LogArea.Win32Platform)?
.Log(null, "Unable to create ApiInformation instance: {0}", ex);
return null;
}
});
public static bool IsTypePresent(string typeName)
{
using var typeNamePtr = new HStringInterop(typeName);
var result = 0;
if (s_statics.Value?.IsTypePresent(typeNamePtr.Handle, &result) == 0)
{
return result == 1;
}
return false;
}
public static bool IsMethodPresent(string typeName, string methodName)
{
using var typeNamePtr = new HStringInterop(typeName);
using var methodNamePtr = new HStringInterop(methodName);
var result = 0;
if (s_statics.Value?.IsMethodPresent(typeNamePtr.Handle, methodNamePtr.Handle, &result) == 0)
{
return result == 1;
}
return false;
}
public static bool IsMethodPresentWithArity(string typeName, string methodName, uint inputParameterCount)
{
using var typeNamePtr = new HStringInterop(typeName);
using var methodNamePtr = new HStringInterop(methodName);
var result = 0;
if (s_statics.Value?.IsMethodPresentWithArity(typeNamePtr.Handle, methodNamePtr.Handle, inputParameterCount, &result) == 0)
{
return result == 1;
}
return false;
}
public static bool IsEventPresent(string typeName, string eventName)
{
using var typeNamePtr = new HStringInterop(typeName);
using var eventNamePtr = new HStringInterop(eventName);
var result = 0;
if (s_statics.Value?.IsEventPresent(typeNamePtr.Handle, eventNamePtr.Handle, &result) == 0)
{
return result == 1;
}
return false;
}
public static bool IsPropertyPresent(string typeName, string propertyName)
{
using var typeNamePtr = new HStringInterop(typeName);
using var propertyNamePtr = new HStringInterop(propertyName);
var result = 0;
if (s_statics.Value?.IsPropertyPresent(typeNamePtr.Handle, propertyNamePtr.Handle, &result) == 0)
{
return result == 1;
}
return false;
}
public static bool IsReadOnlyPropertyPresent(string typeName, string propertyName)
{
using var typeNamePtr = new HStringInterop(typeName);
using var propertyNamePtr = new HStringInterop(propertyName);
var result = 0;
if (s_statics.Value?.IsReadOnlyPropertyPresent(typeNamePtr.Handle, propertyNamePtr.Handle, &result) == 0)
{
return result == 1;
}
return false;
}
public static bool IsWriteablePropertyPresent(string typeName, string propertyName)
{
using var typeNamePtr = new HStringInterop(typeName);
using var propertyNamePtr = new HStringInterop(propertyName);
var result = 0;
if (s_statics.Value?.IsWriteablePropertyPresent(typeNamePtr.Handle, propertyNamePtr.Handle, &result) == 0)
{
return result == 1;
}
return false;
}
public static bool IsEnumNamedValuePresent(string enumTypeName, string valueName)
{
using var enumTypeNamePtr = new HStringInterop(enumTypeName);
using var valueNamePtr = new HStringInterop(valueName);
var result = 0;
if (s_statics.Value?.IsEnumNamedValuePresent(enumTypeNamePtr.Handle, valueNamePtr.Handle, &result) == 0)
{
return result == 1;
}
return false;
}
public static bool IsApiContractPresentByMajor(string contractName, ushort majorVersion)
{
using var contractNamePtr = new HStringInterop(contractName);
var result = 0;
if (s_statics.Value?.IsApiContractPresentByMajor(contractNamePtr.Handle, majorVersion, &result) == 0)
{
return result == 1;
}
return false;
}
public static bool IsApiContractPresentByMajorAndMinor(string contractName, ushort majorVersion, ushort minorVersion)
{
using var contractNamePtr = new HStringInterop(contractName);
var result = 0;
if (s_statics.Value?.IsApiContractPresentByMajorAndMinor(contractNamePtr.Handle, majorVersion, minorVersion, &result) == 0)
{
return result == 1;
}
return false;
}
}

14
src/Windows/Avalonia.Win32/WinRT/winrt.idl

@ -872,3 +872,17 @@ interface IAccessibilitySettings : IInspectable
[propget] HRESULT HighContrastScheme([out] [retval] HSTRING* value);
}
[uuid(997439FE-F681-4A11-B416-C13A47E8BA36)]
interface IApiInformationStatics : IInspectable
{
int IsTypePresent(HSTRING typeName, boolean* result);
int IsMethodPresent(HSTRING typeName, HSTRING methodName, boolean* result);
int IsMethodPresentWithArity(HSTRING typeName, HSTRING methodName, UINT32 inputParameterCount, boolean* result);
int IsEventPresent(HSTRING typeName, HSTRING eventName, boolean* result);
int IsPropertyPresent(HSTRING typeName, HSTRING propertyName, boolean* result);
int IsReadOnlyPropertyPresent(HSTRING typeName, HSTRING propertyName, boolean* result);
int IsWriteablePropertyPresent(HSTRING typeName, HSTRING propertyName, boolean* result);
int IsEnumNamedValuePresent(HSTRING enumTypeName, HSTRING valueName, boolean* result);
int IsApiContractPresentByMajor(HSTRING contractName, UINT16 majorVersion, boolean* result);
int IsApiContractPresentByMajorAndMinor(HSTRING contractName, UINT16 majorVersion, UINT16 minorVersion, boolean* result);
}

2
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -165,7 +165,7 @@ namespace Avalonia.Win32
Screen = new ScreenImpl();
_storageProvider = new Win32StorageProvider(this);
_inputPane = Win32Platform.WindowsVersion >= PlatformConstants.Windows10 ? new WindowsInputPane(this) : null;
_inputPane = WindowsInputPane.TryCreate(this);
_nativeControlHost = new Win32NativeControlHost(this, !UseRedirectionBitmap);
_defaultTransparencyLevel = UseRedirectionBitmap ? WindowTransparencyLevel.None : WindowTransparencyLevel.Transparent;
_transparencyLevel = _defaultTransparencyLevel;

Loading…
Cancel
Save