DOBON.NET

OSのバージョンを取得する、OSの種類を判別する

ここでは、現在のOSのバージョン情報やOSの種類等を取得する方法について説明します。

Environment.OSVersionプロパティを使用する方法

OSのバージョン情報は、EnvironmentクラスのOSVersionプロパティを使って取得できます。OSVersionプロパティで取得できるOperatingSystemオブジェクトのVersionプロパティで、OSのバージョンが分かります。また、ServicePackプロパティで、OSのサービスパックの情報が分かります。さらに、Platformプロパティで、OSがWindows 95系かNT系かが分かります。

注意:Windows 8.1以上、もしくはWindows Server 2012 R2以上では、Environment.OSVersionプロパティが正しいバージョン「6.3」を返さずに、「6.2」と返す可能性があります。これについて詳しくは、後述します。

以下の例では、OSVersionプロパティを使って、現在のOSの情報を表示しています。

VB.NET
コードを隠すコードを選択
'OSの情報を取得する
Dim os As System.OperatingSystem = System.Environment.OSVersion

'OSの情報を表示する
Console.WriteLine(os.ToString())
'Windows 8.1では、「Microsoft Windows NT 6.2.9200.0」

'次のようにしても同じ(.NET Framework 2.0以降)
Console.WriteLine(os.VersionString)

'OSのバージョンを表示する
Console.WriteLine(os.Version.ToString())
'Windows 8では、「6.2.9200.0」

'OSの各バージョン情報を表示する
'OSのPlatformIDを表示する
Console.WriteLine(os.Platform)
'Windows 8では、「Win32NT」

'OSのメジャーバージョン番号を表示する
Console.WriteLine(os.Version.Major)
'Windows 8では、「6」

'OSのマイナーバージョン番号を表示する
Console.WriteLine(os.Version.Minor)
'Windows 8では、「2」

'OSのビルド番号を表示する
Console.WriteLine(os.Version.Build)
'Windows 8では、「9200」

'OSのリビジョン番号を表示する
Console.WriteLine(os.Version.Revision)
'Windows 8では、「0」

'OSのサービスパックのバージョンを表示する(.NET Framework 2.0以降)
Console.WriteLine(os.ServicePack)
'Windows 8では、空の文字列

'OSのメジャーリビジョン番号を表示する(.NET Framework 2.0以降)
Console.WriteLine(os.Version.MajorRevision)
'Windows 8では、「0」

'OSのマイナーリビジョン番号を表示する(.NET Framework 2.0以降)
Console.WriteLine(os.Version.MinorRevision)
'Windows 8では、「0」
C#
コードを隠すコードを選択
//OSの情報を取得する
System.OperatingSystem os = System.Environment.OSVersion;

//OSの情報を表示する
Console.WriteLine(os.ToString());
//Windows 8.1では、「Microsoft Windows NT 6.2.9200.0」

//次のようにしても同じ(.NET Framework 2.0以降)
Console.WriteLine(os.VersionString);

//OSのバージョンを表示する
Console.WriteLine(os.Version.ToString());
//Windows 8では、「6.2.9200.0」

//OSの各バージョン情報を表示する
//OSのPlatformIDを表示する
Console.WriteLine(os.Platform);
//Windows 8では、「Win32NT」

//OSのメジャーバージョン番号を表示する
Console.WriteLine(os.Version.Major);
//Windows 8では、「6」

//OSのマイナーバージョン番号を表示する
Console.WriteLine(os.Version.Minor);
//Windows 8では、「2」

//OSのビルド番号を表示する
Console.WriteLine(os.Version.Build);
//Windows 8では、「9200」

//OSのリビジョン番号を表示する
Console.WriteLine(os.Version.Revision);
//Windows 8では、「0」

//OSのサービスパックのバージョンを表示する(.NET Framework 2.0以降)
Console.WriteLine(os.ServicePack);
//Windows 8では、空の文字列

//OSのメジャーリビジョン番号を表示する(.NET Framework 2.0以降)
Console.WriteLine(os.Version.MajorRevision);
//Windows 8では、「0」

//OSのマイナーリビジョン番号を表示する(.NET Framework 2.0以降)
Console.WriteLine(os.Version.MinorRevision);
//Windows 8では、「0」

次に、現在のOSが指定したバージョンより上かどうかを調べる例を紹介します。以下の例では、OSがWindows Vista以降か、さらにWindows 7以降かを調べています。

VB.NET
コードを隠すコードを選択
'OSのバージョン情報を取得する
Dim os As System.OperatingSystem = System.Environment.OSVersion

'Windows NT系か調べる
If os.Platform = PlatformID.Win32NT Then
    'メジャーバージョン番号が6以上ならば、Vista(または、Server 2008)以降
    If os.Version.Major >= 6 Then
        Console.WriteLine("OSは、Windows Vista以降です。")
        'マイナーバージョン番号が1以上ならば、7(または、Server 2008 R2)以降
        If os.Version.Minor >= 1 Then
            Console.WriteLine("OSは、Windows 7以降です。")
        End If
    End If
End If
C#
コードを隠すコードを選択
//OSのバージョン情報を取得する
System.OperatingSystem os = System.Environment.OSVersion;

//Windows NT系か調べる
if (os.Platform == PlatformID.Win32NT)
{
    //メジャーバージョン番号が6以上ならば、Vista(または、Server 2008)以降
    if (os.Version.Major >= 6)
    {
        Console.WriteLine("OSは、Windows Vista以降です。");
        //マイナーバージョン番号が1以上ならば、7(または、Server 2008 R2)以降
        if (os.Version.Minor >= 1)
        {
            Console.WriteLine("OSは、Windows 7以降です。");
        }
    }
}

補足:Windows XP互換モードでは、Environment.OSVersionと、後述するGetVersionExが別の値を返すことがあるという不具合が「互換モードでのSystem.Environment.クラスとWin32 APIの動作違い | Microsoft Connect」で報告されています。

Windowsのバージョンと製品名

Windowsのバージョンと製品名を表にまとめます。バージョンは、「(メジャーバージョン番号).(マイナーバージョン番号)」です。

この表には、.NET Framework非対応のOSも含まれています。

この表は、MSDNの「OSVERSIONINFOEX structure」やWikipediaの「Comparison of Microsoft Windows versions」を参考にして作成しました。

OSの製品名バージョン
Windows 1010.0
Windows Server 201610.0
Windows 8.16.3
Windows Server 2012 R26.3
Windows 86.2
Windows Server 20126.2
Windows 76.1
Windows Server 2008 R26.1
Windows Home Server 20116.1
Windows Vista6.0
Windows Server 20086.0
Windows XP Professional x64 Edition5.2
Windows Server 20035.2
Windows Server 2003 R25.2
Windows Home Server5.2
Windows XP5.1
Windows 20005.0
Windows Millennium Edition4.90
Windows 98 Second Edition4.10
Windows 984.10
Windows NT 4.04.0
Windows 954.0
Windows NT 3.513.51
Windows NT 3.53.5
Windows NT 3.13.1

PlatformプロパティとOSの種類

OperatingSystem.Platformプロパティは、PlatformID列挙値として取得できます。PlatformID列挙値の意味は、以下の通りです。

PlatformID列挙体のメンバ名説明基になる値
Win32NTWindows NT系のOSです。(Windows XP, Vista, 7, 8, Server 2003, Server 2008, Server 2012など)2
Win32WindowsWindows 95系のOSです。(Windows 95, 98, Meなど)1
Win32SWin32sです。0
WinCEWindows CEです。3
UnixUnixです。(.NET Framework 2.0以降)4
XboxXbox 360です(開発プラットフォーム)。(.NET Framework 3.5以降)5
MacOSXMacintoshです。(.NET Framework 3.5以降)6

WMIを使用する方法

WMIのWin32_OperatingSystemクラスを使用してもOSのバージョンを取得することができます。Environment.OSVersionプロパティでは取得できないような情報も得ることができます。

なおWin32_OperatingSystemクラスを使った例は、「メモリの合計サイズ、利用可能なメモリのサイズなどを取得する」でも紹介しています。

下に例を示します。この例を実行するには、System.Management.dllを参照設定に追加する必要があります。

VB.NET
コードを隠すコードを選択
Dim mc As New System.Management.ManagementClass("Win32_OperatingSystem")
Dim moc As System.Management.ManagementObjectCollection = mc.GetInstances()
For Each mo As System.Management.ManagementObject In moc
    '簡単な説明(Windows 8.1では「Microsoft Windows 8.1 Pro」等)
    Console.WriteLine(mo("Caption"))
    'バージョン(Windows 8.1では、「6.3.9600」)
    Console.WriteLine(mo("Version"))
    'ビルド番号(Windows 8.1では「9600」)
    Console.WriteLine(mo("BuildNumber"))
    'OSのタイプ(Windows NT系は「18」)
    Console.WriteLine(mo("OSType"))
    '0:ワークステーション 1:ドメインコントローラ 2:サーバー
    Console.WriteLine(mo("ProductType"))
    'サービスパック(Windows 8.1ではNULL)
    Console.WriteLine(mo("CSDVersion"))
    '言語(日本語は「1041」)
    Console.WriteLine(mo("OSLanguage"))
    '製品スイートを示すビットフラグ(Enterprise、BackOffice、Terminalなど)
    Console.WriteLine(mo("OSLanguage"))
Next
moc.Dispose()
mc.Dispose()
C#
コードを隠すコードを選択
System.Management.ManagementClass mc =
    new System.Management.ManagementClass("Win32_OperatingSystem");
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
    //簡単な説明(Windows 8.1では「Microsoft Windows 8.1 Pro」等)
    Console.WriteLine(mo["Caption"]);
    //バージョン(Windows 8.1では、「6.3.9600」)
    Console.WriteLine(mo["Version"]);
    //ビルド番号(Windows 8.1では「9600」)
    Console.WriteLine(mo["BuildNumber"]);
    //OSのタイプ(Windows NT系は「18」)
    Console.WriteLine(mo["OSType"]);
    //0:ワークステーション 1:ドメインコントローラ 2:サーバー
    Console.WriteLine(mo["ProductType"]);
    //サービスパック(Windows 8.1ではNULL)
    Console.WriteLine(mo["CSDVersion"]);
    //言語(日本語は「1041」)
    Console.WriteLine(mo["OSLanguage"]);
    //製品スイートを示すビットフラグ(Enterprise、BackOffice、Terminalなど)
    Console.WriteLine(mo["OSLanguage"]);
}
moc.Dispose();
mc.Dispose();

GetVersionExを使用する方法

Win32 APIのGetVersionEx functionを使うことによって、OSのバージョン情報を取得することもできます。

ただしWindows 8.1からは、GetVersionExはdeprecated(廃止予定)とされ、正しいバージョンを返さない可能性があります。詳しくは、後述します。

以下にGetVersionExを使用した例を示します。

VB.NET
コードを隠すコードを選択
<System.Runtime.InteropServices.StructLayout( _
    System.Runtime.InteropServices.LayoutKind.Sequential)> _
Public Structure OSVERSIONINFO
    Public dwOSVersionInfoSize As Integer
    Public dwMajorVersion As Integer
    Public dwMinorVersion As Integer
    Public dwBuildNumber As Integer
    Public dwPlatformId As Integer
    <System.Runtime.InteropServices.MarshalAs( _
        System.Runtime.InteropServices.UnmanagedType.ByValTStr, _
        SizeConst:=128)> _
    Public szCSDVersion As String
End Structure

'Windows 2000以降は、OSVERSIONINFOEXも使える
<System.Runtime.InteropServices.StructLayout( _
    System.Runtime.InteropServices.LayoutKind.Sequential)> _
Public Structure OSVERSIONINFOEX
    Public dwOSVersionInfoSize As UInteger
    Public dwMajorVersion As UInteger
    Public dwMinorVersion As UInteger
    Public dwBuildNumber As UInteger
    Public dwPlatformId As UInteger
    <System.Runtime.InteropServices.MarshalAs( _
        System.Runtime.InteropServices.UnmanagedType.ByValTStr, _
        SizeConst:=128)> _
    Public szCSDVersion As String
    Public wServicePackMajor As Short
    Public wServicePackMinor As Short
    Public wSuiteMask As Short
    Public wProductType As Byte
    Public wReserved As Byte
End Structure

<System.Runtime.InteropServices.DllImport("kernel32")> _
Public Shared Function GetVersionEx(ByRef osvi As OSVERSIONINFOEX) As Boolean
End Function

'Button1のClickイベントハンドラ
Private Sub Button1_Click(sender As Object, e As EventArgs) _
        Handles Button1.Click
    Dim osvi As New OSVERSIONINFOEX()
    osvi.dwOSVersionInfoSize = _
        CUInt(System.Runtime.InteropServices.Marshal.SizeOf(osvi))
    GetVersionEx(osvi)

    'メジャーバージョン番号
    Console.WriteLine(osvi.dwMajorVersion)
    'マイナーバージョン番号
    Console.WriteLine(osvi.dwMinorVersion)
    'ビルド番号
    Console.WriteLine(osvi.dwBuildNumber)
    'PlatformId
    Console.WriteLine(osvi.dwPlatformId)
    'サービスパック
    Console.WriteLine(osvi.szCSDVersion)
    '0:ワークステーション 1:ドメインコントローラ 2:サーバー
    Console.WriteLine(osvi.wProductType)
    '製品スイートを示すビットフラグ(Enterprise、BackOffice、Terminalなど)
    Console.WriteLine(osvi.wSuiteMask)
End Sub
C#
コードを隠すコードを選択
[System.Runtime.InteropServices.StructLayout(
    System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct OSVERSIONINFO
{
    public int dwOSVersionInfoSize;
    public int dwMajorVersion;
    public int dwMinorVersion;
    public int dwBuildNumber;
    public int dwPlatformId;
    [System.Runtime.InteropServices.MarshalAs(
        System.Runtime.InteropServices.UnmanagedType.ByValTStr,
        SizeConst = 128)]
    public string szCSDVersion;
}

//Windows 2000以降は、OSVERSIONINFOEXも使える
[System.Runtime.InteropServices.StructLayout(
    System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct OSVERSIONINFOEX
{
    public uint dwOSVersionInfoSize;
    public uint dwMajorVersion;
    public uint dwMinorVersion;
    public uint dwBuildNumber;
    public uint dwPlatformId;
    [System.Runtime.InteropServices.MarshalAs( 
        System.Runtime.InteropServices.UnmanagedType.ByValTStr,
        SizeConst = 128)]
    public string szCSDVersion;
    public short wServicePackMajor;
    public short wServicePackMinor;
    public short wSuiteMask;
    public byte wProductType;
    public byte wReserved;
}

[System.Runtime.InteropServices.DllImport("kernel32")]
public static extern bool GetVersionEx(ref OSVERSIONINFOEX osvi);

//Button1のClickイベントハンドラ
private void Button1_Click(object sender, EventArgs e)
{
    OSVERSIONINFOEX osvi = new OSVERSIONINFOEX();
    osvi.dwOSVersionInfoSize =
        (uint)System.Runtime.InteropServices.Marshal.SizeOf(osvi);
    GetVersionEx(ref osvi);

    //メジャーバージョン番号
    Console.WriteLine(osvi.dwMajorVersion);
    //マイナーバージョン番号
    Console.WriteLine(osvi.dwMinorVersion);
    //ビルド番号
    Console.WriteLine(osvi.dwBuildNumber);
    //PlatformId
    Console.WriteLine(osvi.dwPlatformId);
    //サービスパック
    Console.WriteLine(osvi.szCSDVersion);
    //0:ワークステーション 1:ドメインコントローラ 2:サーバー
    Console.WriteLine(osvi.wProductType);
    //製品スイートを示すビットフラグ(Enterprise、BackOffice、Terminalなど)
    Console.WriteLine(osvi.wSuiteMask);
}

VerifyVersionInfoを使用する方法

Windows 2000 APIのVerifyVersionInfo functionVerSetConditionMask functionを使用すれば、現在のOSが指定したバージョンより上か(あるいは、下か、等しいか)を知ることができます。ただしVerifyVersionInfoができるのは比較することだけで、ズバリとバージョン番号を取得することはできません。

補足:一つ一つのバージョンをしらみつぶしに調べていけば、VerifyVersionInfoでもOSのバージョンを特定することはできます。その例が、「Windows8.1でもバージョン情報を正しく取得する C#編」などで紹介されています。

以下に、VerifyVersionInfoを使用した例を示します。このIsWindowsVersionOrGreaterメソッドを使えば、現在のOSが指定されたバージョン以上かを調べることができます。例えば、現在のOSがWindows 8.1以上かを調べるには「IsWindowsVersionOrGreater(6, 3, 0)」を呼び出して、Trueが返されたらWindows 8.1以上です。

VB.NET
コードを隠すコードを選択
<System.Runtime.InteropServices.DllImport("kernel32.dll")> _
Private Shared Function VerifyVersionInfo( _
    <System.Runtime.InteropServices.In> _
    ByRef lpVersionInfo As OSVERSIONINFOEX, _
    dwTypeMask As UInteger, _
    dwlConditionMask As ULong) As Boolean
End Function

<System.Runtime.InteropServices.DllImport("kernel32.dll")> _
Private Shared Function VerSetConditionMask( _
    dwlConditionMask As ULong, _
    dwTypeBitMask As UInteger, _
    dwConditionMask As Byte) As ULong
End Function

Private Const VER_MINORVERSION As UInteger = &H1
'dwMajorVersion
Private Const VER_MAJORVERSION As UInteger = &H2
'dwMinorVersion
Private Const VER_BUILDNUMBER As UInteger = &H4
'dwBuildNumber
Private Const VER_PLATFORMID As UInteger = &H8
'dwPlatformId
Private Const VER_SERVICEPACKMINOR As UInteger = &H10
'wServicePackMajor
Private Const VER_SERVICEPACKMAJOR As UInteger = &H20
'wServicePackMinor
Private Const VER_SUITENAME As UInteger = &H40
'wSuiteMask
Private Const VER_PRODUCT_TYPE As UInteger = &H80
'wProductType
'現在の値と指定された値が同じでなければならない
Private Const VER_EQUAL As Byte = 1
'現在の値が指定された値より大きくなければならない
Private Const VER_GREATER As Byte = 2
'現在の値が指定された値より大きいか同じでなければならない
Private Const VER_GREATER_EQUAL As Byte = 3
'現在の値が指定された値より小さいくなければならない
Private Const VER_LESS As Byte = 4
'現在の値が指定された値より小さいか同じでなければならない
Private Const VER_LESS_EQUAL As Byte = 5
'指定されたwSuiteMaskがすべて含まれていななければならない
Private Const VER_AND As Byte = 6
'指定されたwSuiteMaskの少なくとも1つが含まれていななければならない
Private Const VER_OR As Byte = 7

<System.Runtime.InteropServices.StructLayout( _
System.Runtime.InteropServices.LayoutKind.Sequential)> _
Public Structure OSVERSIONINFOEX
    Public dwOSVersionInfoSize As UInteger
    Public dwMajorVersion As UInteger
    Public dwMinorVersion As UInteger
    Public dwBuildNumber As UInteger
    Public dwPlatformId As UInteger
    <System.Runtime.InteropServices.MarshalAs( _
        System.Runtime.InteropServices.UnmanagedType.ByValTStr, _
        SizeConst:=128)> _
    Public szCSDVersion As String
    Public wServicePackMajor As Short
    Public wServicePackMinor As Short
    Public wSuiteMask As Short
    Public wProductType As Byte
    Public wReserved As Byte
End Structure

''' <summary>
''' 現在のOSが指定されたバージョン以上かを調べる
''' </summary>
''' <param name="majorVersion">
''' メジャーバージョン番号。負の数の時は調べない。</param>
''' <param name="minorVersion">
''' マイナーバージョン番号。負の数の時は調べない。</param>
''' <param name="servicePackMajor">
''' サービスパックのメジャーバージョン番号。負の数の時は調べない。</param>
''' <returns>現在のOSが指定されたバージョン以上ならTrue。</returns>
Public Shared Function IsWindowsVersionOrGreater( _
        majorVersion As Integer, _
        minorVersion As Integer, _
        servicePackMajor As Integer) As Boolean
    If majorVersion < 0 AndAlso _
        minorVersion < 0 AndAlso _
        servicePackMajor < 0 Then
        Return True
    End If

    'lpVersionInfo、dwTypeMask、dwlConditionMaskを作成する
    Dim osvi As New OSVERSIONINFOEX()
    Dim typeMask As UInteger = 0
    Dim conditionMask As ULong = 0
    If 0 < majorVersion Then
        osvi.dwMajorVersion = CUInt(majorVersion)
        conditionMask = VerSetConditionMask(conditionMask, _
            VER_MAJORVERSION, VER_GREATER_EQUAL)
        typeMask = typeMask Or VER_MAJORVERSION
    End If
    If 0 < minorVersion Then
        osvi.dwMinorVersion = CUInt(minorVersion)
        conditionMask = VerSetConditionMask(conditionMask, _
            VER_MINORVERSION, VER_GREATER_EQUAL)
        typeMask = typeMask Or VER_MINORVERSION
    End If
    If 0 < servicePackMajor Then
        osvi.wServicePackMajor = CShort(servicePackMajor)
        conditionMask = VerSetConditionMask(conditionMask, _
            VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL)
        typeMask = typeMask Or VER_SERVICEPACKMAJOR
    End If

    'VerifyVersionInfoを呼び出す
    Return VerifyVersionInfo(osvi, typeMask, conditionMask)
End Function
C#
コードを隠すコードを選択
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool VerifyVersionInfo(
    [System.Runtime.InteropServices.In]
    ref OSVERSIONINFOEX lpVersionInfo,
    uint dwTypeMask,
    ulong dwlConditionMask);

[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern ulong VerSetConditionMask(
    ulong dwlConditionMask,
    uint dwTypeBitMask,
    byte dwConditionMask);

private const uint VER_MINORVERSION = 0x0000001; //dwMajorVersion
private const uint VER_MAJORVERSION = 0x0000002; //dwMinorVersion
private const uint VER_BUILDNUMBER = 0x0000004; //dwBuildNumber
private const uint VER_PLATFORMID = 0x0000008; //dwPlatformId
private const uint VER_SERVICEPACKMINOR = 0x0000010; //wServicePackMajor
private const uint VER_SERVICEPACKMAJOR = 0x0000020; //wServicePackMinor
private const uint VER_SUITENAME = 0x0000040; //wSuiteMask
private const uint VER_PRODUCT_TYPE = 0x0000080; //wProductType

//現在の値と指定された値が同じでなければならない
private const byte VER_EQUAL = 1;
//現在の値が指定された値より大きくなければならない
private const byte VER_GREATER = 2;
//現在の値が指定された値より大きいか同じでなければならない
private const byte VER_GREATER_EQUAL = 3;
//現在の値が指定された値より小さいくなければならない
private const byte VER_LESS = 4;
//現在の値が指定された値より小さいか同じでなければならない
private const byte VER_LESS_EQUAL = 5;
//指定されたwSuiteMaskがすべて含まれていななければならない
private const byte VER_AND = 6;
//指定されたwSuiteMaskの少なくとも1つが含まれていななければならない
private const byte VER_OR = 7;

[System.Runtime.InteropServices.StructLayout(
    System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct OSVERSIONINFOEX
{
    public uint dwOSVersionInfoSize;
    public uint dwMajorVersion;
    public uint dwMinorVersion;
    public uint dwBuildNumber;
    public uint dwPlatformId;
    [System.Runtime.InteropServices.MarshalAs( 
        System.Runtime.InteropServices.UnmanagedType.ByValTStr,
        SizeConst = 128)]
    public string szCSDVersion;
    public short wServicePackMajor;
    public short wServicePackMinor;
    public short wSuiteMask;
    public byte wProductType;
    public byte wReserved;
}

/// <summary>
/// 現在のOSが指定されたバージョン以上かを調べる
/// </summary>
/// <param name="majorVersion">
/// メジャーバージョン番号。負の数の時は調べない。</param>
/// <param name="minorVersion">
/// マイナーバージョン番号。負の数の時は調べない。</param>
/// <param name="servicePackMajor">
/// サービスパックのメジャーバージョン番号。負の数の時は調べない。</param>
/// <returns>現在のOSが指定されたバージョン以上ならTrue。</returns>
public static bool IsWindowsVersionOrGreater(
    int majorVersion, int minorVersion, int servicePackMajor)
{
    if (majorVersion < 0 && minorVersion < 0 && servicePackMajor < 0)
    {
        return true;
    }

    //lpVersionInfo、dwTypeMask、dwlConditionMaskを作成する
    OSVERSIONINFOEX osvi = new OSVERSIONINFOEX();
    uint typeMask = 0;
    ulong conditionMask = 0;
    if (0 < majorVersion)
    {
        osvi.dwMajorVersion = (uint)majorVersion;
        conditionMask = VerSetConditionMask(
            conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
        typeMask |= VER_MAJORVERSION;
    }
    if (0 < minorVersion)
    {
        osvi.dwMinorVersion = (uint)minorVersion;
        conditionMask = VerSetConditionMask(
            conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
        typeMask |= VER_MINORVERSION;
    }
    if (0 < servicePackMajor)
    {
        osvi.wServicePackMajor = (short)servicePackMajor;
        conditionMask = VerSetConditionMask(
            conditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
        typeMask |= VER_SERVICEPACKMAJOR;
    }

    //VerifyVersionInfoを呼び出す
    return VerifyVersionInfo(ref osvi, typeMask, conditionMask);
}

システムDLLのバージョンを調べる方法

MSDNの「Getting the System Version」によると、OSのフルのバージョン番号を取得するには、Kernel32.dllのようなシステムDLLのバージョンを取得するということです。この方法に従うなら、「ファイルのバージョン情報を取得する」で紹介しているFileVersionInfoクラスを使ってKernel32.dllのバージョンを取得すればよいということになりそうです。

ただ、OSのバージョンとKernel32.dllのバージョンが必ず一致するのかは、私には分かりません。

VB.NET
コードを隠すコードを選択
'kernel32.dllのパスを取得する
Dim dllPath As String = System.IO.Path.Combine( _
    System.Environment.SystemDirectory, "kernel32.dll")

If System.IO.File.Exists(dllPath) Then
    'FileVersionInfoを作成する
    Dim vi As System.Diagnostics.FileVersionInfo = _
        System.Diagnostics.FileVersionInfo.GetVersionInfo(dllPath)

    'バージョン番号
    Console.WriteLine(vi.FileVersion)
    'メジャーバージョン番号
    Console.WriteLine(vi.FileMajorPart)
    'マイナバージョン番号
    Console.WriteLine(vi.FileMinorPart)
End If
C#
コードを隠すコードを選択
//kernel32.dllのパスを取得する
string dllPath = System.IO.Path.Combine(
    System.Environment.SystemDirectory, "kernel32.dll");

if(System.IO.File.Exists(dllPath))
{
    //FileVersionInfoを作成する
    System.Diagnostics.FileVersionInfo vi =
        System.Diagnostics.FileVersionInfo.GetVersionInfo(dllPath);

    //バージョン番号
    Console.WriteLine(vi.FileVersion);
    //メジャーバージョン番号
    Console.WriteLine(vi.FileMajorPart);
    //マイナバージョン番号
    Console.WriteLine(vi.FileMinorPart);
}

レジストリから取得する方法

レジストリの「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion」(Windows 95系のOSの場合は「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion」)キーにWindowsのバージョン情報があります。「CurrentVersion」に現在のバージョン([メジャーバージョン番号].[マイナーバージョン番号])、「CurrentBuild」にビルド番号、「ProductName」に製品名が格納されています。

ただ、レジストリにあるバージョンが常に正しいという保証があるかという点は、分かりません。

なおレジストリから値を取得する方法については、「レジストリへの書き込み、読み込み、削除を行う」をご覧ください。

VB.NET
コードを隠すコードを選択
'キーを開く
Dim regkey As Microsoft.Win32.RegistryKey = _
    Microsoft.Win32.Registry.LocalMachine.OpenSubKey( _
        "SOFTWARE\Microsoft\Windows NT\CurrentVersion", False)
'キーが存在しないときは、Windows 95系のキーを試す
If regkey Is Nothing Then
    regkey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( _
        "SOFTWARE\Microsoft\Windows\CurrentVersion", False)
    If regkey Is Nothing Then
        Return
    End If
End If

'バージョンを取得する
Dim versionString As String = _
    DirectCast(regkey.GetValue("CurrentVersion"), String)

'閉じる
regkey.Close()

'結果を表示する
Console.WriteLine(versionString)
C#
コードを隠すコードを選択
//キーを開く
Microsoft.Win32.RegistryKey regkey =
    Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
    @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", false);
//キーが存在しないときは、Windows 95系のキーを試す
if (regkey == null)
{
    regkey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
        @"SOFTWARE\Microsoft\Windows\CurrentVersion", false);
    if (regkey == null)
    {
        return;
    }
}

//バージョンを取得する
string versionString = (string)regkey.GetValue("CurrentVersion");

//閉じる
regkey.Close();

//結果を表示する
Console.WriteLine(versionString);

Windows 8.1(または、Windows Server 2012 R2)以上で正しいバージョンを取得する

前述したように、GetVersionExはWindows 8.1(およびWindows Server 2012 R2)からはdeprecatedとされ、何もしないと正しいバージョン(6.3)を返さず、間違ったバージョン(6.2)を返します。Environment.OSVersionプロパティも内部でGetVersionEx(あるいは、GetVersion)を使用していますので、やはり正しいバージョンを取得できません。

解決法としては、まずEnvironment.OSVersionプロパティやGetVersionExを使わない方法に切り替えることが考えられます。

どうしてもEnvironment.OSVersionプロパティやGetVersionExを使い続けなければならない場合は、解決法が「Operating system version changes in Windows 8.1 and Windows Server 2012 R2」にあります。これによると、アプリケーションがWindows 8.1をサポートしていることをマニフェストに明記していれば、GetVersionExでも正しいバージョンを取得できるということです。

具体的には、プロジェクトにまだマニフェストファイルがなければ、まずこれを作成します。Visual Studio 2008以上では、プロジェクトに新しい項目として「アプリケーションマニフェストファイル」を追加することで作成することができます。詳しくは、「マニフェストファイルを使用して、起動時に自動で管理者に昇格させるようにする」をご覧ください。

次に、マニフェストファイルのcompatibilityセクションにサポートするOSとしてWindows 8.1を追加します。Visual Studio 2013でアプリケーションマニフェストファイルを作成した時は以下のような内容になるため、必要なsupportedOSノードのコメントを解除するだけでOKです。

<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
        <!-- UAC マニフェスト オプション
            Windows のユーザー アカウント制御のレベルを変更するには、
            requestedExecutionLevel ノードを以下のいずれかで置換します。

        <requestedExecutionLevel  level="asInvoker" uiAccess="false" />
        <requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />
        <requestedExecutionLevel  level="highestAvailable" uiAccess="false" />

            requestedExecutionLevel ノードを指定すると、ファイルおよびレジストリの仮想化は無効になります。
            旧バージョンとの互換性のためにファイルおよびレジストリの仮想化を
            使用する場合は、requestedExecutionLevel ノードを削除します。
        -->
        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
      </requestedPrivileges>
    </security>
  </trustInfo>

  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!--このアプリケーションが動作するように設計されている、Windows のすべてのバージョンの一覧。
      Windows は最も互換性の高い環境を自動的に選択します。-->

      <!--アプリケーションが Windows Vista で動作するように設計されている場合は、次の supportedOS ノードのコメントを解除します-->
      <!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS>-->

      <!-- アプリケーションが Windows 7 で動作するように設計されている場合は、次の supportedOS ノードのコメントを解除します。-->
      <!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>-->

      <!--アプリケーションが Windows 8 で動作するように設計されている場合は、次の supportedOS ノードのコメントを解除します-->
      <!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS>-->

      <!-- アプリケーションが Windows 8.1 で動作するように設計されている場合は、次の supportedOS ノードのコメントを解除してください-->
      <!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>-->

    </application>
  </compatibility>

  <!-- Windows のコモン コントロールとダイアログのテーマを有効にします (Windows XP 以降) -->
  <!-- <dependency>
    <dependentAssembly>
      <assemblyIdentity
          type="win32"
          name="Microsoft.Windows.Common-Controls"
          version="6.0.0.0"
          processorArchitecture="*"
          publicKeyToken="6595b64144ccf1df"
          language="*"
        />
    </dependentAssembly>
  </dependency>-->

</asmv1:assembly>

Visual Studio 2015では、アプリケーションマニフェストファイルにWindows 10用のsupportedOSノードも記述されています。Windows 10用のsupportedOSノードは、「<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />」です。

MSDNには、「Targeting your application for Windows」にアプリケーションマニフェストファイルのサンプルがあります。

サービスパックのバージョンを取得する

.NET Framework 2.0からは、OperatingSystem.ServicePackプロパティでサービスパックのバージョンを取得できます。また、OperatingSystem.VersionStringプロパティでもサービスパック情報の付いた文字列を取得できます。例えば、Windows XP SP2の場合は、ServicePackプロパティが「Service Pack 2」、VersionStringプロパティが「Microsoft Windows NT 5.1.2600 Service Pack 2」のようになります。

WMIのWin32_OperatingSystemクラスを使用した時は、CSDVersionプロパティで「Service Pack 2」のように取得できます。また、ServicePackMajorVersionプロパティでサービスパックのメジャーバージョン番号を、ServicePackMinorVersionプロパティでマイナーバージョン番号を取得できます。「Service Pack 2」の場合は、メジャーバージョン番号が2、マイナーバージョン番号が0です。

GetVersionExなどを使ってOSVERSIONINFOEXで取得した時は、szCSDVersionフィールドにサービスパックの情報が「Service Pack 2」のように入ります。また、サービスパックのメジャーバージョン番号がwServicePackMajor、マイナーバージョン番号がwServicePackMinorに入ります。

サーバーかどうか調べる

OSがサーバーかどうかは、Environment.OSVersionプロパティでは分かりません。

WMIを使用した方法ならば、Win32_OperatingSystemクラスのProductTypeプロパティで分かります。ProductTypeプロパティが1ならば、ワークステーション(Windows 8, Windows 7, Windows Vistaなど)です。それ以外ならば、OSはサーバー(Windows Server 2012, Windows Server 2008 R2, Windows Server 2008など)です(ProductTypeが2の時は、ドメインコントローラです)。

また、GetVersionExなどを使ってOSVERSIONINFOEXで取得したのであれば、wProductTypeフィールドによって同じ判断(1以外ならサーバー)ができます。

c# - Determining if the program is running on Windows Server」によると、サーバーかどうかを調べるだけならば、IsOS functionを使用することもできます。

VB.NET
コードを隠すコードを選択
<System.Runtime.InteropServices.DllImport("shlwapi.dll", _
    SetLastError:=True, EntryPoint:="#437")> _
Private Shared Function IsOS(os As Integer) As Boolean
End Function
Private Const OS_ANYSERVER As Integer = 29

''' <summary>
''' 現在のOSがサーバーかどうか調べる
''' </summary>
''' <returns>サーバーならTrue。それ以外はFalse。</returns>
Public Shared Function IsWindowsServer() As Boolean
    Return IsOS(OS_ANYSERVER)
End Function
C#
コードを隠すコードを選択
[System.Runtime.InteropServices.DllImport("shlwapi.dll",
    SetLastError = true, EntryPoint = "#437")]
private static extern bool IsOS(int os);
private const int OS_ANYSERVER = 29;

/// <summary>
/// 現在のOSがサーバーかどうか調べる
/// </summary>
/// <returns>サーバーならTrue。それ以外はFalse。</returns>
public static bool IsWindowsServer()
{
    return IsOS(OS_ANYSERVER);
}

64ビットかどうか調べる

アプリケーションが64ビットで動いているか調べる」で説明しています。

  • 履歴:
  • 2005/1/5 Service Packの取得方法を追加。
  • 2007/2/20 OperatingSystem.ServicePackプロパティを使用した方法を追加。
  • 2007/5/17 OSの判別にWindows Vistaを追加。
  • 2010/3/30 OSの判別にWindows 7等を追加。説明の補足など。
  • 2014/6/11 「VerifyVersionInfoを使用する方法」、「システムDLLのバージョンを調べる方法」、「レジストリから取得する方法」、「Windows 8.1(または、Windows Server 2012 R2)で正しいバージョンを取得する」、「サーバーかどうか調べる」を追加。「GetVersionExを使用する方法」のサンプルでOSVERSIONINFOEXを使うように変更。「Environment.OSVersionプロパティを使用する方法」で、OSを特定するサンプルコードをやめて、別のコードに変更。Windowsのバージョンと製品名の表を追加。
  • 2016/8/28 Windows 10に関する記述を追加。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。
  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。
  • 「???を参照に追加します」の意味が分からないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。
共有する

この記事への評価

この記事へのコメント

この記事に関するコメントを投稿するには、下のボタンをクリックしてください。投稿フォームへ移動します。通常のご質問、ご意見等は掲示板へご投稿ください。