/* Copyright (C) 2008-2016 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov * * 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. */ using System; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Security; namespace Alphaleonis.Win32 { /// Static class providing access to information about the operating system under which the assembly is executing. public static class OperatingSystem { #region OperatingSystem Name Enum /// A set of flags that describe the named Windows versions. /// The values of the enumeration are ordered. A later released operating system version has a higher number, so comparisons between named versions are meaningful. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Os")] [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Os")] public enum EnumOsName { /// A Windows version earlier than Windows 2000. Earlier = -1, /// Windows 2000 (Server or Professional). Windows2000 = 0, /// Windows XP. WindowsXP = 1, /// Windows Server 2003. WindowsServer2003 = 2, /// Windows Vista. WindowsVista = 3, /// Windows Server 2008. WindowsServer2008 = 4, /// Windows 7. Windows7 = 5, /// Windows Server 2008 R2. WindowsServer2008R2 = 6, /// Windows 8. Windows8 = 7, /// Windows Server 2012. WindowsServer2012 = 8, /// Windows 8.1. Windows81 = 9, /// Windows Server 2012 R2 WindowsServer2012R2 = 10, /// Windows 10 Windows10 = 11, /// Windows Server WindowsServer = 12, /// A later version of Windows than currently installed. Later = 65535 } #endregion // OperatingSystem Name Enum #region ProcessorArchitecture Name enum /// A set of flags to indicate the current processor architecture for which the operating system is targeted and running. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Pa")] [SuppressMessage("Microsoft.Design", "CA1028:EnumStorageShouldBeInt32")] public enum EnumProcessorArchitecture { /// PROCESSOR_ARCHITECTURE_INTEL /// The system is running a 32-bit version of Windows. /// X86 = 0, /// PROCESSOR_ARCHITECTURE_IA64 /// The system is running on a Itanium processor. /// [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Ia")] [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Ia")] IA64 = 6, /// PROCESSOR_ARCHITECTURE_AMD64 /// The system is running a 64-bit version of Windows. /// X64 = 9, /// PROCESSOR_ARCHITECTURE_UNKNOWN /// Unknown architecture. /// Unknown = 65535 } #endregion // ProcessorArchitecture Name enum #region Properties #region IsServer private static bool _isServer; /// Gets a value indicating whether the operating system is a server operating system. /// if the current operating system is a server operating system; otherwise, . public static bool IsServer { get { if (_servicePackVersion == null) UpdateData(); return _isServer; } } #endregion // IsServer #region IsWow64Process private static bool? _isWow64Process; /// Gets a value indicating whether the current process is running under WOW64. /// if the current process is running under WOW64; otherwise, . public static bool IsWow64Process { get { if (_isWow64Process == null) { bool value; IntPtr processHandle = Process.GetCurrentProcess().Handle; if (!NativeMethods.IsWow64Process(processHandle, out value)) Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error()); // A pointer to a value that is set to TRUE if the process is running under WOW64. // If the process is running under 32-bit Windows, the value is set to FALSE. // If the process is a 64-bit application running under 64-bit Windows, the value is also set to FALSE. _isWow64Process = value; } return (bool) _isWow64Process; } } #endregion // IsWow64Process #region OSVersion private static Version _osVersion; /// Gets the numeric version of the operating system. /// The numeric version of the operating system. public static Version OSVersion { get { if (_osVersion == null) UpdateData(); return _osVersion; } } #endregion // OSVersion #region VersionName private static EnumOsName _enumOsName = EnumOsName.Later; /// Gets the named version of the operating system. /// The named version of the operating system. public static EnumOsName VersionName { get { if (_servicePackVersion == null) UpdateData(); return _enumOsName; } } #endregion // VersionName #region ProcessorArchitecture private static EnumProcessorArchitecture _processorArchitecture; /// Gets the processor architecture for which the operating system is targeted. /// The processor architecture for which the operating system is targeted. /// If running under WOW64 this will return a 32-bit processor. Use to determine if this is the case. public static EnumProcessorArchitecture ProcessorArchitecture { get { if (_servicePackVersion == null) UpdateData(); return _processorArchitecture; } } #endregion // ProcessorArchitecture #region ServicePackVersion private static Version _servicePackVersion; /// Gets the version of the service pack currently installed on the operating system. /// The version of the service pack currently installed on the operating system. /// Only the and fields are used. public static Version ServicePackVersion { get { if (_servicePackVersion == null) UpdateData(); return _servicePackVersion; } } #endregion // ServicePackVersion #endregion // Properties #region Methods #region IsAtLeast /// Determines whether the operating system is of the specified version or later. /// if the operating system is of the specified or later; otherwise, . /// The lowest version for which to return true. public static bool IsAtLeast(EnumOsName version) { return VersionName >= version; } /// Determines whether the operating system is of the specified version or later, allowing specification of a minimum service pack that must be installed on the lowest version. /// if the operating system matches the specified with the specified service pack, or if the operating system is of a later version; otherwise, . /// The minimum required version. /// The major version of the service pack that must be installed on the minimum required version to return true. This can be 0 to indicate that no service pack is required. public static bool IsAtLeast(EnumOsName version, int servicePackVersion) { return IsAtLeast(version) && ServicePackVersion.Major >= servicePackVersion; } #endregion // IsAtLeast #endregion // Methods #region Private [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "RtlGetVersion")] private static void UpdateData() { var verInfo = new NativeMethods.RTL_OSVERSIONINFOEXW(); // Needed to prevent: System.Runtime.InteropServices.COMException: // The data area passed to a system call is too small. (Exception from HRESULT: 0x8007007A) verInfo.dwOSVersionInfoSize = Marshal.SizeOf(verInfo); var sysInfo = new NativeMethods.SYSTEM_INFO(); NativeMethods.GetNativeSystemInfo(ref sysInfo); // RtlGetVersion returns STATUS_SUCCESS (0). if (NativeMethods.RtlGetVersion(ref verInfo)) throw new Win32Exception(Marshal.GetLastWin32Error(), "Function RtlGetVersion() failed to retrieve the operating system information."); _osVersion = new Version(verInfo.dwMajorVersion, verInfo.dwMinorVersion, verInfo.dwBuildNumber); _processorArchitecture = (EnumProcessorArchitecture) sysInfo.wProcessorArchitecture; _servicePackVersion = new Version(verInfo.wServicePackMajor, verInfo.wServicePackMinor); _isServer = verInfo.wProductType == NativeMethods.VER_NT_DOMAIN_CONTROLLER || verInfo.wProductType == NativeMethods.VER_NT_SERVER; // RtlGetVersion: https://msdn.microsoft.com/en-us/library/windows/hardware/ff561910%28v=vs.85%29.aspx // The following table summarizes the most recent operating system version numbers. // Operating system Version number Other // ================================================================================ // Windows 10 10.0 OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION // Windows Server 10.0 OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION // Windows 8.1 6.3 OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION // Windows Server 2012 R2 6.3 OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION // Windows 8 6.2 OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION // Windows Server 2012 6.2 OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION // Windows 7 6.1 OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION // Windows Server 2008 R2 6.1 OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION // Windows Server 2008 6.0 OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION // Windows Vista 6.0 OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION // Windows Server 2003 R2 5.2 GetSystemMetrics(SM_SERVERR2) != 0 // Windows Server 2003 5.2 GetSystemMetrics(SM_SERVERR2) == 0 // Windows XP 64-Bit Edition 5.2 (OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION) && (sysInfo.PaName == PaName.X64) // Windows XP 5.1 Not applicable // Windows 2000 5.0 Not applicable // 10 == The lastest MajorVersion of Windows. if (verInfo.dwMajorVersion > 10) _enumOsName = EnumOsName.Later; else switch (verInfo.dwMajorVersion) { #region Version 10 case 10: switch (verInfo.dwMinorVersion) { // Windows 10 or Windows Server case 0: _enumOsName = (verInfo.wProductType == NativeMethods.VER_NT_WORKSTATION) ? EnumOsName.Windows10 : EnumOsName.WindowsServer; break; } break; #endregion // Version 10 #region Version 6 case 6: switch (verInfo.dwMinorVersion) { // Windows Vista or Windows Server 2008 case 0: _enumOsName = (verInfo.wProductType == NativeMethods.VER_NT_WORKSTATION) ? EnumOsName.WindowsVista : EnumOsName.WindowsServer2008; break; // Windows 7 or Windows Server 2008 R2 case 1: _enumOsName = (verInfo.wProductType == NativeMethods.VER_NT_WORKSTATION) ? EnumOsName.Windows7 : EnumOsName.WindowsServer2008R2; break; // Windows 8 or Windows Server 2012 case 2: _enumOsName = (verInfo.wProductType == NativeMethods.VER_NT_WORKSTATION) ? EnumOsName.Windows8 : EnumOsName.WindowsServer2012; break; // Windows 8.1 or Windows Server 2012 R2 case 3: _enumOsName = (verInfo.wProductType == NativeMethods.VER_NT_WORKSTATION) ? EnumOsName.Windows81 : EnumOsName.WindowsServer2012R2; break; default: _enumOsName = EnumOsName.Later; break; } break; #endregion // Version 6 #region Version 5 case 5: switch (verInfo.dwMinorVersion) { case 0: _enumOsName = EnumOsName.Windows2000; break; case 1: _enumOsName = EnumOsName.WindowsXP; break; case 2: _enumOsName = (verInfo.wProductType == NativeMethods.VER_NT_WORKSTATION && _processorArchitecture == EnumProcessorArchitecture.X64) ? EnumOsName.WindowsXP : (verInfo.wProductType != NativeMethods.VER_NT_WORKSTATION) ? EnumOsName.WindowsServer2003 : EnumOsName.Later; break; default: _enumOsName = EnumOsName.Later; break; } break; #endregion // Version 5 default: _enumOsName = EnumOsName.Earlier; break; } } #region P/Invoke members / NativeMethods private static class NativeMethods { internal const short VER_NT_WORKSTATION = 1; internal const short VER_NT_DOMAIN_CONTROLLER = 2; internal const short VER_NT_SERVER = 3; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct RTL_OSVERSIONINFOEXW { public int dwOSVersionInfoSize; public readonly int dwMajorVersion; public readonly int dwMinorVersion; public readonly int dwBuildNumber; public readonly int dwPlatformId; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public readonly string szCSDVersion; public readonly ushort wServicePackMajor; public readonly ushort wServicePackMinor; public readonly ushort wSuiteMask; public readonly byte wProductType; public readonly byte wReserved; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct SYSTEM_INFO { public readonly ushort wProcessorArchitecture; private readonly ushort wReserved; public readonly uint dwPageSize; public readonly IntPtr lpMinimumApplicationAddress; public readonly IntPtr lpMaximumApplicationAddress; public readonly IntPtr dwActiveProcessorMask; public readonly uint dwNumberOfProcessors; public readonly uint dwProcessorType; public readonly uint dwAllocationGranularity; public readonly ushort wProcessorLevel; public readonly ushort wProcessorRevision; } /// The RtlGetVersion routine returns version information about the currently running operating system. /// RtlGetVersion returns STATUS_SUCCESS. /// Available starting with Windows 2000. [SuppressMessage("Microsoft.Security", "CA5122:PInvokesShouldNotBeSafeCriticalFxCopRule"), DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool RtlGetVersion([MarshalAs(UnmanagedType.Struct)] ref RTL_OSVERSIONINFOEXW lpVersionInformation); /// Retrieves information about the current system to an application running under WOW64. /// If the function is called from a 64-bit application, it is equivalent to the GetSystemInfo function. /// /// This function does not return a value. /// To determine whether a Win32-based application is running under WOW64, call the function. /// Minimum supported client: Windows XP [desktop apps | Windows Store apps] /// Minimum supported server: Windows Server 2003 [desktop apps | Windows Store apps] [SuppressMessage("Microsoft.Security", "CA5122:PInvokesShouldNotBeSafeCriticalFxCopRule")] [DllImport("kernel32.dll", SetLastError = false, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] internal static extern void GetNativeSystemInfo([MarshalAs(UnmanagedType.Struct)] ref SYSTEM_INFO lpSystemInfo); /// Determines whether the specified process is running under WOW64. /// /// If the function succeeds, the return value is a nonzero value. /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// /// Minimum supported client: Windows Vista, Windows XP with SP2 [desktop apps only] /// Minimum supported server: Windows Server 2008, Windows Server 2003 with SP1 [desktop apps only] [SuppressMessage("Microsoft.Security", "CA5122:PInvokesShouldNotBeSafeCriticalFxCopRule")] [DllImport("kernel32.dll", SetLastError = false, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool IsWow64Process([In] IntPtr hProcess, [Out, MarshalAs(UnmanagedType.Bool)] out bool lpSystemInfo); } #endregion // P/Invoke members / NativeMethods #endregion // Private } }