Introduction
I needed to check the host operating system version for an application I was writing. I wanted to be able to write something like this:
if ( OperatingSystemVersion.Current < OSVersionInfo.WinXP )
{
MessageBox.Show( "Please upgrade your OS" );
Application.Exit();
}
I looked in MSDN and found a lot of links. However, the information I needed was spread out across all the links and none of them did what I wanted. The closest .NET class I found was System.OperatingSystem
, which is available through the Environment.OSVersion
property. This class almost does what I wanted: it gets some information about the OS. However, it doesn't go far enough; it doesn't get all the information I wanted and you have to know the details of Microsoft's version system to use it.
I wanted to demystify all this, so I wrote a higher level abstraction that encapsulates all the different version information for all the Windows operating systems since Windows 95. It's only 1000 lines of code, but it makes what I wanted possible. It includes all the properties of System.OperatingSystem
, so you don't lose anything by using it. It also adds the extra information available on later operating systems (like Service Pack numbers).
So this project makes the code above possible, while also exposing all the available properties of the host operating system if you want to get more details.
Using the Code
To use the code, you can either include the source file ( Common/OSVersion.cs ) in your C# project or copy the library ( Common.OSVersion.dll ) to your project and add a reference to it. The classes are all in the Common
namespace. The code above works as-is. There are 15 static
objects in the OSVersionInfo
class, covering all the 32-bit and 64-bit Windows operating systems. These are:
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; }
...
}
You can also use any of the comparison operators ( ==
, !=
, <=
, >=
, <
, >
) in your test, or you can use the Equals
and CompareTo
methods. If this is all you want to do, then you can skip the rest of this article :)
=== UPDATE v3 ===
The version numbers (both major and minor) for XP x64 and 2003 are identical == 5.2. The same applies to Vista and 2008 == 6.0 and to 2008 R2 and Win7 == 6.1. If you need to differentiate between these systems, you can check the OSVersionInfo.OSProductType
property against OSProductType.Workstation
.
OperatingSystemVersion
This class derives from the main OSVersionInfo
class. It doesn't add any properties; all it does is populate the base OSVersionInfo
object with the current host values in its constructor. It uses PInvoke
to call GetVersionEx
, using either an OSVERSIONINFO
or an OSVERSIONINFOEX
structure to get this information.
OSVersionInfo
This is the main class that you will use most often. It holds all the available information about an operating system and makes this available through properties. All the properties and methods of this class can throw an InvalidOperationException
if they cannot complete. I have grouped the properties into a few sections:
State Properties
These properties handle the state of the OSVersionInfo
object. They are:
public bool IsLocked { get; }
If this property is true
, then the object is "locked" and the set
methods will throw an exception if called. You can lock
an instance in the constructors or call the Lock()
method. You cannot "unlock" an instance except by copying it (then the copy is unlocked).
public bool ExtendedPropertiesAreSet { get; set; }
The extended properties are only set by the OperatingSystemVersion
constructor if the host operating system is NT4 SP6 or later. If you call the get
method of an extended property when this value is false
, an exception will be thrown.
Normal Properties
These properties provide direct access to the underlying fields and are available for all operating systems. They are:
public Common.OSPlatformId OSPlatformId { get; set; }
This property returns an OSPlatformId
, which is an enum
. There are four values:
public enum OSPlatformId
{
Win32s = 0, Win32Windows = 1, Win32NT = 2, WinCE = 3, }
Note that WinCE is defined to be the "latest" operating system.
public int OSMajorVersion { get; set; }
This is the Major Version number. See OSValues for possible values.
public int OSMinorVersion { get; set; }
This is the Minor Version number. See OSValues for possible values.
public int BuildNumber { get; set; }
This is the Build number. I couldn't find a list of possible values, but this will change with each service pack. I have started an associated enum
called OSBuildNumber
, but it only has three values so far. (I only have access to three systems.)
public enum OSBuildNumber
{
None = 0,
Win2000SP4 = 2195,
WinXPSP2 = 2600,
Win2003SP1 = 3790,
}
Note: I would appreciate it if you have access to a different version and if you would email me with the build number of your system. You can get the build number by running the demo OSVersionDemo
. I will then update this article with the appropriate values. I would especially like the build number of NT4 SP6, as this is the first operating system that supports the extended information.
public string OSCSDVersion { get; set; }
This is a string
, such as "Service Pack 3", that indicates the latest service pack installed on the system. If no service pack has been installed, the string
is empty.
Extended Properties
These properties provide direct access to the underlying fields, but are only available for operating systems including or later than NT4 SP6. You can check whether these properties are available by getting the value of the ExtendedPropertiesAreSet
property. If you try to access these properties when ExtendedPropertiesAreSet
is false
, they will throw an exception. They are:
public Commmon.OSSuites OSSuiteFlags { get; set; }
This property is a bit-wise combination of the 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,
}
As you can see, these values mostly apply to server systems.
""OSProductType""> public Commmon.OSProductType OSProductType { get; set; }
This property is an OSProductType
:
public enum OSProductType
{
Invalid = 0,
Workstation = 1,
DomainController = 2,
Server = 3,
}
These values differentiate between the different types of an operating system family.
public Int16 OSServicePackMajor { get; set; }
This property is the Major Version number of the latest service pack that has been applied. If no service pack has been installed, the value is zero.
public Int16 OSServicePackMinor { get; set; }
This property is the Minor Version number of the latest service pack that has been applied. If no service pack has been installed, the value is zero.
public byte OSReserved { get; set; }
This property is reserved for future use.
Underlying Properties
These properties give access to the underlying values in the OSVERSIONINFO
or OSVERSIONINFOEX
structures. They are provided for compatibility with the System.OperatingSystem
class.
public int Platform { get; }
This property is the operating system PlatformId
. See OSPlatformId.
public int SuiteMask { get; }
This property is a bit flag value that identifies the product suites available on the system. See OSSuiteFlags.
public byte ProductType { get; }
This property provides additional information about the system. See OSProductType.
Calculated Properties
These properties are calculated from the underlying fields (and so cannot be set).
public System.Version Version { get; }
This property is provided for compatibility with the System.OperatingSystem
class.
public Common.OSVersion OSVersion { get; }
This property is very useful. It calculates the operating system version from the OSPlatformId
, OSMajorVersion
and OSMinorVersion
. See OSValues for details. It returns a Common.OSVersion
, which is an enum
:
public enum OSVersion
{
Win32s,
Win95,
Win98,
WinME,
WinNT351,
WinNT4,
Win2000,
WinXP,
Win2003,
WinXPx64,
WinCE,
Vista,
Win2008,
Win2008R2,
Win7,
}
This enum
specifies one of the 15 Windows operating system versions.
String Properties
These properties return string
representations of some of the properties:
public string VersionString { get; }
public string OSPlatformIdString { get; }
public string OSSuiteString { get; }
public string OSProductTypeString { get; }
public string OSVersionString { get; }
The Object.ToString()
method is also overridden and provides a full description of the operating system.
Points of Interest
This code is just a wrapper for low-level methods, to provide a useful abstraction of the details. It's not very interesting code, but it does a good job - at least I think so. :)
The hardest part was finding enough information to differentiate between the versions. I've done this now, so you don't have to. :)
Out of interest, here are the PlatformId
, Major and Minor Version Numbers of the 15 32-bit and 64-bit Windows operating systems:
+------------+------------+-------+-------+---------+
| 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 |
+------------+------------+-------+-------+---------+
This is the data that has been encapsulated by the OSVersionInfo
class. Using this class is easier and less error-prone than coding these values across your solution.
References
The information required to decipher the operating system version numbers is spread throughout MSDN. Here are some of the sources I used:
Platform SDK
Knowledge Base
.NET Framework
As you can see, Microsoft didn't make this easy. :)
As always, Lutz Roeder's Reflector [^] and the PInvoke.net [^] Wiki proved very useful.
History
- 29th March, 2010: Version 3 - supports 2008, 2008 R2 and Win7
- 3rd January, 2008: Version 2 - supports XP x64 and Vista
- 25th May, 2005: Version 1 - supports up to 2003