轻松获取和比较操作系统版本信息






4.74/5 (25投票s)
一对类,可轻松无误地检查主机 OS 版本。

引言
我需要为我正在编写的应用程序检查主机操作系统版本。我想写类似这样的代码:
if ( OperatingSystemVersion.Current < OSVersionInfo.WinXP )
{
MessageBox.Show( "Please upgrade your OS" );
Application.Exit();
}
我在MSDN上查找,发现了许多链接。然而,我需要的信息分散在所有链接中,没有任何一个链接能做到我想要的。我找到最接近的.NET类是System.OperatingSystem
,它可以通过Environment.OSVersion
属性访问。这个类几乎能满足我的需求:它能获取一些关于操作系统的基本信息。但是,它不够完善;它不能获取我想要的所有信息,而且你需要了解微软版本系统的细节才能使用它。
我想把这一切都弄清楚,所以我编写了一个更高级别的抽象,它封装了自Windows 95以来的所有Windows操作系统的不同版本信息。代码只有1000行,但它实现了我想要的功能。它包含了System.OperatingSystem
的所有属性,所以你使用它不会丢失任何东西。它还增加了新操作系统(如Service Pack编号)上可用的额外信息。
因此,这个项目使得上面的代码成为可能,同时也暴露了主机操作系统所有可用的属性,如果你想获取更多细节的话。
Using the Code
要使用该代码,你可以将源代码文件(Common/OSVersion.cs)包含在你的C#项目中,或者将库文件(Common.OSVersion.dll)复制到你的项目中并添加一个引用。这些类都在Common
命名空间下。上面的代码可以按原样工作。OSVersionInfo
类中有15个static
对象,涵盖了所有32位和64位Windows操作系统。它们是:
public class OSVersionInfo : IComparable, ICloneable
{
...
public static OSVersionInfo Win32s { get; }
public static OSVersionInfo Win95 { get; }
public static OSVersionInfo Win98 { get; }
public static OSVersionInfo WinME { get; }
public static OSVersionInfo WinNT351 { get; }
public static OSVersionInfo WinNT4 { get; }
public static OSVersionInfo Win2000 { get; }
public static OSVersionInfo WinXP { get; }
public static OSVersionInfo Win2003 { get; }
public static OSVersionInfo WinXPx64 { get; }
public static OSVersionInfo WinCE { get; }
public static OSVersionInfo Vista { get; }
public static OSVersionInfo Win2008 { get; }
public static OSVersionInfo Win2008R2 { get; }
public static OSVersionInfo Win7 { get; }
...
}
你也可以在你的测试中使用任何比较运算符(==
, !=
, <=
, >=
, <
, >
),或者你可以使用Equals
和CompareTo
方法。如果你只想做这些,那么你可以跳过本文的其余部分:)
=== 更新 v3 ===
XP x64和2003的版本号(主版本号和次版本号)是相同的 == 5.2。Vista和2008也是如此 == 6.0,2008 R2和Win7也是如此 == 6.1。如果你需要区分这些系统,你可以检查OSVersionInfo.OSProductType
属性是否等于OSProductType.Workstation
。
OperatingSystemVersion
这个类继承自主OSVersionInfo
类。它不添加任何属性;它所做的就是在其构造函数中用当前主机的值填充基类OSVersionInfo
对象。它使用PInvoke
调用GetVersionEx
,使用OSVERSIONINFO
或OSVERSIONINFOEX
结构来获取此信息。
OSVersionInfo
这是你最常使用的类。它保存了关于操作系统所有可用信息,并通过属性公开。如果OSVersionInfo
类的所有属性和方法无法完成,它们都可能抛出InvalidOperationException
。我将属性分为几个部分:
状态属性
这些属性处理OSVersionInfo
对象的状态。它们是:
public bool IsLocked { get; }
如果此属性为true
,则该对象被“锁定”,并且调用set
方法将抛出异常。你可以在构造函数中lock
一个实例或调用Lock()
方法。你不能“解锁”一个实例,除非通过复制它(然后副本是未锁定的)。
public bool ExtendedPropertiesAreSet { get; set; }
扩展属性仅由OperatingSystemVersion
构造函数设置,前提是主机操作系统为NT4 SP6或更高版本。如果你在ExtendedPropertiesAreSet
为false
时调用扩展属性的get
方法,将抛出异常。
普通属性
这些属性提供对底层字段的直接访问,并适用于所有操作系统。它们是:
public Common.OSPlatformId OSPlatformId { get; set; }
此属性返回一个OSPlatformId
,它是一个enum
。有四个值:
public enum OSPlatformId
{
Win32s = 0, // Win32s
Win32Windows = 1, // Win95, Win98, WinME
Win32NT = 2, // WinNT351, WinNT4, Win2000, WinXP, Win2003, Vista
WinCE = 3, // WinCE
}
请注意,WinCE被定义为“最新”的操作系统。
public int OSMajorVersion { get; set; }
这是主版本号。可能的数值请参见OSValues。
public int OSMinorVersion { get; set; }
这是次版本号。可能的数值请参见OSValues。
public int BuildNumber { get; set; }
这是Build编号。我找不到可能的数值列表,但这会随着每个Service Pack而变化。我已经开始了一个相关的enum
,名为OSBuildNumber
,但目前只有三个值。(我只有三个系统的访问权限。)
public enum OSBuildNumber
{
None = 0,
Win2000SP4 = 2195,
WinXPSP2 = 2600,
Win2003SP1 = 3790,
}
注意:如果你有不同版本系统的访问权限,并且愿意通过电子邮件向我发送你的系统Build编号,我将不胜感激。你可以通过运行演示程序OSVersionDemo
来获取Build编号。然后,我将更新本文档,包含相应的数值。我特别需要NT4 SP6的Build编号,因为它是第一个支持扩展信息的操作系统。
public string OSCSDVersion { get; set; }
这是一个string
,例如“Service Pack 3”,表示系统中安装的最新Service Pack。如果没有安装Service Pack,则该string
为空。
扩展属性
这些属性提供对底层字段的直接访问,但仅适用于包括NT4 SP6或更高版本的操作系统。你可以通过获取ExtendedPropertiesAreSet
属性的值来检查这些属性是否可用。如果你尝试在ExtendedPropertiesAreSet
为false
时访问这些属性,它们将抛出异常。它们是:
public Commmon.OSSuites OSSuiteFlags { get; set; }
此属性是OSSuites enum
的位组合
[ Flags ]
public enum OSSuites
{
None = 0,
SmallBusiness = 0x00000001,
Enterprise = 0x00000002,
BackOffice = 0x00000004,
Communications = 0x00000008,
Terminal = 0x00000010,
SmallBusinessRestricted = 0x00000020,
EmbeddedNT = 0x00000040,
Datacenter = 0x00000080,
SingleUserTS = 0x00000100,
Personal = 0x00000200,
Blade = 0x00000400,
EmbeddedRestricted = 0x00000800,
}
正如你所见,这些值大多适用于服务器系统。
public Commmon.OSProductType OSProductType { get; set; }
此属性是一个OSProductType
public enum OSProductType
{
Invalid = 0,
Workstation = 1,
DomainController = 2,
Server = 3,
}
这些值区分了操作系统家族的不同类型。
public Int16 OSServicePackMajor { get; set; }
此属性是已应用的最新Service Pack的主版本号。如果没有安装Service Pack,则值为零。
public Int16 OSServicePackMinor { get; set; }
此属性是已应用的最新Service Pack的次版本号。如果没有安装Service Pack,则值为零。
public byte OSReserved { get; set; }
此属性保留供将来使用。
底层属性
这些属性允许访问OSVERSIONINFO
或OSVERSIONINFOEX
结构中的底层值。它们是为了与System.OperatingSystem
类兼容而提供的。
public int Platform { get; }
此属性是操作系统的PlatformId
。参见OSPlatformId。
public int SuiteMask { get; }
此属性是一个位标志值,用于标识系统中可用的产品套件。参见OSSuiteFlags。
public byte ProductType { get; }
此属性提供有关系统的附加信息。参见OSProductType。
计算属性
这些属性是从底层字段计算出来的(因此不能设置)。
public System.Version Version { get; }
此属性是为了与System.OperatingSystem
类兼容而提供的。
public Common.OSVersion OSVersion { get; }
此属性非常有用。它根据OSPlatformId
、OSMajorVersion
和OSMinorVersion
计算操作系统版本。有关详细信息,请参见OSValues。它返回一个Common.OSVersion
,它是一个enum
。
public enum OSVersion
{
Win32s,
Win95,
Win98,
WinME,
WinNT351,
WinNT4,
Win2000,
WinXP,
Win2003,
WinXPx64,
WinCE,
Vista,
Win2008,
Win2008R2,
Win7,
}
此enum
指定了15种Windows操作系统版本之一。
字符串属性
这些属性返回某些属性的string
表示形式。
public string VersionString { get; }
public string OSPlatformIdString { get; }
public string OSSuiteString { get; }
public string OSProductTypeString { get; }
public string OSVersionString { get; }
Object.ToString()
方法也已重写,并提供操作系统的完整描述。
关注点
这段代码只是一个低级方法的包装器,用于提供对细节的有用抽象。它不是很有趣的代码,但它做得很好——至少我认为是这样。:)
最困难的部分是找到足够的信息来区分不同的版本。我现在已经做到了,所以你不需要了。:)
OSValues
出于兴趣,以下是15种32位和64位Windows操作系统的PlatformId
、主版本号和次版本号:
+------------+------------+-------+-------+---------+
| Version | PlatformId | Major | Minor | Release |
+------------+------------+-------+-------+---------+
| Win32s | 0 | ? | ? | |
| Win95 | 1 | 4 | 0 | 1995 08 |
| Win98 | 1 | 4 | 10 | 1998 06 |
| WinME | 1 | 4 | 90 | 2000 09 |
| WinNT351 | 2 | 3 | 51 | 1995 04 |
| WinNT4 | 2 | 4 | 0 | 1996 07 |
| Win2000 | 2 | 5 | 0 | 2000 02 |
| WinXP | 2 | 5 | 1 | 2001 10 |
| Win2003 | 2 | 5 | 2 | 2003 04 |
| WinXPx64 | 2 | 5 | 2 | 2003 03 |
| WinCE | 3 | ? | ? | |
| Vista | 2 | 6 | 0 | 2007 01 |
| Win2008 | 2 | 6 | 0 | 2008 02 |
| Win2008R2 | 2 | 6 | 1 | 2009 10 |
| Win7 | 2 | 6 | 1 | 2009 10 |
+------------+------------+-------+-------+---------+
这是OSVersionInfo
类所封装的数据。使用此类比在解决方案中硬编码这些值更容易,也更不容易出错。
参考文献
解读操作系统版本号所需的信息分散在MSDN中。以下是我使用的一些来源:
Platform SDK
- 获取系统版本 [^]
- 操作系统版本 [^]
- GetVersionEx [^]
- OSVERSIONINFO 结构 [^]
- OSVERSIONINFOEX 结构 [^]
知识库
.NET Framework
正如你所见,微软并没有让这件事变得容易。:)
一如既往,Lutz Roeder的Reflector [^]和PInvoke.net [^] Wiki都非常有帮助。
历史
- 2010年3月29日:版本3 - 支持2008、2008 R2和Win7
- 2008年1月3日:版本2 - 支持XP x64和Vista
- 2005年5月25日:版本1 - 支持到2003