私はWin 8.1でVS 2013に取り組んでいます。この警告を解決する方法は?
基本的な質問は、「そもそもなぜGetVersionExW
を呼び出すのですか?」です。その質問に対する答えによって、代わりに何をすべきかが決まります。
非推奨の警告は、Windows 8.1で開始されたappcompatの動作の変更について開発者に注意を促すためのものです。 WindowsおよびWindows Server互換性クックブック:Windows 8、Windows 8.1、およびWindows Server 2012 を参照してください。 要するに、その関数はデフォルトで返すと思われるものを返しません。
歴史的に、不適切に作成されたOSバージョンチェックは、Windows OSアップグレードのappcompatバグの主な原因です。この問題を軽減するためのさまざまなアプローチがあり(AppVerifierのバージョン、VerifyVersionInfo
APIなど)、これはこれまでで最も攻撃的です。
コメントで言及されている_VersionHelpers.h
_は、Visual Studio 2013に付属のWindows 8.1 SDKに含まれています。これらは新しいAPIではありません。これらは、Windows 2000で導入されたVerifyVersionInfo
APIを利用するユーティリティコードです。これらの関数は、「この乗り心地に乗るにはこれほど高くなければなりません」スタイルチェックを行うためのものです。コードは非常に簡単です。たとえば、_IsWindowsVistaSP2OrGreater
_テストは次のとおりです。
_VERSIONHELPERAPI
IsWindowsVersionOrGreater(Word wMajorVersion, Word wMinorVersion, Word wServicePackMajor)
{
OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
DWORDLONG const dwlConditionMask = VerSetConditionMask(
VerSetConditionMask(
VerSetConditionMask(
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
VER_MINORVERSION, VER_GREATER_EQUAL),
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
osvi.dwMajorVersion = wMajorVersion;
osvi.dwMinorVersion = wMinorVersion;
osvi.wServicePackMajor = wServicePackMajor;
return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
}
VERSIONHELPERAPI
IsWindowsVistaSP2OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_Vista), LOBYTE(_WIN32_WINNT_Vista), 2);
}
_
_VersionHelpers.h
_を使用する必要はありません。この種のコードを自分で行うことができますが、VS 2013コンパイラを既に使用している場合は便利です。ゲームについては、記事があります バージョン番号には何が記載されていますか? これはVerifyVersionInfo
を使用して、ゲームの展開に必要な妥当なチェックを行います。
_
v120_xp
_プラットフォームツールセットでVS 2013を使用してWindows XPをターゲットにしている場合、実際にはWindows 7.1A SDKを使用しているため、_#include <VersionHelpers.h>
_は機能しません。もちろん、VerifyVersionInfo
を直接使用できます。
GetVersionExW
のその他の主な用途は、診断ログとテレメトリです。この場合、1つのオプションは、そのAPIを引き続き使用し、アプリケーションに適切なマニフェストエントリがあることを確認して、合理的に正確な結果を確保することです。これを達成するためにここで何をするかの詳細については、 マニフェストマッドネス を参照してください。留意すべき主なことは、コードを定期的に更新しない限り、将来のバージョンのOSで完全に正確な情報の取得をやめることです。
一般的なベストプラクティスとして
GetVersionEx
の結果を気にするかどうかに関係なく、埋め込みマニフェストに_<compatibility>
_セクションを配置することをお勧めします。これにより、アプリが最初にテストされた方法を知ることに基づいて、OSが将来のappcompat修正を自動的に適用できます。
診断ログの場合、もう少し堅牢なもう1つの方法は、GetFileVersionInfoW
を使用して_kernel32.dll
_のようなシステムDLLからバージョン番号を取得することです。このアプローチには大きな重要性があります:この方法で取得したファイルバージョンに基づいて、解析、比較、コードの仮定を試みないでください。どこかに書いてください。それ以外の場合は、VerifyVersionInfo
でより適切に解決される同じ不良OSバージョンチェック問題を再作成するリスクがあります。このオプションは、Windowsストアアプリ、Windows Phoneアプリなどでは使用できませんが、Win32デスクトップアプリでは機能します。
_#include <windows.h>
#include <stdint.h>
#include <memory>
#pragma comment(lib, "version.lib" )
bool GetOSVersionString( WCHAR* version, size_t maxlen )
{
WCHAR path[ _MAX_PATH ];
if ( !GetSystemDirectoryW( path, _MAX_PATH ) )
return false;
wcscat_s( path, L"\\kernel32.dll" );
//
// Based on example code from this article
// http://support.Microsoft.com/kb/167597
//
DWORD handle;
#if (_WIN32_WINNT >= _WIN32_WINNT_Vista)
DWORD len = GetFileVersionInfoSizeExW( FILE_VER_GET_NEUTRAL, path, &handle );
#else
DWORD len = GetFileVersionInfoSizeW( path, &handle );
#endif
if ( !len )
return false;
std::unique_ptr<uint8_t> buff( new (std::nothrow) uint8_t[ len ] );
if ( !buff )
return false;
#if (_WIN32_WINNT >= _WIN32_WINNT_Vista)
if ( !GetFileVersionInfoExW( FILE_VER_GET_NEUTRAL, path, 0, len, buff.get() ) )
#else
if ( !GetFileVersionInfoW( path, 0, len, buff.get() ) )
#endif
return false;
VS_FIXEDFILEINFO *vInfo = nullptr;
UINT infoSize;
if ( !VerQueryValueW( buff.get(), L"\\", reinterpret_cast<LPVOID*>( &vInfo ), &infoSize ) )
return false;
if ( !infoSize )
return false;
swprintf_s( version, maxlen, L"%u.%u.%u.%u",
HIWORD( vInfo->dwFileVersionMS ),
LOWORD(vInfo->dwFileVersionMS),
HIWORD(vInfo->dwFileVersionLS),
LOWORD(vInfo->dwFileVersionLS) );
return true;
}
_
GetVersionExW
を呼び出している他の理由がある場合、おそらく呼び出すべきではありません。欠落している可能性のあるコンポーネントをチェックすることは、バージョンチェックに結び付けられるべきではありません。たとえば、アプリケーションにMedia Foundationが必要な場合、VersionHelpers.h IsWindowsVistaOrGreater
のような「このライドチェックに乗るにはこれだけ高い必要があります」を設定する必要がありますが、実行時にはLoadLibrary
またはLoadLibaryEx
による明示的なリンクを使用してエラーまたは_MFPLAT.DLL
_が見つからない場合はフォールバックを使用します。
明示的なリンクは、Windowsストアアプリのオプションではありません。 Windows 8.xは、スタブ_
MFPLAT.DLL
_とMFStartUp
がE_NOTIMPLを返すことにより、この特定の問題を解決します。 「[Windows Media] Cheeseを移動した人」を参照してください。
別の例:アプリケーションでDirect3D 11.2が使用可能であれば使用し、DirectX 11.0を使用する場合は、おそらく D3D11InstallHelper を使用して、展開に_IsWindowsVistaSP2OrGreater
_最小バーを設定します。その後、実行時にDirectX 11.0デバイスを作成し、失敗した場合はエラーを報告します。 _ID3D11Device
_を取得した場合、_ID3D11Device2
_のQueryInterface
になります。成功した場合は、DirectX 11.2をサポートするOSを使用していることを意味します。 Direct3D 11 Create Deviceの構造 を参照してください。
この仮想のDirect3DアプリケーションがWindows XPをサポートしている場合、_IsWindowsXPSP2OrGreater
_または_IsWindowsXPSP3OrGreater
_の展開バーを使用し、実行時に明示的なリンクを使用して_D3D11.DLL
_を見つけようとします。存在しない場合は、Direct3D 9の使用に戻ります。最小バーを設定しているため、DirectX 9.0c以降が常に存在することがわかります。
ここで重要な点は、ほとんどの場合、GetVersionEx
を使用しないことです。
Windows 10では、
VerifyVersionInfo
およびkernel32.libのGetFileVersionInfo
を介したファイルバージョンスタンプの取得は、GetVersionEx
と同じマニフェストベースの動作に従うことに注意してください(つまり、 Windows 10のマニフェストGUIDがなければ、OSバージョンが10.0ではなく6.2であるかのように結果を返します。Windows 10のユニバーサルWindowsアプリの場合、新しいWinRT API AnalyticsInfo を使用して、診断ログとテレメトリのバージョンスタンプ文字列を取得できます。
GetVersionExは非推奨と宣言されましたが、Windows 8.1およびWindows 10との互換性を宣言する適切な互換性マニフェストを投げると、GetVersionExは正しいバージョン番号を返します。 GetVersionExを使用してWindows 8以降を検出します。Windows8はWindowsの最後のバージョンであり、適切なWindowsバージョンを返すためにマニフェストを必要としないため、APIがWindows 6.2、6.3、6.4を返すかどうかに関係なくコードは正常に動作します初期のWindows 10プレビュー)、または10.0。
とはいえ、MicrosoftはこのAPIの不適切な使用のために、このAPIを非推奨にしました。たとえば、Windows XPまたはそれ以上:
BOOL IsXPOrGreater;
OSVERSIONINFO osver;
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osver);
if((osver.dwMajorVersion >= 5) && (osver.dwMinorVersion >=1) IsXPOrGreater = TRUE;
else IsXPOrGreater = FALSE;
このサンプルは、Windows XP、Server 2003、7、8、および8.1ではTRUEを返しますが、Windows Vistaまたは10ではFALSEを返します。1行追加するとこれが修正されます。
BOOL IsXPOrGreater;
OSVERSIONINFO osver;
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osver);
if((osver.dwMajorVersion >= 5) && (osver.dwMinorVersion >=1) IsXPOrGreater = TRUE;
else if(osver.dwMajorVersion >= 6) IsXPOrGreater = TRUE;
else IsXPOrGreater = FALSE;
このサンプルは、メジャーバージョンが6以上であればXPよりも大きいことを知っているため、正しく機能します。
とにかくこの警告を無効にしてGetVersionExを使用できます:
#pragma warning(disable : 4996)