私は何年も前にPC監査ツールを作成し、それを最新の状態に保っています。基本的な機能の1つは、GetVersionEx呼び出しを常に使用している監査対象のPCで実行されているWindowsのバージョンを報告することです。
これはWindows 8まで機能しますが、Windows 10ではサポートされておらず、実際にWindows 10はWindows 8と同様に8.2を返します。マイクロソフトは、OSを調べるのではなく、必要な特定の機能をチェックすることを提案する直接的な代替として何かを導入していないようですが、監査の目的で実際にOS名が必要です。
「スキャナー」は非特権アカウントで実行する必要があるC++プログラムであるため、別の提案を読んだとは思わない-システムのバージョンを選択するDLLなどkernel32.dllこれらのフォルダは通常ユーザーがアクセスできないため、機能します。
他の提案/考えは大歓迎です!
GetVersionとGetVersionExは さまざまなバージョンヘルパー関数 に置き換えられました。必要なものは IsWindows10OrGreater です。それらはVersionHelpers.hにあります。
IsWindows10OrGreaterは、最新のSDK/Visual Studio 2015でのみ使用可能です。IsWindowsVersionOrGreaterただし、一般的な場合。たとえば、7ボックスではIsWindowsVersionOrGreater(6、0、0)に対してTRUEを取得します。
この関数が取るパラメーターは、マーケティング名ではなくWindowsビルド番号に関連していることに注意してください。したがって、Windows 8はビルド6.2です。 Windows 7は6.0などです。
Windows 8.1以降では、 GetVersion()
および GetVersionEx()
はアプリケーションの明示の対象となります。
Windows 8.1のリリースでは、
GetVersionEx
APIの動作が、オペレーティングシステムのバージョンに対して返される値で変更されました。GetVersionEx
関数によって返される値は、アプリケーションがどのように現れるかによって異なります。Windows 8.1またはWindows 10用に明示されていないアプリケーションは、Windows 8 OSバージョン値(6.2)を返します。特定のオペレーティングシステムのバージョンに対してアプリケーションが明示されると、
GetVersionEx
は、将来のリリースでアプリケーションが明示されるバージョンを常に返します。 Windows 8.1またはWindows 10用のアプリケーションをマニフェストするには、 Windows用のアプリケーションの対象指定 を参照してください。
新しい バージョンヘルパー関数 は、単に VerifyVersionInfo()
のラッパーです。 Windows 10以降では、同様に顕在化の対象になりました。
Windows 10:
VerifyVersionInfo
パラメーターがWindows 8.1またはWindows 10を指定するように設定されている場合、Windows 8.1またはWindows 10の互換性マニフェストを持たないアプリケーションによって呼び出されると、lpVersionInfo
はfalseを返します。現在のオペレーティングシステムのバージョンがWindows 8.1またはWindows 10の場合。具体的には、VerifyVersionInfo
の動作は次のとおりです。
- アプリケーションにマニフェストがない場合、
VerifyVersionInfo
はオペレーティングシステムのバージョンがWindows 8(6.2)であるかのように動作します。- アプリケーションに、Windows 8.1に対応するGUID=)を含むマニフェストがある場合、
VerifyVersionInfo
は、オペレーティングシステムのバージョンがWindows 8.1(6.3)であるかのように動作します。- アプリケーションがWindows 10に対応するGUID=を含むマニフェストを持っている場合、
VerifyVersionInfo
はオペレーティングシステムのバージョンがWindows 10(10.0)であるかのように動作します。バージョンヘルパー関数 は
VerifyVersionInfo
関数を使用するため、IsWindows8Point1OrGreater
およびIsWindows10OrGreater
の動作は、マニフェスト。Windows 8.1またはWindows 10のアプリケーションをマニフェストするには、「 Windowsのアプリケーションのターゲット設定 」を参照してください。
マニフェストに関係なくtrueOSバージョンを取得するには、システムDLLのファイルバージョンを照会することをお勧めします。
オペレーティングシステムの完全なバージョン番号を取得するには、
Kernel32.dll
などのシステムDLLの1つでGetFileVersionInfo
関数を呼び出してから、VerQueryValue
を呼び出してファイルバージョン情報の\\StringFileInfo\\<lang><codepage>\\ProductVersion
サブブロックを取得します。
別の方法は、 RtlGetVersion()
、 NetServerGetInfo()
、または NetWkstaGetInfo()
を使用することです代わりに。それらはすべて正確なOSバージョンを報告し、症状の影響を受けません(まだ?)。
次の機能を使用します。
double getSysOpType()
{
int ret = 0.0;
NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOEXW);
OSVERSIONINFOEXW osInfo;
*(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");
if (NULL != RtlGetVersion)
{
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
RtlGetVersion(&osInfo);
ret = osInfo.dwMajorVersion;
}
return ret;
}
Windowsバージョンをdouble(7、8、8.1、10)として返します。
これは、VSコンパイラの古いバージョンで動作するため、およびQtフレームワーク内でさらに動作するために必要でした。ここに私がそれを達成した方法があります。
このファイルを追加GetWinVersion.h
Qtプロジェクトへ:
#ifndef GETWINVERSION
#define GETWINVERSION
#include <QtGlobal>
#ifdef Q_OS_WIN
#include <windows.h>
#include <stdio.h>
float GetWinVersion()
{
OSVERSIONINFO osvi;
ZeroMemory( &osvi, sizeof(OSVERSIONINFO) );
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
return GetVersionEx( &osvi ) ?
(float)osvi.dwMajorVersion +
((float)osvi.dwMinorVersion/10) :
0.0 ;
}
#endif //Q_OS_WIN
#endif // GETWINVERSION
Proまたはpri qmakeファイルに必要なリンケージを追加します。
msvc: LIBS += -lKernel32
そのようにヘルパー関数を実装します(ここで使用されているSystemInfoは私のカスタムクラスですが、あなたはアイデアを得る...):
#include "GetWinVersion.h"
SystemInfo info;
#ifdef Q_OS_WIN
info.setPlatform( SystemInfo::WINDOWS );
switch(QSysInfo::windowsVersion())
{
case QSysInfo::WV_32s: info.setOsName( L"3.1" ); info.setOsVersion( 3.1 ); break;
case QSysInfo::WV_95: info.setOsName( L"95" ); info.setOsVersion( 4.0 ); break;
case QSysInfo::WV_98: info.setOsName( L"98" ); info.setOsVersion( 4.1 ); break;
case QSysInfo::WV_Me: info.setOsName( L"Me" ); info.setOsVersion( 4.9 ); break;
case QSysInfo::WV_NT: info.setOsName( L"NT" ); info.setOsVersion( 4.0 ); break;
case QSysInfo::WV_2000: info.setOsName( L"2000" ); info.setOsVersion( 5.0 ); break;
case QSysInfo::WV_XP: info.setOsName( L"XP" ); info.setOsVersion( 5.1 ); break;
case QSysInfo::WV_2003: info.setOsName( L"2003" ); info.setOsVersion( 5.2 ); break; // Windows Server 2003, Windows Server 2003 R2, Windows Home Server, Windows XP Professional x64 Edition
case QSysInfo::WV_Vista: info.setOsName( L"Vista" ); info.setOsVersion( 6.0 ); break; // Windows Vista, Windows Server 2008
case QSysInfo::WV_WINDOWS7: info.setOsName( L"7" ); info.setOsVersion( 6.1 ); break; // Windows 7, Windows Server 2008 R2
case QSysInfo::WV_WINDOWS8: info.setOsName( L"8" ); info.setOsVersion( 6.2 ); break; // Windows 8, Windows Server 2012
// These cases are never reached due to Windows api changes
// As of Qt 5.5, this not accounted for by QSysInfo::windowsVersion()
//case QSysInfo::WV_WINDOWS8_1: info.setOsName( L"8.1" ); info.setOsVersion( 6.3 ); break; // Windows 8.1, Windows Server 2012 R2
//case QSysInfo::WV_WINDOWS10: info.setOsName( L"10" ); info.setOsVersion( 10.0 ); break; // Windows 10, Windows Server 2016
default:
// On Windows 8.1 & 10, this will only work when the exe
// contains a manifest which targets the specific OS's
// you wish to detect. Else 6.2 (ie. Win 8.0 is returned)
info.setOsVersion( GetWinVersion() );
if( info.osVersion() == 6.3f ) // Windows 8.1, Windows Server 2012 R2
info.setOsName( L"8.1" );
else if( info.osVersion() == 10.0f ) // Windows 10, Windows Server 2016
info.setOsName( L"10" );
else
info.setOsName( L"UNKNOWN" );
}
info.setOsBits( IsWow64() ? 64 : 32 );
#else
...
これが本当の鍵です。最新のWindowsバージョンを「ターゲット」にするマニフェストファイルをexeに添付する必要があります。そうしないと、それらを検出できません(MSドキュメントを参照してください: https://msdn.Microsoft.com/en-us /library/windows/desktop/ms724451%28v=vs.85%29.aspx )。これを行うマニフェストの例を次に示します。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Assembly xmlns="urn:schemas-Microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
name="MyOrg.MyDept.MyAppName"
version="1.0.0.0"
processorArchitecture="x86"
type="win32" />
<compatibility xmlns="urn:schemas-Microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
</Assembly>
そして、ここにマニフェストを添付するバッチがあります:
set exeFile=MyApp.exe
set manifestFile=MyApp.manifest
set manifestExe=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\x64\mt.exe
"%manifestExe%" -manifest "%manifestFile%" -outputresource:"%exeFile%"
理論的には、qmakeを使用して、マニフェストを添付する最後のビットを実行できます。私が見つけた例に運がなかったので、今のところこのバッチで「だまされました」...