在.NET Framework中,要获得操作系统版本,可以使用Environment.OSVersion
,Major
和Minor
值告诉您Windows的版本(即6.1=Windows 7,10.0=Windows 10)。尽管Windows 11已经发布(开发和测试频道)一个多月了,但文档中没有提到如何检测Windows 11。
对于Windows API,GetVersion
已被永远弃用,甚至版本助手API也只能升级到IsWindows10OrGreater
。有没有一个简单的检查来找出主要的Windows版本,特别是Windows 11?有人也有类似的问题,但对于Delphi(如何使用Delphi 10.3.3检测Windows 11),公认的答案都是黑客。为什么微软很难提供一个简单的API来返回当前的系统版本?GetVersion
不应该被弃用。
这很可能并不完美,但这是我已经使用了一段时间的变通方法:
Environment.OSVersion.Version.Build >= 22000;
Windows 11从内部版本号22000开始,Windows 10 Insider内部版本号大致为21390,所以据我所知,这只会检测到Windows 11内部版本。
首先要检查它是否是Windows系统,不过另一个操作系统的内部版本号可能更高。
由于这个答案仍然有效,让我们多谈谈这个解决方案的优点和缺点:
- 检查功能可用性,而不是在";Windows 11〃;应该是您的第一个想法,但是在某些情况下,检测特定的操作系统版本也有一些优点
- 如评论中所述,这也不会区分Windows Server,并在Windows Server 2019中返回true。快速搜索如何检测服务器操作系统返回了这个答案,我还没有测试过,但乍一看是合理的
- 我应该补充的另一点是,下一个版本的Windows的内部版本号,在这种情况下,它显然会返回true,因为它们会更高。如果你真的想准确地检测Windows 11,而不想让Windows 12(或它之后的任何东西)不惜任何代价出现,这不是你的解决方案
- 最后,一位微软员工驳斥了Windows 10的内部版本数是否会达到22000或更高的问题
- 您可以在此处或此处找到每个Windows 10更新以及每个Windows 11更新的当前内部版本号
在我们公司,我们决定检测Windows版本的唯一可靠方法是发出命令提示符并运行"systeminfo";。理由如下。
-
在微软API版本帮助函数的官方文档中(https://learn.microsoft.com/en-us/windows/win32/sysinfo/operating-system-version),它不会检测到Windows 11,微软建议测试是否存在某个功能。出于这个原因,我们相信微软会故意阻止程序员获得准确的版本。
-
LW001建议检查版本#222000,但一位用户表示它不起作用,另一位用户则表示它很弱。鉴于上述(1),这似乎不是一个安全的长期解决方案。
-
"systeminfo";,另一方面,它是Windows内置的Microsoft工具,专门设计用于帮助调试PC的配置。因此,与(1)不同,它必须报告正确的Windows版本信息。
唯一的缺点是(3)需要几秒钟的时间才能运行,但我们在后台显示启动屏幕时却在看不见的情况下运行。我们实际上在Delphi而不是.Net中实现了检查,但基本轮廓是一样的,看起来是这样的:
BatFile := MakeTempPath('Win11Check-%d.bat');
ResultFile := MakeTempPath('Win11Result-%d.txt');
SaveStringToFile(BatFile, AnsiString('systeminfo>"' + ResultFile + '"'));
LaunchProcessAndWaitForExit(BatFile, '', True);
Results := LoadWideStringFromFile(ResultFile);
OsName := GetStringBetween(Results, 'OS Name', #13) + ' 0';
我们创建了一个运行systeminfo的批处理文件,并将结果转储到结果文件中。我们在后台不可见地运行该批处理文件,然后等待进程终止。然后我们以字符串的形式读取结果文件的内容。最后,我们通过查找";OS名称";以及下一个车厢返回。实际上字符串中还有一个冒号和一些空格,但你明白了。。。我们只是在寻找一个整数"10〃;vs";11〃;。。。或者甚至";2019";或";2022";在Windows Server的情况下。
总之,微软相信,每次实现新的操作系统时,它都可以完美地模仿以前的操作系统,甚至可以模仿旧的版本号。在实践中,程序员反复发现特定版本的兼容性问题(在我们的案例中,我们看到了一个可重复且明确的问题,特别是Windows 11)。因此,我们认为微软的战略(如上文(1)所述)是错误的;systeminfo";是我们可靠检测当前Windows的最佳选择。
您可以在ntdll.dll
中使用RtlGetVersion()
,它不受操作系统兼容性的影响,就像GetVersion/Ex()
和其他类似的API一样(尤其是因为还没有为Windows 11定义supportedOS
GUID)。
使用此代码:
public static bool IsWindows11()
{
var reg = Registry.LocalMachine.OpenSubKey(@"SOFTWAREMicrosoftWindows NTCurrentVersion");
var currentBuildStr = (string)reg.GetValue("CurrentBuild");
var currentBuild = int.Parse(currentBuildStr);
return currentBuild >= 22000;
}
这是基于我在HKLM\Software\Microsoft\Windows NT\CurrentVersion:What';CurrentBuild和CurrentBuildNumber之间的区别是什么?
请注意,如果注册表项不存在或值不是数字,则此代码可以引发异常。在正常系统中不应该发生这种情况。但如果你想安全,你可以把它扭曲成一个试抓块。
使用从Environment.OSVersion.version返回的版本号获取操作系统名称的VB.NET方法
Public Shared Function GetOsFriendlyName(osVersion As Version) As String
Select Case osVersion.Major
Case 10
Select Case osVersion.Minor
Case 0
Select Case osVersion.Build
Case >= 20000
Return "Windows 11"
Case Else
Return "Windows 10"
End Select
End Select
Case 6
Select Case osVersion.Minor
Case 3
Return "Windows 8.1"
Case 2
Return "Windows 8"
Case 1
Return "Windows 7"
Case 0
Return "Windows Vista"
End Select
Case 5
Return "Windows XP"
End Select
Return "Windows"
End Function
应用程序应在app.manifest 中设置支持的操作系统兼容性操作系统
RtlGetVersion()在Windows 10和11上给出了与我相同的结果https://stackoverflow.com/a/49641055.我尝试了WMI的Win32_OperatingSystem类的Caption属性。
using (var objOS = new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem"))
{
foreach (ManagementObject objMgmt in objOS.Get())
{
Console.WriteLine("{0}: {1}", objMgmt.Properties["Caption"].Name, objMgmt.Properties["Caption"].Value);
}
}
对于Windows 10,我得到了";Microsoft Windows 10企业版";而对于Windows 11〃;Microsoft Windows 11 Pro";。您可能可以使用Name属性,但它包含过多的信息,如Windows文件夹和系统驱动器或类似的信息。
Windows 10从版本10240开始,到版本19044结束
Windows 11从版本22000 开始
源
include <iostream>
#include <sstream>
#include <bitset>
#include <windows.h>
bool isWin11()
{
// the container in the registry to look for
std::wstring regstr(L"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
// the key to look for
std::wstring strkey(L"CurrentBuild");
// handle to the container
HKEY hKey = nullptr;
// get the handle if it is there
LONG lres = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regstr.c_str(), 0, KEY_READ, &hKey);
// the return value is it is success, convert to bool
bool bExistsAndSuccess(lres == ERROR_SUCCESS);
// if success get the value of CurrentBuild
if(bExistsAndSuccess)
{
// not good if it stays bad
std::wstring strValue(L"bad");
// c string buffer
WCHAR szBuffer[1024]{ 0 };
// size of c string
DWORD dwBufferSize = sizeof(szBuffer);
// error is now still ok
ULONG nError = 0;
// get the value in szBuffer
nError = RegQueryValueEx(hKey, strkey.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize);
// if success the buffer is copied to the string
if (ERROR_SUCCESS == nError)
{
// copy the szBuffer to the c string type
strValue = szBuffer;
// convert to int
int n = std::stoi(strValue);
// if higher or equal to 22000 it is Windows 11
return(n >= 22000);
}
else
// failure for some reason
return false;
}
// failed to get the container
return false;
}
int main()
{
if (isWin11())
{
printf("Is Windows 11");
}
return 0;
}
这是我用来获取有关当前环境的有用信息的类。需要参考nuget包System.Management
。
注意:Win32_OperatingSystem中的Caption
字段是Microsoft Windows 11 [Pro/Home/Etc]
,可用于检测Win11。
using System.Management;
using System.Runtime.Versioning;
[SupportedOSPlatform("windows")]
public static class OSInfo
{
public static bool IsVirtualMachine { get; }
public static bool IsDomainJoined { get; }
public static bool IsWin11 { get; }
public static string Version { get; }
static OSInfo()
{
using (var searcher = new ManagementObjectSearcher("Select Manufacturer,Model,PartOfDomain from Win32_ComputerSystem"))
using (var items = searcher.Get())
{
IsVirtualMachine = items.Cast<ManagementBaseObject>()
.Any(item =>
{
var manufacturer = ((string?)item["Manufacturer"])?.ToLowerInvariant() ?? string.Empty;
var model = ((string?)item["Model"])?.ToLowerInvariant() ?? string.Empty;
return (manufacturer == "microsoft corporation" && model.Contains("virtual"))
|| manufacturer.Contains("vmware")
|| model == "virtualbox";
});
IsDomainJoined = items.Cast<ManagementBaseObject>()
.Any(item => item["PartOfDomain"] is true);
}
using (var searcher = new ManagementObjectSearcher("select Caption,Version from Win32_OperatingSystem"))
using (var items = searcher.Get())
{
IsWin11 = items.Cast<ManagementBaseObject>()
.Any(obj => ((string) obj["Caption"]).StartsWith("Microsoft Windows 11"));
Version = items.Cast<ManagementBaseObject>()
.Select(obj =>
{
var caption = (string)obj["Caption"];
caption = caption.Replace("Microsoft Windows ", string.Empty);
var version = (string)obj["Version"];
// ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault
var platform = Environment.OSVersion.Platform switch
{
PlatformID.Win32S => "Win32S",
PlatformID.Win32NT => "Windows NT",
PlatformID.WinCE => "Windows CE",
_ => throw new ArgumentException($"Unknown platform {Environment.OSVersion.Platform}")
};
return $"Microsoft {platform} {caption} {version}";
})
.First();
}
}
}