ユーザーが実行しているCPUアーキテクチャ(i386、X64、AMD64)を確認したいと思います。C#でやりたいです。WMIまたはレジストリを試すことができることはわかっています。これら2つ以外に他の方法はありますか?私のプロジェクトは.NET2.0をターゲットにしています!
14 に答える
試すこともできます(操作されていない場合にのみ機能します):
System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")
ここで私を導いたのは、32ビットと64ビットのOSをチェックすることです。最も評価の高い答えは、現在のプロセスの設定を調べることです。答えが見つからなかった後、私は次の設定を見つけました。これがあなたのために働くことを願っています。
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アーキテクチャおよびWindowsXPをサポートしています。最新バージョンの.NETでは、System.Runtime.InteropServices.RuntimeInformation名前空間に組み込み関数があります。
Win32_ProcessorWMIクラスがその役割を果たします。MgmtClassGen.exeを使用して、強く型付けされたラッパーを生成します。
最後に、C#で現在実行中のCLRランタイムのプラットフォーム/プロセッサアーキテクチャを解決するための最短のトリックは次のとおりです。
PortableExecutableKinds peKind;
ImageFileMachine machine;
typeof(object).Module.GetPEKind(out peKind, out machine);
ここで、 Module.GetPEKindは、.NETv2以降に存在するImageFileMachine列挙を返します。
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ソースコード(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
設定しません。それは、新しいAssemblyNameに対してのみです。ProcessorArchitecture
None
したがって、将来の読者のために、ImageFileMachineでその醜いGetPEKindを使用することをお勧めします!
ノート:
- これにより、基盤となるシステムアーキテクチャではなく、現在実行中のランタイムアーキテクチャが返されます。
とはいえ、唯一の例外は、I386ランタイムがAMD64システムで実行される可能性があることです。 - mono / 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:
、まだテストされていません。
たぶん、このCodeProjectの記事が役立つでしょうか?System.Management名前空間のManagementObjectSearcherを使用して、ハードウェア情報を検索します。
知りたい理由によっては、IntPtr構造体のサイズを確認するのが最も簡単な方法である場合があります。
これは私には最も簡単なようです:
System.Environment.Is64BitOperatingSystem
あなたはおそらくユーザーに尋ねることができますか?
もちろん冗談です...WMIはそのために使用するものだと思います。しかし、他の方法もあるのでしょうか?
WMIを使用する場合は、LinqToWmiが役立つ可能性があります。一度試してみましたが、かなり簡単に見えました=)-> http://www.codeplex.com/linq2wmi
これが私のやり方です:
オペレーティングシステムがLinuxの場合は、libc-syscall unameをピンボークします。ここで、プロセッサが[マシン]フィールドにあります。
OSが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%の確率で)。
すばやく起動して実行するには、Intelサイトでwincpuidサンプルを確認し、そこからcpuid.hからピースを抽出します。ベンダーは2つしかなく、1つはメモリレイテンシーに優れており、もう1つはそうではありません(ネイティブコードとマネージコードのように)。そのため、他のアーキテクチャなどでMonoに問題が発生します(btwではありません)。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ビットアーキテクチャを使用している場合は、2つのプログラムファイルの環境変数があります。x86を使用している場合は、1つしかありません。