Stanislas Dolcini
Stanislas Dolcini

Reputation: 21

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

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!

Upvotes: 1

Views: 3379

Answers (3)

so_sc
so_sc

Reputation: 17

I am able to retrieve the version number properly. Copying my code below. Using windows.h should work instead of sysinfoapi.h

#include<windows.h>
#include<stdio.h>
int main() {
     OSVERSIONINFOEX info;
     ZeroMemory(&info, sizeof(OSVERSIONINFOEX));
     info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
     GetVersionEx((LPOSVERSIONINFO)&info);
     printf("Windows version: %u.%u\n", info.dwMajorVersion, info.dwMinorVersion);
}

Alternate way to read version number is to use GetProcAddress. 'GetProcAddress' returns the address of specified DLL function.

#include<iostream>
#include<string>
#include <windows.h>
using namespace std;
void main() {
   int osver= 0.0;
   NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOEXW);
   OSVERSIONINFOEXW osInfo;
   *(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");    
     if (NULL != RtlGetVersion) {
            osInfo.dwOSVersionInfoSize = sizeof(osInfo);
            RtlGetVersion(&osInfo);
            osver = osInfo.dwMajorVersion;
      }
}

Upvotes: -1

Denis B
Denis B

Reputation: 56

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.

Upvotes: 2

LancesLance
LancesLance

Reputation: 170

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

Upvotes: 2

Related Questions