diff --git a/src/Windows/Avalonia.Win32/Win32PlatformSettings.cs b/src/Windows/Avalonia.Win32/Win32PlatformSettings.cs index c5f7f17b32..0372979824 100644 --- a/src/Windows/Avalonia.Win32/Win32PlatformSettings.cs +++ b/src/Windows/Avalonia.Win32/Win32PlatformSettings.cs @@ -8,6 +8,10 @@ namespace Avalonia.Win32; internal class Win32PlatformSettings : DefaultPlatformSettings { + private static readonly Lazy 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(); } diff --git a/src/Windows/Avalonia.Win32/WinRT/WinRTApiInformation.cs b/src/Windows/Avalonia.Win32/WinRT/WinRTApiInformation.cs new file mode 100644 index 0000000000..2c59257c74 --- /dev/null +++ b/src/Windows/Avalonia.Win32/WinRT/WinRTApiInformation.cs @@ -0,0 +1,160 @@ +using System; +using Avalonia.Logging; +using MicroCom.Runtime; + +namespace Avalonia.Win32.WinRT; + +/// +/// 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. +/// +internal static unsafe class WinRTApiInformation +{ + private static readonly Lazy s_statics = new(() => + { + if (Win32Platform.WindowsVersion.Major < 10) + { + return null; + } + + try + { + using var apiStatics = NativeWinRTMethods.CreateActivationFactory( + "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; + } +} diff --git a/src/Windows/Avalonia.Win32/WinRT/winrt.idl b/src/Windows/Avalonia.Win32/WinRT/winrt.idl index beb88352dd..b80a0de11b 100644 --- a/src/Windows/Avalonia.Win32/WinRT/winrt.idl +++ b/src/Windows/Avalonia.Win32/WinRT/winrt.idl @@ -871,3 +871,18 @@ interface IAccessibilitySettings : IInspectable [propget] HRESULT HighContrast([out] [retval] boolean* value); [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); +}