简体   繁体   English

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

[英]Getting Windows OS version programmatically

I am trying to fetch Windows version with C# on my Windows 10 machine.我正在尝试在我的 Windows 10 机器上使用 C# 获取 Windows 版本。

I always get those values (with C#\\C++):我总是得到这些值(使用 C#\\C++):

Major: 6专业:6

Minor: 2未成年人:2

Which is Windows 8 OS, accordingly to MSDN 根据 MSDN ,这是 Windows 8 操作系统

C# code: C#代码:

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

C++ code C++代码

void print_os_info()
{
    //http://stackoverflow.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 suppose to be with those: Windows 10 假设与那些:

Major: 10专业:10

Minor: 0*次要:0*

  • (When I am taking a dump file from running process I can see that the OS version of that file is set to 10.0) (当我从正在运行的进程中获取转储文件时,我可以看到该文件的操作系统版本设置为 10.0)

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

What am I missing here?我在这里缺少什么?

In my scenario I needed my application to capture computer info for possible bug-reports and statistics.在我的场景中,我需要我的应用程序来捕获计算机信息以获取可能的错误报告和统计信息。

I did not find the solutions where an application manifest had to be added satisfactory.我没有找到必须令人满意地添加应用程序清单的解决方案。 Most of the suggestions I found while googling this suggested just that, unfortunately.不幸的是,我在谷歌搜索时发现的大多数建议都表明了这一点。

Thing is, when using a manifest, each OS version has to be added manually to it in order for that particular OS version to be able to report itself at runtime.事实是,在使用清单时,必须手动向其中添加每个操作系统版本,以便该特定操作系统版本能够在运行时报告自身。

In other words, this becomes a race condition: A user of my app may very well be using a version of my app that pre-dates the OS in use.换句话说,这变成了一种竞争条件:我的应用程序的用户很可能正在使用我的应用程序的一个版本,该版本于正在使用的操作系统。 I would have to upgrade the app immediately when a new OS version was launched by Microsoft.当 Microsoft 推出新的操作系统版本时,我必须立即升级该应用程序。 I would also have to force the users to upgrade the app at the same time as they updated the OS.我还必须强制用户在更新操作系统的同时升级应用程序。

In other words, not very feasible.换句话说,不太可行。

After browsing through the options I found some references (surprisingly few compared to the app manifest) that instead suggested using registry lookups.在浏览选项后,我发现了一些建议使用注册表查找的参考(与应用程序清单相比出奇地少)。

My (chopped down) ComputerInfo class with only WinMajorVersion , WinMinorVersion and IsServer properties looks like this:我只有WinMajorVersionWinMinorVersionIsServer属性的我的(砍掉的) ComputerInfo类如下所示:

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

You'll need to add an app.manifest to your application:您需要将app.manifest添加到您的应用程序中:

在此处输入图片说明

在此处输入图片说明

then uncomment the following line:然后取消注释以下行:

<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentBuildNumber", string.Empty).ToString()

same code for all OSes from XP till current 10.16299, over scenarios not properly work from windows 8从 XP 到当前 10.16299 的所有操作系统的相同代码,在 Windows 8 中无法正常工作的情况下

The OSVersion property reports the same version number (6.2.0.0) for both Windows 8 and Windows 8.1 and the same major and minor version number for Windows 10. OSVersion 属性报告 Windows 8 和 Windows 8.1 的相同版本号 (6.2.0.0) 以及 Windows 10 的相同主要和次要版本号。

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

As the accepted answer is only for C#, here is a solution for C++.由于接受的答案仅适用于 C#,这里是 C++ 的解决方案。

It uses the RtlGetVersion in the ntdll.dll that uses the same structure as GetVersionEx (name is different, but the elements are the same) and gives you the correct version.它使用 ntdll.dll 中的 RtlGetVersion 使用与 GetVersionEx 相同的结构(名称不同,但元素相同)并为您提供正确的版本。 As this function is normally used for driver development, the function is declared in the DDK and not in the SDK.由于此函数通常用于驱动程序开发,因此该函数是在 DDK 中声明的,而不是在 SDK 中声明的。 So I used a dynamic solution to call the function.所以我使用了动态解决方案来调用函数。 Please be aware that the ntdll.dll is loaded and released in every call.请注意,ntdll.dll 在每次调用中都会被加载和释放。 So if you need the function more often, keep the library loaded.因此,如果您更频繁地需要该功能,请保持库加载。

The structure pOSversion is pointing to must be initialized like for GetVersionEx. 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

You can do this in C# the same way C++ answer has it您可以在 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.
}

You can read from registry through code and do specific action what you intended.您可以通过代码从注册表中读取并按照您的意图执行特定操作。

Say for example:比如说:

Registry key is located at HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion and then look for "ProductName".注册表项位于 HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion,然后查找“ProductName”。

You can open registry information by giving regedit.exe in run (Windows+r)您可以通过在运行中提供 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
        {
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM