diff --git a/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs b/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs index b3e039b..41c8f0a 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs @@ -19,6 +19,8 @@ internal class StorageGroup : IGroup if (Software.OperatingSystem.IsUnix) return; + var storageSpaceDiskToPhysicalDiskMap = StorageSpaceDiskToPhysicalDiskMapping(); + //https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-diskdrive using var diskDriveSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive") { Options = { Timeout = TimeSpan.FromSeconds(10) } }; foreach (ManagementBaseObject diskDrive in diskDriveSearcher.Get()) @@ -35,10 +37,79 @@ internal class StorageGroup : IGroup { _hardware.Add(instance); } + + if (storageSpaceDiskToPhysicalDiskMap.ContainsKey(idx)) + { + var physicalDisks = storageSpaceDiskToPhysicalDiskMap[idx]; + foreach ((uint, ulong) physicalDisk in physicalDisks) + { + var physicalDiskInstance = AbstractStorage.CreateInstance(@$"\\.\PHYSICALDRIVE{physicalDisk.Item1}", physicalDisk.Item1, physicalDisk.Item2, scsi, settings); + if (physicalDiskInstance != null) + { + _hardware.Add(physicalDiskInstance); + } + } + } } } } + /// + /// Maps each StorageSpace to the PhysicalDisks it is composed of. + /// + /// + private static Dictionary> StorageSpaceDiskToPhysicalDiskMapping() + { + var diskToPhysicalDisk = new Dictionary>(); + if (!Software.OperatingSystem.IsWindows8OrGreater) + { + return diskToPhysicalDisk; + } + + ManagementScope scope = new ManagementScope(@"\root\Microsoft\Windows\Storage"); + + // https://learn.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-disk + // Lists all the disks visible to your system, the output is the same as Win32_DiskDrive. + // If you're using a storage Space, the "hidden" disks which compose your storage space will not be listed. + using var diskSearcher = new ManagementObjectSearcher(scope, new ObjectQuery("SELECT * FROM MSFT_Disk")); + foreach (ManagementBaseObject disk in diskSearcher.Get()) + { + var diskIdx = (uint)disk["Number"]; + diskToPhysicalDisk[diskIdx] = new List<(uint, ulong)>(); + // https://learn.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-virtualdisk + // Maps the current Disk to its corresponding VirtualDisk. If the current Disk is not a storage space, it does not have a corresponding VirtualDisk. + // Each Disk maps to one or zero VirtualDisk. + using (var toVirtualDisk = new ManagementObjectSearcher(scope, new ObjectQuery(FollowAssociationQuery("MSFT_Disk", (string)disk["ObjectId"], "MSFT_VirtualDiskToDisk")))) + { + foreach (ManagementBaseObject virtualDisk in toVirtualDisk.Get()) + { + // https://learn.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-physicaldisk + // Maps the current VirtualDisk to the PhysicalDisk it is composed of. + // Each VirtualDisk maps to one or more PhysicalDisk. + using (var toPhysicalDisk = new ManagementObjectSearcher(scope, new ObjectQuery(FollowAssociationQuery("MSFT_VirtualDisk", (string)virtualDisk["ObjectId"], "MSFT_VirtualDiskToPhysicalDisk")))) + { + foreach (ManagementBaseObject physicalDisk in toPhysicalDisk.Get()) + { + var physicalDiskSize = (ulong)physicalDisk["Size"]; + uint physicalDiskIdx; + if (uint.TryParse((string)physicalDisk["DeviceId"], out physicalDiskIdx)) + { + diskToPhysicalDisk[diskIdx].Add((physicalDiskIdx, physicalDiskSize)); + } + } + } + } + } + } + + return diskToPhysicalDisk; + } + + private static string FollowAssociationQuery(string source, string objectId, string associationClass) + { + return @$"ASSOCIATORS OF {{{source}.ObjectId=""{objectId.Replace(@"\", @"\\").Replace(@"""", @"\""")}""}} WHERE AssocClass = {associationClass}"; + } + public IReadOnlyList Hardware => _hardware; public string GetReport() @@ -51,4 +122,4 @@ internal class StorageGroup : IGroup foreach (AbstractStorage storage in _hardware) storage.Close(); } -} \ No newline at end of file +} diff --git a/LibreHardwareMonitorLib/Software/OperatingSystem.cs b/LibreHardwareMonitorLib/Software/OperatingSystem.cs index d1ec00c..4c16bb7 100644 --- a/LibreHardwareMonitorLib/Software/OperatingSystem.cs +++ b/LibreHardwareMonitorLib/Software/OperatingSystem.cs @@ -20,10 +20,13 @@ public static class OperatingSystem { // The operating system doesn't change during execution so let's query it just one time. PlatformID platform = Environment.OSVersion.Platform; + Version version = Environment.OSVersion.Version; IsUnix = platform is PlatformID.Unix or PlatformID.MacOSX; if (Environment.Is64BitOperatingSystem) Is64Bit = true; + + IsWindows8OrGreater = !IsUnix && ((version.Major == 6 && version.Minor >= 2) || version.Major > 6); } /// @@ -35,4 +38,9 @@ public static class OperatingSystem /// Gets information about whether the current system is Unix based. /// public static bool IsUnix { get; } -} \ No newline at end of file + + /// + /// Returns true if the current system is Windows 8 or a more recent Windows version + /// + public static bool IsWindows8OrGreater { get; } +}