如何获取内存名称?

How to get the RAM name?

我有一个关于 RAM 信息的问题 - 你是如何得到它的名字的?

到目前为止,从 Win32_PhysicalMemoryWin32_PhysicalMemoryArray 类 我能够获得除名称(显示名称;例如 CRUCIAL BALLISTIX SPORT LT RED)之外的大部分信息

我编写代码的平台是 .NET WinForms - C#。

我看过的参考资料

我的问题是:如何获取内存名称?

这是我用来检索 RAM 名称 and/or 制造商的一段代码。

ManagementObjectSearcher myRamObject = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMemory");

foreach(ManagementObject obj in myRamObject.Get())
{
    RAM.NAME = obj["Name"].ToString();
}

下面显示了如何查找计算机内存信息,包括制造商。

获取计算机制造商:(PowerShell)

打开 PowerShell window 并输入以下内容:

Get-WmiObject -Namespace Root\cimv2 -Query "Select * from Win32_PhysicalMemory" | ForEach-Object { $_ | Select-Object -Property BankLabel, Capacity, Manufacturer, MemoryType, PartNumber, Speed }

获取计算机制造商: (cmd)

打开 cmd window 并输入以下内容:

wmic path Win32_PhysicalMemory get BankLabel, Capacity, Manufacturer, MemoryType, PartNumber, Speed

C#:

创建一个class(名称:MemoryInfoWmi)

MemoryInfoWmi:

public class MemoryInfoWmi
{
    public string BankLabel { get; set; }
    public int Capacity { get; set; }
    public string Manufacturer { get; set; }
    public int MemoryType { get; set; }
    public string PartNumber { get; set; }
    public int Speed { get; set; }
}

获取内存:

private List<MemoryInfoWmi> GetMemory()
{
    List<MemoryInfoWmi> memoryInfoList = new List<MemoryInfoWmi>();

    StringBuilder sb = new StringBuilder();

    using (ManagementObjectSearcher moSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMemory"))
    {
        foreach (ManagementObject mObj in moSearcher.Get())
        {
            if (mObj == null)
                continue;

            MemoryInfoWmi mInfo = new MemoryInfoWmi();
            mInfo.BankLabel = mObj["BankLabel"]?.ToString();

            int capacity = 0;
            if (Int32.TryParse(mObj["Capacity"]?.ToString(), out capacity))
                mInfo.Capacity = capacity;

            mInfo.Manufacturer = mObj["Manufacturer"]?.ToString();

            int memoryType = 0;
            if (Int32.TryParse(mObj["MemoryType"]?.ToString(), out memoryType))
                mInfo.MemoryType = memoryType;

            mInfo.PartNumber = mObj["PartNumber"]?.ToString();

            int speed = 0;
            if (Int32.TryParse(mObj["Speed"]?.ToString(), out speed))
                mInfo.Speed = speed;

            //add
            memoryInfoList.Add(mInfo);

            Debug.WriteLine($"Bank Label: {mInfo.BankLabel} Manufacturer: {mInfo.Manufacturer}");
        }
    }

    return memoryInfoList;
}

有时,制造商的名称显示为一个或多个十六进制数字(无空格)。

如果发生这种情况,需要参考Standard Manufacturer's Identification Code (JEP106)出版物以找到相关信息。文档名称为 JEP106<revision number>(例如:JEP106BE)- 列表会定期修订。

值可能采用以下格式:

两个十六进制值:第一个十六进制值是连续数,第二个十六进制值是(从1开始的)entry/index数。 (如果有5个continuations,那就意味着想要的值在第6个bank/group)。

例如:859B

注意859B的值实际上是两个十六进制数:859B.

我相信可能还使用了第二种格式,其中每个延续都使用 7F 列出。最后一个十六进制值将是所需的值。

例如:7F7F7F7F7F9B

在文档中,数据列在一系列值从 1 到 126 的组(组)中。一个组可能少于 126 个条目,但不能更多。本质上,它是一个列表的列表。

Bank/Group #1: Range from 1...126
Bank/Group #2: Range from 1...126
Bank/Group #3: Range from 1...126
          ...

查看文档时,您会注意到值 1, 2, 3, 4, 5... 以及列出的十六进制值。但是,您还会注意到十六进制值似乎与十进制值不对应。十进制的 1, 2, 3, 4, 5 也应该是十六进制的 1, 2, 3, 4, 5。为什么值不同?

根据文档,十六进制值使用 7 个数据位和 1 个奇偶校验位(奇校验)。

让我们看看第 5 个条目会是什么样子。条目编号使用从 1 开始的索引,因此人们期望值是 5。但是,由于奇偶校验位,该值显示为 85.

打开Windows中的计算器,select“程序员”。然后单击“十六进制”一词。然后输入“85”。您会注意到以下内容:

HEX: 85
DEC: 133
BIN: 1000 0101

注意第 8 位是“1”。如果我们查看位 0-7,我们有 000 0101。在计算器中,如果我们点击“BIN”并输入这个数字,我们将看到以下内容:

HEX: 5
DEC: 5
BIN: 0000 0101

如前所述,第8位是校验位。获取位 0-7 的一种方法是用“0”替换第 8 位,然后读取整个 8 位。我们该怎么做?

我们需要利用逻辑规则。让我们看一些真值表。

给定:假=0;真 = 1

我们通过重复创建所有可能的排列。

这将如何运作?在 C# 中,我们可以使用 & 进行逻辑 AND 操作。同样,| 用于逻辑 OR 操作。

为了将其付诸实践,让我们从一个测试十六进制值开始:85.

HEX: 85
DEC: 133
BIN: 1000 0101

我们需要确定可以将第 8 位更改为 0 的逻辑 AND 使用什么值。位顺序是[8][7][6][5][4][3][2][1](Little Endian)

确定字节顺序:(PowerShell)

[System.BitConverter]::IsLittleEndian

以下在使用奇校验时将校验位改为0

GetValueWithoutParity:

private uint GetValueWithoutParity(uint originalValue)
{
    //values have odd parity
    //if number of 1's is odd, then eighth bit = 0
    //if number of 1's is even, then eighth bit = 1

    //we need to zero out the eighth bit in order to get the actual value
    //ie: in order to get the value of bits 0-7

    uint mask = 0x7F; //01111111

    //logical AND - search "Bitwise operators" for more info
    return originalValue & mask; 
}

如果有一个没有校验位的值,可以通过以下方式添加校验位后得到该值:

GetValueWithParity:

注意:该方法代码来自here.

private uint GetValueWithParity(uint originalValue)
{
    //values have odd parity
    //if number of 1's is odd, then eighth bit = 0
    //if number of 1's is even, then eighth bit = 1

    string binaryVal = Convert.ToString(originalValue, 2);
    byte[] numberAsByte = new byte[] { (byte)originalValue };

    //create new instance and set value
    BitArray bits = new BitArray(numberAsByte);

    int onesCount = 0;
    
    //count number of 1's
    for (int i = 0; i < 8; i++)
    {
        if (bits[i])
            onesCount++; //increment
    }

    if (onesCount % 2 == 0)
    {
        //set the left most bit for odd parity
        bits[7] = true; 
    }

    //copy
    bits.CopyTo(numberAsByte, 0);

    return numberAsByte[0];
}

现在,我们可以将十六进制值解码为无奇偶校验的值。移除 85 的奇偶校验位后,我们确定没有奇偶校验的值是 5。如前所述,第一个十六进制值是连续数,第二个十六进制值是(基于 1 的)entry/index 数。 (如果有5个continuations,那就意味着想要的值在第6个bank/group)。

解码第二个值后,我们发现(1-based)index/entry,是27


在继续之前,让我们创建一些 classes 来存储我们的数据。我决定将数据存储为 JSON。如果您愿意,可以使用 XML。

Download/install NuGet 包: Newtonsoft.Json

  • 在 VS 菜单中,单击 查看
  • Select 解决方案资源管理器
  • 在解决方案资源管理器中,right-click 您的<项目名称>,select 管理 NuGet 包...。单击浏览。在搜索框中,tpe Newtonsoft.Json。单击 安装 。如果出现提示,请单击

创建一个class:(名称:制造商)

public class Manufacturer
{
    [JsonProperty(PropertyName = "groupNumber")]
    public int GroupNumber { get; set; }

    [JsonProperty(PropertyName = "names")]
    public List<String> Names { get; set; } = new List<String>();
}

创建一个class:(名称:RootObjectJson)

public class RootObjectJson
{
    [JsonProperty(PropertyName = "manufacturer")]
    public List<Manufacturer> Manufacturers { get; set; } = new List<Manufacturer>();
}

将以下 using 语句添加到您的 classes:

  • 使用系统;
  • 使用 System.Collections.Generic;
  • 使用 Newtonsoft.Json;

ToDo:将数据加载到 classes。这个repository可能有用。

注意:使用下面的代码时,需要对齐数据,以便所需数据从索引 1 开始。一个简单的方法是添加填充数据 (索引 0 中不会使用的数据)。

例子:

以下表示索引 0 中的数据条目。不会使用此数据,但用于使我们的数据看起来像是使用从 1 开始的索引。

{
  "manufacturer": [
    {
      "groupNumber": 0,
      "names": [ "None" ]
    }
 ]
}

然后给定一个值(例如:859B),可以执行类似于以下的操作来检索所需的数据。

注意:如果你不想使用“填充数据”(将未使用的数据放在索引0中),请在下面的方法中更改索引。

解码制造商:

private void DecodeManufacturer(string manufacturerVal, RootObjectJson root)
{
    uint groupNumber = 0;
    uint numberOfContinuations = 1;
    uint entryNumber = 1;
    if (!String.IsNullOrEmpty(manufacturerVal))
    {
        if (manufacturerVal.Length > 2)
        {
            uint currentVal = 0;

            //ToDo: ensure each hex value is 2 chars
            //if necessary, pad with a leading '0'
            for (int i = 0; i < manufacturerVal.Length; i+=2)
            {
                //Debug.WriteLine($"i = {i} manufacturerVal.Length: {manufacturerVal.Length}");

                //get decimal value of hex value
                string currentStr = manufacturerVal.Substring(i, 2);
                string currentStrAsHex = String.Format("0x{0}", currentStr);

                //convert to uint
                currentVal = Convert.ToUInt32(currentStrAsHex, 16);

                //Debug.WriteLine($"currentStrAsHex: {currentStrAsHex} currentVal: {currentVal}");

                if (i == 0 && manufacturerVal.Length > 2 && manufacturerVal.Length <= 4)
                {
                    
                    numberOfContinuations = GetValueWithoutParity(currentVal);

                    //set value
                    groupNumber = numberOfContinuations + 1;

                    //Debug.WriteLine($"numberOfContinuations: {numberOfContinuations} groupNumber: {groupNumber}");
                }
                else if (i == 2 && manufacturerVal.Length > 2 && manufacturerVal.Length <= 4)
                {
                    
                    entryNumber = GetValueWithoutParity(currentVal);
                    //Debug.WriteLine("entryNumber: " + entryNumber);

                    Debug.WriteLine($"numberOfContinuations: {numberOfContinuations} groupNumber: {groupNumber} entryNumber: {entryNumber}");

                    //need to convert to int to use as an index for the lists
                    int groupNumberInt = (int)groupNumber;
                    int entryNumberInt = (int)entryNumber;

                    if (groupNumberInt < root.Manufacturers.Count && entryNumber < root.Manufacturers[groupNumberInt].Names.Count)
                    {
                        Debug.WriteLine($"Manufacturer Name: '{root.Manufacturers[groupNumberInt].Names[entryNumberInt]}' Hex: {GetValueWithParity(entryNumber).ToString("X2")} Hex2: {GetValueWithParity2(entryNumber).ToString("X2")}");
                    }
                    else
                    {
                        Debug.WriteLine("Error: Invalid input.");
                    }
                }
            }
        }
    }
}

资源: