Click here to Skip to main content
15,441,629 members
Articles / Programming Languages / C#
Article
Posted 2 Jul 2022

Tagged as

Stats

15.8K views
1.1K downloads
20 bookmarked

Windows 11 Version Detection

Rate me:
Please Sign up or sign in to vote.
4.91/5 (26 votes)
30 Aug 2022CPOL4 min read
Windows 11 Version Detection using C# and C++
In this article, you will see how to detect Windows 11 Version by using C# and C++

Table of Contents

The example code is hosted on Github.

Introduction

Image 1

No mistake in the above table! Windows 11 version is indeed 10.0. From the Windows kernel perspective, Windows 10 and 11 are largely the same. The Windows 11 naming is perhaps a marketing decision.

Windows Vista Fiasco

Many programs written for Windows XP, refused to run on Vista due to the check below. Vista version is 6.0 in which the version.Minor check will fail because 0 is neither greater than nor equal to 1. Windows 7 version is 6.1 so it is not affected by it.

C++
if (version.Major >= 5 && version.Minor >= 1) 
{
    // WinXP or later: good to go!?
}

The corrected check is below but was too late to fix the Windows XP applications out there during Vista era.

C++
if (version.Major > 5 || 
   (version.Major == 5 && version.Minor >= 1) )
{
    // WinXP or later
}

To prevent history from repeating itself, Microsoft devised another method of querying the Windows version based on an XML-format manifest file for .NET Framework 4.8 and C++ respectively. The manifest file is embedded in the final executable. .NET6 does not need this manifest file to obtain the correct Windows version. Sadly, it does seem .NET Framework 4.8 and C++ projects are left behind by Microsoft in favor of .NET6.

Manifest Method

In this section, we'll use the code below to explore the XML manifest method to query the Windows version. Click on the C++ tab to see C++ source code if you're a C++ programmer.

C#
using System;

var info = Environment.OSVersion.Version;
Console.WriteLine("Windows Version: {0}.{1}.{2}", 
                  info.Major, info.Minor, info.Build);
C++
#include <Windows.h>

OSVERSIONINFOW osv;
osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
if (GetVersionExW(&osv))
{
    std::cout << "Windows Version: "
              << osv.dwMajorVersion << "." 
              << osv.dwMinorVersion << "." 
              << osv.dwBuildNumber << "\n";
}

This is the version outputted by the above code on a Windows 11 machine. 6.2 is the version of Windows 8.0. Clearly, this is incorrect. Let's add a manifest file to the project to fix it.

Windows Version: 6.2.9200

In the Visual Studio solution, right-click on the C# project name in Solution Explorer and select Add->New Item. A selection dialog comes up and click General and select the Application Manifest File (Windows Only) and enter its filename as app.manifest.

Image 2

For Visual C++, Microsoft did not provide a way to add a manifest file. We'll do this instead: copy the app.manifest from the C# project to the Visual C++ project folder and rename it to manifest.xml and follow these steps to inform Visual C++ of this manifest.xml. Right-click on the C++ project in the Solution Explorer and select Properties and in the Properties Dialog that pops up and click Manifest Tool->Input and Output->Additional Manifest Files and add "manifest.xml".

Image 3

In the manifest file, we'll uncomment the supportedOS for Windows 8.1 by deleting the surrounding <!-- and --> and see its effect.

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

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

Now the code outputs 6.3 which is Windows 8.1 which is still incorrect. Remember my machine is installed with Windows 11.

Windows Version: 6.3.9600

Next, we'll uncomment the supportedOS for Windows 10 to see its effect.

Windows Version: 10.0.22000

Now, this is correct. Windows 10 and 11 share the same major and minor version and Windows 11 is differentiated by its build number, 22000. The manifest method ensures that the application never gets a version higher than what is specified in its manifest. Next, we'll use a Windows kernel function RtlGetVersion to bypass the manifest file to always report the current Windows version without affecting by the presence/absence of manifest.

RTLGetVersion

In our GetVersion, we'll call RtlGetVersion via P/Invoke and check if the build number is 22000. If it is, the major version is updated to 11. For C++ programmers, please click on the C++ tab to see the C++ source code.

C#
public static bool GetVersion(out VersionInfo info)
{
    info.Major = 0;
    info.Minor = 0;
    info.BuildNum = 0;
    OSVERSIONINFOEXW osv = new OSVERSIONINFOEXW();
    osv.dwOSVersionInfoSize = 284;
    if (RtlGetVersion(out osv) == 0)
    {
        info.Major = osv.dwMajorVersion;
        info.Minor = osv.dwMinorVersion;
        info.BuildNum = osv.dwBuildNumber;
        if (osv.dwBuildNumber >= 22000)
            info.Major = 11;
        return true;
    }
    return false;
}
C++
bool WinVersion::GetVersion(VersionInfo& info)
{
	OSVERSIONINFOEXW osv;
	osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
	if (RtlGetVersion(&osv) == 0)
	{
		info.Major = osv.dwMajorVersion;
		info.Minor = osv.dwMinorVersion;
		info.BuildNum = osv.dwBuildNumber;
		if (osv.dwBuildNumber >= 22000)
			info.Major = 11;
		return true;
	}
	return false;
}

This is the .NET6's GetVersion where Windows kernel function RtlGetVersion is not required here because .NET6 Environment.OSVersion.Version gives the correct version without having app.manifest.

C#
public static void GetVersion(out VersionInfo info)
{
    info.Major = Environment.OSVersion.Version.Major;
    info.Minor = Environment.OSVersion.Version.Minor;
    info.BuildNum = Environment.OSVersion.Version.Build;
    if (info.BuildNum >= 22000)
        info.Major = 11;
}

This is how the GetVersion() is used.

C#
if (WinVersion.GetVersion(out var info))
{
    Console.WriteLine("Windows Version: {0}.{1}.{2}", 
                      info.Major, info.Minor, info.BuildNum);
    Console.ReadKey();
}
C++
VersionInfo info;
if (WinVersion::GetVersion(info))
{
    std::cout << "Windows Version : " 
              << info.Major << "." 
              << info.Minor << "." 
              << info.BuildNum << "\n";
}

This is our edited Windows Version.

Windows Version: 11.0.22000

References

History

  • 30th August, 2022: Added IsBuildNumGreaterOrEqual() method in the source code for users who like to detect version via build number.
  • 5th July, 2022: Added the corrected Windows XP check
  • 3rd July, 2022: First release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Singapore Singapore
Shao Voon is from Singapore. CodeProject awarded him an MVP in recognition of his article contributions in 2019. He prefers to write applications based on 3rd party libraries than rolling out his own library. His interest lies primarily in computer graphics, software optimization, concurrency, security, and Agile methodologies.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Member 1370414331-Aug-22 0:45
MemberMember 1370414331-Aug-22 0:45 
QuestionGetting System Version in C# Pin
Mark Gillespie 20226-Jul-22 6:32
MemberMark Gillespie 20226-Jul-22 6:32 
AnswerRe: Getting System Version in C# Pin
Shao Voon Wong6-Jul-22 14:43
mvaShao Voon Wong6-Jul-22 14:43 
GeneralMy vote of 5 Pin
Member 137041434-Jul-22 8:46
MemberMember 137041434-Jul-22 8:46 
QuestionMicrosoft has documented APIs Pin
Scot Brennecke4-Jul-22 5:37
professionalScot Brennecke4-Jul-22 5:37 
AnswerRe: Microsoft has documented APIs Pin
Shao Voon Wong4-Jul-22 15:00
mvaShao Voon Wong4-Jul-22 15:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.