【问题标题】:Identifying the CPU architecture type using C#使用 C# 识别 CPU 架构类型
【发布时间】:2009-04-20 09:49:08
【问题描述】:

我想检查用户运行的是哪个 CPU 架构,是 i386 或 X64 或 AMD64。我想用 C# 来做。 我知道我可以尝试 WMI 或注册表。除了这两种方法还有其他方法吗? 我的项目面向 .NET 2.0!

【问题讨论】:

    标签: c# architecture cpu identify


    【解决方案1】:

    你也可以试试(只有在不被操纵的情况下才有效):

    System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")
    

    【讨论】:

    • 未设置转到“操纵”的情况(至少在 Vista 上,默认设置)。我建议它作为一种替代方式,不一定是最好的方式。
    • 我在 AMD64 和 Vista 64 位上,查看控制台窗口中的变量,我看到 AMD64 用于 PROCESSOR_ARCHITECTURE,但使用 ReSharper 运行我的单元测试时,我看到“x86”返回。如果测试在 32 位模式下运行可能没问题,但我使用此结果来决定如何启动另一个可执行文件并选择拒绝在 64 位操作系统上启动的 32 位版本。
    • @romeok:这不应该用于检测机器的处理器架构。它可用于检测程序运行的架构。如果要检查操作系统是否为 64 位,则应使用 WMI 等其他方法。然而,OP 明确提到他想要别的东西。
    • 注意:返回值取决于调用进程的编译方式(x86、x64、AnyCPU)!解决方案是传递第二个参数:System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE", EnvironmentVariableTarget.Machine) 另见stackoverflow.com/a/1739055/1468842
    【解决方案2】:

    我在这里的原因是检查 32 位和 64 位操作系统。评分最高的答案是查看当前流程的设置。在没有找到答案后,我找到了以下设置。希望这对你有用。

    bool is64 = System.Environment.Is64BitOperatingSystem
    

    【讨论】:

    • 抱歉恢复旧线程,但作为对未来读者的建议:由于 32 位进程可以在 64 位操作系统上愉快地运行,System.Environment.Is64BitProcess 在我的情况下更有用(根据架构为“正确的”sqlite3.dll 设置PATH 变量)。就我而言,操作系统确实是 64 位的,但由于另一个库,我不得不将我的应用程序编译为 32 位。
    • Is64BitProcess 至少直到第 4 版才出现。对于任何版本,我认为 IntPtr.Size 是最优雅的解决方案;我在将我带到此页面的代码中围绕它包裹了一个三元表达式。
    【解决方案3】:

    我知道这个问题来自过去,但截至 2017 年,现在有一个简单的方法可以了解当前进程的架构,在 .net 标准中:

    System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture
    

    返回的值是 X86、X64、ARM、ARM64 之一,并给出了它正在运行的进程的体系结构。OSArchitecture 返回已安装操作系统的体系结构。

    文档的链接(虽然没什么用...):

    RuntimeInformation.ProcessArchitecture: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.runtimeinformation.processarchitecture?view=netstandard-1.4

    架构枚举: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.architecture?view=netstandard-1.4

    【讨论】:

    【解决方案4】:

    这是一段似乎可以工作的代码(基于 P/Invoke);它允许确定 CPU/机器架构、当前进程架构以及给定的二进制文件架构(它是如何编译的):

        public enum Architecture
        {
            Unknown,
            x86,
            x64,
            arm64,
        }
    
        public static Architecture ProcessArchitecture
        {
            get
            {
                var si = new SYSTEM_INFO();
                GetSystemInfo(ref si);
                return GetArchitecture(ref si);
            }
        }
    
        public static Architecture MachineArchitecture
        {
            get
            {
                var si = new SYSTEM_INFO();
                GetNativeSystemInfo(ref si);
                return GetArchitecture(ref si);
            }
        }
    
        public static Architecture ReadFileArchitecture(string filePath)
        {
            if (filePath == null)
                throw new ArgumentNullException(nameof(filePath));
    
            using (var stream = File.OpenRead(filePath))
            {
                return ReadFileArchitecture(stream);
            }
        }
    
        // note .NET dll will come out as x86
        public static Architecture ReadFileArchitecture(Stream stream)
        {
            if (stream == null)
                throw new ArgumentNullException(nameof(stream));
    
            var length = stream.Length;
            if (length < 64)
                return Architecture.Unknown;
    
            var reader = new BinaryReader(stream);
            stream.Position = 60;
            var peHeaderPtr = reader.ReadUInt32();
            if (peHeaderPtr == 0)
            {
                peHeaderPtr = 128;
            }
            if (peHeaderPtr > length - 256)
                return Architecture.Unknown;
    
            stream.Position = peHeaderPtr;
            var peSignature = reader.ReadUInt32();
            if (peSignature != 0x00004550) // "PE"
                return Architecture.Unknown;
    
            var machine = reader.ReadUInt16();
            Architecture arch;
            switch (machine)
            {
                case IMAGE_FILE_MACHINE_AMD64:
                    arch = Architecture.x64;
                    break;
    
                case IMAGE_FILE_MACHINE_I386:
                    arch = Architecture.x86;
                    break;
    
                case IMAGE_FILE_MACHINE_ARM64:
                    arch = Architecture.arm64;
                    break;
    
                default:
                    return Architecture.Unknown;
            }
            return arch;
        }
    
        private static Architecture GetArchitecture(ref SYSTEM_INFO si)
        {
            switch (si.wProcessorArchitecture)
            {
                case PROCESSOR_ARCHITECTURE_AMD64:
                    return Architecture.x64;
    
                case PROCESSOR_ARCHITECTURE_ARM64:
                    return Architecture.arm64;
    
                case PROCESSOR_ARCHITECTURE_INTEL:
                    return Architecture.x86;
    
                default:
                    throw new PlatformNotSupportedException();
            }
        }
    
        private const int PROCESSOR_ARCHITECTURE_AMD64 = 9;
        private const int PROCESSOR_ARCHITECTURE_INTEL = 0;
        private const int PROCESSOR_ARCHITECTURE_ARM64 = 12;
        private const int IMAGE_FILE_MACHINE_ARM64 = 0xAA64;
        private const int IMAGE_FILE_MACHINE_I386 = 0x14C;
        private const int IMAGE_FILE_MACHINE_AMD64 = 0x8664;
    
        [DllImport("kernel32")]
        private static extern void GetSystemInfo(ref SYSTEM_INFO lpSystemInfo);
    
        [DllImport("kernel32")]
        private static extern void GetNativeSystemInfo(ref SYSTEM_INFO lpSystemInfo);
    
        [StructLayout(LayoutKind.Sequential)]
        private struct SYSTEM_INFO
        {
            public short wProcessorArchitecture;
            public short wReserved;
            public int dwPageSize;
            public IntPtr lpMinimumApplicationAddress;
            public IntPtr lpMaximumApplicationAddress;
            public IntPtr dwActiveProcessorMask;
            public int dwNumberOfProcessors;
            public int dwProcessorType;
            public int dwAllocationGranularity;
            public short wProcessorLevel;
            public short wProcessorRevision;
        }
    

    此代码支持 x86、x64 和 arm64 架构以及 Windows XP。在现代版本的 .NET 中,System.Runtime.InteropServices.RuntimeInformation namespace 中有内置函数。

    【讨论】:

    • 谢谢这很好用...我希望机器类型不是操作系统类型。
    • Simon,这是迄今为止提供的最精简的解决方案。每个害怕平台调用的人,克服它;它不会(通常)咬人!
    • 请记住,SYSTEM_INFO 的文档使用 DWORDWORD,它们都是未签名的。结构中的所有内容都已签名。如果您使用此结构的任何其他成员,这可能会导致问题。
    【解决方案5】:

    Win32_Processor WMI 类将完成这项工作。使用MgmtClassGen.exe 生成强类型包装器。

    【讨论】:

    • 这可能是这个问题的最佳答案。
    • Win32_Processor 类应该如何提供帮助?如果你说的是 OSArchitecture,那么这个属性在大多数 Windows 版本上是不可用的,只有少数最新版本支持它。
    【解决方案6】:

    最后,在 C# 中为当前运行的 CLR 运行时解析平台/处理器架构的最短技巧是:

    PortableExecutableKinds peKind;
    ImageFileMachine machine;
    typeof(object).Module.GetPEKind(out peKind, out machine);
    

    这里Module.GetPEKind 返回一个ImageFileMachine 枚举,它从.NET v2 开始就存在:

    public enum ImageFileMachine
    {
        I386    = 0x014C,
        IA64    = 0x0200,
        AMD64   = 0x8664,
        ARM     = 0x01C4    // new in .NET 4.5
    }
    

    为什么不使用new AssemblyName(fullName)typeof(object).Assembly.GetName()
    那么在 ASP.NET MVC 源代码中有这个HACK 注释(从 1.0 开始):

    private static string GetMvcVersionString() {
        // DevDiv 216459:
        // This code originally used Assembly.GetName(), but that requires FileIOPermission, which isn't granted in
        // medium trust. However, Assembly.FullName *is* accessible in medium trust.
        return new AssemblyName(typeof(MvcHttpHandler).Assembly.FullName).Version.ToString(2);
    }
    

    看到他们为自己使用了一些隐藏的技巧。遗憾的是,AssemblyName 构造函数没有正确设置 ProcessorArchitecture 字段,它只是 None 用于任何新的 AssemblyName。

    因此,对于未来的读者,我建议您将丑陋的 GetPEKind 与 ImageFileMachine 一起使用!

    注意事项:

    • 这将返回当前正在运行的运行时架构,而不是底层系统架构!
      也就是说,唯一的例外是 I386 运行时可能在 AMD64 系统上运行。
    • 在 mono/ubuntu 14.04/AMD64 和 .NET/Win7/I386 上测试。

    【讨论】:

    • 这是错误的 - 这在运行 32 位进程的 64 位机器上得到 x86 而不是 x64。它应该得到处理器架构,而不是可执行架构,除非那是你想要的。
    【解决方案7】:

    这个怎么样?

    switch (typeof(string).Assembly.GetName().ProcessorArchitecture) {
        case System.Reflection.ProcessorArchitecture.X86:
            break;
        case System.Reflection.ProcessorArchitecture.Amd64:
            break;
        case System.Reflection.ProcessorArchitecture.Arm:
            break;
    }
    

    但是case *.Arm: 尚未经过测试。

    【讨论】:

      【解决方案8】:

      也许this CodeProject 的文章可以提供帮助?它使用 System.Management 命名空间中的 ManagementObjectSearcher 来搜索硬件信息。

      【讨论】:

        【解决方案9】:

        根据您想知道的原因,您可能会发现检查 IntPtr 结构的大小是最简单的方法。

        【讨论】:

        • 我喜欢匿名懦夫的想法!
        【解决方案10】:

        也许你可以问用户?

        当然开个玩笑...我认为 WMI 就是你会使用的。但也许还有其他方法?

        如果您选择 WMI,那么 LinqToWmi 可能会有用。我试过一次,它看起来很简单 =) -> http://www.codeplex.com/linq2wmi

        【讨论】:

          【解决方案11】:

          这对我来说似乎是最简单的:

          System.Environment.Is64BitOperatingSystem
          

          【讨论】:

          • 它在 .NET 4.0 中可用,而问题是关于 .NET 2.0
          【解决方案12】:

          这是我的方式:

          如果操作系统是 Linux,请 pinvoke libc-syscall uname,您将在 Machine-field 中拥有处理器。

          如果操作系统是 Windows,检查 System.IntPtr.Size * 8 = 64,那么它是 64 位的。 如果不是 64 位,则检查 IsWow64Process 是否存在,如果存在,并且进程是 Wow64,则它是 x86-64,否则它是 x86-32。

          这个靠谱。
          检查处理器架构环境变量不是。

          代码:

          namespace RamMonitorPrototype
          {
          
          
              // https://stackoverflow.com/a/55202696/155077
              //[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
              //unsafe internal struct Utsname_internal
              //{
              //    public fixed byte sysname[65];
              //    public fixed byte nodename[65];
              //    public fixed byte release[65];
              //    public fixed byte version[65];
              //    public fixed byte machine[65];
              //    public fixed byte domainname[65];
              //}
          
          
              public class Utsname
              {
                  public string SysName; // char[65]
                  public string NodeName; // char[65]
                  public string Release; // char[65]
                  public string Version; // char[65]
                  public string Machine; // char[65]
                  public string DomainName; // char[65]
          
                  public void Print()
                  {
                      System.Console.Write("SysName:\t");
                      System.Console.WriteLine(this.SysName); // Linux 
          
                      System.Console.Write("NodeName:\t");
                      System.Console.WriteLine(this.NodeName); // System.Environment.MachineName
          
                      System.Console.Write("Release:\t");
                      System.Console.WriteLine(this.Release); // Kernel-version
          
                      System.Console.Write("Version:\t");
                      System.Console.WriteLine(this.Version); // #40~18.04.1-Ubuntu SMP Thu Nov 14 12:06:39 UTC 2019
          
                      System.Console.Write("Machine:\t");
                      System.Console.WriteLine(this.Machine); // x86_64
          
                      System.Console.Write("DomainName:\t");
                      System.Console.WriteLine(this.DomainName); // (none)
                  }
          
          
              }
          
          
              // https://github.com/microsoft/referencesource/blob/master/System/compmod/microsoft/win32/UnsafeNativeMethods.cs
              // https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/Environment.Windows.cs
              public class DetermineOsBitness
              {
                  private const string Kernel32 = "kernel32.dll";
          
          
          
                  [System.Runtime.InteropServices.DllImport("libc", EntryPoint = "uname", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
                  private static extern int uname_syscall(System.IntPtr buf);
          
                  // https://github.com/jpobst/Pinta/blob/master/Pinta.Core/Managers/SystemManager.cs
                  public static Utsname Uname()
                  {
                      Utsname uts = null;
                      System.IntPtr buf = System.IntPtr.Zero;
          
                      buf = System.Runtime.InteropServices.Marshal.AllocHGlobal(8192);
                      // This is a hacktastic way of getting sysname from uname ()
                      if (uname_syscall(buf) == 0)
                      {
                          uts = new Utsname();
                          uts.SysName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(buf);
          
                          long bufVal = buf.ToInt64();
                          uts.NodeName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new System.IntPtr(bufVal + 1 * 65));
                          uts.Release = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new System.IntPtr(bufVal + 2 * 65));
                          uts.Version = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new System.IntPtr(bufVal + 3 * 65));
                          uts.Machine = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new System.IntPtr(bufVal + 4 * 65));
                          uts.DomainName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new System.IntPtr(bufVal + 5 * 65));
          
                          if (buf != System.IntPtr.Zero)
                              System.Runtime.InteropServices.Marshal.FreeHGlobal(buf);
                      } // End if (uname_syscall(buf) == 0) 
          
                      return uts;
                  } // End Function Uname
          
          
          
                  [System.Runtime.InteropServices.DllImport(Kernel32, CharSet = System.Runtime.InteropServices.CharSet.Auto, BestFitMapping = false)]
                  [System.Runtime.Versioning.ResourceExposure(System.Runtime.Versioning.ResourceScope.Machine)]
                  private static extern System.IntPtr GetModuleHandle(string modName);
          
          
                  [System.Runtime.InteropServices.DllImport(Kernel32, CharSet = System.Runtime.InteropServices.CharSet.Ansi, BestFitMapping = false, SetLastError = true, ExactSpelling = true)]
                  [System.Runtime.Versioning.ResourceExposure(System.Runtime.Versioning.ResourceScope.None)]
                  private static extern System.IntPtr GetProcAddress(System.IntPtr hModule, string methodName);
          
          
                  [System.Runtime.InteropServices.DllImport(Kernel32, SetLastError = true, CallingConvention = System.Runtime.InteropServices.CallingConvention.Winapi)]
                  [return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
                  private static extern bool IsWow64Process(
                       [System.Runtime.InteropServices.In] Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid hProcess,
                       [System.Runtime.InteropServices.Out, System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)] out bool wow64Process
                  );
          
          
                  [System.Security.SecurityCritical]
                  private static bool DoesWin32MethodExist(string moduleName, string methodName)
                  {
                      System.IntPtr hModule = GetModuleHandle(moduleName);
          
                      if (hModule == System.IntPtr.Zero)
                      {
                          System.Diagnostics.Debug.Assert(hModule != System.IntPtr.Zero, "GetModuleHandle failed.  Dll isn't loaded?");
                          return false;
                      }
          
                      System.IntPtr functionPointer = GetProcAddress(hModule, methodName);
                      return (functionPointer != System.IntPtr.Zero);
                  }
          
                  public static bool Is64BitOperatingSystem()
                  {
                      if (System.IntPtr.Size * 8 == 64)
                          return true;
          
                      if (!DoesWin32MethodExist(Kernel32, "IsWow64Process"))
                          return false;
          
                      bool isWow64;
          
                      using(Microsoft.Win32.SafeHandles.SafeWaitHandle safeHandle = new Microsoft.Win32.SafeHandles.SafeWaitHandle(System.Diagnostics.Process.GetCurrentProcess().Handle, true))
                      {
                          IsWow64Process(safeHandle, out isWow64);
                      }
                      return isWow64;
                  }
          
                  // This doesn't work reliably
                  public static string GetProcessorArchitecture()
                  {
                      string strProcessorArchitecture = null;
          
                      try
                      {
                          strProcessorArchitecture = System.Convert.ToString(System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"));
          
                          switch (typeof(string).Assembly.GetName().ProcessorArchitecture)
                          {
                              case System.Reflection.ProcessorArchitecture.X86:
                                  strProcessorArchitecture = "x86";
                                  break;
                              case System.Reflection.ProcessorArchitecture.Amd64:
                                  strProcessorArchitecture = "x86";
                                  break;
                              case System.Reflection.ProcessorArchitecture.Arm:
                                  strProcessorArchitecture = "ARM";
                                  break;
                          }
          
                          bool is64bit = !string.IsNullOrEmpty(System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432"));
          
                          if (is64bit)
                              strProcessorArchitecture += "-64";
                          else
                              strProcessorArchitecture += "-32";
                      }
                      catch (System.Exception ex)
                      {
                          strProcessorArchitecture = ex.Message;
                      }
          
                      return strProcessorArchitecture;
                  } // End Function GetProcessorArchitecture
          
          
              }
          
          
          }
          

          【讨论】:

            【解决方案13】:

            我相信你应该避免像 WMI 和 LINQ 这样的臃肿。你最终将不得不在你前进的过程中获得更多的信息,这些都不能满足于臃肿的 API 和框架。

            只需调用一个调用并提取 CPUID 信息的 dll。 C++/CLI 或 pinvoke 可以获取您需要的有关供应商的所有信息。首先,您需要查看是否支持该指令(99% 的时间是)。

            要快速启动并运行,请检查英特尔站点的 wincpuid 示例,然后从那里从 cpuid.h 中提取片段。只有 2 家供应商,其中一家擅长内存延迟,而另一家则不然(如本机代码与托管代码)。所以你会在其他架构等上遇到 Mono 的问题(谁没有顺便说一句)。至于 x64,您已经知道它或者只是获得了 corflags(它已经存在并使用 .NET 分发杀死您的客户硬盘)..

            (http://software.intel.com/en-us/articles/api-detects-ia-32-and-x64-platform-cpu-characteristics/)

            【讨论】:

            • 感谢您在我阅读使用 WMI 的建议时表达了我的想法(这引起了我的抱怨)。
            • 您与 intel.com 的链接现已失效。
            【解决方案14】:

            这就是我所做的:

            public static bool Isx86()
            {
                return (Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%").Length == 0);
            }
            

            如果您使用 64 位架构,您将拥有两个程序文件环境变量。如果您使用的是 x86,那么您将只有一个。

            【讨论】:

            • 丑陋,如果你关心的只是 32 位 vs 64 位 aka x86 vs x64,只需使用以下 BCL 属性 Environment.Is64BitOperatingSystem
            猜你喜欢
            • 2020-11-22
            • 2015-10-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-09-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多