【问题标题】:How to get the "friendly" OS Version Name?如何获得“友好”的操作系统版本名称?
【发布时间】:2010-10-09 07:45:41
【问题描述】:

我正在寻找一种优雅的方式来获取操作系统版本,例如:“Windows XP Professional Service Pack 1”或“Windows Server 2008 Standard Edition”等。

有没有一种优雅的方式来做到这一点?

我也对处理器架构(如 x86 或 x64)感兴趣。

【问题讨论】:

  • 小心,我已经看到很多代码示例在用户不是管理员时会中断......当然还有很多代码示例也适用于非管理员用户.小心点^^

标签: c# .net winforms operating-system


【解决方案1】:

您可以使用 WMI 获取产品名称(“Microsoft® Windows Server® 2008 Enterprise”):

using System.Management;
var name = (from x in new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem").Get().Cast<ManagementObject>()
                      select x.GetPropertyValue("Caption")).FirstOrDefault();
return name != null ? name.ToString() : "Unknown";

【讨论】:

  • 使用FirstOrDefault而不是First方法,否则由于调用空集合的First,此行将失败并出现异常。
  • 使用Cast&lt;T&gt; 代替OfType&lt;T&gt; 也会产生稍微更好的性能。
  • 当我的软件完全运行上述代码时,我的一些用户收到了UnauthorizedAccessException 异常。知道为什么会这样吗?
  • @WaltD 我假设这些用户没有管理权限。使用 WMI 的 Afaik 需要管理权限。
  • Wmi 可以冻结进程,尤其是在重新启动安装 Windows 更新后
【解决方案2】:

您确实应该尽量避免 WMI 用于本地使用。它非常方便,但在性能方面您要付出高昂的代价。这既快速又简单:

    public string HKLM_GetString(string path, string key)
    {
        try
        {
            RegistryKey rk = Registry.LocalMachine.OpenSubKey(path);
            if (rk == null) return "";
            return (string)rk.GetValue(key);
        }
        catch { return ""; }
    }

    public string FriendlyName()
    {
        string ProductName = HKLM_GetString(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName");
        string CSDVersion = HKLM_GetString(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CSDVersion");
        if (ProductName != "")
        {
            return (ProductName.StartsWith("Microsoft") ? "" : "Microsoft ") + ProductName +
                        (CSDVersion != "" ? " " + CSDVersion : "");
        }
        return "";
    }

【讨论】:

  • 如果就这么简单,为什么suffering的人这么多?
  • 获取本地机器操作系统的“友好”名称就是这么简单。当涉及操作系统版本号时,它会变得更加复杂,这不是我们所要求的。
  • @NateS 没有受苦。 this 受苦了!
  • 注意:这仅在本地计算机上有效。您必须将Registry.LocalMachine.OpenSubKey(path) 更改为Registry.OpenRemoteBaseKey(RegistryHive.LocalMachine, computer).OpenSubKey(path); 以使其成为真正的WMI 替代品(通常用于连接到远程计算机),并传入computer。您还需要使用ServiceController sc = new ServiceController("RemoteRegistry", computer); if (sc.Status.Equals(ServiceControllerStatus.Running)) { ... // do your stuff } 检查远程注册表服务是否正在运行,如果没有,可以启动它:sc.Start();
【解决方案3】:

为什么不使用Environment.OSVersion?它还会告诉您这是什么操作 - Windows、Mac OS X、Unix 等。要了解您是在 64 位还是 32 位上运行,请使用 IntPtr.Size - 这将返回 32 位的 4 个字节和 64 位的 8 个字节。

【讨论】:

  • Environment.OSVersion 确实为您提供了人类版本的 hte 操作系统名称。例如,WMI 将提供 Microsoft Windows 8.1 ProEnvironment.OSVersion 将提供 Microsoft Windows NT 6.2.9200.0
  • 我发现 Environment.OSVersion 不合适,除非您有一个 app.manafest 文件说明支持的操作系统。否则,例如,如果您的应用运行为 Windows Vista 而不是 Windows 10,您可能会得到完全错误的操作系统版本。
  • IntPtr.Size 如果您正在为 x86 平台编译 .NET 应用程序,即使在 64 位操作系统上运行,也会返回 4。更好的解决方案在这里:*.com/questions/336633/…
  • 来自配置器的链接:“从 Windows 8 开始,OSVersion 属性为所有 Windows 平台返回相同的主要和次要版本号。因此,我们不建议您检索此属性的值来确定操作系统版本。"
  • 除了 @AdamVenezia 所说的自定义 app.manifest 不能应用于类库。最重要的是,app.manifest 需要注释中的受支持操作系统的操作系统 Guid。我需要遥测客户端中的操作系统友好名称,即使该应用程序不(正式)支持该特定 Windows,它也应该发送正确的操作系统版本,因此会误导在 app.manifest 中将其标记为此类。这两个限制都使Environmen.OSVersion 无法用于我的情况。
【解决方案4】:

试试:

new ComputerInfo().OSVersion;

输出:

Microsoft Windows 10 企业版

注意: 添加对Microsoft.VisualBasic.Devices;的引用

【讨论】:

  • new ComputerInfo().OSFullName 给出该输出。
  • OSVersion,正如您所料,返回的是版本,而不是名称。使用OSFullName 获取名称。 ComputerInfo Class
【解决方案5】:

有点晚了,但我就是这样做的。将来可能会帮助某人。

using Microsoft.Win32;

RegistryKey registryKey = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion");
        string pathName = (string)registryKey.GetValue("productName");

【讨论】:

  • 这太棒了。或将其用于远程计算机:registryKey = Registry.OpenRemoteBaseKey(RegistryHive.LocalMachine, computer).OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion"); string version = registryKey.GetValue("productName").ToString();
  • 另外,为了满足OP的要求,Service Pack在同一个位置,不同的字符串:string servicePack = rk.GetValue("CSDVersion").ToString();
【解决方案6】:

样本输出:

Name = Windows Vista
Edition = Home Premium
Service Pack = Service Pack 1
Version = 6.0.6001.65536
Bits = 64

示例类:

class Program
{
    static void Main( string[] args )
    {
        Console.WriteLine( "Operation System Information" );
        Console.WriteLine( "----------------------------" );
        Console.WriteLine( "Name = {0}", OSInfo.Name );
        Console.WriteLine( "Edition = {0}", OSInfo.Edition );
        Console.WriteLine( "Service Pack = {0}", OSInfo.ServicePack );
        Console.WriteLine( "Version = {0}", OSInfo.VersionString );
        Console.WriteLine( "Bits = {0}", OSInfo.Bits );
        Console.ReadLine();
    }
}

OSInfo 类的源代码:http://www.csharp411.com/determine-windows-version-and-edition-with-c/ 但是代码中有错误,您需要将“case 6”语句(就在#endregion NAME 之前)替换为:

case 6:
    switch (minorVersion)
    {
        case 0:

            switch (productType)
            {
                case 1:
                    name = "Windows Vista";
                    break;
                case 3:
                    name = "Windows Server 2008";
                    break;
            }
            break;
        case 1:
            switch (productType)
            {
                case 1:
                    name = "Windows 7";
                    break;
                case 3:
                    name = "Windows Server 2008 R2";
                    break;
            }
            break;
    }
    break;

如果你想更进一步,看看你的程序是在 64 位还是 32 位运行:

public static class Wow
{
    public static bool Is64BitProcess
    {
        get { return IntPtr.Size == 8; }
    }

    public static bool Is64BitOperatingSystem
    {
        get
        {
            // Clearly if this is a 64-bit process we must be on a 64-bit OS.
            if (Is64BitProcess)
                return true;
            // Ok, so we are a 32-bit process, but is the OS 64-bit?
            // If we are running under Wow64 than the OS is 64-bit.
            bool isWow64;
            return ModuleContainsFunction("kernel32.dll", "IsWow64Process") && IsWow64Process(GetCurrentProcess(), out isWow64) && isWow64;
        }
    }

    static bool ModuleContainsFunction(string moduleName, string methodName)
    {
        IntPtr hModule = GetModuleHandle(moduleName);
        if (hModule != IntPtr.Zero)
            return GetProcAddress(hModule, methodName) != IntPtr.Zero;
        return false;
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    extern static bool IsWow64Process(IntPtr hProcess, [MarshalAs(UnmanagedType.Bool)] out bool isWow64);
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    extern static IntPtr GetCurrentProcess();
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    extern static IntPtr GetModuleHandle(string moduleName);
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    extern static IntPtr GetProcAddress(IntPtr hModule, string methodName);
}

【讨论】:

  • 我有 Windows 8.1,但它显示的是 Windows Vista...查看源代码,甚至没有针对 Windows 7 或 8 的 case 语句...
  • @TheMuffinMan - 也许是因为那是 2.5 年前写的?随着新版本 Windows 的出现,您将不得不对其进行更新。
【解决方案7】:

对我来说,下面的行作品给我的输出如下: Microsoft Windows 10.0.18362

System.Runtime.InteropServices.RuntimeInformation.OSDescription

它也可以用来获取建筑等信息 https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.runtimeinformation?view=netframework-4.8

属性

FrameworkDescription:返回一个字符串,指示运行应用的 .NET 安装的名称。

OSArchitecture:获取当前应用运行的平台架构。

OSDescription:获取描述应用运行的操作系统的字符串。

ProcessArchitecture:获取当前运行应用的进程架构。

【讨论】:

  • 这似乎是微软文档中Environment.OSVersion 的官方替代品,请参阅Environment.OSVersion Property
  • 是一个不错的选择,但至少需要 .net framework 4.7.1
【解决方案8】:

需要注意的一点是,这些信息通常是本地化的,并且会根据操作系统的语言以不同的方式报告。

您可以从WMI 获取大量信息,查找Win32_OperatingSystem

【讨论】:

  • WMI 似乎是未来的证明,因为它会在没有任何转换的情况下立即返回友好名称......将仔细研究。谢谢...
【解决方案9】:

请注意,处理器架构问题很复杂:

您的意思是(数字越大,数字越小):

  1. CPU 能够处理 64 位(从某种意义上说,它支持 AMD/intel x64 或 Itanium)
  2. 操作系统为 64 位
    • GPR 和指针是 64 位的,即 XP 64、Vista 64、64 位服务器版本或用于单声道的 64 位操作系统
  3. 当前正在执行的进程是64位进程(例如在Wow64下不执行)

如果你很高兴这三个都是真的,那么

IntPtr.Size == 8

表示三个都为真

【讨论】:

  • 这不是和IntPtr.Size == 8一样吗?
  • 我知道这个问题很复杂——正如你所说。但我只是对哪个框架版本正在处理我的可执行文件感兴趣。所以我认为 IntPtr 方法就足够了。
  • @Hosam:不完全是。不过,IntPtr.Size 是正确的做法。
  • @configurator:您能解释一下它们有何不同吗?
  • 为什么不使用 Environment.Is64BitOperatingSystem 或 Environment.Is64BitProcess?
【解决方案10】:

您可以使用 Visual Basic 设备获取版本信息。

代码:

using Microsoft.VisualBasic.Devices;

var versionID = new ComputerInfo().OSVersion;//6.1.7601.65536
var versionName = new ComputerInfo().OSFullName;//Microsoft Windows 7 Ultimate
var verionPlatform = new ComputerInfo().OSPlatform;//WinNT

Console.WriteLine(versionID);
Console.WriteLine(versionName);
Console.WriteLine(verionPlatform);

输出:

6.1.7601.65536

Microsoft Windows 10 企业版

WinNT

注意: 您需要添加对Microsoft.VisualBasic;的引用

【讨论】:

  • 虽然我可以理解为某些项目添加 VisualBasic 参考的犹豫,但我的范围和上下文完全不会打扰我。这对我来说是一个很好的解决方案。
  • Windows 10 的版本为10.0.x.x6.1.7601.x 对应于 Windows 7。可以从这里得到的最大值是 6.2.9200.0,即 Windows 8(.1)。
【解决方案11】:

我知道这不是问题的直接答案,而且也有点晚了,但是对于那些只想确定操作系统是客户端操作系统还是服务器的人来说,有一种方法可以使用以下:(您需要包含 System.Management 参考)

        using System;
        using System.Management;

        ManagementClass osClass = new ManagementClass("Win32_OperatingSystem");
        foreach (ManagementObject queryObj in osClass.GetInstances())
        {

            foreach (PropertyData prop in queryObj.Properties)
            {

                if (prop.Name == "ProductType")
                {

                    ProdType = int.Parse(prop.Value.ToString());
                }
            }
        }

而变量 ProdType 是一个之前初始化的整数。它将包含一个介于 1 和 3 之间的值,其中 1 代表工作站,2 代表域控制器,3 代表服务器。

这是取自 Accessing the properties of Win32_OperatingSystem 并稍作改动...

【讨论】:

    【解决方案12】:

    披露:发布此消息后,我意识到我依赖于一个名为 Z.ExntensionMethods 的 Nuget 扩展方法库,其中包含 IndexOf()

    using Microsoft.VisualBasic.Devices;

    string SimpleOSName()
    {
        var name = new ComputerInfo().OSFullName;
        var parts = name.Split(' ').ToArray();
        var take = name.Contains("Server")?3:2;
        return string.Join(" ", parts.Skip(parts.IndexOf("Windows")).Take(take));
    }
    

    更快的性能using System.Management;

    string SimpleOSName()
    {
        var name = new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem")
            .Get().Cast<ManagementObject>()
            .Select(x => x.GetPropertyValue("Caption").ToString())
            .First();
        var parts = name.Split(' ').ToArray();
        var take = name.Contains("Server")?3:2;
        return string.Join(" ", parts.Skip(parts.IndexOf("Windows")).Take(take));
    }
    

    输出示例:

    Windows 7

    Windows 服务器 2008

    【讨论】:

      最近更新 更多