📜 ⬆️ ⬇️

Ensuring backward compatibility of .NET applications when using WinRT

Creating the Windows Runtime (WinRT) as an API, on the one hand, is welcome, since the previous one, WinAPI, was not particularly simple and did not like philanthropy. On the other hand, the problem of backward compatibility emerges in full growth. What if you need to use some nice little thing that appeared in Win8, but at the same time not lose compatibility with Win7, still cheerfully walking in the ranks?

The official MSDN refers to this quite unequivocally: if WinRT is needed, then we forget about versions of Windows older than eight; if you need to support any old stuff, then we assemble the application separately without mentioning WinRT. Such are the simple and unpretentious guys working at Microsoft. Nevertheless, a solution to the problem, and a rather simple one, was found.

The bottom line is that we can carry all the necessary implementation for happiness, which requires WinRT, into a separate assembly, and if necessary, try to load it dynamically: succeeds — great, well, but fails — we accept and slip the stub with the same interface.

Let's say we had a desire, using WinRT, to read the values ​​of the brightness sensor of a laptop / tablet. The LightSensor class from the Windows.Devices.Sensors namespace is responsible for this. In this case, the class diagram can be represented as follows:
image
')
Interfaces is the most common Class Library, containing the IWinRTAccessor interface, returning exactly what we need with its only GetLightValue method, namely the light level in the case of a sensor and null in the absence of a sensor. There is also a FakeWinRTAccessor stub that implements this interface and always returns null. In addition, the WinRTAccessorFactory class is also located here, whose factory method instantiates the desired IWinRTAccessor implementation. The most primitive implementation of this factory method is as follows:
public static IWinRTAccessor GetAccessor() { if (_winRtAccessor == null) { try { String path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), WinRTAccessorAssemblyName); Assembly assembly = Assembly.LoadFile(path); Type type = assembly.GetTypes().First(t => t.GetInterface(typeof (IWinRTAccessor).Name) != null); _winRtAccessor = (IWinRTAccessor) Activator.CreateInstance(type); } catch { _winRtAccessor = new FakeWinRTAccessor(); } } return _winRtAccessor; } 


WinRTLib is no less an ordinary Class Library (the WinRTAccessorAssemblyName constant indicates the name of which), in which the logic of working with WinRT is concentrated, but to support it you need to go for a little trick: write the following Property Group in the project file (.csproj):

<PropertyGroup>
<targetplatformversion> 8.0 </ targetplatformversion>
</ PropertyGroup>

And only after that add Windows Core References. In this case, we are interested in Windows.Devices:


The method itself that retrieves the light sensor readings, thanks to the new API, is quite simple:
  public Single? GetLightValue() { LightSensor light = LightSensor.GetDefault(); if (light != null) return light.GetCurrentReading().IlluminanceInLux; return null; } 


In principle, this would be enough if not deferred compilation: in earlier versions of Windows, this assembly has all the chances to correctly boot and instantiate an instance of RealWinRTAccessor, and to fall already on calling its method when accessing WinRT. To prevent this from happening, we jerk WinRT right in the constructor:
  public RealWinRTAccessor() { LightSensor.GetDefault(); } 


Now, when you need to get the light sensor reading, you can pull:
  WinRTAccessorFactory.GetAccessor().GetLightValue() 


This code will work for both WinRT and for earlier versions of Windows - in this case, the result of calling GetLightValue will be null.

From the advantages of this approach: the achievement of the goal and relative simplicity.
Among the shortcomings: the need for rights to download assemblies via Assembly.LoadFile, manual checking (it’s not here, but should be) the originality of the assembly being loaded, manual control of the assembly and location of WinRTLib, since it is not Reference to anyone.

Source: https://habr.com/ru/post/258015/


All Articles