65.9K
CodeProject 正在变化。 阅读更多。
Home

获取操作系统版本信息 - 甚至适用于 Windows 10!

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (70投票s)

2010年4月15日

CPOL

4分钟阅读

viewsIcon

411930

downloadIcon

19783

获取操作系统版本和版本,已更新至 Windows 10

 

OSVersionInfo

引言

我一直在寻找一种方法来确定我的程序正在运行的操作系统的版本。当我用谷歌搜索时,我得到了很多代码片段,但它们都有同一个问题:它们没有为 Windows 7 更新。

此外,它们都有相同的两个缺点:

  1. 它们没有包含所有可用的 Windows 版本(尤其是“专业版”的缺失困扰了我,因为那是我通常使用的操作系统版本)。
  2. 我想知道操作系统是 32 位还是 64 位,而我找到的解决方案都无法正确确定。稍后将详细介绍...

背景

我找到了这篇文章 http://www.csharp411.com/determine-windows-version-and-edition-with-c/,在我看来,这是最好也是最新的版本。所以我决定简单地修改那段代码,并添加缺失的部分。

请注意:原始代码的所有功劳都归功于“TIMM”,即上述文章的作者...

我所做的修改

  1. 我在检测方案中添加了“Windows 7”和“Windows Server 2008 R2”。
  2. 我添加了所有我能找到的缺失的 Windows 版本。
  3. 完全重写了 32/64 位检测代码。

Using the Code

我提出的类非常易于使用。只需将 CS 文件包含到您的项目中(或将其编译为 DLL 以便在您的 VB 项目中使用),然后像这样查询属性:

StringBuilder sb = new StringBuilder(String.Empty);
sb.AppendLine("Operation System Information");
sb.AppendLine("----------------------------");
sb.AppendLine(String.Format("Name = {0}", OSVersionInfo.Name));
sb.AppendLine(String.Format("Edition = {0}", OSVersionInfo.Edition));
if (OSVersionInfo.ServicePack!=string.Empty)
   sb.AppendLine(String.Format("Service Pack = {0}", OSVersionInfo.ServicePack));
else
   sb.AppendLine("Service Pack = None");
sb.AppendLine(String.Format("Version = {0}", OSVersionInfo.VersionString));
sb.AppendLine(String.Format("ProcessorBits = {0}", OSVersionInfo.ProcessorBits));
sb.AppendLine(String.Format("OSBits = {0}", OSVersionInfo.OSBits));
sb.AppendLine(String.Format("ProgramBits = {0}", OSVersionInfo.ProgramBits));

textBox1.Text = sb.ToString();

关注点

这其中最大的问题其实是检测您的操作系统是 32 位还是 64 位。如前所述,我找到了许多关于如何检测的建议,但没有一个能正常工作。对于有兴趣的人,以及为了学习/分享信息,我将在下面列出不同的建议:

  1. 使用 IntPtr 大小

    最流行的方法似乎是基于这个的变种:

    return IntPtr.Size * 8;

    但这段代码实际上返回的是运行程序的位数,而不是操作系统的位数架构。因此,对于在 64 位 Windows 上以 32 位模式运行的程序,上面的代码将返回 32。

  2. 使用 'PROCESSOR_ARCHITECTURE' 环境变量
    string pa = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
    return ((String.IsNullOrEmpty(pa) || String.Compare(pa, 0,
        "x86", 0, 3, true) == 0) ? 32 : 64);

    这实际上非常具有误导性,因为它的结果与第一个方法完全相同:它返回的是运行程序的位数,而不是处理器本身的位数架构。对于在 64 位 Windows 上以 32 位模式运行的程序,上面的代码也将返回 32。

  3. 使用 PInvoke GetSystemInfo

    请注意:为了使文章长度合理,我没有包含结构声明和 PInvoke API 声明……它们可以在源代码中找到。

    ProcessorArchitecture pbits = ProcessorArchitecture.Unknown;
    try
    {
        SYSTEM_INFO l_System_Info = new SYSTEM_INFO();
        GetSystemInfo(ref l_System_Info);
        switch (l_System_Info.uProcessorInfo.wProcessorArchitecture)
        {
            case 9: // PROCESSOR_ARCHITECTURE_AMD64
                pbits = ProcessorArchitecture.Bit64;
                break;
    
            case 6: // PROCESSOR_ARCHITECTURE_IA64
                pbits = ProcessorArchitecture.Itanium64;
                break;
    
            case 0: // PROCESSOR_ARCHITECTURE_INTEL
                pbits = ProcessorArchitecture.Bit32;
                break;
    
            default: // PROCESSOR_ARCHITECTURE_UNKNOWN
                pbits = ProcessorArchitecture.Unknown;
                break;
        }
    }
    catch
    {
        Ignore 
    }
    return pbits;

    再次令人失望。这段代码——尽管存在处理器特定的标志——也返回的是运行程序的位数,而不是操作系统或处理器的位数。

  4. 使用 PInvoke GetNativeSystemInfo

    我在某处读到,上述方法(正如我早已发现的那样)不应被信任,而应该使用 GetNativeSystemInfo API 代替。

    代码与上面完全相同,只是将 GetSystemInfo 替换为 GetNativeSystemInfo ,并在 API 声明中也进行相应的更改。

    现在我得到了另一个结果。但唉,似乎这个 API 实际上返回的是处理器本身的位数架构。而我感兴趣的是操作系统的位数架构。您可以在 64 位处理器机器上轻松运行 32 位 Windows 版本。

    所以我还没有完成。

    经过大量研究,我找到了在类中使用的那个方法:

  5. IntPtr.Size IsWow64Process 的组合
    static public SoftwareArchitecture OSBits
    {
        get
        {
            SoftwareArchitecture osbits = SoftwareArchitecture.Unknown;
    
            switch (IntPtr.Size * 8)
            {
                case 64:
                    osbits = SoftwareArchitecture.Bit64;
                    break;
    
                case 32:
                    if (Is32BitProcessOn64BitProcessor())
                        osbits = SoftwareArchitecture.Bit64;
                    else
                        osbits = SoftwareArchitecture.Bit32;
                    break;
    
                default:
                    osbits = SoftwareArchitecture.Unknown;
                    break;
            }
    
            return osbits;
        }
    }
    
    private static IsWow64ProcessDelegate GetIsWow64ProcessDelegate()
    {
        IntPtr handle = LoadLibrary("kernel32");
    
        if (handle != IntPtr.Zero)
        {
            IntPtr fnPtr = GetProcAddress(handle, "IsWow64Process");
    
            if (fnPtr != IntPtr.Zero)
            {
                return (IsWow64ProcessDelegate)Marshal.GetDelegateForFunctionPointer((IntPtr)fnPtr,
                        typeof(IsWow64ProcessDelegate));
            }
        }
    
        return null;
    }
    
    private static bool Is32BitProcessOn64BitProcessor()
    {
        IsWow64ProcessDelegate fnDelegate = GetIsWow64ProcessDelegate();
    
        if (fnDelegate == null)
        {
            return false;
        }
    
        bool isWow64;
        bool retVal = fnDelegate.Invoke(Process.GetCurrentProcess().Handle, out isWow64);
    
        if (retVal == false)
        {
            return false;
        }
    
        return isWow64;
    }

    如果 IntPtr 的大小是 64,那么操作系统也一定是 64 位的,因为您无法在 32 位操作系统上运行 64 位程序。

    如果程序以 32 位模式运行,那么代码会检查程序本身来确定它是 32 位还是 64 位。

    如果它是 64 位,那么操作系统就是 64 位,但程序是以 32 位模式运行的。如果它是 32 位,那么操作系统也是 32 位。

    最终,我在最终的类库中包含了大部分这些方法,因为能够区分程序、操作系统和处理器的位数架构可能会很有用。

致谢

感谢 Member 7861383,Scott Vickery 提供了 Windows 8.1 更新和解决方法。
感谢 Brisingr Aerowing 协助完成 Windows 10 的适配。

历史 

  • 2016-02-11 - 版本 3.0,添加了 Windows 8.1 和 Windows 10 的代码
  • 2012-11-21 - 版本 2.0,添加了 Windows 8 和 Windows Server 2012 的版本号
  • 2010-04-15 - 版本 1.0,首次发布
© . All rights reserved.