Подтвердить что ты не робот

Обнаружение версии Windows 10

Моя цель - обнаружить Windows 10 в моем коде, который должен работать как в кросс-платформенной, так и в разных версиях Windows (по крайней мере, 7 и выше). Windows предоставляет IsWindows10OrGreater() для решения этой проблемы, но есть и другая проблема с ней, эта функция отсутствует в предыдущих версиях Windows.

Вы найдете бесчисленные блоги и SO-вопросы, касающиеся этого, а также манифестное безумие, где такие функции, как this и getversion, и другие возвращают некоторую другую версию, а не правильную.

Например, на моей машине - метод IsWindows10OrGreater() не компилируется (я должен был установить Win10 SDK), а IsWindowsVersionOrGreater() сообщает 6 в качестве основной версии.

Итак, есть ли разумный способ с несколькими версиями, я мог бы решить эту проблему?

4b9b3361

Ответ 1

Самый простой способ получить истинную версию ОС - вызвать RtlGetVersion. Это то, что GetVersionEx и VerifyVersionInfo вызывают, но не использует прокладки совместимости.

Вы можете либо использовать DDK (#include <ntddk.h> и связать его с NtosKrnl.lib из режима ядра, либо ntdll.lib из пользовательского режима), либо использовать динамическое связывание во время выполнения, как показано в следующем фрагменте:

typedef LONG NTSTATUS, *PNTSTATUS;
#define STATUS_SUCCESS (0x00000000)

typedef NTSTATUS (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);

RTL_OSVERSIONINFOW GetRealOSVersion() {
    HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
    if (hMod) {
        RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
        if (fxPtr != nullptr) {
            RTL_OSVERSIONINFOW rovi = { 0 };
            rovi.dwOSVersionInfoSize = sizeof(rovi);
            if ( STATUS_SUCCESS == fxPtr(&rovi) ) {
                return rovi;
            }
        }
    }
    RTL_OSVERSIONINFOW rovi = { 0 };
    return rovi;
}

В случае, если вам нужна дополнительная информация вы можете передать RTL_OSVERSIONINFOEXW структуру вместо RTL_OSVERSIONINFOW структуры (правильно назначая элемент dwOSVersionInfoSize).

Это возвращает ожидаемый результат в Windows 10, даже если нет прикрепленного манифеста.


Кроме того, общепринятым считается лучшее решение для предоставления различных реализаций, основанных на доступных функциях, а не версиях ОС.

Ответ 2

IsWindows10OrGreater() от VersionHelpers.h

Отметьте заметки в Функции поддержки версий на MSDN

Файл VersionHelpers.h поставляется с Windows 10 SDK, но он будет работать и в предыдущих версиях. Просто скопируйте его в среду разработки.

Это только ограниченная заголовком небольшая библиотека, которая использует функции VerSetConditionMask и VerifyVersionInfoW, доступные в WinAPI с Windows 2000.

Обновление. Если вы не можете включить файл манифеста с исходным кодом, вы можете использовать простой хак: просто получите версию любой системной dll, например, kernel32.dll с помощью функции GetFileVersionInfo.

Ответ 3

Вы можете прочитать реальный номер сборки из реестра, а затем вывести из него версию Windows. Вашему приложению не нужно иметь манифест для этой работы: на моей машине он правильно определяет номер сборки ОС как 10586. Например:

#include <Windows.h>
#include <sstream>

struct HKeyHolder
{
private:
    HKEY m_Key;

public:
    HKeyHolder() :
        m_Key(nullptr)
    {
    }

    HKeyHolder(const HKeyHolder&) = delete;
    HKeyHolder& operator=(const HKeyHolder&) = delete;

    ~HKeyHolder()
    {
        if (m_Key != nullptr)
            RegCloseKey(m_Key);
    }

    operator HKEY() const
    {
        return m_Key;
    }

    HKEY* operator&()
    {
        return &m_Key;
    }
};

bool IsRunningOnWindows10()
{
    HKeyHolder currentVersion;
    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", 0, KEY_QUERY_VALUE, &currentVersion) != ERROR_SUCCESS)
        return false;

    DWORD valueType;
    BYTE buffer[256];
    DWORD bufferSize = 256;

    if (RegQueryValueExW(currentVersion, L"CurrentBuild", nullptr, &valueType, buffer, &bufferSize) != ERROR_SUCCESS)
        return false;

    if (valueType != REG_SZ)
        return false;

    int version;
    std::wistringstream versionStream(reinterpret_cast<wchar_t*>(buffer));
    versionStream >> version;

    return version > 9800;
}