获取 Windows 版本 "1511"

3
最新的Windows 10版本(目前为Insider Preview)标记为:
版本1511(OS Build 10586.3)
在“关于Windows”中查看(开始 > 运行 > winver)
使用适当清单的控制台应用程序,从System.Environment.OSVersion.Version返回的Windows版本是10.0.10586.0,其中不包含winver报告的版本的“1511”或“.3”组件。
似乎在注册表下有字符串,例如ReleaseId,可以提供此信息,但这将依赖于实现细节而不是API契约。
简而言之,是否有一个(记录在文档中的)API可从.net应用程序调用,提供类似于winver和/或Windows组件(如记事本)中显示的Windows 10版本的信息?

使用适当的清单控制台应用程序。也许这不是1511的正确清单?可能会出现另一个支持的操作系统GUID。 - Sören Kuklau
一般来说,你不需要关心这个。对于终端用户而言,它是“Windows 10”,而对于遥测/支持数据而言,则是“10.0.10586.0”。 - Chuck Walbourn
2个回答

8

以下是一些间接证据,表明除了从“ReleaseId”注册表值中读取之外,没有API可以获取“1511”字符串。这不是绝对的证据,可能不是您寻求的答案,但这是我目前所拥有的。

使用sysinternals的ProcMon记录“winver”运行情况显示,确实查询了注册表键,正如@Sören Kuklau已经指出的那样。

winver.exe RegQueryValue HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ReleaseID SUCCESS Type: REG_SZ, Length: 10, Data: 1511

在执行RegQueryValueExW函数查询“ReleaseID”时,调用栈如下所示(来自ProcMon报告)。

 0 ntoskrnl.exe   NtQueryInformationFile + 0x3d50
 1 ntoskrnl.exe   NtOpenThreadTokenEx + 0x258c
 2 ntoskrnl.exe   setjmpex + 0x3963
 3 ntdll.dll      ZwQueryValueKey + 0x14
 4 KernelBase.dll MapPredefinedHandleInternal + 0x729
 5 KernelBase.dll RegQueryValueExW + 0xed
 6 SHCore.dll     SHQueryValueExW + 0xdd
 7 SHCore.dll     SHQueryValueExW + 0x32
 8 shell32.dll    Ordinal897 + 0x86f
 9 shell32.dll    Ordinal897 + 0xb8b
10 shell32.dll    Ordinal897 + 0x304
11 user32.dll     IsDialogMessageW + 0x76e
12 user32.dll     IsDialogMessageW + 0x941
13 user32.dll     IsDialogMessageW + 0x866
14 user32.dll     DispatchMessageW + 0x689
15 user32.dll     SendMessageW + 0x395
16 user32.dll     SetWindowLongPtrA + 0x979
17 user32.dll     DialogBoxIndirectParamAorW + 0x18c
18 user32.dll     DialogBoxIndirectParamAorW + 0x52
19 user32.dll     DialogBoxParamW + 0x85
20 shell32.dll    SHELL32_PifMgr_OpenProperties + 0x223d
21 shell32.dll    ShellAboutW + 0x72
22 winver.exe     winver.exe + 0x11d3
23 winver.exe     winver.exe + 0x1516
24 kernel32.dll   BaseThreadInitThunk + 0x22
25 ntdll.dll      RtlUserThreadStart + 0x34

所以,winver.exe从shell32.dll调用ShellAboutW,打开对话框并填写数据。在此过程中,它读取“HKLM \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ ReleaseID”注册表值,返回“1511”。确实可以在shell32.dll中找到"ReleaseID"的值名称作为硬编码字符串。此外,唯一其他带有“ReleaseId”字符串的System32 DLL是SettingsHandlers_nt.dll和WSShared.dll,但winver.exe没有加载其中任何一个,并且两者都具有不同的大小写形式(其中一个以小写“d”结尾)。这强烈暗示: (a)传递到RegQueryValueExW中的字符串是在shell32.dll中硬编码的字符串; (b)其他Microsoft代码也有相似的字符串硬编码,可能是因为没有API来获取它。
这仍然保留了通过 shell32.dll 的其他 API 可能公开相同的 “1511” 信息(或至少 “ReleaseID” 值名称)的可能性。例如,偏移量为 8、9、10 的“Ordinal897”调用中的其中一个可能实际上是像 “GetWin10RelID(LPTSTR lpRellD, int nMaxChars);” 这样的函数,还可能通过名称导出,并在未来的 SDK 中得到记录。然而,目前这些都是通过序数导出的匿名函数,没有文档说明,并且不能保证下次更新 shell32.dll 时它们甚至会保持相同的顺序。

2
releaseid在21h1中不再适用,现在使用displayversion。但是这对于旧版本来说并不存在。 - az1d
@az1d 很好知道,谢谢。你可以把它作为一个答案发布。 - dxiv

6

值得一提的是,进程监视器表明winver只是查询ReleaseId。因此,“版本1511”可能确实是全部内容。

23:59:30,6022870    winver.exe  7004    RegQueryValue   HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ReleaseID SUCCESS Type: REG_SZ, Length: 10, Data: 1511

将注册表值更改为随机字符串后,再次启动winver即可立即反映出更改。删除该值将使winver显示为空字符串。

因此,虽然不太友好和可能不受支持,但这似乎目前是解决问题的方法:

using (var hklmKey = Microsoft.Win32.Registry.LocalMachine)
using (var subKey = hklmKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"))
{
     if (subKey != null)
     {
         string release = subKey.GetValue("ReleaseId") as string;

         if (release != null)
             retVal += " Version " + release;
     }
}

感谢您花时间了解进程管理器的情况(从而验证了我的数据可能来自何处的理论)。虽然这是有价值的信息,但我不会接受它作为答案,因为我的问题是要求一个特定的API。在winver.exe及其MUI文件上运行sysinternals“strings”未找到“ReleaseId”的引用,因此看起来它可能确实在调用API... - Rob
1
releaseid在21h1中不再适用,现在使用displayversion。但是这对于旧版本来说并不存在。 - az1d
1
该死,他们为什么总是改来改去的?(我还没有安装21H1。不过在20H2上,DisplayVersion已经存在。不清楚它是什么时候引入的。) - Sören Kuklau

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