Windowsのバージョンを表示(VerifyVersionInfo版)

icon 項目のみ表示/展開表示の切り替え

概要

Visual C++ 2013でGetVersionEx APIを使用したコードをコンパイルすると警告が出てコンパイルできません。これはWindows 8.1で将来GetVersionExが廃止する予定であるため使わないでほしいという 意思表示です。とりあえずは、警告をプラグマで抑制すればコンパイルはできます。マニフェストで実行環境をWindows 8.1にしないとWindows 8.1上で実行してもGetVersionEx APIはWindows 8相当を返します。
マニフェストを設定した場合、Windows 9x系のWindowsでは実行できなくなります。(いまさらWindows9x系ですが趣味のプログラムなのでサポートしています。)
将来廃止予定のAPIを使用するのは、気が引けるので、Windows 2000からサポートしている、VerifyVersionInfo APIを使用してバージョンを取得します。Windows 9x系等のVerifyVersionInfo APIをサポートしていない場合は、GetVersionEx APIを使用します。
プログラムは、GetVerrionEx関数で使われる構造体OSVERSIONINFOEXを継承したEXTOSVERSIONINFOEXクラスを作成し、そのメンバー関数としてバージョンの取得等をサポートしています。
Visual C++ 2005 ExpressでコンパイルするとWindows 98にも対応します。Windows 9x系はMessageBox API以外はUNICODEに対応していないのでマルチバイトでコンパイルしてください。

テスト環境

コンパイラ

Visual C++ 2005/2008/2010/2013 Express 32/64bit マルチバイト/UNICODE

実行環境

クリックすると実行したときの画面が表示されます。
本ソフトの実行状況、マイコンピュータのプロパティをプリントスクリーンした状態です。
Windows 98 Second Editon 32bit(Virtual Box上の仮想マシーン)
Windows 98Second Editonのビルド番号は67766446(0x40a08ae)という変な数字になっているが下位16bitを抽出すると2222(0x08ae)となり一致する。
Windows 2000 Professional Service Pack 4 32bit(Virtual Box上の仮想マシーン)
Windows XP Professional Service Pack 3 32bit(Virtual Box上の仮想マシーン)
Windows Vista Ulitimate Service Pack 2 32bit(Virtual Box上の仮想マシーン)
Windows 7 Enterprise Service Pack 1 64bit
Windows 8.1 Enterprise 64bit
Windows Server 2003R2 Enterprise Service Pack 2 64bit 英語版(Virtual Box上の仮想マシーン)
Windows Server 2008R2 Datacenter Service Pack 1 64bit(Virtual Box上の仮想マシーン)
Windows Server 2012 Standard 64bit(Virtual Box上の仮想マシーン)

プログラムソースの概要

osver3.cpp

_tWinMain

英語版でもメッセージが読めるようにまず、GetOEMCP APIでコードページを取得します。
なぜ英語版を対象としているかと言うと評価版で手に入るWindows 2003R2が英語版しかないからです。
日本語版の場合は932が返ってくるので日本語メッセージをそれ以外の場合は英語メッセージを設定します。
後述するOSVERSIONINFOEXを拡張したクラスであるEXTOSVERSIONINFOEXオブジェクトを作成します。
EXTOSVERSIONINFOEX::get()を呼び出し、バージョン情報を取得します。
EXTOSVERSIONINFOEX::getOsname()を呼び出し、Windows名(7 vista等)を取得します。Windows名が不明のときはNULLが返されます。
NULLが返されたときは、unknownまたは不明という名称に設定します。
_stprintf_s関数で取得されたバージョン情報から表示する文字列を作成し、MessageBox APIを呼び出します。

extosversion.h extosversion.cpp

OSVERSIONINFOEXを拡張したクラスであるEXTOSVERSIONINFOEXの定義およびWindows名をあらわしたマクロの定義、Visual C++ 2005/2008で定義されていないSM_SERVERR2を定義しています。

EXTOSVERSIONINFOEXクラス

OSVERSIONINFOEX構造体を基本クラスとしていくつかのメンバー変数・関数を追加しています。
したがって、クラスへのポインタをOSVERSIONINFOEX*へキャストすればOSVERSIONINFOEXを対象としたAPIがそのまま使えます。
メンバー変数は、GetVersionEx,VerifyVersionInfo等のAPIへのエントリポイントやWindows 2003とWindows 2003R2を判別するためのsm2があります。
EXTOSVERSIONINFOEX() //コンストラクタ
EXTOSVERSIONINFOEXが作成されたときに呼び出されます。
まず、クラスのメンバーをZeroMemory APIにより全部0でクリアします。
GetVersionEx,VerifyVersionInfo等のAPIがサポートされていないWindowsを想定し、DLL内のAPIへのエントリポイントをGetProcAddress APIで取得してみます。
マルチバイトとUNICODEでAPI名が異なる場合は、UNICODEマクロを見て必要なAPI名を設定します。
エントリポイントが0の場合は、そのAPIはサポートされていないことになります。
直接APIを記述しないメリットは、コンパイラの警告に引っかからないこと、サポートされていないAPI名が直接記述されているとサポートされていないWindows上で実行した場合、門前払いされ強制終了されますが、エントリポイントを使えば、違うAPIで対応するなど実行時に柔軟な対応ができることです。
get() //Windows Versionを取得する
VerifyVersionInfo APIが使える(Windows 2000以上)場合は、GetSystemMetrics APIでWindows 2003とWindows 2003R2を判別するための情報を取得した後、 メンバー関数 GetDWORD()・GetWORD()・GetBYTE()を使用してバージョンを取得します。
VerifyVersionInfo APIが使えない場合はGetVersionEx APIで従来どおりバージョンを取得します。
コンストラクタで説明したとおり、直接APIを呼び出すのではなくGetProcAddress APIで取得したエントリポイントを使って、APIを呼び出しているので、Visual C++ 2013でコンパイルしても警告はでません。
Windows 2000以降を実行対象と限定すれば、if文の条件が成立した場合の{}の中のみ有効にすれば問題ありません。
GetDWORD() //VerifyVersionInfo APIによりOSVERSIONINFOEXのメンバー変数(32bit値)を得る
VerifyVersionInfo APIを使用して指定されたメンバー変数(32bit値)を取得します。
このAPIはGetVersionExと違い、OSVERSIONINFOEXのメンバー変数に設定された値と実行時のWindowsの指定された項目とを比較し、同一、以上、以下のいずれかの情報しか返しません。
このAPIを使用した例として、Visual C++ 2013のVersionHelpers.hで定義されている、IsWindows8Point1OrGreater()などが参考になると思います。この関数は、内部的にメージャーとマイナーバージョンを設定しVerifyVersionInfo APIで比較しているだけです。
このようにWindows 8.1以上などという比較は割合簡単ですが、バージョンが想定されないときは面倒なAPIです。
バージョンを取得する 方法としては、たとえば0から1ずつ加算しながらにVerifyVersionInfo APIを呼び出していき、同一と判定された場合その値がバージョン情報となります。メジャーやマイナーバージョンはWindowsでは32bit値のメンバー変数として定義されていますが、Windowsのメジャーバージョンがたとえば65535(Windows 8.1では6)などという大きな値が将来てきに使われることはあまり考えられません。しかし、今後はビルト番号が10000を超えることもありそうなので、1ずつ加算して同一になるのをチェックするのは、効率が非常に悪いです。
本プログラムでは、上位1bitから下位に向ってビット単位で比較をします。そのほかの方法としては、10,100,1000単位で10進数の桁ごとにチェックするなどいろいろ方法は考えられます。ビット単位の比較をするために、まずsum=0として上位1bitを比較(変数bitとsumを加算した値をOSVERSIONINFOEXのメンバーに設定してVerifyVersionInfo APIを呼び出す)をしてWindowsのバージョンがそれ以上(戻り値がTRUEの場合)であればsumにOSVERSIONINFOEXのメンバーに設定した値を代入します。その後、bitを1bit右シフトし、比較を下位0ビットになるまで比較します。比較が終了したときのsumの値がWindowsバージョンになります。
OSVERSIONINFOEXのどのメンバーを比較するかは、本メンバー関数の第2引数(例えば VER_MAJORVERSION)で指定します。どのメンバーを取得するかは、そのメンバーのポインタを渡すことにより決定されます。(第1引数)
VerifyVersionInfo APIの第3引数は比較対象を指定するものであり、VerSetConditionMask APIで作成された値を用います。前述のとおりマイナーバージョンを比較するためには、メジャーバージョンとマイナーバージョンを比較対象にする必要があるので本メンバー関数の第2引数を下位1bitから上位に向かって1bitずつチェックし、bitが1の場合、VerSetConditionMask APIにより比較対象を示す値を合成してゆきます。
32bitを得るためには、32回VerifyVersionInfo APIを呼び出す必要がありますが、一番大きい値となるビルと番号でも16bitに収まる値なので、最初に16bitを超えるかどうかチェックし、超える場合は32bit比較し、超えない場合は16回比較します。通常であれば17回の比較ですみます。
ビルト番号を取得する必要がなく、メジャーバージョンとマイナーバージョンを取得するだけの場合は単純にメジャーバージョンを4から7程度、マイナーバージョンを0から10程度1ずつ加算してゆけば十分かと思います。ここでは32bitのメンバー変数を1つのメンバー関数で対応するためにこのような記述となっています。バージョン取得を1つのプログラムでベンチマークのように何万回とか実行するわけではないので、問題ないかと思います。
比較対象は複数設定することが可能です。
GetMinor()
GetDword()でマイナーバージョンのみを取得する場合Windows 8.1では正常な動作をしませんでした。テストのためにメジャーバージョン・マイナーバージョン・サービスパック・一致条件を入力するとVerifyVersionInfo APIの結果を表示するプログラムを作成してみました。

実行ファイルとソースファイルのダウンロード(Visual C++ 2005 マルチバイトでコンパイル)


実行結果は、Windows 8.1で期待した動作をしていません。
Windows 8.1は メジャー 6 マイナー 3 サービスパックは無であり、VER_EQUALで比較した場合は正常です。
マイナーバージョンを変化させた場合、指定したマイナーバージョン16に対して実際は3なのでVerifyVersionInfo APIはFALSEを返さなければなりませんがTRUEを返しています。128,256,1024,2048,16384も同様です。他のメンバーと同様にGetDWord()を使用すると異常なマイナーバージョンを取得してしまいます。VER_EQUALを指定した場合は、正常に動作しているので、マイナーバージョンに限っては、0から1ずつ加算しながらマイナーバージョンが一致するまで検索することにしました。
実行結果の一覧
Windows 8.1                             
Major   Minor   SP      cond    return
6       3       0       Equal   TRUE
6       16384   0       Greate_Equal    TRUE
6       8192    0       Greate_Equal    FALSE
6       4096    0       Greate_Equal    FALSE
6       2048    0       Greate_Equal    TRUE
6       1024    0       Greate_Equal    TRUE
6       512     0       Greate_Equal    FALSE
6       256     0       Greate_Equal    TRUE
6       128     0       Greate_Equal    TRUE
6       64      0       Greate_Equal    FALSE
6       32      0       Greate_Equal    FALSE
6       16      0       Greate_Equal    TRUE
6       8       0       Greate_Equal    FALSE
6       4       0       Greate_Equal    FALSE
6       2       0       Greate_Equal    TRUE
6       1       0       Greate_Equal    TRUE
                                
windows 7                               
Major   Minor   SP      cond    return
6       1       1       Equal   TRUE
6       1       1       Greater_Equal   TRUE
6       1       1       Greater TRUE
6       1       0       Greater TRUE
6       1       0       Less    FALSE
6       1       0       Less_Equal      FALSE
6       1       1       Less_Equal      TRUE
6       1       1       Less    TRUE
6       1       0       Less    TRUE
6       16384   0       Greater_Equal   FALSE
6       8192    0       Greater_Equal   FALSE
6       4096    0       Greater_Equal   FALSE
6       2048    0       Greater_Equal   FALSE
6       1024    0       Greater_Equal   FALSE
6       512     0       Greater_Equal   FALSE
6       256     0       Greater_Equal   FALSE
6       128     0       Greater_Equal   FALSE
6       64      0       Greater_Equal   FALSE
6       32      0       Greater_Equal   FALSE
6       16      0       Greater_Equal   FALSE
6       8       0       Greater_Equal   FALSE
6       4       0       Greater_Equal   FALSE
6       2       0       Greater_Equal   FALSE
6       1       0       Greater_Equal   TRUE
                                
Windows Vista                           
Major   Minor   SP      cond    return
6       0       2       Equal   TRUE
6       0       2       Less    TRUE
6       0       2       Greater_Equal   TRUE
6       0       2       Less_Equal      TRUE
6       1       2       Less_Equal      TRUE
6       1       2       Equal   FALSE
6       1       2       Less    TRUE
6       1       2       Greater_Equal   FALSE
6       8192    2       Greater_Equal   FALSE
6       4096    2       Greater_Equal   FALSE
6       2048    2       Greater_Equal   FALSE
6       1024    2       Greater_Equal   FALSE
6       512     2       Greater_Equal   FALSE
6       256     2       Greater_Equal   FALSE
6       128     2       Greater_Equal   FALSE
6       64      2       Greater_Equal   FALSE
6       32      2       Greater_Equal   FALSE
6       16      2       Greater_Equal   FALSE
6       8       2       Greater_Equal   FALSE
6       4       2       Greater_Equal   FALSE
6       2       2       Greater_Equal   FALSE
6       1       2       Greater_Equal   FALSE
                                
Windows XP                              
Major   Minor   SP      cond    return
5       1       3       Equal   TRUE
5       2       3       Equal   FALSE
5       2       3       Less    TRUE
5       2       3       Less_Equal      TRUE
5       16384   3       Greater_Equal   FALSE
5       8192    3       Greater_Equal   FALSE
5       4096    3       Greater_Equal   FALSE
5       2048    3       Greater_Equal   FALSE
5       1024    3       Greater_Equal   FALSE
5       512     3       Greater_Equal   FALSE
5       256     3       Greater_Equal   FALSE
5       128     3       Greater_Equal   FALSE
5       64      3       Greater_Equal   FALSE
5       32      3       Greater_Equal   FALSE
5       16      3       Greater_Equal   FALSE
5       8       3       Greater_Equal   FALSE
5       4       3       Greater_Equal   FALSE
5       2       3       Greater_Equal   FALSE
5       1       3       Greater_Equal   TRUE

GetWORD() //VerifyVersionInfo APIによりOSVERSIONINFOEXのメンバー変数(16bit値)を得る
上記のGetDWORD()の16bit版です。ただし、第2引数には1つのメンバーしか指定できません。
GetBYTE() //VerifyVersionInfo APIによりOSVERSIONINFOEXのメンバー変数(8bit値)を得る
上記のGetDWORD()の8bit版です。ただし、第2引数には1つのメンバーしか指定できません。
Is系のメンバー関数
IsVerifyVersionInfo() // VerifyVersionInfo APIが実装されている場合trueを返す
IsGetVersionEx() // GetVersionEx APIが実装されている場合trueを返す
Is9x() // Windows 9x系の場合 trueが返る(本関数の実行前にget()関数によりバージョン情報を取得する必要があります)
IsNT() // Windows NT 4系の場合 trueが返る(本関数の実行前にget()関数によりバージョン情報を取得する必要があります)
IsServer() // Windows Serverの場合 trueが返る(本関数の実行前にget()関数によりバージョン情報を取得する必要があります)
getOSname()
バージョン情報より一致するWindows名(7 Vista等)を示す文字列定数を返します。
Window名が見つからない場合はNULLを返します。
バージョン番号とWindows名との対比はVER_TBL ver_tbl[]で定義されている内容に従って行います。
VER_TBL型はバージョン情報とWindows名を定義した型です。
ソースを見やすくするためにメンバー変数の順番がアライメントの面から非効率的になっています。
例えば、メンバー変数をTCHAR*,DWORD,WORD,BYTEの順番に定義したほうが構造体のサイズが小さくなります。
これは実行速度を優先して、例えば32bit値なら32bitの境界にそろうようにアドレスが決定されるからです。
WORD,DWORDの順に定義するとWORD,DWORDの間に1個のWORDが挿入され位置調整がされ構造体サイズが2byte増えます。ただし構造体も効率のいい境界に配置されるので、結果的にメモリサイズは増えないかもしれません。
set(TCHAR* )
引数で指定されたWindows名(7 Vista等)に一致するバージョン情報を本クラスのメンバー変数に設定します。
Windows XP相当のバージョン情報を設定する例
EXTOSVERSIONINFOEX os;
os.set(OSNAME_XP);
上記のOSNAME_XPはextosversion.hで定義されているマクロで実体は、_TEXT("XP")と定義されています。

ソースコード

osver3.cpp

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

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

int WINAPI _tWinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,LPTSTR lpsCmdLine, int nCmdShow){
        TCHAR buf[256];
        TCHAR* osname;
        TCHAR* unknown;
        TCHAR* support;
        TCHAR* notsupport;

//      IsWindows8Point1OrGreater();

        UINT cp=GetOEMCP();     //      コードページを取得
        if(cp==932){    //      日本語版の場合
                 unknown=_TEXT("不明");
                 support=_TEXT("サポート");
                 notsupport=_TEXT("未サポート");
        }else{  //      日本語版以外は、英語で表示
                unknown=_TEXT("unknown");
                support=_TEXT("support");
                notsupport=_TEXT("not support");
        }
        EXTOSVERSIONINFOEX os;
        os.get();       //      Windowsバージョンの取得
        osname=os.getOSname();  //      Windows名(7 vistaなど)の取得
        if(osname==0){
                osname = unknown;
        }
        _stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("Windows %s\nMajorVersion %d\nMinorVersion %d\nBuild %d\n")
                _TEXT("ServicePack %d\nProductType 0x%.2x\nPlatformId 0x%.8x\nCSDVersion %s\nVerifyVersionInfo API %s\nGetVersionEX API %s"),
                osname ,os.dwMajorVersion, os.dwMinorVersion, os.dwBuildNumber, os.wServicePackMajor, os.wProductType,os.dwPlatformId,os.szCSDVersion,
                os.IsVerifyVersionInfo()==true ? support : notsupport ,
                os.IsGetVersionEx()==true ? support : notsupport );

        MessageBox(0,buf,_TEXT("Windows Version"),MB_OK);
        return (int)0;
}

extosversion.h

#ifndef EXTOSVERSION_H

#define EXTOSVERSION_H 1

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

#ifndef SM_SERVERR2
        #define SM_SERVERR2                             89
#endif

//      DLL内の関数へのポインタ型を定義
typedef BOOL (WINAPI *GetVersionExFunc)(LPOSVERSIONINFOEX );
typedef BOOL (WINAPI *VerifyVersionInfoFunc)(LPOSVERSIONINFOEX , DWORD , DWORDLONG);
typedef ULONGLONG (WINAPI *VerSetConditionMaskFunc)(ULONGLONG ,DWORD ,BYTE );


//      拡張版OSVERSIONINFOEXクラス

class EXTOSVERSIONINFOEX : public OSVERSIONINFOEX{
        GetVersionExFunc pGetVersionEx;
        VerifyVersionInfoFunc pVerifyVersionInfo;
        VerSetConditionMaskFunc pVerSetConditionMask;
        DWORD GetDWORD(DWORD* dw, DWORD dwTypeMask);
        WORD GetWORD(WORD* w, DWORD dwTypeMask);
        BYTE GetBYTE(BYTE* b, DWORD dwTypeMask);
public:
        DWORD GetMinor(void);
        bool sm2;       //      Server R2の場合true
        bool IsVerifyVersionInfo(void){ //      APIが実装されている場合trueを返す
                return pGetVersionEx ? true : false;
        }
        bool IsGetVersionEx(void){      //      APIが実装されている場合trueを返す
                return pGetVersionEx ? true : false;
        }
        bool Is9x(void){        //      Windows 9x系の場合 trueが返る
                if(dwMajorVersion ==4 && dwPlatformId==VER_PLATFORM_WIN32_WINDOWS) // Windows 9x
                        return true;
                else
                        return false;
        }
        bool IsNT(void){        //      Windows NTの場合 trueが返る
                if(dwMajorVersion ==4 && dwPlatformId==VER_PLATFORM_WIN32_NT) // Windows NT
                        return true;
                else
                        return false;
        }
        bool IsServer(void){    //      Windows Serverの場合 trueが返る
                return wProductType==VER_NT_SERVER ? true : false;
        }
        EXTOSVERSIONINFOEX(){   //      APIが実装されていない場合を想定してDLL内の関数へのエントリを取得する
                ZeroMemory(this,sizeof(OSVERSIONINFOEX));
                #ifdef UNICODE
                        pGetVersionEx = (GetVersionExFunc)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetVersionExW");
                #else
                        pGetVersionEx = (GetVersionExFunc)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetVersionExA");
                #endif
                #ifdef UNICODE
                         pVerifyVersionInfo= (VerifyVersionInfoFunc)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "VerifyVersionInfoW");
                #else
                         pVerifyVersionInfo= (VerifyVersionInfoFunc)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "VerifyVersionInfoA");
                #endif
                pVerSetConditionMask= (VerSetConditionMaskFunc)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "VerSetConditionMask");
        }
        void get(void); //      Windows Versionを取得する
        void set(TCHAR* osname);        // osnameで指定されたWindows Versionをクラスに設定します        
        TCHAR* getOSname(void); //      WindowsのOS名を取得する(7やVistaなど)
};

#define OSNAME_NT4  _TEXT("NT4")
#define OSNAME_95  _TEXT("95")
#define OSNAME_95OSR1  _TEXT("95OSR1")
#define OSNAME_95OSR2  _TEXT("95OSR2")
#define OSNAME_95OSR25  _TEXT("95OSR2.5")
#define OSNAME_98  _TEXT("98")
#define OSNAME_98SE  _TEXT("98Second Edition")
#define OSNAME_ME  _TEXT("me")
#define OSNAME_2000  _TEXT("2000")
#define OSNAME_2000_SERVER  _TEXT("2000 Server")
#define OSNAME_XP  _TEXT("XP")
#define OSNAME_SERVER_2003  _TEXT("Server 2003")
#define OSNAME_SERVER_2003R2  _TEXT("Server 2003R2")
#define OSNAME_VISTA  _TEXT("Vista")
#define OSNAME_7  _TEXT("7")
#define OSNAME_8  _TEXT("8")
#define OSNAME_81  _TEXT("8.1")
#define OSNAME_SERVER_2008  _TEXT("Server 2008")
#define OSNAME_SERVER_2008R2  _TEXT("Server 2008R2")
#define OSNAME_SERVER_2012  _TEXT("Server 2012")
#define OSNAME_SERVER_2012R2  _TEXT("Server 2012R2")


#endif

extosversion.cpp

/*
 Windowsバージョンを取得するためのクラス等を定義

  将来的にGetVersionEx APIが廃止(Windows 8.1では将来的に廃止が予告されている)されてもGetVersionEx API相当のバージョン情報取得をサポート
 マニフェストで実行環境をWindows 8.1に設定しなくても良いのでWindows 9x系もサポート
 バージョン情報よりWindowsの名称(Vista,7 等)の取得が可能。又はWindowsの名称からバージョン情報の設定が可能
 指定バージョンより上位であるか判定するIsWindows系関数(VersionHelpers.hで定義されVerifyVersionInfo APIに置き換えているだけ)を
サポートしていないVisual C++ 2005/2008でもバージョンチェックが可能
  Windows 9x系での実行を考慮する場合はVisual C++ 2005でマルチバイトでコンパイルしなければならない。
*/


#include "extosversion.h"

#if _MSC_VER==1800      //      Visual C++ 2013の場合
#include <VersionHelpers.h>
#endif


struct VER_TBL{ //      バージョン番号とOS名との一覧
        DWORD major, minor;
        DWORD platform;
        BYTE  product;
        DWORD bulid;
        WORD  sp;
        struct {
                BYTE win9x:2;   //      OSRの区別又は98と98SEの判別に使用
                BYTE server2:1; //      2003と2003R2の判別に使用
                BYTE rev:5;     //      予約済みというなの単なるビットの穴埋め
        };
        TCHAR* name;
};

VER_TBL ver_tbl[] = {
/*
         m   m  p  p  b s  w  s r   n
         a   i  l  r  u p  i  e e   a
         j   n  a  o  i    n  r v   m
         o   r  t  d  l    9  v     e
         r   r  f  c  d    x  e
                o  u          r
                r  t          2
                m
*/
        { 4, 0, 2, 0, 0,0,{ 0,0,0 }, OSNAME_NT4 },
        { 4, 0, 1, 0, 0,0,{ 0,0,0 }, OSNAME_95 },
        { 4, 0, 1, 0, 0,0,{ 0,1,0 }, OSNAME_95OSR1 },
        { 4, 0, 1, 0, 0,0,{ 0,2,0 }, OSNAME_95OSR2 },
        { 4, 0, 1, 0, 0,0,{ 0,3,0 }, OSNAME_95OSR25 },
        { 4,10, 1, 0, 0,0,{ 0,0,0 }, OSNAME_98 },
        { 4,10, 1, 0, 0,0,{ 1,0,0 }, OSNAME_98SE },
        { 4,90, 1, 0, 0,0,{ 0,0,0 }, OSNAME_ME },
        { 5, 0, 2, 1, 0,0,{ 0,0,0 }, OSNAME_2000 },
        { 5, 0, 2, 3, 0,0,{ 0,0,0 }, OSNAME_2000_SERVER },
        { 5, 1, 2, 1, 0,0,{ 0,0,0 }, OSNAME_XP },
        { 5, 2, 2, 3, 0,0,{ 0,0,0 }, OSNAME_SERVER_2003 },
        { 5, 2, 2, 3, 0,0,{ 0,1,0 }, OSNAME_SERVER_2003R2 },
        { 6, 0, 2, 1, 0,0,{ 0,0,0 }, OSNAME_VISTA },
        { 6, 1, 2, 1, 0,0,{ 0,0,0 }, OSNAME_7 },
        { 6, 2, 2, 1, 0,0,{ 0,0,0 }, OSNAME_8 },
        { 6, 3, 2, 1, 0,0,{ 0,0,0 }, OSNAME_81 },
        { 6, 0, 2, 3, 0,0,{ 0,0,0 }, OSNAME_SERVER_2008 },
        { 6, 1, 2, 3, 0,0,{ 0,0,0 }, OSNAME_SERVER_2008R2 },
        { 6, 2, 2, 3, 0,0,{ 0,0,0 }, OSNAME_SERVER_2012 },
        { 6, 3, 2, 3, 0,0,{ 0,0,0 }, OSNAME_SERVER_2012R2 },
        { 0, 0, 0, 0, 0,0,{ 0,0,0 }, 0 }        };


//      Windows Versionを取得する(GetVersionEx API相当の情報が取得できる)

void EXTOSVERSIONINFOEX::get(void){

        if(pVerifyVersionInfo){// && win2k==false){     //      VerifyVersionInfo APIをサポートしている場合 Window2000以降だがWindows2000はGetVersionEx APIで取得
                dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
                sm2=GetSystemMetrics(SM_SERVERR2) ? 1 : 0;
                GetDWORD(&(dwMajorVersion),VER_MAJORVERSION );
                GetMinor();
                GetWORD(&(wServicePackMajor), VER_SERVICEPACKMAJOR);
                GetWORD(&(wServicePackMinor), VER_SERVICEPACKMINOR);
                GetDWORD(&(dwPlatformId), VER_PLATFORMID);
                GetDWORD(&(dwBuildNumber), VER_BUILDNUMBER);
                GetWORD(&(wSuiteMask), VER_SUITENAME);
                GetBYTE(&(wProductType), VER_PRODUCT_TYPE);
                if(wServicePackMajor==0)
                        szCSDVersion[0]=_T('\0');
                else
                        _stprintf_s(szCSDVersion,sizeof(szCSDVersion)/sizeof(TCHAR),_TEXT("Service Pack %d"),wServicePackMajor);
        }else{  //      Windows 9x 又は Windows NTの場合はGetVersionEx APIを使用
                sm2=0;
                dwOSVersionInfoSize=sizeof(OSVERSIONINFOEX);
                LPOSVERSIONINFOEX lp=(LPOSVERSIONINFOEX)this;
                if(pGetVersionEx(lp)==0){
                        dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
                        pGetVersionEx(lp);
                }
        }
}

DWORD EXTOSVERSIONINFOEX::GetMinor(void){
        DWORDLONG       dwlConditionMask = 0;
        int n;

        dwlConditionMask = pVerSetConditionMask(dwlConditionMask, VER_MAJORVERSION, VER_EQUAL);
        dwlConditionMask = pVerSetConditionMask(dwlConditionMask, VER_MINORVERSION, VER_EQUAL);
        for (n = 0; n < 30000; n++){
                dwMinorVersion=n;
                if (pVerifyVersionInfo(this, VER_MAJORVERSION | VER_MINORVERSION, dwlConditionMask)){
                        return dwMinorVersion;
                }
        }
        return 0;
}

//      VerifyVersionInfo APIによりOSVERSIONINFOEXのメンバー変数(32bit値)を得る

DWORD EXTOSVERSIONINFOEX::GetDWORD(DWORD* dw, DWORD dwTypeMask){
        DWORDLONG       dwlConditionMask = 0;
        int n;
        DWORD bit=1;
        
        for(n=0;n<32;n++){ 
                if(dwTypeMask & bit){
                        dwlConditionMask=pVerSetConditionMask(dwlConditionMask,bit , VER_GREATER_EQUAL);
                }
                bit=bit<<1;
        }
        DWORD mask = (VER_MAJORVERSION | VER_MINORVERSION);
        if ( dwTypeMask == mask){
                dwlConditionMask = 0;
                dwlConditionMask = pVerSetConditionMask(dwlConditionMask, VER_MAJORVERSION , VER_EQUAL);
                dwlConditionMask = pVerSetConditionMask(dwlConditionMask, VER_MINORVERSION , VER_GREATER_EQUAL);
        }

        bit = 0x80000000;       //      31bit目が1
        DWORD sum = 0;

        *dw = 0x00010000;

        if(pVerifyVersionInfo(this, dwTypeMask, dwlConditionMask)){     //      16bit以上である
                for (n = 0; n < 32; n++){
                        *dw = sum+bit;
                        if (pVerifyVersionInfo(this, dwTypeMask, dwlConditionMask)){
                                sum = *dw;
                        }
                        bit = bit >> 1;
                }
        }else{  //      16bit以下である。
                bit=0x8000;     //      15bit目が1
                for (n = 0; n < 16; n++){
                        *dw = sum+bit;
                        if (pVerifyVersionInfo(this, dwTypeMask,dwlConditionMask)){
                                sum = *dw;
                        }
                        bit = bit >> 1;
                }
        }

        return *dw=sum;
}

//      VerifyVersionInfo APIによりOSVERSIONINFOEXのメンバー変数(16bit値)を得る

WORD EXTOSVERSIONINFOEX::GetWORD(WORD* w, DWORD dwTypeMask){
        DWORDLONG       const dwlConditionMask = pVerSetConditionMask(0,dwTypeMask , VER_GREATER_EQUAL);
        WORD bit = 0x8000;      //      15bit目が1
        WORD sum = 0;

        int n;
                for (n = 0; n < 16; n++){
                *w = sum+bit;
                if (pVerifyVersionInfo(this, dwTypeMask,dwlConditionMask)){
                        sum = *w;
                }
                bit = bit >> 1;
        }
        return *w=sum;
}

//      VerifyVersionInfo APIによりOSVERSIONINFOEXのメンバー変数(8bit値)を得る

BYTE EXTOSVERSIONINFOEX::GetBYTE(BYTE* b, DWORD dwTypeMask){
        DWORDLONG       const dwlConditionMask = pVerSetConditionMask(0,dwTypeMask , VER_GREATER_EQUAL);
        BYTE bit = 0x80;        //      7bit目が1
        BYTE sum = 0;

        int n;
        for (n = 0; n < 16; n++){
                *b = sum+bit;
                if (pVerifyVersionInfo(this, dwTypeMask,dwlConditionMask)){
                        sum = *b;
                }
                bit = bit >> 1;
        }
        return *b=sum;
}

//      WindowsのOS名を取得する(7やVistaなど)

TCHAR* EXTOSVERSIONINFOEX::getOSname(void ){
        int n = 0;
        while (ver_tbl[n].major){
                if (ver_tbl[n].major == dwMajorVersion &&
                        ver_tbl[n].minor == dwMinorVersion &&
                        ver_tbl[n].product == wProductType &&
                        ver_tbl[n].platform== dwPlatformId &&
                        ver_tbl[n].server2 == sm2 )
                {
                        if(Is9x()){ // Windows 9xの場合
                                int win9x=0;
                                if(szCSDVersion[0] && szCSDVersion[2]){
                                        win9x=szCSDVersion[1]-_TEXT('A')+1;
                                }
                                if(ver_tbl[n].win9x==win9x){
                                        return ver_tbl[n].name;
                                }
                        }else
                                return ver_tbl[n].name;
                }
                ++n;
        }
        return 0;
}

//      osnameで指定されたWindows Versionをクラスに設定します

void EXTOSVERSIONINFOEX::set(TCHAR* osname){
        int n = 0;
        while (ver_tbl[n].major){
                if(_tcscmp(ver_tbl[n].name,osname)==0){
                        this->dwMajorVersion=ver_tbl[n].major;
                        this->dwMinorVersion=ver_tbl[n].minor;
                        this->dwPlatformId=ver_tbl[n].platform;
                        this->wProductType=ver_tbl[n].product;
                        this->sm2=ver_tbl[n].server2;
                        this->dwBuildNumber=ver_tbl[n].bulid;
                        this->wServicePackMajor=ver_tbl[n].sp;
                        this->wServicePackMinor=0;
                        szCSDVersion[0]=_T('\0');
                        if(wServicePackMajor)
                                _stprintf_s(szCSDVersion,sizeof(szCSDVersion)/sizeof(TCHAR),_TEXT("Service Pack %d"),wServicePackMajor);
                        if(Is9x()){
                                if(ver_tbl[n].win9x)
                                        _stprintf_s(szCSDVersion,sizeof(szCSDVersion)/sizeof(TCHAR),_TEXT(" %c"),_T('A')+ver_tbl[n].win9x-1);
                        }
                        return;
                }
                ++n;
        }
}

実行ファイルとソースファイルのダウンロード(Visual C++ 2005 マルチバイトでコンパイル)