カンテラの光の下で

dNaga392's memorandom

【C++】Windowsのバージョン情報を取得する

要点

  • C++Windowsのバージョン情報を取得します。
  • Windows 固有のライブラリ ntdll.dll の RtlGetVersion 関数を使います。
  • 内部バージョンが取得できるので、ユーザー向け表示にはひと手間必要です。

説明

Windows のバージョン情報を取得する方法はいくつかありますが、その一つが ntdll.dllRtlGetVersion 関数を使う方法です。

この方法は、マニフェストファイルなど設定ファイルが不要なため、実行の準備が少なくてすむという利点があります。

実際には次の手順で行います。

  1. ntdll.dll を利用するため、 GetModuleHandle 関数でモジュールのハンドルを取得します。
  2. RtlGetVersion を使うため、GetProcAddress 関数で ntdll.dll のモジュールハンドルから関数のアドレスを取得します。
  3. RtlGetVersion を用いて、OS のバージョン情報を取得します。

この方法で得られるバージョン情報は、RTL_OSVERSIONINFOW 構造体として取得されます。

構造体のメンバである dwMajorVersion および dwMinorVersion に、OSの内部バージョンが格納されるので、どのOSなのかは次の表に従って判断します。

dwMajorVersion dwMinorVersion
Windows 10 10 0
Windows 8.1 6 3
Windows 8 6 2
Windows 7 6 1
Windows Vista 6 0

実装例

#include <ntstatus.h>  // RtlGetVersion 関数の戻り値となる STATUS_SUCCESS の定義を使用するため
#include <windows.h>   // GetModuleHandle など、Windows特有の処理を使用するため
#include <iostream>    // std::cout など、実行結果を画面に表示するため

/// DLL 内の関数ポインタを定義
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW lpVersionInformation);

/*!
    \brief OSのバージョンを取得。
*/
RTL_OSVERSIONINFOW GetOsVersion()
{
    auto versionInfo = RTL_OSVERSIONINFOW{sizeof(RTL_OSVERSIONINFOW), 0, 0, 0, 0, 0};

    // 1. `ntdll.dll` を利用するため、 `GetModuleHandle` 関数でモジュールのハンドルを取得します。
    auto hModule = GetModuleHandle(L"ntdll.dll");
    if (!hModule)
    {
        std::cerr << "GetModuleHandle Error" << std::endl;
        return versionInfo;
    }

    // 2. `RtlGetVersion` を使うため、`GetProcAddress` 関数で `ntdll.dll` のモジュールハンドルから関数のアドレスを取得します。
    auto RtlGetVersion = (RtlGetVersionPtr)GetProcAddress(hModule, "RtlGetVersion");
    if (!RtlGetVersion)
    {
        std::cerr << "GetProcAddress Error" << std::endl;
        return versionInfo;
    }

    // 3. `RtlGetVersion` を用いて、OS のバージョン情報を取得します。
    if (RtlGetVersion(&versionInfo) != STATUS_SUCCESS)
    {
        std::cerr << "RtlGetVersion Error" << std::endl;
        return versionInfo;
    }

    return versionInfo;
}

int main(int /*argc*/, char** /*argv*/)
{
    auto version = GetOsVersion();
    std::cout << "OSVersionInfoSize: " << version.dwOSVersionInfoSize << std::endl;
    std::cout << "MajorVersion: " << version.dwMajorVersion << std::endl;
    std::cout << "MinorVersion: " << version.dwMinorVersion << std::endl;
    std::cout << "BuildNumber: " << version.dwBuildNumber << std::endl;
    std::cout << "PlatformId: " << version.dwPlatformId << std::endl;
    std::cout << "CSDVersion: " << version.szCSDVersion << std::endl;
    return 0;
}

実行した結果がこちら。winver の結果とも合っていることが分かりますね。

f:id:dNaga392:20200513233442p:plain

参考資料