You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

507 lines
21 KiB

/* 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
{
/// <summary>Static class providing access to information about the operating system under which the assembly is executing.</summary>
public static class OperatingSystem
{
#region OperatingSystem Name Enum
/// <summary>A set of flags that describe the named Windows versions.</summary>
/// <remarks>The values of the enumeration are ordered. A later released operating system version has a higher number, so comparisons between named versions are meaningful.</remarks>
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Os")]
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Os")]
public enum EnumOsName
{
/// <summary>A Windows version earlier than Windows 2000.</summary>
Earlier = -1,
/// <summary>Windows 2000 (Server or Professional).</summary>
Windows2000 = 0,
/// <summary>Windows XP.</summary>
WindowsXP = 1,
/// <summary>Windows Server 2003.</summary>
WindowsServer2003 = 2,
/// <summary>Windows Vista.</summary>
WindowsVista = 3,
/// <summary>Windows Server 2008.</summary>
WindowsServer2008 = 4,
/// <summary>Windows 7.</summary>
Windows7 = 5,
/// <summary>Windows Server 2008 R2.</summary>
WindowsServer2008R2 = 6,
/// <summary>Windows 8.</summary>
Windows8 = 7,
/// <summary>Windows Server 2012.</summary>
WindowsServer2012 = 8,
/// <summary>Windows 8.1.</summary>
Windows81 = 9,
/// <summary>Windows Server 2012 R2</summary>
WindowsServer2012R2 = 10,
/// <summary>Windows 10</summary>
Windows10 = 11,
/// <summary>Windows Server</summary>
WindowsServer = 12,
/// <summary>A later version of Windows than currently installed.</summary>
Later = 65535
}
#endregion // OperatingSystem Name Enum
#region ProcessorArchitecture Name enum
/// <summary>A set of flags to indicate the current processor architecture for which the operating system is targeted and running.</summary>
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Pa")]
[SuppressMessage("Microsoft.Design", "CA1028:EnumStorageShouldBeInt32")]
public enum EnumProcessorArchitecture
{
/// <summary>PROCESSOR_ARCHITECTURE_INTEL
/// <para>The system is running a 32-bit version of Windows.</para>
/// </summary>
X86 = 0,
/// <summary>PROCESSOR_ARCHITECTURE_IA64
/// <para>The system is running on a Itanium processor.</para>
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Ia")]
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Ia")]
IA64 = 6,
/// <summary>PROCESSOR_ARCHITECTURE_AMD64
/// <para>The system is running a 64-bit version of Windows.</para>
/// </summary>
X64 = 9,
/// <summary>PROCESSOR_ARCHITECTURE_UNKNOWN
/// <para>Unknown architecture.</para>
/// </summary>
Unknown = 65535
}
#endregion // ProcessorArchitecture Name enum
#region Properties
#region IsServer
private static bool _isServer;
/// <summary>Gets a value indicating whether the operating system is a server operating system.</summary>
/// <value><see langword="true"/> if the current operating system is a server operating system; otherwise, <see langword="false"/>.</value>
public static bool IsServer
{
get
{
if (_servicePackVersion == null)
UpdateData();
return _isServer;
}
}
#endregion // IsServer
#region IsWow64Process
private static bool? _isWow64Process;
/// <summary>Gets a value indicating whether the current process is running under WOW64.</summary>
/// <value><see langword="true"/> if the current process is running under WOW64; otherwise, <see langword="false"/>.</value>
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;
/// <summary>Gets the numeric version of the operating system.</summary>
/// <value>The numeric version of the operating system.</value>
public static Version OSVersion
{
get
{
if (_osVersion == null)
UpdateData();
return _osVersion;
}
}
#endregion // OSVersion
#region VersionName
private static EnumOsName _enumOsName = EnumOsName.Later;
/// <summary>Gets the named version of the operating system.</summary>
/// <value>The named version of the operating system.</value>
public static EnumOsName VersionName
{
get
{
if (_servicePackVersion == null)
UpdateData();
return _enumOsName;
}
}
#endregion // VersionName
#region ProcessorArchitecture
private static EnumProcessorArchitecture _processorArchitecture;
/// <summary>Gets the processor architecture for which the operating system is targeted.</summary>
/// <value>The processor architecture for which the operating system is targeted.</value>
/// <remarks>If running under WOW64 this will return a 32-bit processor. Use <see cref="IsWow64Process"/> to determine if this is the case.</remarks>
public static EnumProcessorArchitecture ProcessorArchitecture
{
get
{
if (_servicePackVersion == null)
UpdateData();
return _processorArchitecture;
}
}
#endregion // ProcessorArchitecture
#region ServicePackVersion
private static Version _servicePackVersion;
/// <summary>Gets the version of the service pack currently installed on the operating system.</summary>
/// <value>The version of the service pack currently installed on the operating system.</value>
/// <remarks>Only the <see cref="System.Version.Major"/> and <see cref="System.Version.Minor"/> fields are used.</remarks>
public static Version ServicePackVersion
{
get
{
if (_servicePackVersion == null)
UpdateData();
return _servicePackVersion;
}
}
#endregion // ServicePackVersion
#endregion // Properties
#region Methods
#region IsAtLeast
/// <summary>Determines whether the operating system is of the specified version or later.</summary>
/// <returns><see langword="true"/> if the operating system is of the specified <paramref name="version"/> or later; otherwise, <see langword="false"/>.</returns>
/// <param name="version">The lowest version for which to return true.</param>
public static bool IsAtLeast(EnumOsName version)
{
return VersionName >= version;
}
/// <summary>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.</summary>
/// <returns><see langword="true"/> if the operating system matches the specified <paramref name="version"/> with the specified service pack, or if the operating system is of a later version; otherwise, <see langword="false"/>.</returns>
/// <param name="version">The minimum required version.</param>
/// <param name="servicePackVersion">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.</param>
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;
}
/// <summary>The RtlGetVersion routine returns version information about the currently running operating system.</summary>
/// <returns>RtlGetVersion returns STATUS_SUCCESS.</returns>
/// <remarks>Available starting with Windows 2000.</remarks>
[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);
/// <summary>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.
/// </summary>
/// <returns>This function does not return a value.</returns>
/// <remarks>To determine whether a Win32-based application is running under WOW64, call the <see cref="IsWow64Process"/> function.</remarks>
/// <remarks>Minimum supported client: Windows XP [desktop apps | Windows Store apps]</remarks>
/// <remarks>Minimum supported server: Windows Server 2003 [desktop apps | Windows Store apps]</remarks>
[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);
/// <summary>Determines whether the specified process is running under WOW64.</summary>
/// <returns>
/// 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.
/// </returns>
/// <remarks>Minimum supported client: Windows Vista, Windows XP with SP2 [desktop apps only]</remarks>
/// <remarks>Minimum supported server: Windows Server 2008, Windows Server 2003 with SP1 [desktop apps only]</remarks>
[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
}
}