Detecting Windows 11 properly

I'm a developper from the FOSS game 0 A.D. (https://play0ad.com) and I recently realised that our detection of the Windows version was failing for Windows 11, just like it did between Windows 8.1 and Windows 10.

It reports Windows 10.0.22000 which is technically the correct version, but we'd like it to report Windows 11 instead.

Here is the current code we use

  • https://github.com/0ad/0ad/blob/master/source/lib/sysdep/os/win/wposix/wutsname.cpp#L35
  • https://github.com/0ad/0ad/blob/master/source/lib/sysdep/os/win/wversion.cpp
  • https://github.com/0ad/0ad/blob/master/source/lib/sysdep/os/win/wversion.h

We're stuck with the Windows 7 SDK for compatibility reasons.

Easy solution would be to replace

    if (osInfo.dwMajorVersion >= 10)
    {
        stream << "Win" << osInfo.dwMajorVersion;
    }

by

    if (osInfo.dwMajorVersion >= 10)
    {
        if (osInfo.dwMinorVersion > 22000)
            stream << "Win" << 11;
        else
            stream << "Win" << osInfo.dwMajorVersion;
    }

Is there a more robust/future proof solution.

Thanks in advance!


Solution 1:

I'm not sure if this will work, but can you give this code a try? It uses the sysinfoapi.h file. According to the docs, it only works on Windows though.

#include <iostream>
#include <sysinfoapi.h>

void print_os_info()
{
    OSVERSIONINFOEX info;
    ZeroMemory(&info, sizeof(OSVERSIONINFOEX));
    info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

    GetVersionEx((LPOSVERSIONINFO)&info);

    printf("Windows version: %u.%u\n", info.dwMajorVersion, info.dwMinorVersion);
}

int main()
{
    print_os_info();
}

EDIT: Apparently applications not manifested for Windows 8.1 or Windows 10 will return the Windows 8 OS version value (6.2) according the the sysinfoapi.h docs\

EDIT AGAIN: I tried using a $(Filename).exe.manifest file with the contents

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <assemblyIdentity
        type="win32"
        name="Contoso.ExampleApplication.ExampleBinary"
        version="1.2.3.4"
        processorArchitecture="x86"
    />
    <description>Contoso Example Application</description>
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
            <!-- Windows 10 and Windows 11 -->
            <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
            <!-- Windows 8.1 -->
            <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
            <!-- Windows 8 -->
            <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
            <!-- Windows 7 -->
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
            <!-- Windows Vista -->
            <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> 
        </application>
    </compatibility>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedPrivileges>
                <!--
                  UAC settings:
                  - app should run at same integrity level as calling process
                  - app does not need to manipulate windows belonging to
                    higher-integrity-level processes
                  -->
                <requestedExecutionLevel
                    level="asInvoker"
                    uiAccess="false"
                />   
            </requestedPrivileges>
        </security>
    </trustInfo>
</assembly>

Which for me worked and made it print out Windows 10.0 instead of 6.2
Sources: Manifest File, sysinfoapi.h

Solution 2:

Except the very weak, atleast for me, solution of considering Windows 10 builds greater than 22000, such as Windows 11, the only solution I found which is actually working is the WMIs Win32_OperatingSystem class - Caption property.

On my dev Windows 10 machine it gives the following string: Microsoft Windows 10 Pro.

On my other dev machine, with Windows 11 installed, the same function gives: Microsoft Windows 11 Pro.

The difference is in the string values - "10" vs "11" - but this is at least something far better than the "build greater than" solution.

C# and C++ work well.