diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 7213bcd..bec7e5b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -9,7 +9,7 @@ assignees: '' ### Library version -### OS & OS version +### OS, version, architecture (32 bit / 64 bit) ### Describe the bug README.md - https://github.com/Jinjinov/Hardware.Info.git - git Computer;Device;Hardware;Info;Information;NET Standard;Windows;Linux;macOS MIT + True + HardwareInfo.snk + true + true @@ -33,8 +35,9 @@ - - + + + diff --git a/Hardware.Info/HardwareInfo.cs b/Hardware.Info/HardwareInfo.cs index bf9c9e5..8cecca4 100644 --- a/Hardware.Info/HardwareInfo.cs +++ b/Hardware.Info/HardwareInfo.cs @@ -8,27 +8,98 @@ namespace Hardware.Info { + /// + /// Main Hardware.Info class + /// public class HardwareInfo : IHardwareInfo { + /// + /// Operating system + /// public OS OperatingSystem { get; private set; } = new OS(); + + /// + /// Memory status + /// public MemoryStatus MemoryStatus { get; private set; } = new MemoryStatus(); + /// + /// List of + /// public List BatteryList { get; private set; } = new List(); + + /// + /// List of + /// public List BiosList { get; private set; } = new List(); + + /// + /// List of + /// + public List ComputerSystemList { get; private set; } = new List(); + + /// + /// List of + /// public List CpuList { get; private set; } = new List(); + + /// + /// List of + /// public List DriveList { get; private set; } = new List(); + + /// + /// List of + /// public List KeyboardList { get; private set; } = new List(); + + /// + /// List of + /// public List MemoryList { get; private set; } = new List(); + + /// + /// List of + /// public List MonitorList { get; private set; } = new List(); + + /// + /// List of + /// public List MotherboardList { get; private set; } = new List(); + + /// + /// List of + /// public List MouseList { get; private set; } = new List(); + + /// + /// List of + /// public List NetworkAdapterList { get; private set; } = new List(); + + /// + /// List of + /// public List PrinterList { get; private set; } = new List(); + + /// + /// List of + /// public List SoundDeviceList { get; private set; } = new List(); + + /// + /// List of + /// public List VideoControllerList { get; private set; } = new List(); private readonly IHardwareInfoRetrieval _hardwareInfoRetrieval = null!; + /// + /// Main Hardware.Info class + /// + /// causes WMI queries to use SELECT * FROM instead of SELECT with a list of property names + /// sets the Timeout property of the EnumerationOptions in the ManagementObjectSearcher that executes the query. The default value is EnumerationOptions.InfiniteTimeout public HardwareInfo(bool useAsteriskInWMI = true, TimeSpan? timeoutInWMI = null) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // Environment.OSVersion.Platform == PlatformID.Win32NT) @@ -47,6 +118,9 @@ public HardwareInfo(bool useAsteriskInWMI = true, TimeSpan? timeoutInWMI = null) } } + /// + /// Refresh all hardware info + /// public void RefreshAll() { RefreshOperatingSystem(); @@ -54,6 +128,7 @@ public void RefreshAll() RefreshBatteryList(); RefreshBIOSList(); + RefreshComputerSystemList(); RefreshCPUList(); RefreshDriveList(); RefreshKeyboardList(); @@ -67,21 +142,89 @@ public void RefreshAll() RefreshVideoControllerList(); } + /// + /// Refresh operating system info + /// public void RefreshOperatingSystem() => OperatingSystem = _hardwareInfoRetrieval.GetOperatingSystem(); + + /// + /// Refresh memory status info + /// public void RefreshMemoryStatus() => MemoryStatus = _hardwareInfoRetrieval.GetMemoryStatus(); + /// + /// Refresh battery info + /// public void RefreshBatteryList() => BatteryList = _hardwareInfoRetrieval.GetBatteryList(); + + /// + /// Refresh BIOS info + /// public void RefreshBIOSList() => BiosList = _hardwareInfoRetrieval.GetBiosList(); - public void RefreshCPUList(bool includePercentProcessorTime = true) => CpuList = _hardwareInfoRetrieval.GetCpuList(includePercentProcessorTime); + + /// + /// Refresh computer system info + /// + public void RefreshComputerSystemList() => ComputerSystemList = _hardwareInfoRetrieval.GetComputerSystemList(); + + /// + /// Refresh CPU info + /// + /// Include PercentProcessorTime info. This makes the method a bit slower. + /// Delay in milliseconds between two measurements in Linux + public void RefreshCPUList(bool includePercentProcessorTime = true, int millisecondsDelayBetweenTwoMeasurements = 500) => CpuList = _hardwareInfoRetrieval.GetCpuList(includePercentProcessorTime, millisecondsDelayBetweenTwoMeasurements); + + /// + /// Refresh drive info + /// public void RefreshDriveList() => DriveList = _hardwareInfoRetrieval.GetDriveList(); + + /// + /// Refresh keyboard info + /// public void RefreshKeyboardList() => KeyboardList = _hardwareInfoRetrieval.GetKeyboardList(); + + /// + /// Refresh memory info + /// public void RefreshMemoryList() => MemoryList = _hardwareInfoRetrieval.GetMemoryList(); + + /// + /// Refresh monitor info + /// public void RefreshMonitorList() => MonitorList = _hardwareInfoRetrieval.GetMonitorList(); + + /// + /// Refresh motherboard info + /// public void RefreshMotherboardList() => MotherboardList = _hardwareInfoRetrieval.GetMotherboardList(); + + /// + /// Refresh mouse info + /// public void RefreshMouseList() => MouseList = _hardwareInfoRetrieval.GetMouseList(); - public void RefreshNetworkAdapterList(bool includeBytesPerSec = true, bool includeNetworkAdapterConfiguration = true) => NetworkAdapterList = _hardwareInfoRetrieval.GetNetworkAdapterList(includeBytesPerSec, includeNetworkAdapterConfiguration); + + /// + /// Refresh network adapter info + /// + /// Include BytesPerSec info. This makes the method a bit slower. + /// Include NetworkAdapterConfiguration info. This makes the method a bit slower. + /// Delay in milliseconds between two measurements in Linux + public void RefreshNetworkAdapterList(bool includeBytesPerSec = true, bool includeNetworkAdapterConfiguration = true, int millisecondsDelayBetweenTwoMeasurements = 1000) => NetworkAdapterList = _hardwareInfoRetrieval.GetNetworkAdapterList(includeBytesPerSec, includeNetworkAdapterConfiguration, millisecondsDelayBetweenTwoMeasurements); + + /// + /// Refresh printer info + /// public void RefreshPrinterList() => PrinterList = _hardwareInfoRetrieval.GetPrinterList(); + + /// + /// Refresh sound device info + /// public void RefreshSoundDeviceList() => SoundDeviceList = _hardwareInfoRetrieval.GetSoundDeviceList(); + + /// + /// Refresh video controller info + /// public void RefreshVideoControllerList() => VideoControllerList = _hardwareInfoRetrieval.GetVideoControllerList(); #region Static @@ -89,6 +232,11 @@ public void RefreshAll() private static bool _pingInProgress; private static Action? _onPingComplete; + /// + /// Ping + /// + /// Host name or address to ping + /// On ping complete callback with "bool success" parameter public static void Ping(string hostNameOrAddress, Action onPingComplete) { if (_pingInProgress) @@ -132,6 +280,10 @@ private static void PingCompleted(object sender, PingCompletedEventArgs e) _onPingComplete?.Invoke(success); } + /// + /// Get local IPv4 addresses + /// + /// Local IPv4 addresses public static IEnumerable GetLocalIPv4Addresses() { if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) @@ -147,6 +299,11 @@ public static IEnumerable GetLocalIPv4Addresses() } } + /// + /// Get local IPv4 addresses + /// + /// Filter by NetworkInterfaceType + /// Local IPv4 addresses public static IEnumerable GetLocalIPv4Addresses(NetworkInterfaceType networkInterfaceType) { return NetworkInterface.GetAllNetworkInterfaces() @@ -156,6 +313,11 @@ public static IEnumerable GetLocalIPv4Addresses(NetworkInterfaceType .Select(addressInformation => addressInformation.Address); } + /// + /// Get local IPv4 addresses + /// + /// Filter by OperationalStatus + /// Local IPv4 addresses public static IEnumerable GetLocalIPv4Addresses(OperationalStatus operationalStatus) { return NetworkInterface.GetAllNetworkInterfaces() @@ -165,6 +327,12 @@ public static IEnumerable GetLocalIPv4Addresses(OperationalStatus ope .Select(addressInformation => addressInformation.Address); } + /// + /// Get local IPv4 addresses + /// + /// Filter by NetworkInterfaceType + /// Filter by OperationalStatus + /// Local IPv4 addresses public static IEnumerable GetLocalIPv4Addresses(NetworkInterfaceType networkInterfaceType, OperationalStatus operationalStatus) { return NetworkInterface.GetAllNetworkInterfaces() diff --git a/Hardware.Info/HardwareInfo.snk b/Hardware.Info/HardwareInfo.snk new file mode 100644 index 0000000..23136f9 Binary files /dev/null and b/Hardware.Info/HardwareInfo.snk differ diff --git a/Hardware.Info/HardwareInfoBase.cs b/Hardware.Info/HardwareInfoBase.cs index e0b6c16..cef9ed7 100644 --- a/Hardware.Info/HardwareInfoBase.cs +++ b/Hardware.Info/HardwareInfoBase.cs @@ -89,18 +89,24 @@ public virtual List GetDriveList() foreach (DriveInfo driveInfo in DriveInfo.GetDrives()) { - Volume volume = new Volume + try { - FileSystem = driveInfo.DriveFormat, - Description = driveInfo.DriveType.ToString(), - Name = driveInfo.Name, - Caption = driveInfo.RootDirectory.FullName, - FreeSpace = (ulong)driveInfo.TotalFreeSpace, - Size = (ulong)driveInfo.TotalSize, - VolumeName = driveInfo.VolumeLabel - }; - - partition.VolumeList.Add(volume); + Volume volume = new Volume + { + FileSystem = driveInfo.DriveFormat, + Description = driveInfo.DriveType.ToString(), + Name = driveInfo.Name, + Caption = driveInfo.RootDirectory.FullName, + FreeSpace = (ulong)driveInfo.TotalFreeSpace, + Size = (ulong)driveInfo.TotalSize, + VolumeName = driveInfo.VolumeLabel + }; + + partition.VolumeList.Add(volume); + } + catch (UnauthorizedAccessException) + { + } } drive.PartitionList.Add(partition); @@ -110,7 +116,7 @@ public virtual List GetDriveList() return driveList; } - public virtual List GetNetworkAdapterList(bool includeBytesPersec = true, bool includeNetworkAdapterConfiguration = true) + public virtual List GetNetworkAdapterList(bool includeBytesPersec = true, bool includeNetworkAdapterConfiguration = true, int millisecondsDelayBetweenTwoMeasurements = 1000) { List networkAdapterList = new List(); diff --git a/Hardware.Info/IHardwareInfo.cs b/Hardware.Info/IHardwareInfo.cs index cba9470..7084551 100644 --- a/Hardware.Info/IHardwareInfo.cs +++ b/Hardware.Info/IHardwareInfo.cs @@ -2,42 +2,179 @@ namespace Hardware.Info { + /// + /// Main Hardware.Info interface + /// public interface IHardwareInfo { + /// + /// Operating system + /// OS OperatingSystem { get; } + + /// + /// Memory status + /// MemoryStatus MemoryStatus { get; } + /// + /// List of + /// List BatteryList { get; } + + /// + /// List of + /// List BiosList { get; } + + /// + /// List of + /// + List ComputerSystemList { get; } + + /// + /// List of + /// List CpuList { get; } + + /// + /// List of + /// List DriveList { get; } + + /// + /// List of + /// List KeyboardList { get; } + + /// + /// List of + /// List MemoryList { get; } + + /// + /// List of + /// List MonitorList { get; } + + /// + /// List of + /// List MotherboardList { get; } + + /// + /// List of + /// List MouseList { get; } + + /// + /// List of + /// List NetworkAdapterList { get; } + + /// + /// List of + /// List PrinterList { get; } + + /// + /// List of + /// List SoundDeviceList { get; } + + /// + /// List of + /// List VideoControllerList { get; } + /// + /// Refresh all hardware info + /// void RefreshAll(); + /// + /// Refresh operating system info + /// void RefreshOperatingSystem(); + + /// + /// Refresh memory status info + /// void RefreshMemoryStatus(); + /// + /// Refresh battery info + /// void RefreshBatteryList(); + + /// + /// Refresh BIOS info + /// void RefreshBIOSList(); - void RefreshCPUList(bool includePercentProcessorTime = true); + + /// + /// Refresh computer system info + /// + void RefreshComputerSystemList(); + + /// + /// Refresh CPU info + /// + /// Include PercentProcessorTime info. This makes the method a bit slower. + /// Delay in milliseconds between two measurements in Linux + void RefreshCPUList(bool includePercentProcessorTime = true, int millisecondsDelayBetweenTwoMeasurements = 500); + + /// + /// Refresh drive info + /// void RefreshDriveList(); + + /// + /// Refresh keyboard info + /// void RefreshKeyboardList(); + + /// + /// Refresh memory info + /// void RefreshMemoryList(); + + /// + /// Refresh monitor info + /// void RefreshMonitorList(); + + /// + /// Refresh motherboard info + /// void RefreshMotherboardList(); + + /// + /// Refresh mouse info + /// void RefreshMouseList(); - void RefreshNetworkAdapterList(bool includeBytesPerSec = true, bool includeNetworkAdapterConfiguration = true); + + /// + /// Refresh network adapter info + /// + /// Include BytesPerSec info. This makes the method a bit slower. + /// Include NetworkAdapterConfiguration info. This makes the method a bit slower. + /// Delay in milliseconds between two measurements in Linux + void RefreshNetworkAdapterList(bool includeBytesPerSec = true, bool includeNetworkAdapterConfiguration = true, int millisecondsDelayBetweenTwoMeasurements = 1000); + + /// + /// Refresh printer info + /// void RefreshPrinterList(); + + /// + /// Refresh sound device info + /// void RefreshSoundDeviceList(); + + /// + /// Refresh video controller info + /// void RefreshVideoControllerList(); } } \ No newline at end of file diff --git a/Hardware.Info/IHardwareInfoRetrieval.cs b/Hardware.Info/IHardwareInfoRetrieval.cs index b71e604..2d2c8cd 100644 --- a/Hardware.Info/IHardwareInfoRetrieval.cs +++ b/Hardware.Info/IHardwareInfoRetrieval.cs @@ -9,14 +9,15 @@ internal interface IHardwareInfoRetrieval List GetBatteryList(); List GetBiosList(); - List GetCpuList(bool includePercentProcessorTime = true); + List GetComputerSystemList(); + List GetCpuList(bool includePercentProcessorTime = true, int millisecondsDelayBetweenTwoMeasurements = 500); List GetDriveList(); List GetKeyboardList(); List GetMemoryList(); List GetMonitorList(); List GetMotherboardList(); List GetMouseList(); - List GetNetworkAdapterList(bool includeBytesPersec = true, bool includeNetworkAdapterConfiguration = true); + List GetNetworkAdapterList(bool includeBytesPersec = true, bool includeNetworkAdapterConfiguration = true, int millisecondsDelayBetweenTwoMeasurements = 1000); List GetPrinterList(); List GetSoundDeviceList(); List GetVideoControllerList(); diff --git a/Hardware.Info/Linux/HardwareInfoRetrieval.cs b/Hardware.Info/Linux/HardwareInfoRetrieval.cs index 5067e5f..6d81935 100644 --- a/Hardware.Info/Linux/HardwareInfoRetrieval.cs +++ b/Hardware.Info/Linux/HardwareInfoRetrieval.cs @@ -1,13 +1,12 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; -using System.Net.NetworkInformation; using System.Net; +using System.Net.NetworkInformation; using System.Text.RegularExpressions; using System.Threading.Tasks; -using System.Globalization; -using System.Net.Sockets; // https://www.binarytides.com/linux-commands-hardware-info/ @@ -146,34 +145,99 @@ public List GetBiosList() return biosList; } - public List GetCpuList(bool includePercentProcessorTime = true) + public List GetComputerSystemList() { - List cpuList = new List(); + List computerSystemList = new List(); + + ComputerSystem computerSystem = new ComputerSystem + { + Caption = TryReadTextFromFile("/sys/class/dmi/id/product_name"), + Description = TryReadTextFromFile("/sys/class/dmi/id/product_family"), + IdentifyingNumber = TryReadTextFromFile("/sys/class/dmi/id/product_serial"), + Name = TryReadTextFromFile("/sys/class/dmi/id/product_name"), + SKUNumber = TryReadTextFromFile("/sys/class/dmi/id/product_sku"), + UUID = TryReadTextFromFile("/sys/class/dmi/id/product_uuid"), + Vendor = TryReadTextFromFile("/sys/class/dmi/id/sys_vendor"), + Version = TryReadTextFromFile("/sys/class/dmi/id/product_version") + }; + computerSystemList.Add(computerSystem); + + return computerSystemList; + } + + private class Processor + { + public string ProcessorId = string.Empty; + public string VendorId = string.Empty; + public string ModelName = string.Empty; + public uint CpuMhz; + public uint CacheSize; + public uint PhysicalId; + public uint Siblings; + public uint CoreId; + public uint CpuCores; + + public uint L1DataCacheSize; + public uint L1InstructionCacheSize; + public uint L2CacheSize; + public uint L3CacheSize; + + public ulong PercentProcessorTime; + } + + public List GetCpuList(bool includePercentProcessorTime = true, int millisecondsDelayBetweenTwoMeasurements = 500) + { string[] lines = TryReadLinesFromFile("/proc/cpuinfo"); + Regex processorRegex = new Regex(@"^processor\s+:\s+(\d+)"); // processor ID (from 0 to 7 in a PC with two quad core CPUs) Regex vendorIdRegex = new Regex(@"^vendor_id\s+:\s+(.+)"); Regex modelNameRegex = new Regex(@"^model name\s+:\s+(.+)"); Regex cpuSpeedRegex = new Regex(@"^cpu MHz\s+:\s+(.+)"); - Regex cacheSizeRegex = new Regex(@"^cache size\s+:\s+(.+)\s+KB"); - Regex physicalCoresRegex = new Regex(@"^cpu cores\s+:\s+(.+)"); - Regex logicalCoresRegex = new Regex(@"^siblings\s+:\s+(.+)"); + Regex cacheSizeRegex = new Regex(@"^cache size\s+:\s+(.+)\s+KB"); // L2 cache size in KB + Regex physicalIdRegex = new Regex(@"^physical id\s+:\s+(\d+)"); // physical CPU ID (a PC with two quad core CPUs, 4 cores will have one value, and the other 4 will have another value) + Regex logicalCoresRegex = new Regex(@"^siblings\s+:\s+(.+)"); // number of logical cores (no hyperthreading = same as physical, with hyperthreading = 2 * physical) + Regex coreIdRegex = new Regex(@"^core id\s+:\s+(.+)"); // core ID (from 0 to 3 in a PC with two quad core CPUs - for the first CPU, and then the same for second CPU) + Regex physicalCoresRegex = new Regex(@"^cpu cores\s+:\s+(.+)"); // number of cores (in a quad core CPU = 4) - CPU cpu = new CPU(); + List processorList = new List(); + + Processor processor = null!; foreach (string line in lines) { - Match match = vendorIdRegex.Match(line); + Match match = processorRegex.Match(line); + if (match.Success && match.Groups.Count > 1) + { + processor = new Processor(); + + if (uint.TryParse(match.Groups[1].Value, out uint processorId)) + { + processor.ProcessorId = $"cpu{processorId}"; + + GetCpuCacheSize(processor); + + processorList.Add(processor); + } + continue; + } + + if (processor == null) + { + continue; + } + + match = vendorIdRegex.Match(line); if (match.Success && match.Groups.Count > 1) { - cpu.Manufacturer = match.Groups[1].Value.Trim(); + processor.VendorId = match.Groups[1].Value.Trim(); continue; } match = modelNameRegex.Match(line); if (match.Success && match.Groups.Count > 1) { - cpu.Name = match.Groups[1].Value.Trim(); + processor.ModelName = match.Groups[1].Value.Trim(); continue; } @@ -181,7 +245,7 @@ public List GetCpuList(bool includePercentProcessorTime = true) if (match.Success && match.Groups.Count > 1) { if (double.TryParse(match.Groups[1].Value, out double currentClockSpeed)) - cpu.CurrentClockSpeed = (uint)currentClockSpeed; + processor.CpuMhz = (uint)currentClockSpeed; continue; } @@ -189,15 +253,15 @@ public List GetCpuList(bool includePercentProcessorTime = true) if (match.Success && match.Groups.Count > 1) { if (uint.TryParse(match.Groups[1].Value, out uint cacheSize)) - cpu.L3CacheSize = 1024 * cacheSize; + processor.CacheSize = 1024 * cacheSize; continue; } - match = physicalCoresRegex.Match(line); + match = physicalIdRegex.Match(line); if (match.Success && match.Groups.Count > 1) { - if (uint.TryParse(match.Groups[1].Value, out uint numberOfCores)) - cpu.NumberOfCores = numberOfCores; + if (uint.TryParse(match.Groups[1].Value, out uint physicalId)) + processor.PhysicalId = physicalId; continue; } @@ -205,16 +269,82 @@ public List GetCpuList(bool includePercentProcessorTime = true) if (match.Success && match.Groups.Count > 1) { if (uint.TryParse(match.Groups[1].Value, out uint numberOfLogicalProcessors)) - cpu.NumberOfLogicalProcessors = numberOfLogicalProcessors; + processor.Siblings = numberOfLogicalProcessors; + continue; + } + + match = coreIdRegex.Match(line); + if (match.Success && match.Groups.Count > 1) + { + if (uint.TryParse(match.Groups[1].Value, out uint coreId)) + processor.CoreId = coreId; + continue; + } + + match = physicalCoresRegex.Match(line); + if (match.Success && match.Groups.Count > 1) + { + if (uint.TryParse(match.Groups[1].Value, out uint numberOfCores)) + processor.CpuCores = numberOfCores; continue; } } + ulong percentProcessorTime = 0; + + if (includePercentProcessorTime) + { + percentProcessorTime = GetCpuUsage(processorList, millisecondsDelayBetweenTwoMeasurements); + } + + List cpuList = new List(); + + foreach (var group in processorList.GroupBy(processor => processor.PhysicalId)) + { + Processor first = group.First(); + + CPU cpu = new CPU + { + PercentProcessorTime = percentProcessorTime, + ProcessorId = group.Key.ToString(), + Manufacturer = first.VendorId, + Name = first.ModelName, + CurrentClockSpeed = first.CpuMhz, + NumberOfLogicalProcessors = first.Siblings, + NumberOfCores = first.CpuCores, + L1DataCacheSize = first.L1DataCacheSize, + L1InstructionCacheSize = first.L1InstructionCacheSize, + L2CacheSize = first.L2CacheSize, + L3CacheSize = first.L3CacheSize + }; + + if (cpu.L2CacheSize == 0) + cpu.L2CacheSize = first.CacheSize; + + foreach (Processor proc in group) + { + CpuCore core = new CpuCore + { + Name = proc.ProcessorId, + PercentProcessorTime = proc.PercentProcessorTime + }; + + cpu.CpuCoreList.Add(core); + } + + cpuList.Add(cpu); + } + + return cpuList; + } + + private static void GetCpuCacheSize(Processor processor) + { for (int i = 0; i <= 3; i++) { - string level = TryReadTextFromFile($"/sys/devices/system/cpu/cpu0/cache/index{i}/level"); - string type = TryReadTextFromFile($"/sys/devices/system/cpu/cpu0/cache/index{i}/type"); - string size = TryReadTextFromFile($"/sys/devices/system/cpu/cpu0/cache/index{i}/size"); + string level = TryReadTextFromFile($"/sys/devices/system/cpu/{processor.ProcessorId}/cache/index{i}/level"); + string type = TryReadTextFromFile($"/sys/devices/system/cpu/{processor.ProcessorId}/cache/index{i}/type"); + string size = TryReadTextFromFile($"/sys/devices/system/cpu/{processor.ProcessorId}/cache/index{i}/size"); if (uint.TryParse(size.TrimEnd('K'), out uint cacheSize)) { @@ -223,31 +353,22 @@ public List GetCpuList(bool includePercentProcessorTime = true) if (level == "1") { if (type == "Data") - cpu.L1DataCacheSize = cacheSize; + processor.L1DataCacheSize = cacheSize; if (type == "Instruction") - cpu.L1InstructionCacheSize = cacheSize; + processor.L1InstructionCacheSize = cacheSize; } if (level == "2") - cpu.L2CacheSize = cacheSize; + processor.L2CacheSize = cacheSize; if (level == "3") - cpu.L3CacheSize = cacheSize; + processor.L3CacheSize = cacheSize; } } - - if (includePercentProcessorTime) - { - GetCpuUsage(cpu); - } - - cpuList.Add(cpu); - - return cpuList; } - private static void GetCpuUsage(CPU cpu) + private static ulong GetCpuUsage(List processorList, int millisecondsDelayBetweenTwoMeasurements) { // Column Name Description // 1 user Time spent with normal processing in user mode. @@ -268,30 +389,28 @@ private static void GetCpuUsage(CPU cpu) // ... string[] cpuUsageLineLast = TryReadLinesFromFile("/proc/stat"); - Task.Delay(500).Wait(); + Task.Delay(millisecondsDelayBetweenTwoMeasurements).Wait(); string[] cpuUsageLineNow = TryReadLinesFromFile("/proc/stat"); + ulong percentProcessorTime = 0; + if (cpuUsageLineLast.Length > 0 && cpuUsageLineNow.Length > 0) { - cpu.PercentProcessorTime = GetCpuPercentage(cpuUsageLineLast[0], cpuUsageLineNow[0]); + percentProcessorTime = GetCpuPercentage(cpuUsageLineLast[0], cpuUsageLineNow[0]); - for (int i = 0; i < cpu.NumberOfLogicalProcessors; i++) + foreach (Processor processor in processorList) { - string? cpuStatLast = cpuUsageLineLast.FirstOrDefault(s => s.StartsWith($"cpu{i}")); - string? cpuStatNow = cpuUsageLineNow.FirstOrDefault(s => s.StartsWith($"cpu{i}")); + string? cpuStatLast = cpuUsageLineLast.FirstOrDefault(s => s.StartsWith(processor.ProcessorId)); + string? cpuStatNow = cpuUsageLineNow.FirstOrDefault(s => s.StartsWith(processor.ProcessorId)); if (!string.IsNullOrEmpty(cpuStatLast) && !string.IsNullOrEmpty(cpuStatNow)) { - CpuCore core = new CpuCore - { - Name = i.ToString(), - PercentProcessorTime = GetCpuPercentage(cpuStatLast, cpuStatNow) - }; - - cpu.CpuCoreList.Add(core); + processor.PercentProcessorTime = GetCpuPercentage(cpuStatLast, cpuStatNow); } } } + + return percentProcessorTime; } private static UInt64 GetCpuPercentage(string cpuStatLast, string cpuStatNow) @@ -325,6 +444,11 @@ private static UInt64 GetCpuPercentage(string cpuStatLast, string cpuStatNow) // Get the delta between two reads ulong cpuDelta = cpuSumNow - cpuSumLast; + if (cpuDelta == 0) + { + return 0; // avoid System.DivideByZeroException: Attempted to divide by zero. + } + // Get the idle time Delta ulong cpuIdle = 0; @@ -344,7 +468,7 @@ private static UInt64 GetCpuPercentage(string cpuStatLast, string cpuStatNow) public override List GetDriveList() { - List driveList = new List(); + List driveList = base.GetDriveList(); string processOutput = ReadProcessOutput("lshw", "-class disk"); @@ -356,19 +480,18 @@ public override List GetDriveList() { string trimmed = line.Trim(); - if (trimmed.StartsWith("*-")) + if (trimmed.StartsWith("*-cdrom") || trimmed.StartsWith("*-disk")) { - if (disk != null) + if(driveList.Count > 0 && disk == null && trimmed.StartsWith("*-disk")) { + disk = driveList.First(); + } + else + { + disk = new Drive(); driveList.Add(disk); } - disk = null; - } - - if (trimmed.StartsWith("*-cdrom") || trimmed.StartsWith("*-disk")) - { - disk = new Drive(); continue; } @@ -382,15 +505,54 @@ public override List GetDriveList() { disk.Manufacturer = trimmed.Replace("vendor:", string.Empty).Trim(); } + else if (trimmed.StartsWith("description:")) + { + disk.Description = trimmed.Replace("description:", string.Empty).Trim(); + } + else if (trimmed.StartsWith("version:")) + { + disk.FirmwareRevision = trimmed.Replace("version:", string.Empty).Trim(); + } + else if (trimmed.StartsWith("logical name:")) + { + disk.Name = trimmed.Replace("logical name:", string.Empty).Trim(); + } + else if (trimmed.StartsWith("serial:")) + { + disk.SerialNumber = trimmed.Replace("serial:", string.Empty).Trim(); + } + else if (trimmed.StartsWith("size:")) + { + string size = trimmed.Replace("size:", string.Empty).Trim(); + disk.Size = ExtractSizeInBytes(size); + } } } - if (disk != null) + return driveList; + + static ulong ExtractSizeInBytes(string input) { - driveList.Add(disk); - } + Regex regex = new Regex(@"(\d+)\s*(KB|MB|GB|TB)"); + Match match = regex.Match(input); - return driveList; + if (match.Success) + { + if (ulong.TryParse(match.Groups[1].Value, out ulong size)) + { + return match.Groups[2].Value switch + { + "KB" => size * 1024UL, + "MB" => size * 1024UL * 1024UL, + "GB" => size * 1024UL * 1024UL * 1024UL, + "TB" => size * 1024UL * 1024UL * 1024UL * 1024UL, + _ => size, + }; + } + } + + return 0; + } } public List GetKeyboardList() @@ -660,7 +822,7 @@ private List GetNetworkAdapters() Caption = interfaceName, Description = interfaceName, Name = interfaceName, - MACAddress = macAddress, + MACAddress = macAddress.Replace(":", "").ToUpper(), NetConnectionID = interfaceName, ProductName = interfaceName, }; @@ -753,25 +915,16 @@ private bool TryGetInterfaceIp(string[] fibTrieLines, string network, out string return foundIp; } - public override List GetNetworkAdapterList(bool includeBytesPersec = true, bool includeNetworkAdapterConfiguration = true) + public override List GetNetworkAdapterList(bool includeBytesPersec = true, bool includeNetworkAdapterConfiguration = true, int millisecondsDelayBetweenTwoMeasurements = 1000) { - List networkAdapterList; - - try - { - networkAdapterList = base.GetNetworkAdapterList(includeBytesPersec, includeNetworkAdapterConfiguration); - } - catch (NetworkInformationException) - { - networkAdapterList = GetNetworkAdapters(); - } + List networkAdapterList = GetNetworkAdapters(); if (includeBytesPersec) { char[] charSeparators = new char[] { ' ' }; string[] procNetDevLast = TryReadLinesFromFile("/proc/net/dev"); - Task.Delay(1000).Wait(); + Task.Delay(millisecondsDelayBetweenTwoMeasurements).Wait(); string[] procNetDevNow = TryReadLinesFromFile("/proc/net/dev"); foreach (NetworkAdapter networkAdapter in networkAdapterList) @@ -1025,7 +1178,7 @@ 1680x1050 59.88 lines = processOutput.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); - foreach (string line in lines.Where(l => l.Contains("VGA compatible controller"))) + foreach (string line in lines.Where(l => l.Contains("VGA compatible controller") || l.Contains("3D controller") || l.Contains("Display controller"))) { string[] split = line.Split(':'); diff --git a/Hardware.Info/Mac/HardwareInfoRetrieval.cs b/Hardware.Info/Mac/HardwareInfoRetrieval.cs index 0e38500..ff24c63 100644 --- a/Hardware.Info/Mac/HardwareInfoRetrieval.cs +++ b/Hardware.Info/Mac/HardwareInfoRetrieval.cs @@ -326,6 +326,73 @@ public List GetBiosList() return biosList; } + /* + system_profiler SPHardwareDataType +Hardware: + + Hardware Overview: + + Model Name: Mac mini + Model Identifier: Macmini9,1 + Model Number: MGNR3ZE/A + Chip: Apple M1 + Total Number of Cores: 8 (4 performance and 4 efficiency) + Memory: 8 GB + System Firmware Version: 10151.140.19 + OS Loader Version: 10151.140.19 + Serial Number (system): C07JG1XTQ6NV + Hardware UUID: A7C8F6C7-C339-5904-B220-CF4C3D22FB1B + Provisioning UDID: 00008103-001965521E60801E + Activation Lock Status: Enabled + */ + + public List GetComputerSystemList() + { + List computerSystemList = new List(); + + ComputerSystem computerSystem = new ComputerSystem + { + Vendor = "Apple" + }; + + StartProcess("system_profiler", "SPHardwareDataType", + standardOutput => + { + string line = standardOutput.Trim(); + + if (line.StartsWith("Model Name: ")) + { + computerSystem.Caption = line.Replace("Model Name: ", string.Empty); + computerSystem.Name = line.Replace("Model Name: ", string.Empty); + } + else if (line.StartsWith("Model Identifier: ")) + { + computerSystem.Description = line.Replace("Model Identifier: ", string.Empty); + } + else if (line.StartsWith("Serial Number (system): ")) + { + computerSystem.IdentifyingNumber = line.Replace("Serial Number (system): ", string.Empty); + } + else if (line.StartsWith("Model Number: ")) + { + computerSystem.SKUNumber = line.Replace("Model Number: ", string.Empty); + } + else if (line.StartsWith("Hardware UUID: ")) + { + computerSystem.UUID = line.Replace("Hardware UUID: ", string.Empty); + } + else if (line.StartsWith("System Firmware Version: ")) + { + computerSystem.Version = line.Replace("System Firmware Version: ", string.Empty); + } + }, + standardError => { }); + + computerSystemList.Add(computerSystem); + + return computerSystemList; + } + /* SPHardwareDataType Hardware: @@ -346,7 +413,7 @@ Serial Number (system): 0 Hardware UUID: F6D9C340-725A-224A-8855-99AB8348F745 /**/ - public List GetCpuList(bool includePercentProcessorTime = true) + public List GetCpuList(bool includePercentProcessorTime = true, int millisecondsDelayBetweenTwoMeasurements = 500) { List cpuList = new List(); @@ -420,7 +487,7 @@ public override List GetDriveList() VBOX HARDDISK: Capacity: 536,87 GB (536.870.912.000 bytes) - Model: VBOX HARDDISK + Model: VBOX HARDDISK Revision: 1,000000 Serial Number: VBa308df62-62a2d2a0 Native Command Queuing: Yes @@ -464,9 +531,9 @@ public override List GetDriveList() VBOX CD-ROM: - Model: VBOX CD-ROM + Model: VBOX CD-ROM Revision: 1,000000 - Serial Number: VB1-1a2b3c4d + Serial Number: VB1-1a2b3c4d Native Command Queuing: No Detachable Drive: No Power Off: No @@ -871,7 +938,7 @@ Extra Operating Current (mA): 0 return mouseList; } - public override List GetNetworkAdapterList(bool includeBytesPersec = true, bool includeNetworkAdapterConfiguration = true) + public override List GetNetworkAdapterList(bool includeBytesPersec = true, bool includeNetworkAdapterConfiguration = true, int millisecondsDelayBetweenTwoMeasurements = 1000) { /* SPNetworkDataType diff --git a/Hardware.Info/Windows/HardwareInfoRetrieval.cs b/Hardware.Info/Windows/HardwareInfoRetrieval.cs index 203ac7d..0668a3f 100644 --- a/Hardware.Info/Windows/HardwareInfoRetrieval.cs +++ b/Hardware.Info/Windows/HardwareInfoRetrieval.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Management; using System.Net; using System.Runtime.InteropServices; using System.Security; +using System.Text; // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexa @@ -42,6 +44,7 @@ internal class HardwareInfoRetrieval : HardwareInfoBase, IHardwareInfoRetrieval public bool UseAsteriskInWMI { get; set; } private readonly string _managementScope = "root\\cimv2"; + private readonly string _managementScopeWmi = "root\\wmi"; private readonly EnumerationOptions _enumerationOptions = new EnumerationOptions() { ReturnImmediately = true, Rewindable = false, Timeout = EnumerationOptions.InfiniteTimeout }; public HardwareInfoRetrieval(TimeSpan? enumerationOptionsTimeout = null) @@ -162,6 +165,26 @@ public static string GetPropertyString(object obj) return (obj is string str) ? str : string.Empty; } + public static string GetStringFromUInt16Array(ushort[] array) + { + try + { + if (array.Length == 0) + return string.Empty; + + byte[] byteArray = new byte[array.Length * 2]; + Buffer.BlockCopy(array, 0, byteArray, 0, byteArray.Length); + + string str = Encoding.Unicode.GetString(byteArray).Trim('\0'); + + return str; + } + catch + { + return string.Empty; + } + } + // https://docs.microsoft.com/en-us/dotnet/api/system.management.managementpath.defaultpath?view=netframework-4.8 public List GetBatteryList() @@ -221,7 +244,35 @@ public List GetBiosList() return biosList; } - public List GetCpuList(bool includePercentProcessorTime = true) + public List GetComputerSystemList() + { + List computerSystemList = new List(); + + string queryString = UseAsteriskInWMI ? "SELECT * FROM Win32_ComputerSystemProduct" + : "SELECT Caption, Description, IdentifyingNumber, Name, SKUNumber, UUID, Vendor, Version FROM Win32_ComputerSystemProduct"; + using ManagementObjectSearcher mos = new ManagementObjectSearcher(_managementScope, queryString, _enumerationOptions); + + foreach (ManagementBaseObject mo in mos.Get()) + { + ComputerSystem computerSystem = new ComputerSystem + { + Caption = GetPropertyString(mo["Caption"]), + Description = GetPropertyString(mo["Description"]), + IdentifyingNumber = GetPropertyString(mo["IdentifyingNumber"]), + Name = GetPropertyString(mo["Name"]), + SKUNumber = GetPropertyString(mo["SKUNumber"]), + UUID = GetPropertyString(mo["UUID"]), + Vendor = GetPropertyString(mo["Vendor"]), + Version = GetPropertyString(mo["Version"]) + }; + + computerSystemList.Add(computerSystem); + } + + return computerSystemList; + } + + public List GetCpuList(bool includePercentProcessorTime = true, int millisecondsDelayBetweenTwoMeasurements = 500) { List cpuList = new List(); @@ -511,22 +562,47 @@ public List GetMonitorList() { List monitorList = new List(); - string queryString = UseAsteriskInWMI ? "SELECT * FROM Win32_DesktopMonitor WHERE PNPDeviceID IS NOT NULL" - : "SELECT Caption, Description, MonitorManufacturer, MonitorType, Name, PixelsPerXLogicalInch, PixelsPerYLogicalInch FROM Win32_DesktopMonitor WHERE PNPDeviceID IS NOT NULL"; - using ManagementObjectSearcher mos = new ManagementObjectSearcher(_managementScope, queryString, _enumerationOptions); + string win32PnpEntityQuery = UseAsteriskInWMI ? "SELECT * FROM Win32_PnPEntity WHERE PNPClass='Monitor'" + : "SELECT DeviceId FROM Win32_PnPEntity WHERE PNPClass='Monitor'"; + using ManagementObjectSearcher win32PnpEntityMos = new ManagementObjectSearcher(_managementScope, win32PnpEntityQuery, _enumerationOptions); - foreach (ManagementBaseObject mo in mos.Get()) + foreach (ManagementBaseObject win32PnpEntityMo in win32PnpEntityMos.Get()) { - Monitor monitor = new Monitor + string deviceId = GetPropertyString(win32PnpEntityMo["DeviceId"]); + string win32DesktopMonitorQuery = UseAsteriskInWMI ? $"SELECT * FROM Win32_DesktopMonitor WHERE PNPDeviceId='{deviceId}'" + : $"SELECT Caption, Description, MonitorManufacturer, MonitorType, Name, PixelsPerXLogicalInch, PixelsPerYLogicalInch FROM Win32_DesktopMonitor WHERE PNPDeviceId='{deviceId}'"; + using ManagementObjectSearcher win32DesktopMonitorMos = new ManagementObjectSearcher(_managementScope, win32DesktopMonitorQuery.Replace(@"\", @"\\"), _enumerationOptions); + + string wmiMonitorIdQuery = UseAsteriskInWMI ? $"SELECT * FROM WmiMonitorID WHERE InstanceName LIKE '{deviceId}%'" + : $"SELECT Active, ProductCodeID, SerialNumberID, ManufacturerName, UserFriendlyName, WeekOfManufacture, YearOfManufacture FROM WmiMonitorID WHERE InstanceName LIKE '{deviceId}%'"; + using ManagementObjectSearcher wmiMonitorIdMos = new ManagementObjectSearcher(_managementScopeWmi, wmiMonitorIdQuery.Replace(@"\", "_"), _enumerationOptions); + + using ManagementBaseObject? desktopMonitorMo = win32DesktopMonitorMos.Get().Cast().FirstOrDefault(); + using ManagementBaseObject? wmiMonitorIdMo = wmiMonitorIdMos.Get().Cast().FirstOrDefault(); + + Monitor monitor = new Monitor(); + + if (desktopMonitorMo != null) { - Caption = GetPropertyString(mo["Caption"]), - Description = GetPropertyString(mo["Description"]), - MonitorManufacturer = GetPropertyString(mo["MonitorManufacturer"]), - MonitorType = GetPropertyString(mo["MonitorType"]), - Name = GetPropertyString(mo["Name"]), - PixelsPerXLogicalInch = GetPropertyValue(mo["PixelsPerXLogicalInch"]), - PixelsPerYLogicalInch = GetPropertyValue(mo["PixelsPerYLogicalInch"]) - }; + monitor.Caption = GetPropertyString(desktopMonitorMo["Caption"]); + monitor.Description = GetPropertyString(desktopMonitorMo["Description"]); + monitor.MonitorManufacturer = GetPropertyString(desktopMonitorMo["MonitorManufacturer"]); + monitor.MonitorType = GetPropertyString(desktopMonitorMo["MonitorType"]); + monitor.Name = GetPropertyString(desktopMonitorMo["Name"]); + monitor.PixelsPerXLogicalInch = GetPropertyValue(desktopMonitorMo["PixelsPerXLogicalInch"]); + monitor.PixelsPerYLogicalInch = GetPropertyValue(desktopMonitorMo["PixelsPerYLogicalInch"]); + } + + if (wmiMonitorIdMo != null) + { + monitor.Active = GetPropertyValue(wmiMonitorIdMo["Active"]); + monitor.ProductCodeID = GetStringFromUInt16Array(GetPropertyArray(wmiMonitorIdMo["ProductCodeID"])); + monitor.UserFriendlyName = GetStringFromUInt16Array(GetPropertyArray(wmiMonitorIdMo["UserFriendlyName"])); + monitor.SerialNumberID = GetStringFromUInt16Array(GetPropertyArray(wmiMonitorIdMo["SerialNumberID"])); + monitor.ManufacturerName = GetStringFromUInt16Array(GetPropertyArray(wmiMonitorIdMo["ManufacturerName"])); + monitor.WeekOfManufacture = GetPropertyValue(wmiMonitorIdMo["WeekOfManufacture"]); + monitor.YearOfManufacture = GetPropertyValue(wmiMonitorIdMo["YearOfManufacture"]); + } monitorList.Add(monitor); } @@ -582,7 +658,7 @@ public List GetMouseList() return mouseList; } - public override List GetNetworkAdapterList(bool includeBytesPersec = true, bool includeNetworkAdapterConfiguration = true) + public override List GetNetworkAdapterList(bool includeBytesPersec = true, bool includeNetworkAdapterConfiguration = true, int millisecondsDelayBetweenTwoMeasurements = 1000) { List networkAdapterList = new List(); diff --git a/README.md b/README.md index 3f54b60..6c60f64 100644 --- a/README.md +++ b/README.md @@ -7,34 +7,44 @@ Battery, BIOS, CPU - processor, storage drive, keyboard, RAM - memory, monitor, 1. Include NuGet package from https://www.nuget.org/packages/Hardware.Info - + 2. Call `RefreshAll()` or one of the other `Refresh*()` methods: class Program { - static readonly IHardwareInfo hardwareInfo = new HardwareInfo(); + static IHardwareInfo hardwareInfo; static void Main(string[] _) { - //hardwareInfo.RefreshOperatingSystem(); - //hardwareInfo.RefreshMemoryStatus(); - //hardwareInfo.RefreshBatteryList(); - //hardwareInfo.RefreshBIOSList(); - //hardwareInfo.RefreshCPUList(); - //hardwareInfo.RefreshDriveList(); - //hardwareInfo.RefreshKeyboardList(); - //hardwareInfo.RefreshMemoryList(); - //hardwareInfo.RefreshMonitorList(); - //hardwareInfo.RefreshMotherboardList(); - //hardwareInfo.RefreshMouseList(); - //hardwareInfo.RefreshNetworkAdapterList(); - //hardwareInfo.RefreshPrinterList(); - //hardwareInfo.RefreshSoundDeviceList(); - //hardwareInfo.RefreshVideoControllerList(); - - hardwareInfo.RefreshAll(); + try + { + hardwareInfo = new HardwareInfo(); + + //hardwareInfo.RefreshOperatingSystem(); + //hardwareInfo.RefreshMemoryStatus(); + //hardwareInfo.RefreshBatteryList(); + //hardwareInfo.RefreshBIOSList(); + //hardwareInfo.RefreshComputerSystemList(); + //hardwareInfo.RefreshCPUList(); + //hardwareInfo.RefreshDriveList(); + //hardwareInfo.RefreshKeyboardList(); + //hardwareInfo.RefreshMemoryList(); + //hardwareInfo.RefreshMonitorList(); + //hardwareInfo.RefreshMotherboardList(); + //hardwareInfo.RefreshMouseList(); + //hardwareInfo.RefreshNetworkAdapterList(); + //hardwareInfo.RefreshPrinterList(); + //hardwareInfo.RefreshSoundDeviceList(); + //hardwareInfo.RefreshVideoControllerList(); + + hardwareInfo.RefreshAll(); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } Console.WriteLine(hardwareInfo.OperatingSystem); @@ -46,6 +56,9 @@ Battery, BIOS, CPU - processor, storage drive, keyboard, RAM - memory, monitor, foreach (var hardware in hardwareInfo.BiosList) Console.WriteLine(hardware); + foreach (var hardware in hardwareInfo.ComputerSystemList) + Console.WriteLine(hardware); + foreach (var cpu in hardwareInfo.CpuList) { Console.WriteLine(cpu); @@ -54,8 +67,6 @@ Battery, BIOS, CPU - processor, storage drive, keyboard, RAM - memory, monitor, Console.WriteLine(cpuCore); } - Console.ReadLine(); - foreach (var drive in hardwareInfo.DriveList) { Console.WriteLine(drive); @@ -69,8 +80,6 @@ Battery, BIOS, CPU - processor, storage drive, keyboard, RAM - memory, monitor, } } - Console.ReadLine(); - foreach (var hardware in hardwareInfo.KeyboardList) Console.WriteLine(hardware); @@ -98,8 +107,6 @@ Battery, BIOS, CPU - processor, storage drive, keyboard, RAM - memory, monitor, foreach (var hardware in hardwareInfo.VideoControllerList) Console.WriteLine(hardware); - Console.ReadLine(); - foreach (var address in HardwareInfo.GetLocalIPv4Addresses(NetworkInterfaceType.Ethernet, OperationalStatus.Up)) Console.WriteLine(address); @@ -136,6 +143,10 @@ You can avoid the 21 second delay by excluding the queries that cause it (see Se Sometimes `NetworkAdapter.Speed` in `Win32_NetworkAdapter` can be `0` or `long.MaxValue`. The correct value can be retrived from `CurrentBandwidth` in `Win32_PerfFormattedData_Tcpip_NetworkAdapter` but unfortunately reading from `Win32_PerfFormattedData_Tcpip_NetworkAdapter` causes a 21 second delay on the first read, like mentioned in the previous paragraph. Calling `RefreshNetworkAdapterList` with `includeBytesPersec = true` will also read the `CurrentBandwidth`. +### `WmiNetUtilsHelper` will throw an exception in Windows if publish settings use `true` + +This is a known error: https://github.com/dotnet/core/issues/7051#issuecomment-1071484354 + ## Settings ### Constructor settings: @@ -146,16 +157,32 @@ HardwareInfo(bool useAsteriskInWMI = true, TimeSpan? timeoutInWMI = null) The construcotr accepts two settings for WMI: - `useAsteriskInWMI` causes WMI queries to use `SELECT * FROM` instead of `SELECT` with a list of property names. This is slower, but safer, more compatible with older Windows (XP, Vista, 7, 8) where a certain WMI property might be missing and throw an exception when queried by name. The default value is `true`. -- `timeoutInWMI` sets the `Timeout` property of the `EnumerationOptions` in the `ManagementObjectSearcher` that executes the query. The default value is `EnumerationOptions.InfiniteTimeout`. Changing this could cause the query to return empty results in certain cases. +- `timeoutInWMI` sets the `Timeout` property of the `EnumerationOptions` in the `ManagementObjectSearcher` that executes each query. The default value is `EnumerationOptions.InfiniteTimeout`. There are one or more queries for each hardware component, so there are more than 16 queries executed on `RefreshAll()`. If a query reaches the timeout it will throw a `System.Management.ManagementException` exception where `ErrorCode` will be `System.Management.ManagementStatus.Timedout`. If you set the `timeoutInWMI` then use a `try-catch` block like this: -### Refresh methods settings: + IHardwareInfo hardwareInfo; -In these two methods you can exclude some slow queries by setting the parameters to `false`: + try + { + hardwareInfo = new HardwareInfo(timeoutInWMI: TimeSpan.FromMilliseconds(100)); -``` -RefreshCPUList(bool includePercentProcessorTime = true) + hardwareInfo.RefreshAll(); + } + catch (ManagementException ex) when (ex.ErrorCode == ManagementStatus.Timedout) + { + Console.WriteLine(ex); + } + +### Refresh methods settings: -RefreshNetworkAdapterList(bool includeBytesPersec = true, bool includeNetworkAdapterConfiguration = true) +``` +RefreshCPUList( + bool includePercentProcessorTime = true, + int millisecondsDelayBetweenTwoMeasurements = 500) + +RefreshNetworkAdapterList( + bool includeBytesPersec = true, + bool includeNetworkAdapterConfiguration = true, + int millisecondsDelayBetweenTwoMeasurements = 1000) ``` Setting `includePercentProcessorTime` and `includeBytesPersec` to `false` will exclude the queries that: @@ -164,6 +191,24 @@ Setting `includePercentProcessorTime` and `includeBytesPersec` to `false` will e Setting `includeNetworkAdapterConfiguration` to `false` has only a small impact on performance. +Delay in milliseconds between two measurements in Linux: + +For `PercentProcessorTime` in Linux: +``` +string[] cpuUsageLineLast = TryReadLinesFromFile("/proc/stat"); +Task.Delay(millisecondsDelayBetweenTwoMeasurements).Wait(); +string[] cpuUsageLineNow = TryReadLinesFromFile("/proc/stat"); +``` +If `includePercentProcessorTime` is false, `millisecondsDelayBetweenTwoMeasurements` has no effect. + +For `BytesSentPersec` and `BytesReceivedPersec` in Linux: +``` +string[] procNetDevLast = TryReadLinesFromFile("/proc/net/dev"); +Task.Delay(millisecondsDelayBetweenTwoMeasurements).Wait(); +string[] procNetDevNow = TryReadLinesFromFile("/proc/net/dev"); +``` +If `includeBytesPersec` is false, `millisecondsDelayBetweenTwoMeasurements` has no effect. + ## Benchmarks ### Windows 8.1 (Intel i5-2500, 8 GB RAM): @@ -207,6 +252,38 @@ Setting `includeNetworkAdapterConfiguration` to `false` has only a small impact ## Version history: +- 101.0.0.0 + - Fixed `GetCpuList` in Linux - thanks to [@inelisoni](https://github.com/inelisoni) + - Added `int millisecondsDelayBetweenTwoMeasurements` to `GetCpuList` + - Added `int millisecondsDelayBetweenTwoMeasurements` to `GetNetworkAdapterList` +- 100.1.1.1 + - Fixed `GetNetworkAdapterList` in Linux - thanks to [@Pregath0r](https://github.com/Pregath0r) +- 100.1.1.0 + - Added `ComputerSystem` info in Windows, macOS, Linux - thanks to [@Zagrthos](https://github.com/Zagrthos) +- 100.1.0.1 + - Fixed `GetVideoControllerList` in Linux - thanks to [@NogginBops](https://github.com/NogginBops) +- 100.1.0.0 + - Fixed `GetDriveList` in Linux - thanks to [@GusanoGris](https://github.com/GusanoGris) + - Added `Microsoft.SourceLink.GitHub` - by [@andreas-eriksson](https://github.com/andreas-eriksson) +- 100.0.1.1 + - Added XML documentation - thanks to [@andreas-eriksson](https://github.com/andreas-eriksson) +- 100.0.1.0 + - Added `Disk.Description` in Linux + - Added `Disk.FirmwareRevision` in Linux + - Added `Disk.Name` in Linux + - Added `Disk.SerialNumber` in Linux + - Added `Disk.Size` in Linux +- 100.0.0.1 + - Added `HardwareInfo.snk` to sign the assembly with a strong name key +- 100.0.0.0 + - Fixed `GetCpuList` in Linux - thanks to [@inelisoni](https://github.com/inelisoni) +- 11.1.1.1 + - Fixed `GetMonitorList` in Windows - by [@Geevo](https://github.com/Geevo) +- 11.1.1.0 + - Fixed `GetMonitorList` in Windows - by [@Geevo](https://github.com/Geevo) +- 11.1.0.1 + - Fixed `GetNetworkAdapterList` in Linux - thanks to [@Nihlus](https://github.com/Nihlus) + - Fixed `GetCpuList` in Windows - by [@Frooxius](https://github.com/Frooxius) - 11.1.0.0 - Fixed `NetworkAdapter.Speed` in Windows - by [@isenmann](https://github.com/isenmann) - 11.0.1.1