概要

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ファイルのプロパティで互換性で設定できる互換モードです。
このページではRtlGetVersion 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上)

プログラムソースの概要

RtlGetVersion APIはDDK等をインストールしないとヘッダーファイルやライブラリが使えません。またANSI版が存在しません。
上記の煩わしさを解消するためにGetVersion2関数を作成しました。

_tWinMain

GetVersion2関数を呼び出し、OSVERSIONINFOEX構造体にバージョン情報を取得しメッセージボックスに結果を表示します。

GetVersion2

LoadLibrary APIによりntdll.dllを読み込みます。
GetProcAddress APIによりntdll.dllのRtlGetVersion APIのポインタを取得します。
RtlGetVersion APIを呼び出し、バージョン情報をOSVERSIONINFOEXW構造体に取得します。
マルチバイトでコンパイルする場合は、OSVERSIONINFOEXW構造体のメンバーをOSVERSIONINFOEXAのメンバーにコピーします。
UNICODE文字列が保存されているOSVERSIONINFOEXW構造体のszCSDVersionメンバーの文字列を ANSIに変換してOSVERSIONINFOEXA構造体のszCSDVersionメンバーに代入します。
最後にFreeLibrary APIでntdll.dllを解放します。

プログラムソース

RtlGetVersion.cpp

//       RtlGetVersion APIを使用してWindowsのバージョン番号を取得する
//      RtlGetVersion APIをサポートしていない場合は、GetVersionEx APIを使用する
//      Visual C++ 2005/2008/2013 Unicode/マルチバイト

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

//      DLL内の関数へのポインタ型を定義
typedef void (WINAPI *RtlGetVersion_FUNC)(OSVERSIONINFOEXW*);

BOOL GetVersion2(OSVERSIONINFOEX* os);

int WINAPI _tWinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPTSTR lpsCmdLine, int nCmdShow){
        TCHAR buf[256];
        OSVERSIONINFOEX os;
        if (GetVersion2(&os) == TRUE){

                _stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("MajorVersion %d\nMinorVersion %d\nBuild %d\n"),
                        os.dwMajorVersion, os.dwMinorVersion, os.dwBuildNumber);

                MessageBox(0, buf, _TEXT("Windows Version"), MB_OK);
        }
        else{
                MessageBox(0, _TEXT("RtlGetVersion APIがサポートされていません"), _TEXT("Error"), MB_OK);
        }
        return (int)0;
}

BOOL GetVersion2(OSVERSIONINFOEX* os){
        HMODULE hMod;
        RtlGetVersion_FUNC func;
#ifdef UNICODE
        OSVERSIONINFOEXW* osw = os;
#else
        OSVERSIONINFOEXW o;
        OSVERSIONINFOEXW* osw = &o;
#endif

        hMod = LoadLibrary(TEXT("ntdll.dll"));
        if (hMod){
                func = (RtlGetVersion_FUNC)GetProcAddress(hMod, "RtlGetVersion");
                if (func == 0){
                        FreeLibrary(hMod);
                        return FALSE;
                }
                ZeroMemory(osw, sizeof(*osw));
                osw->dwOSVersionInfoSize = sizeof(*osw);
                func(osw);
#ifndef UNICODE
                os->dwBuildNumber = osw->dwBuildNumber;
                os->dwMajorVersion = osw->dwMajorVersion;
                os->dwMinorVersion = osw->dwMinorVersion;
                os->dwPlatformId = osw->dwPlatformId;
                os->dwOSVersionInfoSize = sizeof(*os);
                DWORD sz = sizeof(os->szCSDVersion);
                WCHAR* src = osw->szCSDVersion;
                unsigned char* dtc = (unsigned char*)os->szCSDVersion;
                while (*src)
                        *dtc++ = (unsigned char)*src++;
                *dtc = '\0';
#endif

        }
        else
                return FALSE;
        FreeLibrary(hMod);
        return TRUE;
}

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>

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

ダウンロード RtlGetVersion.zip(67.7kByte)
ZIPファイルに含まれるファイル
RtlGetVersion.cpp               C++ソースファイル
RtlGetVersion.exe       Visual C++ 2013(v120_xp)で作成した実行ファイル(Windows XP~Windows 10で実行可能)
RtlGetVersion2008.exe   Visual C++ 2008で上作成した実行ファイル(Windows 2000~Windows 10で実行可能)