C# 如何在.NET Core中获取CPU名称?

C# 如何在.NET Core中获取CPU名称?,c#,.net,.net-core,C#,.net,.net Core,鉴于WMI仅适用于Windows,并且Linux和Mac等操作系统中没有注册表,如何在.NET Core中获取处理器名称 我打算使以下方法(使用注册表)跨平台: private static string GetProcessorName() { var key = Registry.LocalMachine.OpenSubKey(@"HARDWARE\DESCRIPTION\System\CentralProcessor\0\"); return key?.GetValue("

鉴于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";
}

您可以假设我可以在运行时告诉您我在什么操作系统下运行。

在Linux上,我使用本链接示例中的FreeCSharp类创建了一个可以读取cpuinfo的类。对于.net core,您很可能必须从nuget获取System.Text.RegularExpressions。我还没有在.NETCoreOnly mono下测试过,但我很确定它应该可以工作

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;
            }
        }
    }
}
使用系统;
使用System.Text.RegularExpressions;
使用System.IO;
命名空间Example.Lib.Common
{
/// 
///读取/proc/cpuinfo以获取公共值
/// 
公共类LinuxCpuInfo
{
公共字符串VendorId{get;private set;}
public int cpuffamily{get;private set;}
公共int模型{get;private set;}
公共字符串ModelName{get;private set;}
公共整数步进{get;私有集;}
公共双MHz{get;专用集;}
公共字符串缓存大小{get;private set;}
public void GetValues()
{
字符串[]cpuInfoLines=File.ReadAllLines(@/proc/cpuinfo);
CpuInfoMatch[]cpuInfoMatches=
{
新的CpuInfoMatch(@“^vendor\u id\s+:\s+(.+)”,value=>VendorId=Conversion.ObjectToString(value)),
新的CpuInfoMatch(@“^cpu系列\s+:\s+(.+)”,value=>cpuffamily=Conversion.ObjectToInt(value)),
新的CpuInfoMatch(@“^model\s+:\s+(.+)”,value=>model=Conversion.ObjectToInt(value)),
新的CpuInfoMatch(@“^model name\s+:\s+(.+)”,value=>ModelName=Conversion.ObjectToString(value)),
新的CpuInfoMatch(@“^stepping\s+:\s+(.+)”,value=>stepping=Conversion.ObjectToInt(value)),
新的CpuInfoMatch(@“^cpu MHz\s+:\s+(.+)”,值=>MHz=Conversion.ObjectToDouble(值)),
新的CpuInfoMatch(@“^cache size\s+:\s+(.+)”,value=>CacheSize=Conversion.ObjectToString(value))
};
foreach(cpuInfoLine中的字符串cpuInfoLine)
{
foreach(CpuInfoMatch中的CpuInfoMatch)
{
Match Match=cpuInfoMatch.regex.Match(cpuInfoLine);
if(匹配组[0]。成功)
{
字符串值=匹配。组[1]。值;
cpuInfoMatch.updateValue(值);
}
}
}
}
公共类CpuInfoMatch
{
公共正则表达式正则表达式;
公共行动更新价值;
公共CpuInfoMatch(字符串模式,操作更新)
{
this.regex=新的regex(pattern,RegexOptions.Compiled);
this.updateValue=更新;
}
}
}
}
如果没有“hacks”,就不能用C语言完成。必须使用cpuid指令(或调用cpuid的操作系统函数)。您还可以分配内存并将其设置为可执行文件,并将调用cpuid的代码复制到其中

首先,您必须检测CPU体系结构(对于Windows,这可以通过环境变量
处理器体系结构
处理器体系结构w6432
)-使用什么处理器(x86/x86\u 64/ARM/ARM64)

然后需要通过cpuid指令或ARM等效指令获取处理器名称

您可以修改以下适用于Linux的Windows代码(您需要更改虚拟Alloc函数)


您还可以修改(它在Windows下执行相同的操作)

在Linux上,您可以从
/proc/cpuinfo
读取信息。它应该也能在macOS上工作。@Nasreddine似乎不能在macOS上工作;尽管sysctl-n machdep.cpu.brand\u string
[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
    };


}
var asmCode = new CpuIdAssemblyCode();
CpuIdInfo info = new CpuIdInfo();
asmCode.Call(0, ref info);
asmCode.Dispose();
string ret= info.GetString();