/** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ #include <aws/core/platform/OSVersionInfo.h> #include <aws/core/utils/StringUtils.h> #include <aws/core/utils/memory/stl/AWSStringStream.h> #include <iomanip> #pragma warning(disable: 4996) #include <windows.h> #include <stdio.h> namespace Aws { namespace OSVersionInfo { Aws::String GetSysCommandOutput(const char* command) { Aws::String outputStr; FILE* outputStream; const int maxBufferSize = 256; char outputBuffer[maxBufferSize]; outputStream = _popen(command, "r"); if (outputStream) { while (!feof(outputStream)) { if (fgets(outputBuffer, maxBufferSize, outputStream) != nullptr) { outputStr.append(outputBuffer); } } _pclose(outputStream); return Aws::Utils::StringUtils::Trim(outputStr.c_str()); } return {}; } Aws::String ComputeOSVersionString() { // With the release of Windows 8.1, the behavior of the GetVersionEx API has changed in the value it will return for the operating system version. // The value returned by the GetVersionEx function now depends on how the application is manifested. // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 // // This only works when the application is manifested for Windows 8.1 or 10, which we don't actually care about. // Also, this will cause build headaches for folks not building with VS2015, and is overall an unusable API for us. // The following is the least painful but most reliable hack I can come up with. // // From this article: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724429.aspx // we will do the following: // // To obtain the full version number for the operating system, call the GetFileVersionInfo function on one of the system DLLs, such as Kernel32.dll, // then call VerQueryValue to obtain the \\StringFileInfo\\<lang><codepage>\\ProductVersion subblock of the file version information. // Aws::StringStream ss; ss << "Windows/"; DWORD uselessParameter(0); static const char* FILE_TO_CHECK = "Kernel32.dll"; DWORD fileVersionSize = GetFileVersionInfoSizeA(FILE_TO_CHECK, &uselessParameter); void* blob = Aws::Malloc("OSVersionInfo", static_cast<size_t>(fileVersionSize)); bool versionFound(false); if (GetFileVersionInfoA(FILE_TO_CHECK, 0, fileVersionSize, blob)) { struct LANGANDCODEPAGE { WORD wLanguage; WORD wCodePage; } *lpTranslate; UINT sizeOfCodePage(0); if (VerQueryValueA(blob, "\\VarFileInfo\\Translation", (LPVOID*)&lpTranslate, &sizeOfCodePage)) { //we don't actually care which language pack we get, they should all have the same windows version attached. Aws::StringStream codePageSS; codePageSS << "\\StringFileInfo\\"; codePageSS << std::setfill('0') << std::setw(4) << std::nouppercase << std::hex << lpTranslate[0].wLanguage; codePageSS << std::setfill('0') << std::setw(4) << std::nouppercase << std::hex << lpTranslate[0].wCodePage; codePageSS << "\\ProductVersion"; void* subBlock(nullptr); UINT subBlockSize(0); if (VerQueryValueA(blob, codePageSS.str().c_str(), &subBlock, &subBlockSize)) { ss << static_cast<const char*>(subBlock); versionFound = true; } } } Aws::Free(blob); if (!versionFound) { ss << "Unknown Version"; } SYSTEM_INFO sysInfo; ZeroMemory(&sysInfo, sizeof(SYSTEM_INFO)); GetSystemInfo(&sysInfo); switch (sysInfo.wProcessorArchitecture) { //PROCESSOR_ARCHITECTURE_AMD64 case 0x09: ss << " AMD64"; break; //PROCESSOR_ARCHITECTURE_IA64 case 0x06: ss << " IA64"; break; //PROCESSOR_ARCHITECTURE_INTEL case 0x00: ss << " x86"; break; default: ss << " Unknown Processor Architecture"; break; } return ss.str(); } } // namespace OSVersionInfo } // namespace Aws