+/* Windows version dtection */
+static BOOL is_x64(void)
+{
+ BOOL ret = FALSE;
+ // Detect if we're running a 32 or 64 bit system
+ if (sizeof(uintptr_t) < 8) {
+ DLL_LOAD_PREFIXED(Kernel32.dll, p, IsWow64Process, FALSE);
+ if (pIsWow64Process != NULL) {
+ (*pIsWow64Process)(GetCurrentProcess(), &ret);
+ }
+ } else {
+ ret = TRUE;
+ }
+ return ret;
+}
+
+static void get_windows_version(void)
+{
+ OSVERSIONINFOEXA vi, vi2;
+ const char* w = 0;
+ const char* w64 = "32 bit";
+ char* vptr;
+ size_t vlen;
+ unsigned major, minor;
+ ULONGLONG major_equal, minor_equal;
+ BOOL ws;
+
+ memset(&vi, 0, sizeof(vi));
+ vi.dwOSVersionInfoSize = sizeof(vi);
+ if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
+ memset(&vi, 0, sizeof(vi));
+ vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
+ if (!GetVersionExA((OSVERSIONINFOA *)&vi))
+ return;
+ }
+
+ if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+
+ if (vi.dwMajorVersion > 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion >= 2)) {
+ // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version
+ // See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
+
+ major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
+ for (major = vi.dwMajorVersion; major <= 9; major++) {
+ memset(&vi2, 0, sizeof(vi2));
+ vi2.dwOSVersionInfoSize = sizeof(vi2); vi2.dwMajorVersion = major;
+ if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal))
+ continue;
+ if (vi.dwMajorVersion < major) {
+ vi.dwMajorVersion = major; vi.dwMinorVersion = 0;
+ }
+
+ minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
+ for (minor = vi.dwMinorVersion; minor <= 9; minor++) {
+ memset(&vi2, 0, sizeof(vi2)); vi2.dwOSVersionInfoSize = sizeof(vi2);
+ vi2.dwMinorVersion = minor;
+ if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal))
+ continue;
+ vi.dwMinorVersion = minor;
+ break;
+ }
+
+ break;
+ }
+ }
+
+ if (vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) {
+ ws = (vi.wProductType <= VER_NT_WORKSTATION);
+ windows_version = vi.dwMajorVersion << 4 | vi.dwMinorVersion;
+ switch (windows_version) {
+ case 0x50: w = "2000";
+ break;
+ case 0x51: w = "XP";
+ break;
+ case 0x52: w = (!GetSystemMetrics(89)?"2003":"2003_R2");
+ break;
+ case 0x60: w = (ws?"Vista":"2008");
+ break;
+ case 0x61: w = (ws?"7":"2008_R2");
+ break;
+ case 0x62: w = (ws?"8":"2012");
+ break;
+ case 0x63: w = (ws?"8.1":"2012_R2");
+ break;
+ case 0x64: w = (ws?"8.2":"2012_R3");
+ break;
+ default:
+ if (windows_version < 0x50)
+ windows_version = WINDOWS_UNSUPPORTED;
+ else
+ w = "9 or later";
+ break;
+ }
+ }
+ }
+
+ if (is_x64())
+ w64 = "64-bit";
+
+ vptr = &windows_version_str[sizeof("Windows ") - 1];
+ vlen = sizeof(windows_version_str) - sizeof("Windows ") - 1;
+ if (!w)
+ safe_sprintf(vptr, vlen, "%s %u.%u %s", (vi.dwPlatformId==VER_PLATFORM_WIN32_NT?"NT":"??"),
+ (unsigned)vi.dwMajorVersion, (unsigned)vi.dwMinorVersion, w64);
+ else if (vi.wServicePackMinor)
+ safe_sprintf(vptr, vlen, "%s SP%u.%u %s", w, vi.wServicePackMajor, vi.wServicePackMinor, w64);
+ else if (vi.wServicePackMajor)
+ safe_sprintf(vptr, vlen, "%s SP%u %s", w, vi.wServicePackMajor, w64);
+ else
+ safe_sprintf(vptr, vlen, "%s %s", w, w64);
+}
+