以编程方式获取 Windows 操作系统版本

Posted

技术标签:

【中文标题】以编程方式获取 Windows 操作系统版本【英文标题】:Getting Windows OS version programmatically 【发布时间】:2016-10-08 14:38:13 【问题描述】:

我正在尝试在我的 Windows 10 机器上使用 C# 获取 Windows 版本。

我总是得到这些值(使用 C#\C++):

专业:6

次要:2

Windows 8 操作系统,accordingly to MSDN

C#代码:

var major = OperatingSystem.Version.Major
var minor  = OperatingSystem.Version.Minor

C++ 代码

void print_os_info()

    //http://***.com/questions/1963992/check-windows-version
    OSVERSIONINFOW info;
    ZeroMemory(&info, sizeof(OSVERSIONINFOW));
    info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);

    LPOSVERSIONINFOW lp_info = &info;
    GetVersionEx(lp_info);

    printf("Windows version: %u.%u\n", info.dwMajorVersion, info.dwMinorVersion);

Windows 10 假设与那些:

专业:10

次要:0*

(当我从正在运行的进程中获取转储文件时,我可以看到该文件的操作系统版本设置为 10.0)

构建者:10.0.10586.0 (th2_release.151029-1700)

我在这里错过了什么?

【问题讨论】:

这可能是相关的:从您链接到的页面 - “未针对 Windows 8.1 或 Windows 10 显示的应用程序将返回 Windows 8 操作系统版本值 (6.2)。” 我想你是对的,错过了 我的应用是控制台,所以我只有这个App.config文件(没有manifset) 微软长期以来一直承诺他们将击败版本检查。这是一场 appcompat 的噩梦,他们创建了一个尽可能与前一个版本兼容的新 Windows 版本,然后程序仍然无法工作,因为他们检查版本号并拒绝运行是它不认识的一个。获得 8.3 的唯一方法是使用 Editbin.exe 将子系统版本更改为 10.0。您的程序现在只能在 Win10 上运行。所以检查版本没有意义了。写在墙上,不要这样做。 Version numbers are a compatibility nightmare 【参考方案1】:

在我的场景中,我需要我的应用程序来捕获计算机信息以获取可能的错误报告和统计信息。

我没有找到令人满意的解决方案,应用程序清单必须添加。我在谷歌搜索时发现的大多数建议都表明了这一点,很遗憾。 p>

问题是,在使用清单时,必须手动将每个操作系统版本添加到其中,以便该特定操作系统版本能够在运行时报告自己。

换句话说,这变成了一种竞争条件:我的应用程序的用户很可能正在使用我的应用程序的版本,该版本早于正在使用的操作系统。当 Microsoft 推出新的操作系统版本时,我必须立即升级应用程序。我还必须强制用户在更新操作系统的同时升级应用程序。

换句话说,不太可行。

浏览选项后,我发现了一些建议使用注册表查找的参考(与应用清单相比很少)。

我的(砍掉的)ComputerInfo 类只有 WinMajorVersionWinMinorVersionIsServer 属性如下所示:

using Microsoft.Win32;

namespace Inspection

    /// <summary>
    /// Static class that adds convenient methods for getting information on the running computers basic hardware and os setup.
    /// </summary>
    public static class ComputerInfo
    
        /// <summary>
        ///     Returns the Windows major version number for this computer.
        /// </summary>
        public static uint WinMajorVersion
        
            get
            
                dynamic major;
                // The 'CurrentMajorVersionNumber' string value in the CurrentVersion key is new for Windows 10, 
                // and will most likely (hopefully) be there for some time before MS decides to change this - again...
                if (TryGetRegistryKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentMajorVersionNumber", out major))
                
                    return (uint) major;
                

                // When the 'CurrentMajorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion'
                dynamic version;
                if (!TryGetRegistryKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion", out version))
                    return 0;

                var versionParts = ((string) version).Split('.');
                if (versionParts.Length != 2) return 0;
                uint majorAsUInt;
                return uint.TryParse(versionParts[0], out majorAsUInt) ? majorAsUInt : 0;
            
        

        /// <summary>
        ///     Returns the Windows minor version number for this computer.
        /// </summary>
        public static uint WinMinorVersion
        
            get
            
                dynamic minor;
                // The 'CurrentMinorVersionNumber' string value in the CurrentVersion key is new for Windows 10, 
                // and will most likely (hopefully) be there for some time before MS decides to change this - again...
                if (TryGetRegistryKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentMinorVersionNumber",
                    out minor))
                
                    return (uint) minor;
                

                // When the 'CurrentMinorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion'
                dynamic version;
                if (!TryGetRegistryKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion", out version))
                    return 0;

                var versionParts = ((string) version).Split('.');
                if (versionParts.Length != 2) return 0;
                uint minorAsUInt;
                return uint.TryParse(versionParts[1], out minorAsUInt) ? minorAsUInt : 0;
            
        

        /// <summary>
        ///     Returns whether or not the current computer is a server or not.
        /// </summary>
        public static uint IsServer
        
            get
            
                dynamic installationType;
                if (TryGetRegistryKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "InstallationType",
                    out installationType))
                
                    return (uint) (installationType.Equals("Client") ? 0 : 1);
                

                return 0;
            
        

        private static bool TryGetRegistryKey(string path, string key, out dynamic value)
        
            value = null;
            try
            
                using(var rk = Registry.LocalMachine.OpenSubKey(path))
                
                    if (rk == null) return false;
                    value = rk.GetValue(key);
                    return value != null;
                
            
            catch
            
                return false;
            
        
    

【讨论】:

这真的很棒,谢谢! OpenSubKey 返回一个RegistryKey 实例,它实现了IDisposable。在这种情况下,它的用法应该包含在 using 构造中,以确保正确的确定性处理。 @JesseC.Slicer 我认为你是对的。我会调整的。谢谢。【参考方案2】:

您需要将app.manifest 添加到您的应用程序中:

然后取消注释以下行:

<!-- Windows 10 -->
<supportedOS Id="8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a" />

【讨论】:

我的应用是控制台,所以我只有这个App.config文件 @PavelDurov 在 Windows 10 上使用 Environment.OSVersion.Version.MajorEnvironment.OSVersion.Version.Minor 对我来说效果很好 好的,我看看我这里搞砸了什么【参考方案3】:
Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentBuildNumber", string.Empty).ToString()

从 XP 到当前 10.16299 的所有操作系统都使用相同的代码, 在 Windows 8 中无法正常工作的场景

OSVersion 属性为 Windows 8 和 Windows 8.1 报告相同的版本号 (6.2.0.0),为 Windows 10 报告相同的主要和次要版本号。

https://msdn.microsoft.com/library/system.environment.osversion.aspx

【讨论】:

【参考方案4】:

由于接受的答案仅适用于 C#,因此这里是 C++ 的解决方案。

它使用 ntdll.dll 中的 RtlGetVersion,它使用与 GetVersionEx 相同的结构(名称不同,但元素相同)并为您提供正确的版本。 由于该函数通常用于驱动开发,所以该函数是在DDK中声明的,而不是在SDK中声明的。所以我使用动态解决方案来调用该函数。 请注意,每次调用都会加载和释放 ntdll.dll。因此,如果您更频繁地需要该功能,请保持库的加载。

pOSversion 指向的结构必须像 GetVersionEx 一样初始化。

BOOL GetTrueWindowsVersion(OSVERSIONINFOEX* pOSversion)

   // Function pointer to driver function
   NTSTATUS (WINAPI *pRtlGetVersion)(
      PRTL_OSVERSIONINFOW lpVersionInformation) = NULL;

   // load the System-DLL
   HINSTANCE hNTdllDll = LoadLibrary("ntdll.dll");

   // successfully loaded?
   if (hNTdllDll != NULL)
   
      // get the function pointer to RtlGetVersion
      pRtlGetVersion = (NTSTATUS (WINAPI *)(PRTL_OSVERSIONINFOW))
            GetProcAddress (hNTdllDll, "RtlGetVersion");

      // if successfull then read the function
      if (pRtlGetVersion != NULL)
         pRtlGetVersion((PRTL_OSVERSIONINFOW)pOSversion);

      // free the library
      FreeLibrary(hNTdllDll);
    // if (hNTdllDll != NULL)

   // if function failed, use fallback to old version
   if (pRtlGetVersion == NULL)
      GetVersionEx((OSVERSIONINFO*)pOSversion);

   // always true ...
   return (TRUE);
 // GetTrueWindowsVersion

【讨论】:

这是我在任何地方找到的最佳解决方案!【参考方案5】:

您可以在 C# 中执行此操作,就像 C++ 的答案一样

[SecurityCritical]
[DllImport("ntdll.dll", SetLastError = true)]
internal static extern bool RtlGetVersion(ref OSVERSIONINFOEX versionInfo);
[StructLayout(LayoutKind.Sequential)]
internal struct OSVERSIONINFOEX

    // The OSVersionInfoSize field must be set to Marshal.SizeOf(typeof(OSVERSIONINFOEX))
    internal int OSVersionInfoSize;
    internal int MajorVersion;
    internal int MinorVersion;
    internal int BuildNumber;
    internal int PlatformId;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    internal string CSDVersion;
    internal ushort ServicePackMajor;
    internal ushort ServicePackMinor;
    internal short SuiteMask;
    internal byte ProductType;
    internal byte Reserved;

...

var osVersionInfo = new OSVERSIONINFOEX  OSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEX)) ;
if (!RtlGetVersion(ref osVersionInfo))

  // TODO: Error handling, call GetVersionEx, etc.

【讨论】:

RtlGetVersion 返回 NTSTATUS 而不是 bool,成功返回零。如果您按原样使用互操作,则函数在成功时返回 false 实际上有两个问题:1) 它不是 BOOL,而是 NTSTATUS;2) 您必须在 DllImport 部分添加“CharSet = CharSet.Unicode”。后者不会影响版本号,但某些其他属性(例如 ProductType)未正确填写。根据这里的答案,我创建了一个 GitHub 项目来正确检测 C# 中的所有 Windows 版本:github.com/pruggitorg/detect-windows-version【参考方案6】:

您可以通过代码从注册表中读取并执行您想要的特定操作。

比如说:

注册表项位于 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion,然后查找“ProductName”。

你可以通过在运行中给出regedit.exe来打开注册表信息(Windows+r)

var reg              =Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\WindowsNT\CurrentVersion");

        string productName = (string)reg.GetValue("ProductName");

        if (productName.StartsWith("Windows 10"))
        
        
        else
        
        

【讨论】:

以上是关于以编程方式获取 Windows 操作系统版本的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式获取正确的 iOS 版本?

如何在 x86 程序中以编程方式获取 Nvidia 驱动程序版本?

PC 上的双启动 Windows-Android:如何以编程方式切换操作系统?

以编程方式管理 Windows 防火墙

如何以编程方式在 Android 设备中获取设备 (AOSP) 内部版本号?

以编程方式编辑 grub 选项