aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc')
-rw-r--r--src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc252
1 files changed, 252 insertions, 0 deletions
diff --git a/src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc b/src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc
new file mode 100644
index 0000000000..d89b00d838
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc
@@ -0,0 +1,252 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "WindowsVersion.h"
+
+#include <windows.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <tuple>
+
+#include "DebugClient.h"
+#include "OsModule.h"
+#include "StringBuilder.h"
+#include "StringUtil.h"
+#include "WinptyAssert.h"
+#include "WinptyException.h"
+
+namespace {
+
+typedef std::tuple<DWORD, DWORD> Version;
+
+// This function can only return a version up to 6.2 unless the executable is
+// manifested for a newer version of Windows. See the MSDN documentation for
+// GetVersionEx.
+OSVERSIONINFOEX getWindowsVersionInfo() {
+ // Allow use of deprecated functions (i.e. GetVersionEx). We need to use
+ // GetVersionEx for the old MinGW toolchain and with MSVC when it targets XP.
+ // Having two code paths makes code harder to test, and it's not obvious how
+ // to detect the presence of a new enough SDK. (Including ntverp.h and
+ // examining VER_PRODUCTBUILD apparently works, but even then, MinGW-w64 and
+ // MSVC seem to use different version numbers.)
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4996)
+#endif
+ OSVERSIONINFOEX info = {};
+ info.dwOSVersionInfoSize = sizeof(info);
+ const auto success = GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&info));
+ ASSERT(success && "GetVersionEx failed");
+ return info;
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+}
+
+Version getWindowsVersion() {
+ const auto info = getWindowsVersionInfo();
+ return Version(info.dwMajorVersion, info.dwMinorVersion);
+}
+
+struct ModuleNotFound : WinptyException {
+ virtual const wchar_t *what() const WINPTY_NOEXCEPT override {
+ return L"ModuleNotFound";
+ }
+};
+
+// Throws WinptyException on error.
+std::wstring getSystemDirectory() {
+ wchar_t systemDirectory[MAX_PATH];
+ const UINT size = GetSystemDirectoryW(systemDirectory, MAX_PATH);
+ if (size == 0) {
+ throwWindowsError(L"GetSystemDirectory failed");
+ } else if (size >= MAX_PATH) {
+ throwWinptyException(
+ L"GetSystemDirectory: path is longer than MAX_PATH");
+ }
+ return systemDirectory;
+}
+
+#define GET_VERSION_DLL_API(name) \
+ const auto p ## name = \
+ reinterpret_cast<decltype(name)*>( \
+ versionDll.proc(#name)); \
+ if (p ## name == nullptr) { \
+ throwWinptyException(L ## #name L" is missing"); \
+ }
+
+// Throws WinptyException on error.
+VS_FIXEDFILEINFO getFixedFileInfo(const std::wstring &path) {
+ // version.dll is not a conventional KnownDll, so if we link to it, there's
+ // a danger of accidentally loading a malicious DLL. In a more typical
+ // application, perhaps we'd guard against this security issue by
+ // controlling which directories this code runs in (e.g. *not* the
+ // "Downloads" directory), but that's harder for the winpty library.
+ OsModule versionDll(
+ (getSystemDirectory() + L"\\version.dll").c_str(),
+ OsModule::LoadErrorBehavior::Throw);
+ GET_VERSION_DLL_API(GetFileVersionInfoSizeW);
+ GET_VERSION_DLL_API(GetFileVersionInfoW);
+ GET_VERSION_DLL_API(VerQueryValueW);
+ DWORD size = pGetFileVersionInfoSizeW(path.c_str(), nullptr);
+ if (!size) {
+ // I see ERROR_FILE_NOT_FOUND on Win7 and
+ // ERROR_RESOURCE_DATA_NOT_FOUND on WinXP.
+ if (GetLastError() == ERROR_FILE_NOT_FOUND ||
+ GetLastError() == ERROR_RESOURCE_DATA_NOT_FOUND) {
+ throw ModuleNotFound();
+ } else {
+ throwWindowsError(
+ (L"GetFileVersionInfoSizeW failed on " + path).c_str());
+ }
+ }
+ std::unique_ptr<char[]> versionBuffer(new char[size]);
+ if (!pGetFileVersionInfoW(path.c_str(), 0, size, versionBuffer.get())) {
+ throwWindowsError((L"GetFileVersionInfoW failed on " + path).c_str());
+ }
+ VS_FIXEDFILEINFO *versionInfo = nullptr;
+ UINT versionInfoSize = 0;
+ if (!pVerQueryValueW(
+ versionBuffer.get(), L"\\",
+ reinterpret_cast<void**>(&versionInfo), &versionInfoSize) ||
+ versionInfo == nullptr ||
+ versionInfoSize != sizeof(VS_FIXEDFILEINFO) ||
+ versionInfo->dwSignature != 0xFEEF04BD) {
+ throwWinptyException((L"VerQueryValueW failed on " + path).c_str());
+ }
+ return *versionInfo;
+}
+
+uint64_t productVersionFromInfo(const VS_FIXEDFILEINFO &info) {
+ return (static_cast<uint64_t>(info.dwProductVersionMS) << 32) |
+ (static_cast<uint64_t>(info.dwProductVersionLS));
+}
+
+uint64_t fileVersionFromInfo(const VS_FIXEDFILEINFO &info) {
+ return (static_cast<uint64_t>(info.dwFileVersionMS) << 32) |
+ (static_cast<uint64_t>(info.dwFileVersionLS));
+}
+
+std::string versionToString(uint64_t version) {
+ StringBuilder b(32);
+ b << ((uint16_t)(version >> 48));
+ b << '.';
+ b << ((uint16_t)(version >> 32));
+ b << '.';
+ b << ((uint16_t)(version >> 16));
+ b << '.';
+ b << ((uint16_t)(version >> 0));
+ return b.str_moved();
+}
+
+} // anonymous namespace
+
+// Returns true for Windows Vista (or Windows Server 2008) or newer.
+bool isAtLeastWindowsVista() {
+ return getWindowsVersion() >= Version(6, 0);
+}
+
+// Returns true for Windows 7 (or Windows Server 2008 R2) or newer.
+bool isAtLeastWindows7() {
+ return getWindowsVersion() >= Version(6, 1);
+}
+
+// Returns true for Windows 8 (or Windows Server 2012) or newer.
+bool isAtLeastWindows8() {
+ return getWindowsVersion() >= Version(6, 2);
+}
+
+#define WINPTY_IA32 1
+#define WINPTY_X64 2
+
+#if defined(_M_IX86) || defined(__i386__)
+#define WINPTY_ARCH WINPTY_IA32
+#elif defined(_M_X64) || defined(__x86_64__)
+#define WINPTY_ARCH WINPTY_X64
+#endif
+
+typedef BOOL WINAPI IsWow64Process_t(HANDLE hProcess, PBOOL Wow64Process);
+
+void dumpWindowsVersion() {
+ if (!isTracingEnabled()) {
+ return;
+ }
+ const auto info = getWindowsVersionInfo();
+ StringBuilder b;
+ b << info.dwMajorVersion << '.' << info.dwMinorVersion
+ << '.' << info.dwBuildNumber << ' '
+ << "SP" << info.wServicePackMajor << '.' << info.wServicePackMinor
+ << ' ';
+ switch (info.wProductType) {
+ case VER_NT_WORKSTATION: b << "Client"; break;
+ case VER_NT_DOMAIN_CONTROLLER: b << "DomainController"; break;
+ case VER_NT_SERVER: b << "Server"; break;
+ default:
+ b << "product=" << info.wProductType; break;
+ }
+ b << ' ';
+#if WINPTY_ARCH == WINPTY_IA32
+ b << "IA32";
+ OsModule kernel32(L"kernel32.dll");
+ IsWow64Process_t *pIsWow64Process =
+ reinterpret_cast<IsWow64Process_t*>(
+ kernel32.proc("IsWow64Process"));
+ if (pIsWow64Process != nullptr) {
+ BOOL result = false;
+ const BOOL success = pIsWow64Process(GetCurrentProcess(), &result);
+ if (!success) {
+ b << " WOW64:error";
+ } else if (success && result) {
+ b << " WOW64";
+ }
+ } else {
+ b << " WOW64:missingapi";
+ }
+#elif WINPTY_ARCH == WINPTY_X64
+ b << "X64";
+#endif
+ const auto dllVersion = [](const wchar_t *dllPath) -> std::string {
+ try {
+ const auto info = getFixedFileInfo(dllPath);
+ StringBuilder fb(64);
+ fb << utf8FromWide(dllPath) << ':';
+ fb << "F:" << versionToString(fileVersionFromInfo(info)) << '/'
+ << "P:" << versionToString(productVersionFromInfo(info));
+ return fb.str_moved();
+ } catch (const ModuleNotFound&) {
+ return utf8FromWide(dllPath) + ":none";
+ } catch (const WinptyException &e) {
+ trace("Error getting %s version: %s",
+ utf8FromWide(dllPath).c_str(), utf8FromWide(e.what()).c_str());
+ return utf8FromWide(dllPath) + ":error";
+ }
+ };
+ b << ' ' << dllVersion(L"kernel32.dll");
+ // ConEmu provides a DLL that hooks many Windows APIs, especially console
+ // APIs. Its existence and version number could be useful in debugging.
+#if WINPTY_ARCH == WINPTY_IA32
+ b << ' ' << dllVersion(L"ConEmuHk.dll");
+#elif WINPTY_ARCH == WINPTY_X64
+ b << ' ' << dllVersion(L"ConEmuHk64.dll");
+#endif
+ trace("Windows version: %s", b.c_str());
+}