Хорошо, сначала я должен сказать, что это будет очень похоже на вопрос, который я уже задавал, но уверяю вас, что это совсем другой вопрос.
Предыдущий вопрос был о критериях, которые я должен использовать при выборе основного графического процессора для отображения. Речь идет о том, как я проверяю, что отправленные мной данные правильно декодированы и правильны.
Во-первых, контекст: я переделываю инструмент C#, который я написал недавно, который должен извлекать аппаратные данные из ПК, а затем отправлять их в API (только для ПК с Windows). Моя единственная настоящая головная боль — это непоследовательный способ чтения графических процессоров.
Я использую ManagementBaseObjects из пакета System.Management.
Если быть точным, я в основном получаю свои данные с помощью этого кода:
searcher = new ManagementObjectSearcher($"Select * From {area}");
ManagementObjectCollection results = searcher.Get();
Дело в следующем: объект/данные, которые мне возвращаются, имеют uint в качестве информации о размере оперативной памяти. Это делает его слишком маленьким, чтобы правильно предоставить мне V-RAM более 4 ГБ.
Теперь, судя по тому, что я смог определить, я могу использовать HKLMRegistry, чтобы немного помочь мне здесь.
До сих пор, когда «нормальное» поле memorzSize было слишком маленьким, в объекте HKLM было поле qwMemorySize. ДО СИХ ПОР. (Я добавляю соответствующий код в самый конец)
Дело в том, что в БОЛЬШИНСТВЕ, но не ВСЕХ случаях, когда ОЗУ не слишком большая/отсутствует поле qwMemory, другие поля HKLM, кроме PNP-ID, хранятся в формате base64.
Теперь, когда (я надеюсь) предоставлен достаточный контекст, я попытаюсь сформулировать свои вопросы:
- Всегда ли так, что если VRAM превышает 4 ГБ, будет поле qwMemorySize?
- Когда такое поле НЕ отображается, всегда ли строки будут иметь формат Base64?
- Если нет, то какие еще крайние случаи существуют
- Как можно Я допускаю такие «различные случаи хранения данных», исходя из предположения, что я не могу просто считывать закодированную строку через API, но должен иметь все декодированное и читаемое, когда я отправляю ее в API?
А теперь еще несколько примеров скриншотов.
Изображение первое — это вывод консоли, показывающий графический процессор, который превышает лимит и имеет поле qw, и графический процессор, который этого не делает. На рисунках ниже показано, как это выглядит в HKLM, в том же порядке.



using Microsoft.Win32;
using System.Management;
using System.Text.Json;
namespace StackGPUQuestion
{
internal class Program
{
static void Main(string[] args)
{
GPUsInfo information = InfoExtractor.SimplifiedCondensationOfCode();
JsonSerializerOptions options = new JsonSerializerOptions() { WriteIndented = true };
string gpuInfoString = JsonSerializer.Serialize(information, options);
Console.WriteLine(gpuInfoString);
}
}
//Extensions---------------------------------------------------------------
public static class Extensions
{
//...
public static T GetPropVal(this ManagementBaseObject obj, string name)
{
//todo improve
//this is still a bit in the works, but it will suffice for this
return (T)obj.GetPropertyValue(name);
}
//...
}
//Extensions---------------------------------------------------------------
//System Management---------------------------------------------------------------
public class WinVideoControllerInfo
{
#region Properties
public string Name { get; set; }
public uint AdapterRAM { get; set; }
public string AdapterDACType { get; set; }
public string VideoProcessor { get; set; }
public string PNPDeviceID { get; set; }
#endregion
public WinVideoControllerInfo()
{
//This is empty on purpose. For the function of generics
}
public WinVideoControllerInfo Construct(ManagementBaseObject obj)//This will seem weird, but it has its use
{
return new WinVideoControllerInfo(obj);
}
public WinVideoControllerInfo(ManagementBaseObject obj)
{
Name = obj.GetPropVal(nameof(Name));
AdapterRAM = obj.GetPropVal(nameof(AdapterRAM));
AdapterDACType = obj.GetPropVal(nameof(AdapterDACType));
VideoProcessor = obj.GetPropVal(nameof(VideoProcessor));
PNPDeviceID = obj.GetPropVal(nameof(PNPDeviceID));
}
}
//System Management---------------------------------------------------------------
//HKLM---------------------------------------------------------------
//HKLM Support---------------------------------------------------------------
public interface IRegistry
{
///
/// Retrieves the value associated with the specified name, in the specified registry key.
/// If the name is not found in the specified key, returns a default value that you provide, or null if the specified key does not exist.
///
/// The full registry path of the key, beginning with a valid registry root, such as "HKEY_CURRENT_USER".
/// The name of the name/value pair.
/// The value to return if valueName does not exist.
///
object? GetValue(string keyName, string valueName, object? defaultValue);
}
public class Registry : IRegistry
{
public static Registry RegistryDefault => new();
public object? GetValue(string keyName, string valueName, object? defaultValue)
{
return Microsoft.Win32.Registry.GetValue(keyName, valueName, defaultValue);
}
}
public readonly struct RegistryEntry
{
///
/// The full registry path of the key, beginning with a valid registry root, such as "HKEY_CURRENT_USER".
///
public string FullPathToKey { get; }
///
/// The name of the name/value pair.
///
public string ValueName { get; }
///
/// The value to return if ValueName does not exist.
///
public string? DefaultValueNotFound { get; }
public RegistryEntry(string fullPathToKey, string valueName, string? defaultValue)
{
FullPathToKey = fullPathToKey;
ValueName = valueName;
DefaultValueNotFound = defaultValue;
}
}
//HKLM Support---------------------------------------------------------------
public class HKLMVideoController
{
private const string HKLMRegistryPathBase = @"HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\";
private readonly RegistryEntry _adapterStringRegistry;
private readonly RegistryEntry _biosStringRegistry;
private readonly RegistryEntry _chipTypeRegistry;
private readonly RegistryEntry _dacTypeRegistry;
private readonly RegistryEntry _memorySizeRegistry;
private readonly RegistryEntry _qwMemorySizeRegistry;
private readonly RegistryEntry _matchingDeviceIdRegistry;
private IRegistry _registryProvider;
#region Properties
#region Backers
private object _adapterString;
private object _biosString;
private object _chipType;
private object _dacType;
private object _memorySize;
private object _qwMemorySize;
private object _matchingDeviceId;
#endregion
public object AdapterString => _adapterString;
public object BiosString => _biosString;
public object ChipType => _chipType;
public object DacType => _dacType;
public object MemorySize => _memorySize;
public object QwMemorySize => _qwMemorySize;
public object MatchingDeviceId => _matchingDeviceId;
#endregion
private string HKLMRegistryPath;
public HKLMVideoController(string id = "0000")
{
_registryProvider = Registry.RegistryDefault;
HKLMRegistryPath = HKLMRegistryPathBase + id;
_adapterStringRegistry = new(HKLMRegistryPath, "HardwareInformation.AdapterString", null);
_biosStringRegistry = new(HKLMRegistryPath, "HardwareInformation.BiosString", null);
_chipTypeRegistry = new(HKLMRegistryPath, "HardwareInformation.ChipType", null);
_dacTypeRegistry = new(HKLMRegistryPath, "HardwareInformation.DacType", null);
_memorySizeRegistry = new(HKLMRegistryPath, "HardwareInformation.MemorySize", null);
_qwMemorySizeRegistry = new(HKLMRegistryPath, "HardwareInformation.qwMemorySize", null);
_matchingDeviceIdRegistry = new(HKLMRegistryPath, "MatchingDeviceId", null);
SetAllProperties();
}
private void SetAllProperties()
{
_adapterString = GetProperty(_adapterStringRegistry);
_biosString = GetProperty(_biosStringRegistry);
_chipType = GetProperty(_chipTypeRegistry);
_dacType = GetProperty(_dacTypeRegistry);
_memorySize = GetProperty(_memorySizeRegistry);
_qwMemorySize = GetProperty(_qwMemorySizeRegistry);
_matchingDeviceId = GetProperty(_matchingDeviceIdRegistry);
}
private object GetProperty(RegistryEntry propertyEntry)
{
object? propertyValue = _registryProvider.GetValue(propertyEntry.FullPathToKey, propertyEntry.ValueName, propertyEntry.DefaultValueNotFound);
propertyValue ??= Def(propertyEntry.ValueName);
return propertyValue;
}
private object Def(string valueName)
{
String str = $"Could not determine {valueName}";
object ing = str;
return ing;
}
}
//HKLM---------------------------------------------------------------
//Pairing---------------------------------------------------------------
public class VideoControllerPair
{
public WinVideoControllerInfo WinInfo { get; set; }
public HKLMVideoController HKLMInfo { get; set; }
public VideoControllerPair(WinVideoControllerInfo winInfo)
{
string driverPathId = SystemInformationRetriever.PNPToPathId(winInfo.PNPDeviceID);
HKLMVideoController hklmInfo = new(driverPathId);
WinInfo = winInfo;
HKLMInfo = hklmInfo;
}
}
//Pairing---------------------------------------------------------------
public static class SystemInformationRetriever
{
public static string PNPToPathId(string pnpId)
{
RegistryKey pnpRegistryEntry =
Microsoft.Win32.Registry.LocalMachine.OpenSubKey($@"SYSTEM\CurrentControlSet\Enum\{pnpId}");
object? driverValue = pnpRegistryEntry.GetValue("Driver");
string driverPath = driverValue.ToString();
string driverPathId = new(driverPath.TakeLast(4).ToArray());
return driverPathId;
}
}
//Very simplified version
public class GPUsInfo
{
/*
//actual properties
public int GPUCards => GPUUnits.Count;
public List GPUUnits { get; set; }
*/
//Simplified Property
public List Pairs { get; set; }
public GPUsInfo() { }
public GPUsInfo Construct(List winInfos)
{
return new GPUsInfo(winInfos);
}
public GPUsInfo(List winInfos)
{
if (!winInfos.Any())
{
throw new Exception();
}
List pairedInfos = new();
foreach (WinVideoControllerInfo winInfo in winInfos)
{
VideoControllerPair pairedInfo = new VideoControllerPair(winInfo);
pairedInfos.Add(pairedInfo);
}
Pairs = pairedInfos;
/*
// This would be the actual code
List infos = new();
foreach (VideoControllerPair pairedInfo in pairedInfos)
{
GPUInfo info = new GPUInfo(pairedInfo);
infos.Add(info);
}
GPUUnits = infos;
*/
}
}
//The following extract has been a bit modified from the way it persists in the project, so you guys can actually work with it
public static class InfoExtractor
{
public static GPUsInfo SimplifiedCondensationOfCode()
{
//simplified exert of Searcher Getter (GetSearcherResults(area))
string area = "Win32_VideoController";
ManagementObjectSearcher searcher = new ManagementObjectSearcher($"Select * From {area}");
ManagementObjectCollection results = searcher.Get();
//simplified exert of Extracting Information (RetrieveGenericInformation(area))
//ManagementObjectCollection rawInformation = GetSearcherResults(area);
ManagementObjectCollection rawInformation = results;
List winInfos = new List();
foreach (ManagementBaseObject information in rawInformation)
{
WinVideoControllerInfo winInfo = new WinVideoControllerInfo().Construct(information);
winInfos.Add(winInfo);
}
GPUsInfo info = new GPUsInfo().Construct(winInfos);
return info;
}
}
}
Дополнительно
Теперь конечной целью является как можно лучше реализовать класс GPUInfo (не GPUsInfo, а GPUInfo), который будет иметь следующие свойства
public string AdapterName { get; set; }
public string Processor { get; set; }
public string AdapterDac { get; set; }
public string BIOSString { get; set; }
public object RamSize { get; set; }
Каким образом лучше всего определить реализацию конструктора. Я знаю, что это кажется широким, поэтому это дополнение. По сути, речь идет о том, чтобы система знала, когда следует полагаться на Win, а когда на данные HKLM, а также знала, когда и не нужно декодировать и как.
Вот грубый старт для игры (не фактическая работающая версия, но, на мой взгляд, хорошая основа)
public GPUInfo(VideoControllerPair winInfo)
{
WinVideoControllerInfo a = winInfo.WinInfo;
HKLMVideoController b = winInfo.HKLMInfo;
var winName = a.Name;
var hklName = b.AdapterString;
var winVP = a.VideoProcessor;
var hklVP = b.ChipType;
var winDAC = a.AdapterDACType;
var hklDAC = b.DacType;
var winRam = a.AdapterRAM;
var hklRamOne = b.MemorySize;
var hklRamTwo = b.QwMemorySize;
//Preliminary
AdapterName = winName;
Processor = winVP;
AdapterDac = winDAC;
//todo
}
Подробнее здесь: https://stackoverflow.com/questions/798 ... n-for-gpus
Мобильная версия