OK, so you are using System.Environment.OSVersion.Version…

The .NET Framework provides a class to find out the version of Windows. Take a look at the following example:

using System;

namespace OsVersionCheck
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"" +
                $"{System.Environment.OSVersion.Version.Major}." +
                $"{System.Environment.OSVersion.Version.Minor}." +
                $"{System.Environment.OSVersion.Version.Build}" +
                $"");

            Console.ReadKey();
        }
    }
}

The output of the above code looks something like this:

6.2.9200

This number can be used to identify the operating system. The following table summarizes the most recent operating system version numbers:

Operating system Version number (Major.Minor)
Windows 1010.0*
Windows Server 201910.0*
Windows Server 201610.0*
Windows 8.16.3*
Windows Server 2012 R26.3*
Windows 86.2
Windows Server 20126.2
Windows 76.1
Windows Server 2008 R26.1
Windows Server 20086.0
Windows Vista6.0
Windows Server 2003 R25.2
Windows Server 20035.2
Windows XP 64-Bit Edition5.2
Windows XP5.1
Windows 20005.0

However, this does not work as desired if the function is executed on the operating systems marked with an asterisk in the table above. Specifically, these are: Windows 10, Windows Server 2019, Windows Server 2016, Windows 8.1, Windows Server 2012 R2

This means for example: for Windows 10 it will return 6.2, which is wrong, as this refers to Windows 8 / Windows Server 2012.

How does this behavior come about? (Note: you can skip the following paragraph if you are not interested in technical background details)

Why OSVersion.Version will return wrong results on newer OSes

In Windows 8.1 and Windows 10, the GetVersion and GetVersionEx functions have been deprecated. In Windows 10, the VerifyVersionInfo function has also been deprecated. While you can still call the deprecated functions, if your application does not specifically target Windows 8.1 or Windows 10, you will get Windows 8 version (6.2.0.0).

https://docs.microsoft.com/de-de/windows/win32/sysinfo/targeting-your-application-at-windows-8-1

In order to target Windows 8.1 or Windows 10, you need to include the app manifest in the source file, which is our first possible solution.

Targeting your application for Windows in the app manifest

In Visual Studio you can add an app manifest by doing the following:

Go to your project, right click and choose Add / New Item and choose Application Manifest File. A new file will be added to your project having default name app.manifest. In the following section you can uncomment Windows 8.1 and 10.

  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!-- A list of the Windows versions that this application has been tested on
           and is designed to work with. Uncomment the appropriate elements
           and Windows will automatically select the most compatible environment. -->

      <!-- Windows Vista -->
      <!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->

      <!-- Windows 7 -->
      <!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->

       <!--Windows 8--> 
      <!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->

       Windows 8.1 
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />

       Windows 10 
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />

    </application>
  </compatibility>

If you run the program again, the output on a Windows 10 will be correct now:

10.0.17763

Please note:

  • Microsoft says: Manifesting the .exe for Windows 8.1 or Windows 10 will not have any impact when run on previous operating systems.
  • The GUIDs in manifest file are commented with Windows desktop versions, but they are also valid for the Windows Server edition. E.g., the GUID for Windows 8.1 also represents Windows Server 2012 R2, as they have the same OS version number 6.3
  • The approach with the manifest file has a major drawback: Every time Microsoft launches a new Windows version, you need to update your application with a new manifest file. Without such an update, your app will not be able to detect the new Windows and will report the number wrong (again).

Calling RtlGetVersion in ntdll.dll

The Windows Kernel offers an interesting function. The RtlGetVersion routine returns version information about the currently running operating system. It is available starting with Windows 2000 and also works on Windows 10/Server 2019/Server 2016 right away.

using System;
using System.Runtime.InteropServices;
using System.Security;

namespace ConsoleApp1
{
    class Program
    {
        /// <summary>
        /// taken from https://stackoverflow.com/a/49641055
        /// </summary>
        /// <param name="versionInfo"></param>
        /// <returns></returns>
        [SecurityCritical]
        [DllImport("ntdll.dll", SetLastError = true)]
        internal static extern bool RtlGetVersion(ref OSVERSIONINFOEX versionInfo);
        [StructLayout(LayoutKind.Sequential)]
        internal struct OSVERSIONINFOEX
        {
            // The OSVersionInfoSize field must be set to Marshal.SizeOf(typeof(OSVERSIONINFOEX))
            internal int OSVersionInfoSize;
            internal int MajorVersion;
            internal int MinorVersion;
            internal int BuildNumber;
            internal int PlatformId;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            internal string CSDVersion;
            internal ushort ServicePackMajor;
            internal ushort ServicePackMinor;
            internal short SuiteMask;
            internal byte ProductType;
            internal byte Reserved;
        }

        static void Main(string[] args)
        {
            var osVersionInfo = new OSVERSIONINFOEX { OSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEX)) };
            if (!RtlGetVersion(ref osVersionInfo))
            {
                // TODO: Error handling, call GetVersionEx, etc.
            }
            Console.WriteLine($"Windows Version {osVersionInfo.MajorVersion}.{osVersionInfo.MinorVersion}.{osVersionInfo.BuildNumber}");

            Console.ReadKey();
        }
    }
}

Get source code on GitHub

You can view the source code here: https://github.com/pruggitorg/detect-windows-version

Schreibe einen Kommentar