I want to check which CPU architecture is the user running, is it i386 or X64 or AMD64. I want to do it in C#. I know i can try WMI or Registry. Is there any other way apart
Here is a piece of code that seems to work (based on P/Invoke); It allows to determine the CPU/Machine architecture, current process architecture and also a given binary file architecture (how it's been compiled):
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;
}
This code supports x86, x64 and arm64 architectures and Windows XP. In modern versions of .NET you have built-in functions in the System.Runtime.InteropServices.RuntimeInformation namespace.
How about this?
switch (typeof(string).Assembly.GetName().ProcessorArchitecture) {
case System.Reflection.ProcessorArchitecture.X86:
break;
case System.Reflection.ProcessorArchitecture.Amd64:
break;
case System.Reflection.ProcessorArchitecture.Arm:
break;
}
However case *.Arm:
isn't tested yet.
Win32_Processor WMI Class will do the job. Use MgmtClassGen.exe to generate strongly-typed wrappers.
Depending on why you want to know, you might find that checking the size of the IntPtr structure is the easiest way.
You could ask the user perhaps?
Just kidding of course... I think WMI is what you would use for that. But maybe there is some other way as well?
If you go for WMI then LinqToWmi could be of use. I tried it out once, and it seemed pretty straight forward =) -> http://www.codeplex.com/linq2wmi
Here is my way:
If the operating system is Linux, pinvoke the libc-syscall uname, where you will have the processor in the Machine-field.
If the OS is Windows, check if System.IntPtr.Size * 8 = 64, then it's 64 bit. If it isn't 64-Bit, you check if IsWow64Process exists, and if it exists, and the process is Wow64, then it's x86-64, else it's x86-32.
This one is reliable.
Checking the processor-architecture environment variables is not.
Code:
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
}
}