С++ Как обнаружить Windows 10

Я много лет назад написал инструмент аудита ПК и постоянно его обновляю. Одной из основных функций является сообщение о версии Windows, выполняемой на проверяемом ПК, для которого я всегда использовал вызов GetVersionEx.

Это работает до Windows 8, включая Windows 8, но не поддерживается в Windows 10, и действительно, Windows 10 возвращает 8.2, как это делает Windows 8. Microsoft, похоже, не представила ничего в качестве прямой замены, предлагая вместо этого, что вы проверяете определенные функции, а не смотрите на ОС, но для целей аудита я действительно хочу имя ОС.

"Сканер" - это программа на С++, которая должна запускаться под не-привилегированными учетными записями, поэтому я не думаю, что другое предложение, которое я прочитал, - поиск версии системной DLL, такой как kernel32.dll, будет работать, поскольку эти папки обычно недоступным для пользователей.

Любые другие предложения/мысли приветствуются!

Ответы

Ответ 1

GetVersion и GetVersionEx заменялись различными вспомогательными функциями версии. Вы хотите IsWindows10OrGreater. Их можно найти в VersionHelpers.h.

IsWindows10OrGreater доступен только в последней версии SDK/Visual Studio 2015. Однако вы можете использовать IsWindowsVersionOrGreater в общем случае. Например, в моем ящике 7 я получаю TRUE для IsWindowsVersionOrGreater (6, 0, 0).

Помните, что параметры, которые эта функция принимает, относятся к номеру сборки Windows и НЕму маркетинговому названию. Так что Windows 8 - это сборка 6.2. Windows 7 6.0 и т.д.

Ответ 2

Начиная с Windows 8.1, GetVersion() и GetVersionEx() подлежат заявлению:

С выпуском Windows 8.1 поведение API GetVersionEx изменилось в значении, которое оно вернет для версии операционной системы. Значение, возвращаемое функцией GetVersionEx, теперь зависит от того, как проявляется приложение.

Приложения, которые не отображаются для Windows 8.1 или Windows 10, вернут значение версии ОС Windows 8 (6.2). Как только приложение проявляется для данной версии операционной системы, GetVersionEx всегда будет возвращать версию, в которой приложение проявляется в будущих выпусках. Чтобы продемонстрировать свои приложения для Windows 8.1 или Windows 10, обратитесь к Ориентация на приложение для Windows.

Более новые Функции Версии 1.0 являются просто обертками для VerifyVersionInfo(). Начиная с Windows 10, теперь он также проявляется:

Windows 10: VerifyVersionInfo возвращает false при вызове приложениями, которые не имеют манифеста совместимости для Windows 8.1 или Windows 10, если параметр lpVersionInfo установлен так, чтобы он указывал Windows 8.1 или Windows 10, даже если текущий версия операционной системы - Windows 8.1 или Windows 10. В частности, VerifyVersionInfo имеет следующее поведение:

  • Если приложение не имеет манифеста, VerifyVersionInfo ведет себя так, как если бы операционная система была версией Windows 8 (6.2).
  • Если приложение имеет манифест, содержащий GUID, соответствующий Windows 8.1, VerifyVersionInfo ведет себя так, как если бы операционная система была версией Windows 8.1 (6.3).
  • Если приложение имеет манифест, содержащий GUID, соответствующий Windows 10, VerifyVersionInfo ведет себя так, как если бы операционная система была версией Windows 10 (10.0).

Функции Версии используют функцию VerifyVersionInfo, поэтому поведение IsWindows8Point1OrGreater и IsWindows10OrGreater также влияют присутствие и содержимое манифеста.

Чтобы продемонстрировать свои приложения для Windows 8.1 или Windows 10, см. Ориентация на приложение для Windows.

Чтобы получить версию ОС true независимо от ее проявления, Microsoft предлагает запросить версию файла для системной DLL:

Получение версии системы

Чтобы получить полный номер версии для операционной системы, вызовите функцию GetFileVersionInfo в одной из системных DLL, например Kernel32.dll, затем вызовите VerQueryValue, чтобы получить субблок \\StringFileInfo\\<lang><codepage>\\ProductVersion информации о версии файла.

Другой способ - использовать RtlGetVersion(), NetServerGetInfo(), или NetWkstaGetInfo(). Они все сообщают точную версию ОС и не подлежат манифестации (пока?).

Ответ 3

Мне нужно было это для работы с более старой версией компилятора VS и более в рамках Qt. Вот как я это сделал.

Добавьте этот файл GetWinVersion.h в свой проект Qt:

#ifndef GETWINVERSION
#define GETWINVERSION

#include <QtGlobal>

#ifdef Q_OS_WIN

#include <windows.h>
#include <stdio.h>

float GetWinVersion()
{
    OSVERSIONINFO osvi;
    ZeroMemory( &osvi, sizeof(OSVERSIONINFO) );
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    return GetVersionEx( &osvi ) ?
           (float)osvi.dwMajorVersion +
           ((float)osvi.dwMinorVersion/10) :
           0.0 ;
}

#endif //Q_OS_WIN

#endif // GETWINVERSION

Добавьте необходимую ссылку в файл pro или pri qmake:

msvc: LIBS += -lKernel32

Реализовать вспомогательную функцию, например, (обратите внимание, что SystemInfo, используемая здесь, является моим собственным классом, но вы получаете идею...):

#include "GetWinVersion.h"

SystemInfo info;

#ifdef Q_OS_WIN
    info.setPlatform( SystemInfo::WINDOWS );
    switch(QSysInfo::windowsVersion())
    {
    case QSysInfo::WV_32s:        info.setOsName( L"3.1" );     info.setOsVersion( 3.1 ); break;
    case QSysInfo::WV_95:         info.setOsName( L"95" );      info.setOsVersion( 4.0 ); break;
    case QSysInfo::WV_98:         info.setOsName( L"98" );      info.setOsVersion( 4.1 ); break;
    case QSysInfo::WV_Me:         info.setOsName( L"Me" );      info.setOsVersion( 4.9 ); break;
    case QSysInfo::WV_NT:         info.setOsName( L"NT" );      info.setOsVersion( 4.0 ); break;
    case QSysInfo::WV_2000:       info.setOsName( L"2000" );    info.setOsVersion( 5.0 ); break;
    case QSysInfo::WV_XP:         info.setOsName( L"XP" );      info.setOsVersion( 5.1 ); break;
    case QSysInfo::WV_2003:       info.setOsName( L"2003" );    info.setOsVersion( 5.2 ); break;  // Windows Server 2003, Windows Server 2003 R2, Windows Home Server, Windows XP Professional x64 Edition
    case QSysInfo::WV_VISTA:      info.setOsName( L"Vista" );   info.setOsVersion( 6.0 ); break;  // Windows Vista, Windows Server 2008
    case QSysInfo::WV_WINDOWS7:   info.setOsName( L"7" );       info.setOsVersion( 6.1 ); break;  // Windows 7, Windows Server 2008 R2
    case QSysInfo::WV_WINDOWS8:   info.setOsName( L"8" );       info.setOsVersion( 6.2 ); break;  // Windows 8, Windows Server 2012
  // These cases are never reached due to Windows api changes
  // As of Qt 5.5, this not accounted for by QSysInfo::windowsVersion()
  //case QSysInfo::WV_WINDOWS8_1: info.setOsName( L"8.1" );     info.setOsVersion( 6.3 ); break;  // Windows 8.1, Windows Server 2012 R2
  //case QSysInfo::WV_WINDOWS10:  info.setOsName( L"10" );      info.setOsVersion( 10.0 ); break; // Windows 10, Windows Server 2016
    default:
        // On Windows 8.1 & 10, this will only work when the exe
        // contains a manifest which targets the specific OS's
        // you wish to detect.  Else 6.2 (ie. Win 8.0 is returned)
        info.setOsVersion( GetWinVersion() );
        if(      info.osVersion() == 6.3f )  // Windows 8.1, Windows Server 2012 R2
            info.setOsName( L"8.1" );
        else if( info.osVersion() == 10.0f ) // Windows 10, Windows Server 2016
            info.setOsName( L"10" );
        else
            info.setOsName( L"UNKNOWN" );
    }
    info.setOsBits( IsWow64() ? 64 : 32 );
#else
...

Теперь вот настоящий ключ. Вам необходимо прикрепить файл манифеста к вашему exe, который будет "нацелен" на последние версии Windows, иначе вы не сможете их обнаружить (см. Документы MS: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451%28v=vs.85%29.aspx). Вот пример, чтобы сделать это:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity 
        name="MyOrg.MyDept.MyAppName" 
        version="1.0.0.0" 
        processorArchitecture="x86" 
        type="win32" />
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
        <application> 
            <!-- Windows 10 --> 
            <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>
</assembly>

А вот какая-то партия для прикрепления манифеста:

set exeFile=MyApp.exe
set manifestFile=MyApp.manifest
set manifestExe=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\x64\mt.exe

"%manifestExe%" -manifest "%manifestFile%" -outputresource:"%exeFile%"

В теории вы можете использовать qmake для запуска этого последнего бита с манифестом. Мне не повезло с примерами, которые я нашел, и просто "обманул" эту партию на данный момент...