我想检查用户正在运行哪个 CPU 架构,是 i386 还是 X64 还是 AMD64。我想用 C# 来做。我知道我可以尝试 WMI 或注册表。除了这两种方法还有其他方法吗?我的项目面向 .NET 2.0!
14 回答
您也可以尝试(仅在不被操纵的情况下才有效):
System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")
导致我来到这里的是检查 32 位和 64 位操作系统。评分最高的答案是查看Current process的设置。在没有找到答案后,我找到了以下设置。希望这对你有用。
bool is64 = System.Environment.Is64BitOperatingSystem
我知道这个问题来自过去,但截至 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
这是一段似乎有效的代码(基于 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 命名空间中有内置函数。
Win32_Processor WMI 类将完成这项工作。使用MgmtClassGen.exe生成强类型包装器。
最后,在 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 上测试。
这个怎么样?
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:
还没有测试。
根据您想知道的原因,您可能会发现检查 IntPtr 结构的大小是最简单的方法。
也许这篇CodeProject 文章可以提供帮助?它使用 System.Management 命名空间中的 ManagementObjectSearcher 来搜索硬件信息。
你可以问用户吗?
当然开个玩笑...我认为 WMI 是您将使用的。但也许还有其他方法?
如果你选择 WMI,那么 LinqToWmi 可能会有用。我试过一次,它看起来很简单 =) -> http://www.codeplex.com/linq2wmi
这对我来说似乎是最简单的:
System.Environment.Is64BitOperatingSystem
这是我的方式:
如果操作系统是 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
}
}
我相信你应该避免像 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/)
这是我所做的:
public static bool Isx86()
{
return (Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%").Length == 0);
}
如果您使用 64 位架构,您将有两个程序文件环境变量。如果您使用的是 x86,那么您将只有一个。