Обнаружение версии Windows 10
Моя цель - обнаружить Windows 10 в моем коде, который должен работать как в кросс-платформенной, так и в разных версиях Windows (по крайней мере, 7 и выше). Windows предоставляет IsWindows10OrGreater()
для решения этой проблемы, но есть и другая проблема с ней, эта функция отсутствует в предыдущих версиях Windows.
Вы найдете бесчисленные блоги и SO-вопросы, касающиеся этого, а также манифестное безумие, где такие функции, как this и getversion, и другие возвращают некоторую другую версию, а не правильную.
Например, на моей машине - метод IsWindows10OrGreater()
не компилируется (я должен был установить Win10 SDK), а IsWindowsVersionOrGreater()
сообщает 6
в качестве основной версии.
Итак, есть ли разумный способ с несколькими версиями, я мог бы решить эту проблему?
Ответы
Ответ 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, ¤tVersion) != 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;
}