鉴于 WMI 仅 Windows 且操作系统中缺少注册表,例如 Linux 和 Mac ,如何在 .NET Core 中获取处理器名称?
我打算使用以下方法(使用注册表)跨平台:
private static string GetProcessorName()
{
var key = Registry.LocalMachine.OpenSubKey(@"HARDWARE\DESCRIPTION\System\CentralProcessor\0\");
return key?.GetValue("ProcessorNameString").ToString() ?? "Not Found";
}
您可以假设我可以在运行时告诉我正在运行的 OS 。
答案 0 :(得分:1)
在Linux上,我使用此链接How to get available virtual and physical memory size under Mono?中的示例中的FreeCSharp类创建了一个可以读取cpuinfo的类。对于.net core,您很可能必须从nuget中获取System.Text.RegularExpressions。我还没有在.net core的单声道下进行过测试,但是我敢肯定它应该可以工作。
using System;
using System.Text.RegularExpressions;
using System.IO;
namespace Example.Lib.Common
{
/// <summary>
/// Reads /proc/cpuinfo to obtain common values
/// </summary>
public class LinuxCpuInfo
{
public string VendorId { get; private set; }
public int CpuFamily { get; private set; }
public int Model { get; private set; }
public string ModelName { get; private set; }
public int Stepping { get; private set; }
public double MHz { get; private set; }
public string CacheSize { get; private set; }
public void GetValues()
{
string[] cpuInfoLines = File.ReadAllLines(@"/proc/cpuinfo");
CpuInfoMatch[] cpuInfoMatches =
{
new CpuInfoMatch(@"^vendor_id\s+:\s+(.+)", value => VendorId = Conversion.ObjectToString(value)),
new CpuInfoMatch(@"^cpu family\s+:\s+(.+)", value => CpuFamily = Conversion.ObjectToInt(value)),
new CpuInfoMatch(@"^model\s+:\s+(.+)", value => Model = Conversion.ObjectToInt(value)),
new CpuInfoMatch(@"^model name\s+:\s+(.+)", value => ModelName = Conversion.ObjectToString(value)),
new CpuInfoMatch(@"^stepping\s+:\s+(.+)", value => Stepping = Conversion.ObjectToInt(value)),
new CpuInfoMatch(@"^cpu MHz\s+:\s+(.+)", value => MHz = Conversion.ObjectToDouble(value)),
new CpuInfoMatch(@"^cache size\s+:\s+(.+)", value => CacheSize = Conversion.ObjectToString(value))
};
foreach (string cpuInfoLine in cpuInfoLines)
{
foreach (CpuInfoMatch cpuInfoMatch in cpuInfoMatches)
{
Match match = cpuInfoMatch.regex.Match(cpuInfoLine);
if (match.Groups[0].Success)
{
string value = match.Groups[1].Value;
cpuInfoMatch.updateValue(value);
}
}
}
}
public class CpuInfoMatch
{
public Regex regex;
public Action<string> updateValue;
public CpuInfoMatch(string pattern, Action<string> update)
{
this.regex = new Regex(pattern, RegexOptions.Compiled);
this.updateValue = update;
}
}
}
}
答案 1 :(得分:0)
没有“ hacks”,就无法在C#中完成。您必须使用cpuid指令(或调用cpuid的OS函数)。另外,您可以分配内存并将其设置为可执行文件,然后将其复制到称为cpuid的代码中。
首先,您必须检测CPU架构(对于Windows,可以通过环境变量PROCESSOR_ARCHITECTURE
和PROCESSOR_ARCHITEW6432
完成)-使用什么处理器(x86 / x86_64 / ARM / ARM64)
然后,您需要通过cpuid指令或等效的ARM获取处理器名称。
您可以为Linux修改以下 Windows 代码(您需要更改Virtual Alloc功能)
[StructLayout(LayoutKind.Sequential)]
internal ref struct CpuIdInfo
{
public uint Eax;
public uint Ebx;
public uint Ecx;
public uint Edx;
public static void AppendAsString(StringBuilder builder,uint value)
{
var val = value;
while (val != 0)
{
builder.Append((char) (val & 0xFF));
val >>= 8;
}
}
public string GetString()
{
StringBuilder ret = new StringBuilder(16);
AppendAsString(ret,Ebx);
AppendAsString(ret,Edx);
AppendAsString(ret,Ecx);
return ret.ToString();
}
}
internal sealed class CpuIdAssemblyCode
: IDisposable
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void CpuIDDelegate(int level, ref CpuIdInfo cpuId);
private IntPtr _codePointer;
private uint _size;
private CpuIDDelegate _delegate;
public CpuIdAssemblyCode()
{
byte[] codeBytes = (IntPtr.Size == 4) ? x86CodeBytes : x64CodeBytes;
_size = (uint) codeBytes.Length;
_codePointer = NativeMethods.Kernel32.VirtualAlloc(
IntPtr.Zero,
new UIntPtr(_size),
AllocationType.COMMIT | AllocationType.RESERVE,
MemoryProtection.EXECUTE_READWRITE
);
Marshal.Copy(codeBytes, 0, _codePointer, codeBytes.Length);
#if NET40
_delegate = (CpuIDDelegate) Marshal.GetDelegateForFunctionPointer(_codePointer, typeof(CpuIDDelegate));
#else
_delegate = Marshal.GetDelegateForFunctionPointer<CpuIDDelegate>(_codePointer);
#endif
}
~CpuIdAssemblyCode()
{
Dispose(false);
}
public void Call(int level, ref CpuIdInfo cpuInfo)
{
_delegate(level, ref cpuInfo);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
NativeMethods.Kernel32.VirtualFree(_codePointer, _size, 0x8000);
}
// Basic ASM strategy --
// void x86CpuId(int level, byte* buffer)
// {
// eax = level
// cpuid
// buffer[0] = eax
// buffer[4] = ebx
// buffer[8] = ecx
// buffer[12] = edx
// }
private readonly static byte[] x86CodeBytes = {
0x55, // push ebp
0x8B, 0xEC, // mov ebp,esp
0x53, // push ebx
0x57, // push edi
0x8B, 0x45, 0x08, // mov eax, dword ptr [ebp+8] (move level into eax)
0x0F, 0xA2, // cpuid
0x8B, 0x7D, 0x0C, // mov edi, dword ptr [ebp+12] (move address of buffer into edi)
0x89, 0x07, // mov dword ptr [edi+0], eax (write eax, ... to buffer)
0x89, 0x5F, 0x04, // mov dword ptr [edi+4], ebx
0x89, 0x4F, 0x08, // mov dword ptr [edi+8], ecx
0x89, 0x57, 0x0C, // mov dword ptr [edi+12],edx
0x5F, // pop edi
0x5B, // pop ebx
0x8B, 0xE5, // mov esp,ebp
0x5D, // pop ebp
0xc3 // ret
};
private readonly static byte[] x64CodeBytes = {
0x53, // push rbx this gets clobbered by cpuid
// rcx is level
// rdx is buffer.
// Need to save buffer elsewhere, cpuid overwrites rdx
// Put buffer in r8, use r8 to reference buffer later.
// Save rdx (buffer addy) to r8
0x49, 0x89, 0xd0, // mov r8, rdx
// Move ecx (level) to eax to call cpuid, call cpuid
0x89, 0xc8, // mov eax, ecx
0x0F, 0xA2, // cpuid
// Write eax et al to buffer
0x41, 0x89, 0x40, 0x00, // mov dword ptr [r8+0], eax
0x41, 0x89, 0x58, 0x04, // mov dword ptr [r8+4], ebx
0x41, 0x89, 0x48, 0x08, // mov dword ptr [r8+8], ecx
0x41, 0x89, 0x50, 0x0c, // mov dword ptr [r8+12], edx
0x5b, // pop rbx
0xc3 // ret
};
}
在Windows x86 / x86_64上的用法
var asmCode = new CpuIdAssemblyCode();
CpuIdInfo info = new CpuIdInfo();
asmCode.Call(0, ref info);
asmCode.Dispose();
string ret= info.GetString();
您还可以修改my library(在Windows中也可以执行同样的操作)