使用.NET Framework或Windows API检测Windows 11



在.NET Framework中,要获得操作系统版本,可以使用Environment.OSVersionMajorMinor值告诉您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";。理由如下。

  1. 在微软API版本帮助函数的官方文档中(https://learn.microsoft.com/en-us/windows/win32/sysinfo/operating-system-version),它不会检测到Windows 11,微软建议测试是否存在某个功能。出于这个原因,我们相信微软会故意阻止程序员获得准确的版本。

  2. LW001建议检查版本#222000,但一位用户表示它不起作用,另一位用户则表示它很弱。鉴于上述(1),这似乎不是一个安全的长期解决方案。

  3. "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定义supportedOSGUID)。

使用此代码:

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();
}
}
}

最新更新