山本ワールド
Windowsプログラミング
アルゴリズム Vitual C++ 2008/2013によるWin32/Win64 APIレベルのプログラム 基礎 Vitual C++ 2008/2013によるAPIレベルのプログラム(32/64bit) Wix3でインストーラーを作る Visual C++ 2008 Standard Editonによるフォームアプリケーションのプログラム(32/64bit) Vitual C++ 2008 Standard EditonによるAPIレベルのプログラム(32/64bit) Windows 7対応 Visual C++ 2008 ExpressによるAPIレベルのプログラム Visual C++ 2005 ExpressによるAPIレベルのプログラム Visual C++ Versiosn 5 BORLAND C++ Windowsプログラム全般 Excel VBA その他RtlGetVersion APIによりWindowsバージョンを取得(Windows 10に対応)
概要
Windowsのバージョンを表示します。GetVersionEX APIはマニフェストを設定しないとWindows 8.1などに対応していないのは既知となっていますが、VerfyVersionInfo APIでもWindows 10ではWindows 7相当の結果が取得されました。
ここでは、ドライバの開発などに用いるRtlGetVersion APIを使用してWindows 10でも正常に動作するプログラムを作成しました。
本来RtlGetVersion APIをVsiaul C++で使用するにはntddk.hとNtoskml.libが必要であり、このファイルはおそらくWindows DDKに含まれていると思われます。
API自身はntddl.ddlというありふれたDLLの中にあります。
本プログラムはDDKをインストールしていない環境でもコンパイルできるように、APIを動的に呼び出すようにソースコードの中で記述しています。
マクロソフトのホームページによるとAPIの引数は構造体RTL_OSVERSIONINFOWおよびRTL_OSVERSIONINFOEXW となっていますが、 実態は、windows.hからインクルードされるwinnt.hのOSVERSIONINFOWおよびOSVERSIONINFOEXWと同じです。
サービスパックの情報は文字列で返されますが、RtlGetVersion APIはユニコード版しか存在しないので、マルチバイトでも使用しやすいようにヘルパー関数GetVersion2を経由して呼び出します。
マルチバイトでコンパイルした場合は、ユニコードをANSIに変換するソースが有効になります。
Windows 2000未満ではRtlGetVersionAPIをサポートしておりません。
テスト環境
コンパイラ
Visual C++ 2005/2008/2010/2013 Express 32/64bit マルチバイト/UNICODE実行環境
Visual C++ 2005のマルチバイトでコンパイルした場合、Windows98SEで実行できますが、RtlGetVersion APIをサポートしておりませんのでそのようなメッセージをプログラムで出るように記述しています。Visual C++ 2008でコンパイルした場合、Windows 2000以上で実行できます。
マニフェストは指定していません。
プログラムソースの概要
rtlgetver.cpp
_tWinMain
GetVersion2関数を呼び出しOSVERINFOEX型構造体にバージョン情報を取得します。GetVersion2関数の戻り値がFALSEの場合、APIをサポートしてない旨のメッセージを表示します。
GetVersion2関数の戻り値がTRUEの場合、OSVERSIONINFOEX型構造体の中身を表示します。
GetVersion2
ntdll.dllをロードし、RtlGetVersion APIのエントリーポイントを取得しAPIを呼び出します。このAPIはUNICODEのみサポートしているので、マルチバイトでコンパイルする場合は、UNICODEのOSVERINFOWEX型の変数を定義しAPIを呼び出し、取得結果をOSVERINFOEXに変換します。
UNICODEからマルチバイトへの変換は、サービスパック名のみですので、半角英数及び半角数字のみと仮定できるので、APIを使用せずに単純に上位バイトを切り捨てる処理で対応しています。
ソースコード
RtlGetVer.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;
}