24

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

4

14 回答 14

30

您也可以尝试(仅在不被操纵的情况下才有效):

System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")
于 2009-04-20T09:55:46.430 回答
28

导致我来到这里的是检查 32 位和 64 位操作系统。评分最高的答案是查看Current process的设置。在没有找到答案后,我找到了以下设置。希望这对你有用。

bool is64 = System.Environment.Is64BitOperatingSystem
于 2012-05-07T13:33:22.227 回答
15

我知道这个问题来自过去,但截至 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

于 2017-07-28T12:37:43.197 回答
11

这是一段似乎有效的代码(基于 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 命名空间中有内置函数。

于 2012-08-27T09:37:15.313 回答
6

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

于 2009-04-20T09:55:07.977 回答
5

最后,在 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)or typeof(object).Assembly.GetName()?那么在 ASP.NET MVC 源代码中
有这样的注释(从 1.0 开始):HACK

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 系统上运行。
  • 在单声道/ubuntu 14.04/AMD64 和 .NET/Win7/I386 上测试。
于 2014-08-13T11:08:45.183 回答
2

这个怎么样?

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:还没有测试。

于 2017-12-19T01:05:30.430 回答
1

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

于 2014-11-03T12:30:44.253 回答
1

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

于 2009-04-20T10:00:54.967 回答
0

你可以问用户吗?

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

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

于 2009-04-20T09:51:22.637 回答
0

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

System.Environment.Is64BitOperatingSystem
于 2012-02-15T15:18:22.437 回答
0

这是我的方式:

如果操作系统是 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


    }


}
于 2020-01-15T10:54:49.697 回答
-1

我相信你应该避免像 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/

于 2009-04-20T10:17:46.287 回答
-4

这是我所做的:

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

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

于 2011-08-22T05:56:01.837 回答