diff --git a/MUtilities_VS2013.vcxproj b/MUtilities_VS2013.vcxproj
index 5109d15..d832154 100644
--- a/MUtilities_VS2013.vcxproj
+++ b/MUtilities_VS2013.vcxproj
@@ -109,6 +109,7 @@
MultiThreadedDebugDLL
NoExtensions
$(ProjectDir)\include;$(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;%(AdditionalIncludeDirectories)
+ true
Windows
@@ -135,6 +136,7 @@
Fast
false
$(ProjectDir)\include;$(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;%(AdditionalIncludeDirectories)
+ true
Windows
@@ -163,6 +165,7 @@
Fast
false
$(ProjectDir)\include;$(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;%(AdditionalIncludeDirectories)
+ true
Windows
diff --git a/include/MUtils/OSSupport.h b/include/MUtils/OSSupport.h
index 1a0f9f0..5b674e1 100644
--- a/include/MUtils/OSSupport.h
+++ b/include/MUtils/OSSupport.h
@@ -34,6 +34,48 @@ namespace MUtils
{
namespace OS
{
+ namespace Version
+ {
+ //Supported OS types
+ typedef enum
+ {
+ OS_UNKNOWN = 0,
+ OS_WINDOWS = 1
+ }
+ os_type_t;
+
+ //OS version struct
+ typedef struct _os_info_t
+ {
+ unsigned int type;
+ unsigned int versionMajor;
+ unsigned int versionMinor;
+ bool overrideFlag;
+
+ //comparision operators
+ inline bool operator== (const _os_info_t &rhs) const { return (type == rhs.type) && (versionMajor == rhs.versionMajor) && ((versionMinor == rhs.versionMinor)); }
+ inline bool operator!= (const _os_info_t &rhs) const { return (type != rhs.type) || (versionMajor != rhs.versionMajor) || ((versionMinor != rhs.versionMinor)); }
+ inline bool operator> (const _os_info_t &rhs) const { return (type == rhs.type) && ((versionMajor > rhs.versionMajor) || ((versionMajor == rhs.versionMajor) && (versionMinor > rhs.versionMinor))); }
+ inline bool operator>= (const _os_info_t &rhs) const { return (type == rhs.type) && ((versionMajor > rhs.versionMajor) || ((versionMajor == rhs.versionMajor) && (versionMinor >= rhs.versionMinor))); }
+ inline bool operator< (const _os_info_t &rhs) const { return (type == rhs.type) && ((versionMajor < rhs.versionMajor) || ((versionMajor == rhs.versionMajor) && (versionMinor < rhs.versionMinor))); }
+ inline bool operator<= (const _os_info_t &rhs) const { return (type == rhs.type) && ((versionMajor < rhs.versionMajor) || ((versionMajor == rhs.versionMajor) && (versionMinor <= rhs.versionMinor))); }
+ }
+ os_version_t;
+
+ //Known Windows NT versions
+ static const os_version_t WINDOWS_WIN2K = { OS_WINDOWS, 5, 0 }; // 2000
+ static const os_version_t WINDOWS_WINXP = { OS_WINDOWS, 5, 1 }; // XP
+ static const os_version_t WINDOWS_XPX64 = { OS_WINDOWS, 5, 2 }; // XP_x64
+ static const os_version_t WINDOWS_VISTA = { OS_WINDOWS, 6, 0 }; // Vista
+ static const os_version_t WINDOWS_WIN70 = { OS_WINDOWS, 6, 1 }; // 7
+ static const os_version_t WINDOWS_WIN80 = { OS_WINDOWS, 6, 2 }; // 8
+ static const os_version_t WINDOWS_WIN81 = { OS_WINDOWS, 6, 3 }; // 8.1
+ static const os_version_t WINDOWS_WN100 = { OS_WINDOWS, 6, 4 }; // 10
+
+ //Unknown OS
+ static const os_version_t UNKNOWN_OPSYS = { OS_UNKNOWN, 0, 0 }; // N/A
+ }
+
//Known Folders IDs
typedef enum
{
@@ -52,12 +94,16 @@ namespace MUtils
NETWORK_TYPE_YES = 2 /*connected*/
}
network_type_t;
-
+
//System message
MUTILS_API void system_message_nfo(const wchar_t *const title, const wchar_t *const text);
MUTILS_API void system_message_wrn(const wchar_t *const title, const wchar_t *const text);
MUTILS_API void system_message_err(const wchar_t *const title, const wchar_t *const text);
+ //Get the OS version
+ MUTILS_API const Version::os_version_t &os_version(void);
+ MUTILS_API const char *os_friendly_name(const MUtils::OS::Version::os_version_t &os_version);
+
//Get known Folder
MUTILS_API const QString &known_folder(known_folder_t folder_id);
diff --git a/src/OSSupport_Win32.cpp b/src/OSSupport_Win32.cpp
index 1b9698d..48976e7 100644
--- a/src/OSSupport_Win32.cpp
+++ b/src/OSSupport_Win32.cpp
@@ -61,6 +61,174 @@ void MUtils::OS::system_message_err(const wchar_t *const title, const wchar_t *c
MessageBoxW(NULL, text, title, MB_TOPMOST | MB_TASKMODAL | MB_ICONERROR);
}
+///////////////////////////////////////////////////////////////////////////////
+// OS VERSION DETECTION
+///////////////////////////////////////////////////////////////////////////////
+
+static bool g_os_version_initialized = false;
+static MUtils::OS::Version::os_version_t g_os_version_info = MUtils::OS::Version::UNKNOWN_OPSYS;
+static QReadWriteLock g_os_version_lock;
+
+//Maps marketing names to the actual Windows NT versions
+static const struct
+{
+ MUtils::OS::Version::os_version_t version;
+ const char friendlyName[64];
+}
+g_os_version_lut[] =
+{
+ { MUtils::OS::Version::WINDOWS_WIN2K, "Windows 2000" }, //2000
+ { MUtils::OS::Version::WINDOWS_WINXP, "Windows XP or Windows XP Media Center Edition" }, //XP
+ { MUtils::OS::Version::WINDOWS_XPX64, "Windows Server 2003 or Windows XP x64" }, //XP_x64
+ { MUtils::OS::Version::WINDOWS_VISTA, "Windows Vista or Windows Server 2008" }, //Vista
+ { MUtils::OS::Version::WINDOWS_WIN70, "Windows 7 or Windows Server 2008 R2" }, //7
+ { MUtils::OS::Version::WINDOWS_WIN80, "Windows 8 or Windows Server 2012" }, //8
+ { MUtils::OS::Version::WINDOWS_WIN81, "Windows 8.1 or Windows Server 2012 R2" }, //8.1
+ { MUtils::OS::Version::WINDOWS_WN100, "Windows 10 or Windows Server 2014 (Preview)" }, //10
+ { MUtils::OS::Version::UNKNOWN_OPSYS, "N/A" }
+};
+
+static bool verify_os_version(const DWORD major, const DWORD minor)
+{
+ OSVERSIONINFOEXW osvi;
+ DWORDLONG dwlConditionMask = 0;
+
+ //Initialize the OSVERSIONINFOEX structure
+ memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
+ osvi.dwMajorVersion = major;
+ osvi.dwMinorVersion = minor;
+ osvi.dwPlatformId = VER_PLATFORM_WIN32_NT;
+
+ //Initialize the condition mask
+ VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
+ VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
+ VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL);
+
+ // Perform the test
+ const BOOL ret = VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, dwlConditionMask);
+
+ //Error checking
+ if(!ret)
+ {
+ if(GetLastError() != ERROR_OLD_WIN_VERSION)
+ {
+ qWarning("VerifyVersionInfo() system call has failed!");
+ }
+ }
+
+ return (ret != FALSE);
+}
+
+static bool get_real_os_version(unsigned int *major, unsigned int *minor, bool *pbOverride)
+{
+ *major = *minor = 0;
+ *pbOverride = false;
+
+ //Initialize local variables
+ OSVERSIONINFOEXW osvi;
+ memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
+
+ //Try GetVersionEx() first
+ if(GetVersionExW((LPOSVERSIONINFOW)&osvi) == FALSE)
+ {
+ qWarning("GetVersionEx() has failed, cannot detect Windows version!");
+ return false;
+ }
+
+ //Make sure we are running on NT
+ if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ {
+ *major = osvi.dwMajorVersion;
+ *minor = osvi.dwMinorVersion;
+ }
+ else
+ {
+ qWarning("Not running on Windows NT, unsupported operating system!");
+ return false;
+ }
+
+ //Determine the real *major* version first
+ forever
+ {
+ const DWORD nextMajor = (*major) + 1;
+ if(verify_os_version(nextMajor, 0))
+ {
+ *pbOverride = true;
+ *major = nextMajor;
+ *minor = 0;
+ continue;
+ }
+ break;
+ }
+
+ //Now also determine the real *minor* version
+ forever
+ {
+ const DWORD nextMinor = (*minor) + 1;
+ if(verify_os_version((*major), nextMinor))
+ {
+ *pbOverride = true;
+ *minor = nextMinor;
+ continue;
+ }
+ break;
+ }
+
+ return true;
+}
+
+const MUtils::OS::Version::os_version_t &MUtils::OS::os_version(void)
+{
+ QReadLocker readLock(&g_os_version_lock);
+
+ //Already initialized?
+ if(g_os_version_initialized)
+ {
+ return g_os_version_info;
+ }
+
+ readLock.unlock();
+ QWriteLocker writeLock(&g_os_version_lock);
+
+ //Initialized now?
+ if(g_os_version_initialized)
+ {
+ return g_os_version_info;
+ }
+
+ //Detect OS version
+ unsigned int major, minor; bool overrideFlg;
+ if(get_real_os_version(&major, &minor, &overrideFlg))
+ {
+ g_os_version_info.type = Version::OS_WINDOWS;
+ g_os_version_info.versionMajor = major;
+ g_os_version_info.versionMinor = minor;
+ g_os_version_info.overrideFlag = overrideFlg;
+ }
+ else
+ {
+ qWarning("Failed to determin the operating system version!");
+ }
+
+ g_os_version_initialized = true;
+ return g_os_version_info;
+}
+
+const char *MUtils::OS::os_friendly_name(const MUtils::OS::Version::os_version_t &os_version)
+{
+ for(size_t i = 0; g_os_version_lut[i].version != MUtils::OS::Version::UNKNOWN_OPSYS; i++)
+ {
+ if(os_version == g_os_version_lut[i].version)
+ {
+ return g_os_version_lut[i].friendlyName;
+ }
+ }
+
+ return NULL;
+}
+
///////////////////////////////////////////////////////////////////////////////
// KNWON FOLDERS
///////////////////////////////////////////////////////////////////////////////