Click here to Skip to main content
15,904,155 members
Articles / Programming Languages / C#

Windows Version Detection

Rate me:
Please Sign up or sign in to vote.
4.88/5 (50 votes)
1 Sep 2023CPOL5 min read 74.7K   3.2K   63   50
Windows Version Detection using C# and C++
In this article, you will see how to detect Windows version with 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. 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;

        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;

		return true;
	}
	return false;
}

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 the Windows 11 version.

Windows Version: 10.0.22000

Windows Version Retrieval Hack

In the Windows Native API Programming book by Pavel Yosifovich, it is mentioned a method to get the Windows version through the KUSER_SHARED_DATA struct located at 0x7ffe0000 address in every process. For more information about KUSER_SHARED_DATA, read this MSDN link. KUSER_SHARED_DATA is located in <ntddk.h> that comes with Windows Driver Development Kit (DDK). You must install the DDK to compile the code snippet below.

C++
// Requires installation of the Windows Driver Development Kit (ddk)
#include <ntddk.h>
#include <cstdio>

int main()
{
    auto data = (KUSER_SHARED_DATA*)0x7ffe0000;
    printf("Version: %d.%d.%d\n",
    data->NtMajorVersion, data->NtMinorVersion, data->NtBuildNumber);

    return 0;
}

Since I do not have DDK installed on my system. Fortunately, I found this code snippet in Windows 10 System Programming, Part 1 book, also written by same author. This code does not rely on KUSER_SHARED_DATA but the address offsets to its structure members. It compiles and works fine on my Visual C++ 2022.

C++
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <cstdio>

int main()
{
    auto sharedUserData = (BYTE*)0x7FFE0000;
    printf("Version: %d.%d.%d\n",
        *(ULONG*)(sharedUserData + 0x26c),  // major version offset
        *(ULONG*)(sharedUserData + 0x270),  // minor version offset
        *(ULONG*)(sharedUserData + 0x260)); // build number offset

    return 0;
}

The program output is 10.0.22621 which is correct on my Windows 11 22H2.

Version: 10.0.22621

Update: I completed my 32-bit and 64-bit testing of this hack. On Windows XP, Vista, 7, 8 and 8.1, the build number is an invalid zero while it is valid on Windows 10 and 11. Just beware not to rely on the build number on the Windows OS older than 10 if you use this hack.

References

History

  • 2nd September, 2023: Remove the Windows 11 build number check to set major version to 11.
  • 27th August, 2023: Added testing results of 32-bit and 64-bit Windows OSes to Windows Version Retrieval Hack section
  • 30th July, 2023: Added Windows Version Retrieval Hack section
  • 20th April, 2023: Fixed IsBuildNumGreaterOrEqual() bug and added Windows BuildNumber enum for IsBuildNumGreaterOrEqual()
  • 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. His interest lies primarily in computer graphics, software optimization, concurrency, security, and Agile methodologies.

In recent years, he shifted focus to software safety research. His hobby is writing a free C++ DirectX photo slideshow application which can be viewed here.

Comments and Discussions

 
QuestionCrash on Windows 7 SP1 when built with .Net 3.5 Pin
kmackey25-Oct-23 13:33
kmackey25-Oct-23 13:33 
AnswerRe: Crash on Windows 7 SP1 when built with .Net 3.5 Pin
Shao Voon Wong25-Oct-23 15:26
mvaShao Voon Wong25-Oct-23 15:26 
GeneralRe: Crash on Windows 7 SP1 when built with .Net 3.5 Pin
kmackey26-Oct-23 7:40
kmackey26-Oct-23 7:40 
GeneralRe: Crash on Windows 7 SP1 when built with .Net 3.5 Pin
kmackey3-Nov-23 11:25
kmackey3-Nov-23 11:25 
GeneralRe: Crash on Windows 7 SP1 when built with .Net 3.5 Pin
Shao Voon Wong4-Nov-23 19:20
mvaShao Voon Wong4-Nov-23 19:20 
AnswerWindows Version Detection Pin
rainer erdmann7-Sep-23 7:40
rainer erdmann7-Sep-23 7:40 
GeneralRe: Windows Version Detection Pin
Shao Voon Wong7-Sep-23 15:22
mvaShao Voon Wong7-Sep-23 15:22 
QuestionNice Stuff, but rough edges Pin
Daniel Anderson 202129-Aug-23 12:10
Daniel Anderson 202129-Aug-23 12:10 
AnswerRe: Nice Stuff, but rough edges Pin
Shao Voon Wong29-Aug-23 14:07
mvaShao Voon Wong29-Aug-23 14:07 
AnswerRe: Nice Stuff, but rough edges Pin
Shao Voon Wong1-Sep-23 17:08
mvaShao Voon Wong1-Sep-23 17:08 
Questionmy vote of 5 Pin
Southmountain27-Aug-23 11:52
Southmountain27-Aug-23 11:52 
GeneralMy vote of 3 Pin
lightfinder8-Aug-23 14:05
lightfinder8-Aug-23 14:05 
GeneralMy vote of 5 Pin
t0788717-Aug-23 2:12
t0788717-Aug-23 2:12 
GeneralMy vote of 5 Pin
Michael Haephrati5-Aug-23 7:29
professionalMichael Haephrati5-Aug-23 7:29 
QuestionWhy? Pin
Sergey Alexandrovich Kryukov4-Aug-23 7:41
mvaSergey Alexandrovich Kryukov4-Aug-23 7:41 
AnswerRe: Why? Pin
Shao Voon Wong6-Aug-23 17:09
mvaShao Voon Wong6-Aug-23 17:09 
QuestionRe: Why? Pin
Sergey Alexandrovich Kryukov7-Aug-23 3:17
mvaSergey Alexandrovich Kryukov7-Aug-23 3:17 
AnswerRe: Why? Pin
Jeremy Falcon10-Aug-23 4:22
professionalJeremy Falcon10-Aug-23 4:22 
GeneralRe: Because Pin
Jeremy Falcon10-Aug-23 7:01
professionalJeremy Falcon10-Aug-23 7:01 
GeneralRe: Not arguing... Pin
Jeremy Falcon10-Aug-23 8:51
professionalJeremy Falcon10-Aug-23 8:51 
GeneralMy vote of 5 Pin
Member 465036531-Jul-23 3:35
Member 465036531-Jul-23 3:35 
PraiseThanks Pin
tyjiang24-Apr-23 18:25
tyjiang24-Apr-23 18:25 
QuestionManifest method vs Windows kernel function Pin
Dirk_Strauss24-Apr-23 4:28
professionalDirk_Strauss24-Apr-23 4:28 
How does the manifest method for querying the Windows version in C# and C++ compare to using the Windows kernel function RtlGetVersion, and in what situations would one method be more appropriate than the other?

AnswerRe: Manifest method vs Windows kernel function Pin
Shao Voon Wong24-Apr-23 14:56
mvaShao Voon Wong24-Apr-23 14:56 
Questionmore correct solution Pin
Ivan Gorbachov23-Apr-23 22:04
Ivan Gorbachov23-Apr-23 22:04 

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.