OS Version Information

A couple of classes to make checking the host OS version easy and error-free.
By Nicholas Butler

profile for Nicholas Butler at Stack Overflow, Q&A for professional and enthusiast programmers
Publicly recommend on Google


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:

    OSVersionInfo os = new OperatingSystemVersion();
    if ( os < 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 32-bit Windows operating systems. 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 loose 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 eleven static objects in the OSVersionInfo class, covering all the 32-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 WinCE    { get; }
        public static OSVersionInfo Vista    { 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 :)

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, // Win32s

        Win32Windows     =  1, // Win95, Win98, WinME

        Win32NT          =  2, // WinNT351, WinNT4, Win2000, WinXP, Win2003, Vista

        WinCE            =  3, // WinCE

    }

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.

    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,
        WinCE,
        Vista,
    }

This enum specifies one of the eleven 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 :)

OSValues

Out of interest, here are the PlatformId, Major and Minor Version Numbers of the 10 32-bit Windows operating systems :

+----------+------------+-------+-------+
| Version  | PlatformId | Major | Minor |
+----------+------------+-------+-------+
| Win32s   |      0     |   ?   |   ?   |
| Win95    |      1     |   4   |   0   |
| Win98    |      1     |   4   |  10   |
| WinME    |      1     |   4   |  90   |
| WinNT351 |      2     |   3   |  51   |
| WinNT4   |      2     |   4   |   0   |
| Win2000  |      2     |   5   |   0   |
| WinXP    |      2     |   5   |   1   |
| Win2003  |      2     |   5   |   2   |
| WinCE    |      3     |   ?   |   ?   |
| Vista    |      2     |   6   |   0   |
+----------+------------+-------+-------+

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:

Dr. GUI

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

  • 3rd Jan, 2008: Version 2 - supports Vista
  • 25th May, 2005: Version 1

License

This article, along with any associated source code and files, is licensed under The Code Project Open License.

Contact

If you have any feedback, please feel free to contact me.

Publicly recommend on Google: