Skip to content

Commit

Permalink
Implement ApiInformation checks (#14090)
Browse files Browse the repository at this point in the history
* Create wrapper for IApiInformationStatics

* Use ApiInformation APIs to get if WinRT types are supported

* Add some docs
#Conflicts:
#	src/Windows/Avalonia.Win32/Input/WindowsInputPane.cs
#	src/Windows/Avalonia.Win32/WinRT/winrt.idl
#	src/Windows/Avalonia.Win32/WindowImpl.cs
  • Loading branch information
maxkatz6 committed Jan 17, 2024
1 parent 43a9aa4 commit fc677b2
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/Windows/Avalonia.Win32/Win32PlatformSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -32,7 +36,7 @@ public override Size GetDoubleTapSize(PointerType type)

public override PlatformColorValues GetColorValues()
{
if (Win32Platform.WindowsVersion.Major < 10)
if (!s_uiSettingsSupported.Value)
{
return base.GetColorValues();
}
Expand Down
160 changes: 160 additions & 0 deletions src/Windows/Avalonia.Win32/WinRT/WinRTApiInformation.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
15 changes: 15 additions & 0 deletions src/Windows/Avalonia.Win32/WinRT/winrt.idl
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit fc677b2

Please sign in to comment.