概要

Windows上でバージョン情報を取得する方法はいろいろありますが主な方法として以下の3種類の方法が考えられます。
API マニフェスト 互換モード 備考
GetVersionEx API 8.1以上を取得時には指定が必要 依存 Windows 95以上又はWindows NT 3.5以上で実行可能
Windows 8.1以降は非推奨だが10でも使用可能
VerfyVersionInfo API 10以上を取得時には指定が必要 非依存 自身のWindowsのバージョンに対して上位か同一か下位といった判定しかできない
Windows 2000以上でのみ実行可能
RtlGetVersion API 非依存 依存 DDK等をインストールしていない場合、ヘッダーファイルおよびライブラリが無い
Windows 2000以上でのみ実行可能
上表のマニフェストはマニフェストにより動作バージョンを明示することを意味します。
マニフェストを指定しない場合、Windows 8.1まで正常な答えが得られました。マニフェストを指定しない場合ではWindows 10ではWindows 8相当の答えが返ってきます。 上表の互換モードはexeファイルのプロパティで互換性で設定できる互換モードです。
このページではVerfyVersionInfo APIについて解説します。
VerfyVersionInfo APIは、OSVERSIONINFOEX構造体に設定したバージョンと実行しているWindowsのバージョンを比較し、指定した条件を満足するか否かを返します。
本プログラムではVerfyVersionInfo APIを使用してメージャー・マイナー・サービスパック・ビルド番号を検索して表示します。
以下に本プログラムを各Windowsで実行した例を示します。
Windows 2000 Service Pack 4 Windows XP Service Pack 3 Windows Vista Service Pack 2 Windows 7 Service Pack 1 Windows 8.1 Windows 10

Windowsの内部バージョン一覧

Windowsの内部バージョン一覧を以下に示します。
メンバー NT 3.1
Workstation
NT
3.5 Workstation
NT
3.51 Workstation
dwMajorVersion 3 3 3
dwMinorVersion 1 5 51
wProductType 1 1 1

メンバー NT 4.0
Workstation
95 98 98SE me
dwMajorVersion 4 4 4 4 4
dwMinorVersion 0 0 10 10 90
wProductType 1 0 0 0 0

メンバー 2000 XP 2003R2
dwMajorVersion 5 5 5
dwMinorVersion 0 1 2
wProductType 1 1 3

メンバー Vista 7 2008R2 8 8.1 2012 2012R2
dwMajorVersion 6 6 6 6 6 6 6
dwMinorVersion 0 1 1 2 3 2 3
wProductType 1 1 3 1 1 3 3

メンバー 10
dwMajorVersion 10
dwMinorVersion 0
wProductType 1

テスト環境

コンパイラ

Visual C++ 2008 Standard 32/64bit
Visual C++ 2013 Express 32/64bit

プロジェクトの作成

Win32プロジェクト Windowsアプリケーション

実行環境

Windows 10 Pro 64bit(Virtual Box上)
Windows 8.1 Enterprise 64bit
Windows 7 EnterPrise Service Pack 1 64bit
Windows Vista Ultimate Service Pack 2 32bit
Windows XP Professional Service Pack 3 32bit
Windows 2000 Professional Service Pack 4(Virtual Box上)

プログラムソースの概要

_WinMain関数

OSVERSIONINFOEX構造体をZeroMemoryで0に初期化後、dwOSVersionInfoSizeメンバーに構造体サイズをセットします。
VerSetConditionMask APIによりどのメンバーを検索対象にするか、比較方法をcmaskに保存します。
maskにどのメンバーを検索対象にするかを指定します。
メジャーバージョンを取得するために、 OSVERSIONINFOEX構造体へのポインタ・取得するメンバーへのポインタ・maskとcmaskを指定してgetVerDword関数を 呼び出し指定メンバーの値を取得します。
VerSetConditionMask APIにより検索条件を合成しgetVerDword関数及びgetVerWord関数を呼び出し順番に値を取得していきます。
必要な値の取得が全部終了した後、文字列化してメッセージボックスで表示します。

getVerDword関数

指定メンバーの32bit値を取得します。マイナーバージョンとそれ以外では値の取得方法を変えています。
マイナーバージョンの取得
メンバー変数のポインタとOSVERINFOEX->dwMinorVersionのポインタを比較し一致した場合マイナーバージョンとなります。 マイナーバージョンの場合、OSVERINFOEXのdwMinorVersionメンバーを0から順番に増やしてゆき一致したマイナーバージョンを取得します。
マイナーバージョン以外の取得
上位1bitから下位に向ってビット単位で比較をします。 ビット単位の比較をするために、まずsum=0として上位1bitを比較(変数bit_chkとsumを加算した値をOSVERSIONINFOEXのメンバーに設定してVerifyVersionInfo APIを呼び出す)をして Windowsのバージョンがそれ以上(戻り値がTRUEの場合)であればsumにOSVERSIONINFOEXのメンバーに設定した値を代入します。 その後、bit_chkを1bit右シフトし、比較を下位0ビットになるまで比較します。比較が終了したときのsumの値がWindowsバージョンになります
VerSetConditionMask
VerifyVersionInfo APIの検索条件を作成する関数です。 関数のプロトタイプは以下の通りです。
ULONGLONG WINAPI VerSetConditionMask(
  _In_ ULONGLONG dwlConditionMask,
  _In_ DWORD     dwTypeBitMask,
  _In_ BYTE      dwConditionMask
);
dwlConditionMaskは最初に0にしておく必要があります。
dwTypeBitMaskは検索対象を指定します。
dwTypeBitMask メンバー 取得する項目
VER_BUILDNUMBER dwBuildNumber ビルド番号
VER_MAJORVERSION dwMajorVersion メジャーバージョン
VER_MINORVERSION dwMinorVersion マイナーバージョン
VER_PLATFORMID dwPlatformId プラットフォーム
VER_PRODUCT_TYPE wProductType プロダクトタイプ
VER_SERVICEPACKMAJOR wServicePackMajor サービスパックメジャー
VER_SERVICEPACKMINOR wServicePackMinor サービスパックマイナー
VER_SUITENAME wSuiteMask スイート名
dwConditionMaskは検索対象の比較方法を指定します。
Value Meaning
VER_EQUAL 実行OS==指定OS
VER_GREATER 実行OS>指定OS
VER_GREATER_EQUAL 実行OS>=指定OS
VER_LESS 実行OS<指定OS
VER_LESS_EQUAL 実行OS<=指定OS
検索条件を複数設定する場合には、複数回VerSetConditionMaskを実行し、検索条件を合成します。
VerifyVersionInfo
比較を実行し結果を返す関数です。
比較条件はVerSetConditionMaskで作成します。
指定した比較条件が成立した場合は0以外の値が返り、成立しない場合およびエラーの場合は0が返ります。
以下に実行しているWindowsがWindows 7以上かを判別するコードの例を示します。
なお、Visual C++ 2013ではVersionHelpers.hで定義されている、IsWindows8Point1OrGreater()などを使えば簡単になります。 IsWindows8Point1OrGreater関数は、内部的にメージャーとマイナーバージョンを設定しVerifyVersionInfo APIで比較しているだけです。
VerifyVersionInfo.cpp
#include <windows.h>
#include <tchar.h>

int WINAPI _tWinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPTSTR lpsCmdLine, int nCmdShow){
        OSVERSIONINFOEX ver;
        ver.dwOSVersionInfoSize = sizeof(ver);
        ver.dwMajorVersion = 6;
        ver.dwMinorVersion =1;
        LONGLONG cmask = 0;
        cmask=VerSetConditionMask(cmask, VER_MAJORVERSION, VER_GREATER_EQUAL);
        cmask = VerSetConditionMask(cmask, VER_MINORVERSION, VER_GREATER_EQUAL);

        BOOL b;
        b = VerifyVersionInfo(&ver, VER_MAJORVERSION | VER_MINORVERSION , cmask);
        if (b == TRUE){
                MessageBox(0, _TEXT("使用しているOSはWindows 7以上です。"), _TEXT("情報"), MB_OK);
        }else{
                if (GetLastError()==ERROR_OLD_WIN_VERSION)
                        MessageBox(0, _TEXT("使用しているOSはWindows 7未満です。"), _TEXT("情報"), MB_OK);
                else
                        MessageBox(0, _TEXT("比較に失敗しました。"), _TEXT("エラー"), MB_OK);
        }
}

getVerWord関数

getVerDword関数は取得する値が16bitである以外は、getVerWord関数と同じです。

プログラムソース

VerifyVersionInfo2.cpp

//       VerifyVersionInfo APIを用いてバージョンを取得
//      Visual C++ 2005/2008/2013       32/64bit

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

//      VerifyVersionInfo APIを使いOSVERINFOEXの指定したDWORDの値を取得
void getVerDword(OSVERSIONINFOEX* ver, DWORD* dwp, DWORD mask, LONGLONG cmask);

//      VerifyVersionInfo APIを使いOSVERINFOEXの指定したWORDの値を取得
void getVerWord(OSVERSIONINFOEX* ver, WORD* wp, DWORD mask, LONGLONG cmask);

//      VerifyVersionInfo APIを使いOSVERINFOEXの指定したBYTEの値を取得
void getVerByte(OSVERSIONINFOEX* ver, BYTE* bp, DWORD mask, LONGLONG cmask);

int WINAPI _tWinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPTSTR lpsCmdLine, int nCmdShow){
        OSVERSIONINFOEX ver;
        ZeroMemory(&ver, sizeof(ver));
        ver.dwOSVersionInfoSize = sizeof(ver);

        LONGLONG cmask = 0;
        DWORD mask;
        cmask = VerSetConditionMask(cmask, VER_MAJORVERSION, VER_GREATER_EQUAL);
        mask = VER_MAJORVERSION;
        getVerDword(&ver, &ver.dwMajorVersion, mask, cmask);

        cmask = VerSetConditionMask(cmask, VER_MINORVERSION, VER_GREATER_EQUAL);
        mask |= VER_MINORVERSION;
        getVerDword(&ver, &ver.dwMinorVersion, mask , cmask);

        cmask = VerSetConditionMask(cmask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
        mask |= VER_SERVICEPACKMAJOR;
        getVerWord(&ver, &ver.wServicePackMajor, mask , cmask);

        cmask = VerSetConditionMask(cmask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
        mask |= VER_BUILDNUMBER;
        getVerDword(&ver, &ver.dwBuildNumber,mask , cmask);

        TCHAR buf[64];
        _stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("メジャー%d マイナー%d\nサービスパック%d\nビルド%d"), ver.dwMajorVersion,ver.dwMinorVersion,ver.wServicePackMajor,ver.dwBuildNumber);
        MessageBox(0, buf, _TEXT("Windowsバージョン"), MB_OK);
}

//      VerifyVersionInfo APIを使いOSVERINFOEXの指定したDWORDの値を取得

void getVerDword(OSVERSIONINFOEX* ver, DWORD* dwp, DWORD mask, LONGLONG cmask){

        if ((BYTE*)dwp == (BYTE*)&(ver->dwMinorVersion)){        //      マイナーバージョンの検索である
                LONGLONG cmask = 0;
                cmask = VerSetConditionMask(cmask, VER_MAJORVERSION, VER_EQUAL);
                cmask = VerSetConditionMask(cmask, VER_MINORVERSION, VER_EQUAL);
                for (int n = 0; n < 65536; n++){
                        *dwp = n;
                        BOOL b;
                        b = VerifyVersionInfo(ver, mask, cmask);
                        if (b == TRUE)
                                return;
                }
                *dwp = 0xffffffff;
                return;

        }else{
                UINT sum = 0;
                int bit_max = 15;
                UINT bit_chk = 1 << bit_max;
                while (0 <= bit_max){
                        BOOL b;
                        *dwp = sum | bit_chk;
                        b = VerifyVersionInfo(ver, mask, cmask);
                        if (b == TRUE)
                                sum |= bit_chk;
                        bit_chk >>= 1;
                        --bit_max;
                }
                *dwp = sum;
        }
}

//      VerifyVersionInfo APIを使いOSVERINFOEXの指定したWORDの値を取得

void getVerWord(OSVERSIONINFOEX* ver, WORD* wp, DWORD mask, LONGLONG cmask){
        UINT sum = 0;
        int bit_max = 15;
        UINT bit_chk = 1 << bit_max;
        while (0 <= bit_max){
                BOOL b;
                *wp = sum + bit_chk;
                b = VerifyVersionInfo(ver, mask, cmask);
                if (b == TRUE)
                        sum += bit_chk;
                bit_chk >>= 1;
                --bit_max;
        }
        *wp = sum;
}

//      VerifyVersionInfo APIを使いOSVERINFOEXの指定したBYTEの値を取得

void getVerByte(OSVERSIONINFOEX* ver, BYTE* bp, DWORD mask, LONGLONG cmask){
        UINT sum = 0;
        int bit_max = 15;
        UINT bit_chk = 1 << bit_max;
        while (0 <= bit_max){
                BOOL b;
                *bp = sum + bit_chk;
                b = VerifyVersionInfo(ver, mask, cmask);
                if (b == TRUE)
                        sum += bit_chk;
                bit_chk >>= 1;
                --bit_max;
        }
        *bp = sum;
}

manifest.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
        <application> 
            <!-- Windows 7 -->
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
            <!-- Windows 8 -->
            <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
            <!-- Windows 8.1 -->
            <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
            <!-- Windows 10 -->
            <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>

        </application> 
    </compatibility>
</assembly>

ソースファイルと実行ファイルのダウンロード

ダウンロード VerifyVersionInfo.zip(105kByte)
ZIPファイルに含まれるファイル
VerifyVersionInfo.cpp   Windows 7以上を検出するプログラムのC++ソースファイル
VerifyVersionInfo.exe   Windows 7以上を検出するプログラム
manifest.xml            Windows 7~Windows 10までの動作環境を指定したマニフェストファイル
VerifyVersionInfo2.cpp  メジャー・マイナー・サービスパック・ビルド番号を取得するプログラムのC++ソースファイル
VerifyVersionInfo2.exe  Visual C++ 2013(v120_xp)で上記マニフェストファイルを組み込んで作成した実行ファイル(Windows XP~Windows 10で実行可能)
VerifyVersionInfo2_2008.exe     Visual C++ 2008で上記マニフェストファイルを組み込んで作成した実行ファイル(Windows 2000~Windows 10で実行可能)