Replaced deprecated windows version detect
authorJari Komppa <jari.komppa@siru.fi>
Thu, 1 Mar 2018 12:49:25 +0000 (14:49 +0200)
committerAlexander Galazin <Alexander.Galazin@arm.com>
Wed, 14 Mar 2018 08:08:40 +0000 (04:08 -0400)
The old windows version reporting API has been deprecated and has been
lying since Windows 8.1 - all windows versions since that version have
been reported as Windows 8.0. (It is possible to add manifest files to
the executable to accept later windows versions, but that would require
the UUID of every existing and future versions of Windows).

There is no direct replacement, as Microsoft would prefer applications
to be written against available features instead of relying on Windows
version numbers.

The official workaround is to look at the version numbers in system DLL
files. In addition, the registry contains several strings which tell the
version number. This change attempts to do both, in case future Windows
versions change this behavior.

Windows can also lie about the bit-ness of the operating system; reading
the windows version from registry from a 32bit application may report
the operating system as 32 bit even if it's actually 64 bit. Separate
64-bit detect function is also included. (Hypothetical future 128 bit
Windows will likely report as 64 bit, but I'll leave that problem to the
future generations).

Affects:

dEQP-VK.info.platform

Components: Framework

VK-GL-CTS issue: 1044

Change-Id: I80062d6eefb14b2ce04818a6c3176db0b172419e

framework/platform/win32/tcuWin32VulkanPlatform.cpp

index 3b6cdaaf9fc2e23be3f4cadc686347245b9a0c4d..78edfac76f36469a1fe1e3722ee0ce0fa3dd78dd 100644 (file)
  * \brief Win32 Vulkan platform
  *//*--------------------------------------------------------------------*/
 
-// \todo [2016-01-22 pyry] GetVersionEx() used by getOSInfo() is deprecated.
-//                                                Find a way to get version info without using deprecated APIs.
-#pragma warning(disable : 4996)
-
 #include "tcuWin32VulkanPlatform.hpp"
 #include "tcuWin32Window.hpp"
 
@@ -37,6 +33,8 @@
 #include "deUniquePtr.hpp"
 #include "deMemory.h"
 
+#pragma comment(lib, "version.lib")
+
 namespace tcu
 {
 namespace win32
@@ -121,38 +119,117 @@ vk::Library* VulkanPlatform::createLibrary (void) const
        return new VulkanLibrary();
 }
 
-const char* getProductTypeName (WORD productType)
+ULONG getStringRegKey (const std::string& regKey, const std::string& strValueName, std::string& strValue)
 {
-       switch (productType)
+       HKEY    hKey;
+       ULONG   nError;
+       CHAR    szBuffer[512];
+       DWORD   dwBufferSize = sizeof(szBuffer);
+
+       nError = RegOpenKeyExA(HKEY_LOCAL_MACHINE, regKey.c_str(), 0, KEY_READ, &hKey);
+
+       if (ERROR_SUCCESS == nError)
+               nError = RegQueryValueExA(hKey, strValueName.c_str(), 0, DE_NULL, (LPBYTE)szBuffer, &dwBufferSize);
+
+       if (ERROR_SUCCESS == nError)
+               strValue = szBuffer;
+
+       return nError;
+}
+
+void getWindowsBits (std::ostream& dst)
+{
+#if defined(_WIN64)
+       dst << "64"; // 64-bit programs run only on Win64
+       return;
+#elif defined(_WIN32)
+       BOOL is64 = false;
+       // 32-bit programs run on both 32-bit and 64-bit Windows.
+       // Function is defined from XP SP2 onwards, so we don't need to
+       // check if it exists.
+       if (IsWow64Process(GetCurrentProcess(), &is64))
        {
-               case VER_NT_DOMAIN_CONTROLLER:  return "Windows Server (domain controller)";
-               case VER_NT_SERVER:                             return "Windows Server";
-               case VER_NT_WORKSTATION:                return "Windows NT";
-               default:                                                return DE_NULL;
+               if (is64)
+                       dst << "64";
+               else
+                       dst << "32";
+               return;
        }
+#endif
+#if !defined(_WIN64)
+       // IsWow64Process returns failure or neither of
+       // _WIN64 or _WIN32 is defined
+       dst << "Unknown";
+#endif
 }
 
-static void getOSInfo (std::ostream& dst)
+void getOSNameFromRegistry (std::ostream& dst)
 {
-       OSVERSIONINFOEX osInfo;
+       const char* keypath             = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
+       std::string productname = "Unknown";
+       std::string releaseid   = "Unknown";
+       std::string optional;
 
-       deMemset(&osInfo, 0, sizeof(osInfo));
-       osInfo.dwOSVersionInfoSize = (DWORD)sizeof(osInfo);
+       getStringRegKey(keypath, "ProductName", productname);
+       getStringRegKey(keypath, "ReleaseId", releaseid);
 
-       GetVersionEx((OSVERSIONINFO*)&osInfo);
+       getWindowsBits(dst);
 
+       dst << " bit Windows Product: " << productname << ", Release: " << releaseid;
+
+       if (ERROR_SUCCESS == getStringRegKey(keypath, "EditionID", optional))
        {
-               const char* const       productName     = getProductTypeName(osInfo.wProductType);
+               dst << ", Edition: " << optional;
+               if (ERROR_SUCCESS == getStringRegKey(keypath, "EditionSubstring", optional)
+                       && optional.length() > 0)
+                       dst << " " << optional;
+       }
+}
 
-               if (productName)
-                       dst << productName;
-               else
-                       dst << "unknown product " << tcu::toHex(osInfo.wProductType);
+void getOSVersionFromDLL (std::ostream& dst)
+{
+       DWORD   buffer_size     = GetFileVersionInfoSize(("kernel32.dll"), DE_NULL);
+       char*   buffer          = 0;
+
+       if (buffer_size != 0)
+       {
+               buffer = new char[buffer_size];
+               if (buffer != 0)
+               {
+                       if (GetFileVersionInfo("kernel32.dll", 0, buffer_size, buffer))
+                       {
+                               VS_FIXEDFILEINFO*       version         = DE_NULL;
+                               UINT                            version_len     = 0;
+
+                               if (VerQueryValue(buffer, "\\", (LPVOID*)&version, &version_len))
+                               {
+                                       dst << ", DLL Version: " << HIWORD(version->dwProductVersionMS) << "." << LOWORD(version->dwProductVersionMS)
+                                               << ", DLL Build: "   << HIWORD(version->dwProductVersionLS) << "." << LOWORD(version->dwProductVersionLS);
+                               }
+                       }
+                       delete[] buffer;
+               }
        }
+}
 
-       dst << " " << osInfo.dwMajorVersion << "." << osInfo.dwMinorVersion
-               << ", service pack " << osInfo.wServicePackMajor << "." << osInfo.wServicePackMinor
-               << ", build " << osInfo.dwBuildNumber;
+// Old windows version query APIs lie about the version number. There's no replacement
+// API, and instead applications are supposed to queriy about capabilities instead of
+// relying on operating system version numbers.
+//
+// Since we want to actually know the version number for debugging purposes, we need
+// to use roundabout ways to fetch the information.
+//
+// The registry contains some useful strings, which we print out if the keys
+// are available. The current official way to get version number is to look at a
+// system DLL file and read its version number, so we do that too, in case the
+// registry becomes unreliable in the future.
+//
+// If the DLL method fails, we simply don't print out anything about it.
+// The minimal output from this function is "Windows Product: Unknown, Release: Unknown"
+static void getOSInfo (std::ostream& dst)
+{
+       getOSNameFromRegistry(dst);
+       getOSVersionFromDLL(dst);
 }
 
 const char* getProcessorArchitectureName (WORD arch)