Providing Backward Compatibility for .NET Applications Using WinRT

    The creation of Windows Runtime (WinRT) as an API, on the one hand, can only be welcomed, since the previous one - WinAPI - was not very simple and humane. On the other hand, at the same time, the backward compatibility problem pops up. What should I do if I need to use some nice little thing that appeared in Win8, but at the same time not lose compatibility with Win7, which is still vigorously walking in the ranks?

    The official MSDN refers very clearly to this: if you need WinRT, then forget about the versions of Windows older than eight; if you need to support any junk, then we collect the application separately without mentioning WinRT. Such simple and unpretentious guys work at Microsoft. Nevertheless, a solution to the problem, and quite simple, was found.

    The bottom line is that we can take all the implementation necessary for happiness, which requires WinRT, into a separate assembly, and, if necessary, try to load it dynamically: it succeeds - great, but it doesn’t work out - we put up and slip the plug with the same interface.

    Suppose we had a desire, using WinRT, to read the values ​​of the light 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- the most ordinary Class Library, containing the IWinRTAccessor interface, returning with our only GetLightValue method exactly what we need, namely the level of illumination in the presence of a sensor and null in case of its absence. A FakeWinRTAccessor stub is declared there, which implements this interface and always returns null. In addition, the WinRTAccessorFactory class is located here, whose factory method instantiates the desired implementation of IWinRTAccessor. The most primitive implementation of this factory method looks like this:
            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 a no less ordinary Class Library (whose name is indicated by the WinRTAccessorAssemblyName constant), in which the logic of working with WinRT is concentrated, however, to support it, you need to go for a little trick: write the following Property Group in the project file (.csproj):


    8.0


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


    The method itself, which extracts the readings of the light sensor, thanks to the new API, is very 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 delayed compilation: in earlier versions of Windows, this assembly has every chance of correctly loading and instantiating an instance of RealWinRTAccessor, and falling already upon calling its method when accessing WinRT. To prevent this, pull WinRT directly in the constructor:
            public RealWinRTAccessor()
            {
                LightSensor.GetDefault();
            }
    


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


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

    Of the advantages of this approach: achieving the goal and relative simplicity.
    Among the shortcomings: the need for the rights to download assemblies through Assembly.LoadFile, manual verification (it is not here, but should be) of the originality of the loaded assembly, manual control of the assembly and the location of WinRTLib, because she is not a reference to anyone.

    Also popular now: