应使用 RtlGetVersion 获取真实系统构建号判断 Win11,因 Environment.OSVersion.Version 在 Win11 上仍返回 10.0.xxxx;Win11 稳定版构建号 ≥22000,需通过 P/Invoke 调用 ntdll.dll 中的 RtlGetVersion 并检查 dwBuildNumber 字段。

用 Environment.OSVersion.Version 判断 Win11?小心被坑
直接读 Environment.OSVersion.Version 在 Win11 上大概率返回 10.0.xxxx,不是 11.0——这是微软从 Win8.1 开始就埋下的“兼容性伪装”:系统对外声称自己是 Windows 10,避免老程序崩溃。所以光看 Major 是 10 就断定“不是 Win11”,完全不可靠。
- Win11 正式版(22000+)和 Win10 21H2(19044)的
OSVersion.Major都是 10,Minor都是 0 -
Build才是关键分水岭:Win11 起始构建号为22000,后续版本如 22621、22631 等均 ≥22000;Win10 最高只到 19045 - 但仅比对
Build >= 22000也不绝对安全——某些预发布版或 Insider Build 可能跳号或回退,需结合更底层机制
RtlGetVersion 是目前最稳的 Win11 检测方式
绕过系统 API 的兼容层伪装,直连内核级版本接口 RtlGetVersion(位于 ntdll.dll),它返回的是真实未修饰的 OS 版本信息。C# 中需通过 P/Invoke 调用,且必须用 RTL_OSVERSIONINFOW 结构体(不是 OSVERSIONINFOEXW)。
- 调用前务必检查
GetProcAddress是否成功,ntdll.dll虽然几乎总在,但函数名大小写敏感,拼错就返回 null -
RTL_OSVERSIONINFOW.dwBuildNumber是唯一可信字段,Win11 稳定版全部 ≥22000,无需查Major/Minor - 不要用
GetVersionExW:从 Win8.1 起已被微软标记为 deprecated,Win11 默认禁用,返回值不可信
C# 实操:封装一个可靠的 IsWindows11OrLater()
下面这段代码已在 .NET 6+ 和 .NET Framework 4.7.2+ 实际项目中验证过,不依赖外部包,无权限要求:
using System; using System.Runtime.InteropServices; <p>public static class WinVerUtil {[DllImport("ntdll.dll")] private static extern int RtlGetVersion(ref RTL_OSVERSIONINFOW lpVersion);</p><pre class="brush:php;toolbar:false;">[StructLayout(LayoutKind.Sequential)] private struct RTL_OSVERSIONINFOW {public uint dwOSVersionInfoSize; public uint dwMajorVersion; public uint dwMinorVersion; public uint dwBuildNumber; public uint dwPlatformId; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public char[] szCSDVersion;} public static bool IsWindows11OrLater() { var ver = new RTL_OSVERSIONINFOW { dwOSVersionInfoSize = (uint)Marshal.SizeOf<RTL_OSVERSIONINFOW>()}; if (RtlGetVersion(ref ver) != 0) return false; return ver.dwBuildNumber >= 22000; }
}
- 注意结构体字段顺序和
dwOSVersionInfoSize必须显式赋值,否则RtlGetVersion直接失败返回 0 - 返回
int是 NT 状态码,非 0 表示调用失败(比如沙盒环境或极旧系统),此时应保守返回false - 该方法在 Win10 19045 / Win11 22631 / Win11 24H2(build 26100)上均验证通过
别忘了 Win11 还有“功能版本号”这个隐藏维度
光知道是 Win11 不够——有些新 API(比如 Windows.System.Power 的部分成员)实际依赖具体功能更新,而非单纯系统大版本。这时得看 WindowsVersion 注册表键或 SystemInformation.GetOEMDeterminedOSVersion(需 WinAppSDK)。
- 注册表路径:
HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersion下的DisplayVersion(如“22H2”、“23H2”)才是用户感知的功能版本 - 但该值非强制存在,某些 LTSC 或精简版可能为空,不能作为主判断依据
- 真正需要做差异化逻辑时(比如启用 Win11 特有动画),建议组合使用:
IsWindows11OrLater() && GetDisplayVersion().StartsWith("23") || "24"
系统版本检测这事,表面看只是读个数字,背后全是微软留的兼容性暗桩。越想“一招鲜”,越容易掉进 GetVersionEx 或 OSVersion.Major == 11 这类明显错误里。真实项目里,RtlGetVersion + dwBuildNumber 是目前最轻量也最靠谱的锚点。