/* 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
}
}