313 lines
9.9 KiB
C++
313 lines
9.9 KiB
C++
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "base/win/windows_version.h"
|
|
|
|
#include <windows.h>
|
|
|
|
#include <memory>
|
|
#include <tuple>
|
|
#include <utility>
|
|
|
|
#include "base/file_version_info_win.h"
|
|
#include "base/files/file_path.h"
|
|
#include "base/logging.h"
|
|
#include "base/no_destructor.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "base/strings/utf_string_conversions.h"
|
|
#include "base/win/registry.h"
|
|
|
|
#if !defined(__clang__) && _MSC_FULL_VER < 191125507
|
|
#error VS 2017 Update 3.2 or higher is required
|
|
#endif
|
|
|
|
#if !defined(NTDDI_WIN10_RS4)
|
|
#error Windows 10.0.17134.0 SDK or higher required.
|
|
#endif
|
|
|
|
namespace base {
|
|
namespace win {
|
|
|
|
namespace {
|
|
|
|
// The values under the CurrentVersion registry hive are mirrored under
|
|
// the corresponding Wow6432 hive.
|
|
constexpr wchar_t kRegKeyWindowsNTCurrentVersion[] =
|
|
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
|
|
|
|
// Returns the "UBR" (Windows 10 patch number) and "ReleaseId" (Windows 10
|
|
// release number) from the registry. "UBR" is an undocumented value and will be
|
|
// 0 if the value was not found. "ReleaseId" will be an empty string if the
|
|
// value is not found.
|
|
std::pair<int, std::string> GetVersionData() {
|
|
DWORD ubr = 0;
|
|
std::wstring release_id;
|
|
RegKey key;
|
|
|
|
if (key.Open(HKEY_LOCAL_MACHINE, kRegKeyWindowsNTCurrentVersion,
|
|
KEY_QUERY_VALUE) == ERROR_SUCCESS) {
|
|
key.ReadValueDW(L"UBR", &ubr);
|
|
key.ReadValue(L"ReleaseId", &release_id);
|
|
}
|
|
|
|
return std::make_pair(static_cast<int>(ubr), WideToUTF8(release_id));
|
|
}
|
|
|
|
const _SYSTEM_INFO& GetSystemInfoStorage() {
|
|
static const NoDestructor<_SYSTEM_INFO> system_info([] {
|
|
_SYSTEM_INFO info = {};
|
|
::GetNativeSystemInfo(&info);
|
|
return info;
|
|
}());
|
|
return *system_info;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// static
|
|
OSInfo** OSInfo::GetInstanceStorage() {
|
|
// Note: we don't use the Singleton class because it depends on AtExitManager,
|
|
// and it's convenient for other modules to use this class without it.
|
|
static OSInfo* info = []() {
|
|
_OSVERSIONINFOEXW version_info = {sizeof(version_info)};
|
|
::GetVersionEx(reinterpret_cast<_OSVERSIONINFOW*>(&version_info));
|
|
|
|
DWORD os_type = 0;
|
|
::GetProductInfo(version_info.dwMajorVersion, version_info.dwMinorVersion,
|
|
0, 0, &os_type);
|
|
|
|
return new OSInfo(version_info, GetSystemInfoStorage(), os_type);
|
|
}();
|
|
|
|
return &info;
|
|
}
|
|
|
|
// static
|
|
OSInfo* OSInfo::GetInstance() {
|
|
return *GetInstanceStorage();
|
|
}
|
|
|
|
// static
|
|
OSInfo::WindowsArchitecture OSInfo::GetArchitecture() {
|
|
switch (GetSystemInfoStorage().wProcessorArchitecture) {
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
return X86_ARCHITECTURE;
|
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
|
return X64_ARCHITECTURE;
|
|
case PROCESSOR_ARCHITECTURE_IA64:
|
|
return IA64_ARCHITECTURE;
|
|
case PROCESSOR_ARCHITECTURE_ARM64:
|
|
return ARM64_ARCHITECTURE;
|
|
default:
|
|
return OTHER_ARCHITECTURE;
|
|
}
|
|
}
|
|
|
|
OSInfo::OSInfo(const _OSVERSIONINFOEXW& version_info,
|
|
const _SYSTEM_INFO& system_info,
|
|
int os_type)
|
|
: version_(Version::PRE_XP),
|
|
wow64_status_(GetWOW64StatusForProcess(GetCurrentProcess())) {
|
|
version_number_.major = version_info.dwMajorVersion;
|
|
version_number_.minor = version_info.dwMinorVersion;
|
|
version_number_.build = version_info.dwBuildNumber;
|
|
std::tie(version_number_.patch, release_id_) = GetVersionData();
|
|
version_ = MajorMinorBuildToVersion(
|
|
version_number_.major, version_number_.minor, version_number_.build);
|
|
service_pack_.major = version_info.wServicePackMajor;
|
|
service_pack_.minor = version_info.wServicePackMinor;
|
|
service_pack_str_ = WideToUTF8(version_info.szCSDVersion);
|
|
|
|
processors_ = system_info.dwNumberOfProcessors;
|
|
allocation_granularity_ = system_info.dwAllocationGranularity;
|
|
|
|
if (version_info.dwMajorVersion == 6 || version_info.dwMajorVersion == 10) {
|
|
// Only present on Vista+.
|
|
switch (os_type) {
|
|
case PRODUCT_CLUSTER_SERVER:
|
|
case PRODUCT_DATACENTER_SERVER:
|
|
case PRODUCT_DATACENTER_SERVER_CORE:
|
|
case PRODUCT_ENTERPRISE_SERVER:
|
|
case PRODUCT_ENTERPRISE_SERVER_CORE:
|
|
case PRODUCT_ENTERPRISE_SERVER_IA64:
|
|
case PRODUCT_SMALLBUSINESS_SERVER:
|
|
case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
|
|
case PRODUCT_STANDARD_SERVER:
|
|
case PRODUCT_STANDARD_SERVER_CORE:
|
|
case PRODUCT_WEB_SERVER:
|
|
version_type_ = SUITE_SERVER;
|
|
break;
|
|
case PRODUCT_PROFESSIONAL:
|
|
case PRODUCT_ULTIMATE:
|
|
version_type_ = SUITE_PROFESSIONAL;
|
|
break;
|
|
case PRODUCT_ENTERPRISE:
|
|
case PRODUCT_ENTERPRISE_E:
|
|
case PRODUCT_ENTERPRISE_EVALUATION:
|
|
case PRODUCT_ENTERPRISE_N:
|
|
case PRODUCT_ENTERPRISE_N_EVALUATION:
|
|
case PRODUCT_ENTERPRISE_S:
|
|
case PRODUCT_ENTERPRISE_S_EVALUATION:
|
|
case PRODUCT_ENTERPRISE_S_N:
|
|
case PRODUCT_ENTERPRISE_S_N_EVALUATION:
|
|
case PRODUCT_BUSINESS:
|
|
case PRODUCT_BUSINESS_N:
|
|
version_type_ = SUITE_ENTERPRISE;
|
|
break;
|
|
case PRODUCT_EDUCATION:
|
|
case PRODUCT_EDUCATION_N:
|
|
version_type_ = SUITE_EDUCATION;
|
|
break;
|
|
case PRODUCT_HOME_BASIC:
|
|
case PRODUCT_HOME_PREMIUM:
|
|
case PRODUCT_STARTER:
|
|
default:
|
|
version_type_ = SUITE_HOME;
|
|
break;
|
|
}
|
|
} else if (version_info.dwMajorVersion == 5 &&
|
|
version_info.dwMinorVersion == 2) {
|
|
if (version_info.wProductType == VER_NT_WORKSTATION &&
|
|
system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
|
|
version_type_ = SUITE_PROFESSIONAL;
|
|
} else if (version_info.wSuiteMask & VER_SUITE_WH_SERVER) {
|
|
version_type_ = SUITE_HOME;
|
|
} else {
|
|
version_type_ = SUITE_SERVER;
|
|
}
|
|
} else if (version_info.dwMajorVersion == 5 &&
|
|
version_info.dwMinorVersion == 1) {
|
|
if (version_info.wSuiteMask & VER_SUITE_PERSONAL)
|
|
version_type_ = SUITE_HOME;
|
|
else
|
|
version_type_ = SUITE_PROFESSIONAL;
|
|
} else {
|
|
// Windows is pre XP so we don't care but pick a safe default.
|
|
version_type_ = SUITE_HOME;
|
|
}
|
|
}
|
|
|
|
OSInfo::~OSInfo() = default;
|
|
|
|
Version OSInfo::Kernel32Version() const {
|
|
static const Version kernel32_version =
|
|
MajorMinorBuildToVersion(Kernel32BaseVersion().components()[0],
|
|
Kernel32BaseVersion().components()[1],
|
|
Kernel32BaseVersion().components()[2]);
|
|
return kernel32_version;
|
|
}
|
|
|
|
Version OSInfo::UcrtVersion() const {
|
|
auto ucrt_version_info = FileVersionInfoWin::CreateFileVersionInfoWin(
|
|
FilePath(FILE_PATH_LITERAL("ucrtbase.dll")));
|
|
if (ucrt_version_info) {
|
|
auto ucrt_components = ucrt_version_info->GetFileVersion().components();
|
|
if (ucrt_components.size() == 4) {
|
|
return MajorMinorBuildToVersion(ucrt_components[0], ucrt_components[1],
|
|
ucrt_components[2]);
|
|
}
|
|
}
|
|
return Version();
|
|
}
|
|
|
|
// Retrieve a version from kernel32. This is useful because when running in
|
|
// compatibility mode for a down-level version of the OS, the file version of
|
|
// kernel32 will still be the "real" version.
|
|
base::Version OSInfo::Kernel32BaseVersion() const {
|
|
static const NoDestructor<base::Version> version([] {
|
|
std::unique_ptr<FileVersionInfoWin> file_version_info =
|
|
FileVersionInfoWin::CreateFileVersionInfoWin(
|
|
FilePath(FILE_PATH_LITERAL("kernel32.dll")));
|
|
if (!file_version_info) {
|
|
// crbug.com/912061: on some systems it seems kernel32.dll might be
|
|
// corrupted or not in a state to get version info. In this case try
|
|
// kernelbase.dll as a fallback.
|
|
file_version_info = FileVersionInfoWin::CreateFileVersionInfoWin(
|
|
FilePath(FILE_PATH_LITERAL("kernelbase.dll")));
|
|
}
|
|
CHECK(file_version_info);
|
|
return file_version_info->GetFileVersion();
|
|
}());
|
|
return *version;
|
|
}
|
|
|
|
std::string OSInfo::processor_model_name() {
|
|
if (processor_model_name_.empty()) {
|
|
const wchar_t kProcessorNameString[] =
|
|
L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
|
|
RegKey key(HKEY_LOCAL_MACHINE, kProcessorNameString, KEY_READ);
|
|
std::wstring value;
|
|
key.ReadValue(L"ProcessorNameString", &value);
|
|
processor_model_name_ = WideToUTF8(value);
|
|
}
|
|
return processor_model_name_;
|
|
}
|
|
|
|
// static
|
|
OSInfo::WOW64Status OSInfo::GetWOW64StatusForProcess(HANDLE process_handle) {
|
|
BOOL is_wow64 = FALSE;
|
|
if (!::IsWow64Process(process_handle, &is_wow64))
|
|
return WOW64_UNKNOWN;
|
|
return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED;
|
|
}
|
|
|
|
// With the exception of Server 2003, server variants are treated the same as
|
|
// the corresponding workstation release.
|
|
// static
|
|
Version OSInfo::MajorMinorBuildToVersion(int major, int minor, int build) {
|
|
if (major == 10) {
|
|
if (build >= 19041)
|
|
return Version::WIN10_20H1;
|
|
if (build >= 18362)
|
|
return Version::WIN10_19H1;
|
|
if (build >= 17763)
|
|
return Version::WIN10_RS5;
|
|
if (build >= 17134)
|
|
return Version::WIN10_RS4;
|
|
if (build >= 16299)
|
|
return Version::WIN10_RS3;
|
|
if (build >= 15063)
|
|
return Version::WIN10_RS2;
|
|
if (build >= 14393)
|
|
return Version::WIN10_RS1;
|
|
if (build >= 10586)
|
|
return Version::WIN10_TH2;
|
|
return Version::WIN10;
|
|
}
|
|
|
|
if (major > 6) {
|
|
// Hitting this likely means that it's time for a >10 block above.
|
|
NOTREACHED() << major << "." << minor << "." << build;
|
|
return Version::WIN_LAST;
|
|
}
|
|
|
|
if (major == 6) {
|
|
switch (minor) {
|
|
case 0:
|
|
return Version::VISTA;
|
|
case 1:
|
|
return Version::WIN7;
|
|
case 2:
|
|
return Version::WIN8;
|
|
default:
|
|
DCHECK_EQ(minor, 3);
|
|
return Version::WIN8_1;
|
|
}
|
|
}
|
|
|
|
if (major == 5 && minor != 0) {
|
|
// Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003.
|
|
return minor == 1 ? Version::XP : Version::SERVER_2003;
|
|
}
|
|
|
|
// Win 2000 or older.
|
|
return Version::PRE_XP;
|
|
}
|
|
|
|
Version GetVersion() {
|
|
return OSInfo::GetInstance()->version();
|
|
}
|
|
|
|
} // namespace win
|
|
} // namespace base
|