我该如何在桌面应用程序中检测Windows 8.1?

13
在Windows 8.1预览版中,Environment.OSVersion.Version返回的版本号与Windows 8相同。是否有其他检测Windows 8.1的替代方法?

4
你将此标记为 [tag:winapi],但你引用了 Environment.OSVersion,这是 .NET 的特性。你需要哪种解决方案? - Damien_The_Unbeliever
3
检查操作系统的版本号并不是确定特定功能是否受支持的最佳方法。您为什么需要知道是否运行在Windows 8或8.1上?您试图解决什么问题? - Cody Gray
3
不是的。我也遇到了同样的问题。版本是6.2.9200,与Win 8相同。 - user844541
2
Cody,就这种情况而言,这是最好的方式,我需要的功能深藏在打印池中,测试它不会带来良好的用户体验。 - Tony Edgecombe
4个回答

24

请看这篇文章:

《Windows 8.1 预览版操作系统版本更改》

GetVersion(Ex) API已被弃用。这意味着,虽然您仍然可以调用API,但如果您的应用程序没有明确针对 Windows 8.1 预览版进行目标设置,则会获得 Windows 8 的版本信息(6.2.0.0)。

文章解释了,除非在应用程序清单中明确指定 8.1 版本,否则 GetVersion 函数将给您提供错误的操作系统版本信息。

您需要将以下内容添加到应用清单中:

 <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
    <application> 
      * <!-- Windows 8.1 -->
      * <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
        <!-- Windows Vista -->
        <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> 
        <!-- Windows 7 -->
        <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
        <!-- Windows 8 -->
        <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
    </application> 
</compatibility>

如果您不想这样做,您可以检查以下注册表项:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion

当前版本将会给您6.3

当前构建版本号将是9431


那么我们应该将所有支持的操作系统密钥添加到清单中(假设我们支持所有这些操作系统)?还是只添加最新支持的操作系统? - Cody Gray
我认为你应该将它们全部添加进去。如果在MSDN文档中没有提到,他们应该只写了“<!-- Windows 8.1 --> * <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>”。 - user844541
我猜Windows 7还不知道Windows 8的GUID,所以如果你不想在Windows 7上遇到问题,就把它们全部包含进去。听起来很合理,是吧?;-) - ygoe
1
Windows 10 GUID: 8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a - Paul

6

另一个可能性是使用VerifyVersionInfo函数,即使你的应用程序没有用户844541提到的相应清单文件,它仍然可以返回正确的结果。

例如:

BOOL CompareWindowsVersion(DWORD dwMajorVersion, DWORD dwMinorVersion)
{
    OSVERSIONINFOEX ver;
    DWORDLONG dwlConditionMask = 0;

    ZeroMemory(&ver, sizeof(OSVERSIONINFOEX));
    ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
    ver.dwMajorVersion = dwMajorVersion;
    ver.dwMinorVersion = dwMinorVersion;

    VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_EQUAL);
    VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_EQUAL);

    return VerifyVersionInfo(&ver, VER_MAJORVERSION | VER_MINORVERSION, dwlConditionMask);
}

使用方法:

if(CompareWindowsVersion(6, 3))
{
    // Windows 8.1
}

3
注意:对于发现此问题的任何人,请注意此方法不适用于Windows 10。 - Matt Wilko

6

使用 ntdll!RtlGetVersion。这是GetVersionExVerifyVersionInfo都使用的方法,它可以给出正确的版本号。它需要一个指向OSVersionInfoExW结构体的指针,就像GetVersionExW一样。如果成功,它会返回STATUS_SUCCESS(0)。


1
"RtlGetVersion" 不会受到默认的 OSVersionLie shim 的影响吗?即使是在 Windows 10 上也是如此吗?您能否通过提供一些参考资料来扩展您的答案? - Opmet
我尝试了RtlGetVersion,它不受shim的影响 - 它返回了10(VerifyVersionInfo没有返回,除非更新了清单)。 - FruitBreak
这应该是最受赞和被接受的答案,因为它更好。清单工具会带来更多麻烦,而不是解决问题,对于任何略微超出 Microsoft 设想的内容。而 这个 简单地解决了它。 - 0xC0000022L
@0xC0000022L,至少目前是这样的。无法预测下一个Windows版本会发生什么。我的“这是哪个Windows版本?”例程现在已经有了八种不同的方法,希望至少有一种方法能够在未来继续工作。 - Mark
@Mark:鉴于微软宣称Windows 10将是最后一个Windows版本?... 傻笑 - 0xC0000022L

2

我不确定你是否想深入了解,但通过以下描述的简单WMI查询调用,很容易获得确切的操作系统版本。我已经提供了一种方法,您可以将其直接插入到代码中以获取确切的操作系统版本。对于此C#代码片段所需导入的命名空间,已在函数上方提到:

using System;
using System.Management;
private string GetOsVersion()
{
        var sccmManagementScope = new ManagementScope(@"\\" + System.Environment.MachineName + @"\root\cimv2");
        var searchResult = new ManagementObjectSearcher(sccmManagementScope, new WqlObjectQuery("SELECT Version FROM Win32_OperatingSystem"));
        var resultSet = searchResult.Get();
        var osVersion = string.Empty;
        foreach (ManagementObject managementObject in resultSet)
        {
            osVersion = Convert.ToString(managementObject["Version"]);
        }
        return osVersion;
    }

尽管我仍坚信,System.Environment.OSVersion.Version 应该能够满足你的大部分需求,除非你有关于目标 Windows 8.1 的非常具体的要求。事实上,我曾经在一个需求中使用了同样的技巧,因为如果你的应用程序没有针对 Windows 8.1 操作系统进行清单设置,则 System.Environment 类会错误报告操作系统版本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接