diff --git a/openscad.pro b/openscad.pro index e25639f4..baf92464 100644 --- a/openscad.pro +++ b/openscad.pro @@ -496,6 +496,7 @@ unix:!macx { SOURCES += src/PlatformUtils-posix.cc } win* { + HEADERS += src/findversion.h SOURCES += src/PlatformUtils-win.cc } diff --git a/src/PlatformUtils-win.cc b/src/PlatformUtils-win.cc index 2a54d8fd..c3cba45a 100644 --- a/src/PlatformUtils-win.cc +++ b/src/PlatformUtils-win.cc @@ -1,5 +1,6 @@ #include "PlatformUtils.h" #include "printutils.h" +#include "findversion.h" #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0501 #endif @@ -126,7 +127,8 @@ std::string PlatformUtils::sysinfo() OSVERSIONINFOEX osinfo; osinfo.dwOSVersionInfoSize = sizeof(osinfo); - if (GetVersionEx((OSVERSIONINFO*)&osinfo) == 0) { + + if (GetVersionExEx(&osinfo) == 0) { result += "Unknown Windows"; } else { unsigned int version = osinfo.dwMajorVersion * 1000 + osinfo.dwMinorVersion; @@ -154,9 +156,25 @@ std::string PlatformUtils::sysinfo() // For applications that have been manifested for Windows 8.1. result += (osinfo.wProductType == VER_NT_WORKSTATION ? "Windows 8.1" : "Windows Server 2012 R2"); break; + default: + result += "Unknown Windows"; + break; } - boost::format fmt(" (v%d.%d)"); - fmt % osinfo.dwMajorVersion % osinfo.dwMinorVersion; + + if (osinfo.wServicePackMajor > 0) { + boost::format fmtServicePack; + if (osinfo.wServicePackMinor == 0) { + fmtServicePack = boost::format(" SP%d"); + fmtServicePack % osinfo.wServicePackMajor; + } else { + fmtServicePack = boost::format(" SP%d.%d"); + fmtServicePack % osinfo.wServicePackMajor % osinfo.wServicePackMinor; + } + result += fmtServicePack.str(); + } + + boost::format fmt(" (v%d.%d.%d.%d)"); + fmt % osinfo.dwMajorVersion % osinfo.dwMinorVersion % osinfo.wServicePackMajor % osinfo.wServicePackMinor; result += fmt.str(); } else { boost::format fmt("Unknown Windows (dwPlatformId = %d, dwMajorVersion = %d, dwMinorVersion = %d"); diff --git a/src/findversion.h b/src/findversion.h new file mode 100644 index 00000000..b027f68b --- /dev/null +++ b/src/findversion.h @@ -0,0 +1,120 @@ +/* +* Find Windows version using bisection method and VerifyVersionInfo. +* +* Author: M1xA, www.m1xa.com +* Date: 2013.07.07 +* Licence: MIT +* Version: 1.0 +* +* API: +* +* BOOL GetVersionExEx(OSVERSIONINFOEX * osVer); +* Returns: 0 if fails. +* +* Supported OS: Windows 2000 .. Windows 8.1. +*/ +#ifndef __FIND_VERSION__ +#define __FIND_VERSION__ + +#include + +#define FV_EQUAL 0 +#define FV_LESS -1 +#define FV_GREAT 1 +#define FV_MIN_VALUE 0 +#define FV_MINOR_VERSION_MAX_VALUE 16 + +int testValue(OSVERSIONINFOEX * value, DWORD verPart, DWORDLONG eq, DWORDLONG gt) +{ + if (VerifyVersionInfo(value, verPart, eq) == FALSE) + { + if (VerifyVersionInfo(value, verPart, gt) == TRUE) + return FV_GREAT; + return FV_LESS; + } + else + return FV_EQUAL; +} + +DWORDLONG gtFor(DWORD target) +{ + return VerSetConditionMask(0, target, VER_GREATER); +} + +DWORDLONG eqFor(DWORD target) +{ + return VerSetConditionMask(0, target, VER_EQUAL); +} + +#define findPartTemplate(T)\ +BOOL findPart##T(T * part, DWORD partType, OSVERSIONINFOEX * ret, T a, T b) \ +{ \ + int funx = FV_EQUAL; \ +\ + DWORDLONG const eq = eqFor(partType); \ + DWORDLONG const gt = gtFor(partType); \ +\ + T * p = part; \ +\ + *p = (a + b) / 2; \ +\ + while ((funx = testValue(ret, partType, eq, gt)) != FV_EQUAL) \ + { \ + switch (funx) \ + { \ + case FV_GREAT: a = *p; break; \ + case FV_LESS: b = *p; break; \ + } \ +\ + *p = (a + b) / 2; \ +\ + if (*p == a) \ + { \ + if (testValue(ret, partType, eq, gt) == FV_EQUAL) \ + return TRUE; \ +\ + *p = b; \ +\ + if (testValue(ret, partType, eq, gt) == FV_EQUAL) \ + return TRUE; \ +\ + a = 0; \ + b = 0; \ + *p = 0; \ + } \ +\ + if (a == b) \ + { \ + *p = 0; \ + return FALSE; \ + } \ + } \ +\ + return TRUE; \ +} + +findPartTemplate(DWORD) +findPartTemplate(WORD) +findPartTemplate(BYTE) + +BOOL GetVersionExEx(OSVERSIONINFOEX * osVer) +{ + BOOL ret = TRUE; + + ZeroMemory(osVer, sizeof(OSVERSIONINFOEX)); + + osVer->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + ret &= findPartDWORD(&osVer->dwPlatformId, VER_PLATFORMID, osVer, FV_MIN_VALUE, MAXDWORD); + ret &= findPartDWORD(&osVer->dwMajorVersion, VER_MAJORVERSION, osVer, FV_MIN_VALUE, MAXDWORD); + ret &= findPartDWORD(&osVer->dwMinorVersion, VER_MINORVERSION, osVer, FV_MIN_VALUE, FV_MINOR_VERSION_MAX_VALUE); + ret &= findPartDWORD(&osVer->dwBuildNumber, VER_BUILDNUMBER, osVer, FV_MIN_VALUE, MAXDWORD); + ret &= findPartWORD(&osVer->wServicePackMajor, VER_SERVICEPACKMAJOR, osVer, FV_MIN_VALUE, MAXWORD); + ret &= findPartWORD(&osVer->wServicePackMinor, VER_SERVICEPACKMINOR, osVer, FV_MIN_VALUE, MAXWORD); + ret &= findPartWORD(&osVer->wSuiteMask, VER_SUITENAME, osVer, FV_MIN_VALUE, MAXWORD); + ret &= findPartBYTE(&osVer->wProductType, VER_PRODUCT_TYPE, osVer, FV_MIN_VALUE, MAXBYTE); + + return ret; +} + +#endif