diff --git a/LibreHardwareMonitorLib/Hardware/Battery/Battery.cs b/LibreHardwareMonitorLib/Hardware/Battery/Battery.cs index 0f2ef9b..d7e8be6 100644 --- a/LibreHardwareMonitorLib/Hardware/Battery/Battery.cs +++ b/LibreHardwareMonitorLib/Hardware/Battery/Battery.cs @@ -4,7 +4,6 @@ // All Rights Reserved. using System; -using System.Runtime.InteropServices; using Windows.Win32; using Windows.Win32.System.Power; using LibreHardwareMonitor.Interop; @@ -85,8 +84,8 @@ internal sealed class Battery : Hardware _remainingTime = new Sensor("Remaining Time (Estimated)", 0, SensorType.TimeSpan, this, settings); _temperature = new Sensor("Battery Temperature", 0, SensorType.Temperature, this, settings); - if (batteryInfo.FullChargedCapacity is not Kernel32.BATTERY_UNKNOWN_CAPACITY && - batteryInfo.DesignedCapacity is not Kernel32.BATTERY_UNKNOWN_CAPACITY) + if (batteryInfo.FullChargedCapacity is not PInvoke.BATTERY_UNKNOWN_CAPACITY && + batteryInfo.DesignedCapacity is not PInvoke.BATTERY_UNKNOWN_CAPACITY) { _designedCapacity.Value = batteryInfo.DesignedCapacity; _fullChargedCapacity.Value = batteryInfo.FullChargedCapacity; @@ -148,19 +147,19 @@ internal sealed class Battery : Hardware null, null)) { - if (batteryStatus.Capacity != Kernel32.BATTERY_UNKNOWN_CAPACITY) + if (batteryStatus.Capacity != PInvoke.BATTERY_UNKNOWN_CAPACITY) _remainingCapacity.Value = batteryStatus.Capacity; else _remainingCapacity.Value = null; _chargeLevel.Value = _remainingCapacity.Value * 100f / _fullChargedCapacity.Value; - if (batteryStatus.Voltage is not Kernel32.BATTERY_UNKNOWN_VOLTAGE) + if (batteryStatus.Voltage is not PInvoke.BATTERY_UNKNOWN_VOLTAGE) _voltage.Value = batteryStatus.Voltage / 1000f; else _voltage.Value = null; - if (batteryStatus.Rate is Kernel32.BATTERY_UNKNOWN_RATE) + if ((uint)batteryStatus.Rate is PInvoke.BATTERY_UNKNOWN_RATE) { ChargeDischargeCurrent = null; _chargeDischargeCurrent.Value = null; @@ -212,7 +211,7 @@ internal sealed class Battery : Hardware null, null)) { - if (estimatedRunTime != Kernel32.BATTERY_UNKNOWN_TIME) + if (estimatedRunTime != PInvoke.BATTERY_UNKNOWN_TIME) _remainingTime.Value = estimatedRunTime; else _remainingTime.Value = null; diff --git a/LibreHardwareMonitorLib/Hardware/Battery/BatteryGroup.cs b/LibreHardwareMonitorLib/Hardware/Battery/BatteryGroup.cs index 7a9fe05..e96a0cd 100644 --- a/LibreHardwareMonitorLib/Hardware/Battery/BatteryGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Battery/BatteryGroup.cs @@ -11,6 +11,7 @@ using System.Text; using Windows.Win32; using Windows.Win32.Devices.DeviceAndDriverInstallation; using Windows.Win32.Foundation; +using Windows.Win32.Storage.FileSystem; using Windows.Win32.System.Power; using LibreHardwareMonitor.Interop; using Microsoft.Win32.SafeHandles; @@ -74,7 +75,7 @@ internal class BatteryGroup : IGroup { string devicePath = pData->DevicePath.ToString(); - SafeFileHandle battery = Kernel32.CreateFile(devicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); + SafeFileHandle battery = PInvoke.CreateFile(devicePath, (uint)FileAccess.ReadWrite, FILE_SHARE_MODE.FILE_SHARE_READ | FILE_SHARE_MODE.FILE_SHARE_WRITE, null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, null); if (!battery.IsInvalid) { BATTERY_QUERY_INFORMATION bqi = default; diff --git a/LibreHardwareMonitorLib/Hardware/OpCode.cs b/LibreHardwareMonitorLib/Hardware/OpCode.cs index c7b60c8..e227580 100644 --- a/LibreHardwareMonitorLib/Hardware/OpCode.cs +++ b/LibreHardwareMonitorLib/Hardware/OpCode.cs @@ -251,7 +251,7 @@ internal static class OpCode } else { - _codeBuffer = (IntPtr)PInvoke.VirtualAlloc((void*)0, + _codeBuffer = (IntPtr)PInvoke.VirtualAlloc(null, (UIntPtr)_size, VIRTUAL_ALLOCATION_TYPE.MEM_COMMIT | VIRTUAL_ALLOCATION_TYPE.MEM_RESERVE, PAGE_PROTECTION_FLAGS.PAGE_EXECUTE_READWRITE); diff --git a/LibreHardwareMonitorLib/Hardware/Storage/ATAStorage.cs b/LibreHardwareMonitorLib/Hardware/Storage/ATAStorage.cs index b0ea05f..eeed96f 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/ATAStorage.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/ATAStorage.cs @@ -51,7 +51,7 @@ public abstract class AtaStorage : AbstractStorage ISmart smart = new WindowsSmart(storageInfo.Index); string name = null; string firmwareRevision = null; - Kernel32.SMART_ATTRIBUTE[] smartAttributes = { }; + AtaSmart.SMART_ATTRIBUTE[] smartAttributes = { }; if (smart.IsValid) { @@ -119,7 +119,7 @@ public abstract class AtaStorage : AbstractStorage { bool attributeFound = false; - foreach (Kernel32.SMART_ATTRIBUTE value in smartAttributes) + foreach (AtaSmart.SMART_ATTRIBUTE value in smartAttributes) { if (value.Id == requireAttribute.AttributeId) { @@ -202,7 +202,7 @@ public abstract class AtaStorage : AbstractStorage } } - protected virtual void UpdateAdditionalSensors(Kernel32.SMART_ATTRIBUTE[] values) { } + protected virtual void UpdateAdditionalSensors(AtaSmart.SMART_ATTRIBUTE[] values) { } protected override void UpdateSensors() { @@ -214,12 +214,12 @@ public abstract class AtaStorage : AbstractStorage if (Smart.IsValid) { - Kernel32.SMART_ATTRIBUTE[] smartAttributes = Smart.ReadSmartData(); + AtaSmart.SMART_ATTRIBUTE[] smartAttributes = Smart.ReadSmartData(); foreach (KeyValuePair keyValuePair in _sensors) { SmartAttribute attribute = keyValuePair.Key; - foreach (Kernel32.SMART_ATTRIBUTE value in smartAttributes) + foreach (AtaSmart.SMART_ATTRIBUTE value in smartAttributes) { if (value.Id == attribute.Id) { @@ -233,12 +233,12 @@ public abstract class AtaStorage : AbstractStorage } } - protected override void GetReport(StringBuilder r) + protected override unsafe void GetReport(StringBuilder r) { if (Smart.IsValid) { - Kernel32.SMART_ATTRIBUTE[] values = Smart.ReadSmartData(); - Kernel32.SMART_THRESHOLD[] thresholds = Smart.ReadSmartThresholds(); + AtaSmart.SMART_ATTRIBUTE[] values = Smart.ReadSmartData(); + AtaSmart.SMART_THRESHOLD[] thresholds = Smart.ReadSmartThresholds(); if (values.Length > 0) { r.AppendFormat(CultureInfo.InvariantCulture, @@ -252,13 +252,13 @@ public abstract class AtaStorage : AbstractStorage "Physical".PadRight(8), Environment.NewLine); - foreach (Kernel32.SMART_ATTRIBUTE value in values) + foreach (AtaSmart.SMART_ATTRIBUTE value in values) { if (value.Id == 0x00) break; byte? threshold = null; - foreach (Kernel32.SMART_THRESHOLD t in thresholds) + foreach (AtaSmart.SMART_THRESHOLD t in thresholds) { if (t.Id == value.Id) { @@ -280,7 +280,9 @@ public abstract class AtaStorage : AbstractStorage } } - string raw = BitConverter.ToString(value.RawValue); + Span rawValue = new(value.RawValue, 6); + string raw = BitConverter.ToString(rawValue.ToArray()); + r.AppendFormat(CultureInfo.InvariantCulture, " {0}{1}{2}{3}{4}{5}{6}{7}", value.Id.ToString("X2").PadRight(3), diff --git a/LibreHardwareMonitorLib/Hardware/Storage/AbstractStorage.cs b/LibreHardwareMonitorLib/Hardware/Storage/AbstractStorage.cs index e7f7032..5f9dcac 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/AbstractStorage.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/AbstractStorage.cs @@ -85,7 +85,13 @@ public abstract class AbstractStorage : Hardware info.DiskSize = diskSize; info.DeviceId = deviceId; - info.Handle = Kernel32.OpenDevice(deviceId); + info.Handle = PInvoke.CreateFile(deviceId, + (uint)FileAccess.ReadWrite, + FILE_SHARE_MODE.FILE_SHARE_READ | FILE_SHARE_MODE.FILE_SHARE_WRITE, + null, + FILE_CREATION_DISPOSITION.OPEN_EXISTING, + FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, + null); info.Scsi = $@"\\.\SCSI{scsiPort}:"; //fallback, when it is not possible to read out with the nvme implementation, diff --git a/LibreHardwareMonitorLib/Hardware/Storage/DebugSmart.cs b/LibreHardwareMonitorLib/Hardware/Storage/DebugSmart.cs index 1fa5793..d547672 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/DebugSmart.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/DebugSmart.cs @@ -13,7 +13,8 @@ namespace LibreHardwareMonitor.Hardware.Storage { internal class DebugSmart : ISmart { - private readonly Drive[] _drives = { + private readonly Drive[] _drives = + [ new("KINGSTON SNV425S264GB", null, 16, @" 01 000000000000 100 100 02 000000000000 100 100 @@ -312,7 +313,7 @@ namespace LibreHardwareMonitor.Hardware.Storage C7 020000000000 99 99 0 EB 690000000000 99 99 0 F1 A56AA1F60200 99 99 0") - }; + ]; private int _driveNumber; @@ -336,14 +337,14 @@ namespace LibreHardwareMonitor.Hardware.Storage return true; } - public Kernel32.SMART_ATTRIBUTE[] ReadSmartData() + public AtaSmart.SMART_ATTRIBUTE[] ReadSmartData() { if (_driveNumber < 0) throw new ObjectDisposedException(nameof(DebugSmart)); return _drives[_driveNumber].DriveAttributeValues; } - public Kernel32.SMART_THRESHOLD[] ReadSmartThresholds() + public AtaSmart.SMART_THRESHOLD[] ReadSmartThresholds() { if (_driveNumber < 0) throw new ObjectDisposedException(nameof(DebugSmart)); @@ -372,23 +373,23 @@ namespace LibreHardwareMonitor.Hardware.Storage private class Drive { - public Drive(string name, string firmware, int idBase, string value) + public unsafe Drive(string name, string firmware, int idBase, string value) { Name = name; FirmwareVersion = firmware; - string[] lines = value.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - DriveAttributeValues = new Kernel32.SMART_ATTRIBUTE[lines.Length]; - var thresholds = new System.Collections.Generic.List(); + string[] lines = value.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + DriveAttributeValues = new AtaSmart.SMART_ATTRIBUTE[lines.Length]; + var thresholds = new System.Collections.Generic.List(); for (int i = 0; i < lines.Length; i++) { - string[] array = lines[i].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + string[] array = lines[i].Split([' '], StringSplitOptions.RemoveEmptyEntries); if (array.Length is not 4 and not 5) throw new Exception(); - var v = new Kernel32.SMART_ATTRIBUTE { Id = Convert.ToByte(array[0], idBase), RawValue = new byte[6] }; + var v = new AtaSmart.SMART_ATTRIBUTE { Id = Convert.ToByte(array[0], idBase) }; for (int j = 0; j < 6; j++) { @@ -402,7 +403,7 @@ namespace LibreHardwareMonitor.Hardware.Storage if (array.Length == 5) { - var t = new Kernel32.SMART_THRESHOLD { Id = v.Id, Threshold = Convert.ToByte(array[4], 10) }; + var t = new AtaSmart.SMART_THRESHOLD { Id = v.Id, Threshold = Convert.ToByte(array[4], 10) }; thresholds.Add(t); } } @@ -410,9 +411,9 @@ namespace LibreHardwareMonitor.Hardware.Storage DriveThresholdValues = thresholds.ToArray(); } - public Kernel32.SMART_ATTRIBUTE[] DriveAttributeValues { get; } + public AtaSmart.SMART_ATTRIBUTE[] DriveAttributeValues { get; } - public Kernel32.SMART_THRESHOLD[] DriveThresholdValues { get; } + public AtaSmart.SMART_THRESHOLD[] DriveThresholdValues { get; } public string FirmwareVersion { get; } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/ISmart.cs b/LibreHardwareMonitorLib/Hardware/Storage/ISmart.cs index 7d5b778..559b5f1 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/ISmart.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/ISmart.cs @@ -17,9 +17,9 @@ public interface ISmart : IDisposable bool EnableSmart(); - Kernel32.SMART_ATTRIBUTE[] ReadSmartData(); + AtaSmart.SMART_ATTRIBUTE[] ReadSmartData(); - Kernel32.SMART_THRESHOLD[] ReadSmartThresholds(); + AtaSmart.SMART_THRESHOLD[] ReadSmartThresholds(); bool ReadNameAndFirmwareRevision(out string name, out string firmwareRevision); -} \ No newline at end of file +} diff --git a/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntel.cs b/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntel.cs index 012b6df..25f3767 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntel.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntel.cs @@ -4,7 +4,10 @@ // All Rights Reserved. using System; +using System.IO; using System.Runtime.InteropServices; +using Windows.Win32; +using Windows.Win32.Storage.FileSystem; using Windows.Win32.Storage.IscsiDisc; using Windows.Win32.Storage.Nvme; using Windows.Win32.System.Ioctl; @@ -30,7 +33,7 @@ internal class NVMeIntel : INVMeDrive bool result = false; - Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = new(); + AtaSmart.NVME_PASS_THROUGH_IOCTL passThrough = new(); passThrough.SrbIoCtrl.HeaderLength = (uint)sizeof(SRB_IO_CONTROL); ReadOnlySpan signature = "NvmeMini"u8; @@ -38,35 +41,28 @@ internal class NVMeIntel : INVMeDrive passThrough.SrbIoCtrl.Signature[i] = signature[i]; passThrough.SrbIoCtrl.Timeout = 10; - passThrough.SrbIoCtrl.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; + passThrough.SrbIoCtrl.ControlCode = AtaSmart.NVME_PASS_THROUGH_SRB_IO_CODE; passThrough.SrbIoCtrl.ReturnCode = 0; - passThrough.SrbIoCtrl.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); + passThrough.SrbIoCtrl.Length = (uint)sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL) - (uint)sizeof(SRB_IO_CONTROL); passThrough.NVMeCmd[0] = 6; //identify passThrough.NVMeCmd[10] = 1; //return to host - passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; + passThrough.Direction = AtaSmart.NVME_DATA_IN; passThrough.QueueId = 0; - passThrough.DataBufferLen = Kernel32.IOCTL_BUFFER_SIZE; + passThrough.DataBufferLen = AtaSmart.IOCTL_BUFFER_SIZE; passThrough.MetaDataLen = 0; - passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); + passThrough.ReturnBufferLen = (uint)sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL); - int length = Marshal.SizeOf(); + int length = sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL); IntPtr buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(passThrough, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + bool validTransfer = PInvoke.DeviceIoControl(hDevice, PInvoke.IOCTL_SCSI_MINIPORT, (void*)buffer, (uint)length, (void*)buffer, (uint)length, null, null); if (validTransfer) { - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.NVME_PASS_THROUGH_IOCTL.DataBuffer)); + IntPtr offset = Marshal.OffsetOf(nameof(AtaSmart.NVME_PASS_THROUGH_IOCTL.DataBuffer)); var newPtr = IntPtr.Add(buffer, offset.ToInt32()); - int finalSize = Marshal.SizeOf(); - IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf()); - Kernel32.RtlZeroMemory(ptr, finalSize); - int len = Math.Min(finalSize, Kernel32.IOCTL_BUFFER_SIZE); - Kernel32.RtlCopyMemory(ptr, newPtr, (uint)len); + data = *(NVME_IDENTIFY_CONTROLLER_DATA*)newPtr; Marshal.FreeHGlobal(buffer); - - data = Marshal.PtrToStructure(ptr); - Marshal.FreeHGlobal(ptr); result = true; } else @@ -85,7 +81,7 @@ internal class NVMeIntel : INVMeDrive bool result = false; - Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = new(); + AtaSmart.NVME_PASS_THROUGH_IOCTL passThrough = new(); passThrough.SrbIoCtrl.HeaderLength = (uint)sizeof(SRB_IO_CONTROL); ReadOnlySpan signature = "NvmeMini"u8; @@ -93,28 +89,28 @@ internal class NVMeIntel : INVMeDrive passThrough.SrbIoCtrl.Signature[i] = signature[i]; passThrough.SrbIoCtrl.Timeout = 10; - passThrough.SrbIoCtrl.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; + passThrough.SrbIoCtrl.ControlCode = AtaSmart.NVME_PASS_THROUGH_SRB_IO_CODE; passThrough.SrbIoCtrl.ReturnCode = 0; - passThrough.SrbIoCtrl.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); + passThrough.SrbIoCtrl.Length = (uint)sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL) - (uint)sizeof(SRB_IO_CONTROL); passThrough.NVMeCmd[0] = (uint)STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeLogPage; // GetLogPage passThrough.NVMeCmd[1] = 0xFFFFFFFF; // address passThrough.NVMeCmd[10] = 0x007f0002; // uint cdw10 = 0x000000002 | (((size / 4) - 1) << 16); - passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; + passThrough.Direction = AtaSmart.NVME_DATA_IN; passThrough.QueueId = 0; - passThrough.DataBufferLen = Kernel32.IOCTL_BUFFER_SIZE; + passThrough.DataBufferLen = AtaSmart.IOCTL_BUFFER_SIZE; passThrough.MetaDataLen = 0; - passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); + passThrough.ReturnBufferLen = (uint)sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL); - int length = Marshal.SizeOf(); + int length = sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL); IntPtr buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(passThrough, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + bool validTransfer = PInvoke.DeviceIoControl(hDevice, PInvoke.IOCTL_SCSI_MINIPORT, (void*)buffer, (uint)length, (void*)buffer, (uint)length, null, null); if (validTransfer) { - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.NVME_PASS_THROUGH_IOCTL.DataBuffer)); + IntPtr offset = Marshal.OffsetOf(nameof(AtaSmart.NVME_PASS_THROUGH_IOCTL.DataBuffer)); var newPtr = IntPtr.Add(buffer, offset.ToInt32()); - data = Marshal.PtrToStructure(newPtr); + data = *(NVME_HEALTH_INFO_LOG*)newPtr; Marshal.FreeHGlobal(buffer); result = true; } @@ -128,11 +124,17 @@ internal class NVMeIntel : INVMeDrive public static unsafe SafeHandle IdentifyDevice(StorageInfo storageInfo) { - SafeFileHandle handle = Kernel32.OpenDevice(storageInfo.Scsi); + SafeFileHandle handle = PInvoke.CreateFile(storageInfo.Scsi, + (uint)FileAccess.ReadWrite, + FILE_SHARE_MODE.FILE_SHARE_READ | FILE_SHARE_MODE.FILE_SHARE_WRITE, + null, + FILE_CREATION_DISPOSITION.OPEN_EXISTING, + FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, + null); if (handle?.IsInvalid != false) return null; - Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = new(); + AtaSmart.NVME_PASS_THROUGH_IOCTL passThrough = new(); passThrough.SrbIoCtrl.HeaderLength = (uint)sizeof(SRB_IO_CONTROL); ReadOnlySpan signature = "NvmeMini"u8; @@ -140,22 +142,22 @@ internal class NVMeIntel : INVMeDrive passThrough.SrbIoCtrl.Signature[i] = signature[i]; passThrough.SrbIoCtrl.Timeout = 10; - passThrough.SrbIoCtrl.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; + passThrough.SrbIoCtrl.ControlCode = AtaSmart.NVME_PASS_THROUGH_SRB_IO_CODE; passThrough.SrbIoCtrl.ReturnCode = 0; - passThrough.SrbIoCtrl.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); + passThrough.SrbIoCtrl.Length = (uint)sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL) - (uint)sizeof(SRB_IO_CONTROL); passThrough.NVMeCmd[0] = 6; //identify passThrough.NVMeCmd[10] = 1; //return to host - passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; + passThrough.Direction = AtaSmart.NVME_DATA_IN; passThrough.QueueId = 0; - passThrough.DataBufferLen = Kernel32.IOCTL_BUFFER_SIZE; + passThrough.DataBufferLen = AtaSmart.IOCTL_BUFFER_SIZE; passThrough.MetaDataLen = 0; - passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); + passThrough.ReturnBufferLen = (uint)sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL); - int length = Marshal.SizeOf(); + int length = sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL); IntPtr buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(passThrough, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + bool validTransfer = PInvoke.DeviceIoControl(handle, PInvoke.IOCTL_SCSI_MINIPORT, (void*)buffer, (uint)length, (void*)buffer, (uint)length, null, null); Marshal.FreeHGlobal(buffer); if (validTransfer) diff --git a/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntelRst.cs b/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntelRst.cs index acc93b2..c0560bd 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntelRst.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntelRst.cs @@ -4,12 +4,15 @@ // All Rights Reserved. using System; +using System.IO; using System.Runtime.InteropServices; +using LibreHardwareMonitor.Interop; +using Microsoft.Win32.SafeHandles; +using Windows.Win32; +using Windows.Win32.Storage.FileSystem; using Windows.Win32.Storage.IscsiDisc; using Windows.Win32.Storage.Nvme; using Windows.Win32.System.Ioctl; -using LibreHardwareMonitor.Interop; -using Microsoft.Win32.SafeHandles; namespace LibreHardwareMonitor.Hardware.Storage; @@ -30,7 +33,7 @@ internal class NVMeIntelRst : INVMeDrive bool result = false; - Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = new(); + AtaSmart.NVME_PASS_THROUGH_IOCTL passThrough = new(); passThrough.SrbIoCtrl.HeaderLength = (uint)sizeof(SRB_IO_CONTROL); ReadOnlySpan signature = "IntelNvm"u8; @@ -38,35 +41,28 @@ internal class NVMeIntelRst : INVMeDrive passThrough.SrbIoCtrl.Signature[i] = signature[i]; passThrough.SrbIoCtrl.Timeout = 10; - passThrough.SrbIoCtrl.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; + passThrough.SrbIoCtrl.ControlCode = AtaSmart.NVME_PASS_THROUGH_SRB_IO_CODE; passThrough.SrbIoCtrl.ReturnCode = 0; - passThrough.SrbIoCtrl.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); + passThrough.SrbIoCtrl.Length = (uint)sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL) - (uint)sizeof(SRB_IO_CONTROL); passThrough.NVMeCmd[0] = 6; //identify passThrough.NVMeCmd[10] = 1; //return to host - passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; + passThrough.Direction = AtaSmart.NVME_DATA_IN; passThrough.QueueId = 0; - passThrough.DataBufferLen = Kernel32.IOCTL_BUFFER_SIZE; + passThrough.DataBufferLen = AtaSmart.IOCTL_BUFFER_SIZE; passThrough.MetaDataLen = 0; - passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); + passThrough.ReturnBufferLen = (uint)sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL); - int length = Marshal.SizeOf(); + int length = sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL); IntPtr buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(passThrough, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + bool validTransfer = PInvoke.DeviceIoControl(hDevice, PInvoke.IOCTL_SCSI_MINIPORT, (void*)buffer, (uint)length, (void*)buffer, (uint)length, null, null); if (validTransfer) { - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.NVME_PASS_THROUGH_IOCTL.DataBuffer)); - IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); - int finalSize = Marshal.SizeOf(); - IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf()); - Kernel32.RtlZeroMemory(ptr, finalSize); - int len = Math.Min(finalSize, Kernel32.IOCTL_BUFFER_SIZE); - Kernel32.RtlCopyMemory(ptr, newPtr, (uint)len); + IntPtr offset = Marshal.OffsetOf(nameof(AtaSmart.NVME_PASS_THROUGH_IOCTL.DataBuffer)); + var newPtr = IntPtr.Add(buffer, offset.ToInt32()); + data = *(NVME_IDENTIFY_CONTROLLER_DATA*)newPtr; Marshal.FreeHGlobal(buffer); - - data = Marshal.PtrToStructure(ptr); - Marshal.FreeHGlobal(ptr); result = true; } else @@ -85,7 +81,7 @@ internal class NVMeIntelRst : INVMeDrive bool result = false; - Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = new(); + AtaSmart.NVME_PASS_THROUGH_IOCTL passThrough = new(); passThrough.SrbIoCtrl.HeaderLength = (uint)sizeof(SRB_IO_CONTROL); ReadOnlySpan signature = "IntelNvm"u8; @@ -93,28 +89,28 @@ internal class NVMeIntelRst : INVMeDrive passThrough.SrbIoCtrl.Signature[i] = signature[i]; passThrough.SrbIoCtrl.Timeout = 10; - passThrough.SrbIoCtrl.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; + passThrough.SrbIoCtrl.ControlCode = AtaSmart.NVME_PASS_THROUGH_SRB_IO_CODE; passThrough.SrbIoCtrl.ReturnCode = 0; - passThrough.SrbIoCtrl.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); + passThrough.SrbIoCtrl.Length = (uint)sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL) - (uint)sizeof(SRB_IO_CONTROL); passThrough.NVMeCmd[0] = (uint)STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeLogPage; // GetLogPage passThrough.NVMeCmd[1] = 0xFFFFFFFF; // address passThrough.NVMeCmd[10] = 0x007f0002; // uint cdw10 = 0x000000002 | (((size / 4) - 1) << 16); - passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; + passThrough.Direction = AtaSmart.NVME_DATA_IN; passThrough.QueueId = 0; - passThrough.DataBufferLen = Kernel32.IOCTL_BUFFER_SIZE; + passThrough.DataBufferLen = AtaSmart.IOCTL_BUFFER_SIZE; passThrough.MetaDataLen = 0; - passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); + passThrough.ReturnBufferLen = (uint)sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL); - int length = Marshal.SizeOf(); + int length = sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL); IntPtr buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(passThrough, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + bool validTransfer = PInvoke.DeviceIoControl(hDevice, PInvoke.IOCTL_SCSI_MINIPORT, (void*)buffer, (uint)length, (void*)buffer, (uint)length, null, null); if (validTransfer) { - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.NVME_PASS_THROUGH_IOCTL.DataBuffer)); - IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); - data = Marshal.PtrToStructure(newPtr); + IntPtr offset = Marshal.OffsetOf(nameof(AtaSmart.NVME_PASS_THROUGH_IOCTL.DataBuffer)); + var newPtr = IntPtr.Add(buffer, offset.ToInt32()); + data = *(NVME_HEALTH_INFO_LOG*)newPtr; Marshal.FreeHGlobal(buffer); result = true; } @@ -128,11 +124,17 @@ internal class NVMeIntelRst : INVMeDrive public static unsafe SafeHandle IdentifyDevice(StorageInfo storageInfo) { - SafeFileHandle handle = Kernel32.OpenDevice(storageInfo.Scsi); + SafeFileHandle handle = PInvoke.CreateFile(storageInfo.Scsi, + (uint)FileAccess.ReadWrite, + FILE_SHARE_MODE.FILE_SHARE_READ | FILE_SHARE_MODE.FILE_SHARE_WRITE, + null, + FILE_CREATION_DISPOSITION.OPEN_EXISTING, + FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, + null); if (handle?.IsInvalid != false) return null; - Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = new(); + AtaSmart.NVME_PASS_THROUGH_IOCTL passThrough = new(); passThrough.SrbIoCtrl.HeaderLength = (uint)sizeof(SRB_IO_CONTROL); ReadOnlySpan signature = "IntelNvm"u8; @@ -140,22 +142,22 @@ internal class NVMeIntelRst : INVMeDrive passThrough.SrbIoCtrl.Signature[i] = signature[i]; passThrough.SrbIoCtrl.Timeout = 10; - passThrough.SrbIoCtrl.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; + passThrough.SrbIoCtrl.ControlCode = AtaSmart.NVME_PASS_THROUGH_SRB_IO_CODE; passThrough.SrbIoCtrl.ReturnCode = 0; - passThrough.SrbIoCtrl.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); + passThrough.SrbIoCtrl.Length = (uint)sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL) - (uint)sizeof(SRB_IO_CONTROL); passThrough.NVMeCmd[0] = 6; //identify passThrough.NVMeCmd[10] = 1; //return to host - passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; + passThrough.Direction = AtaSmart.NVME_DATA_IN; passThrough.QueueId = 0; - passThrough.DataBufferLen = Kernel32.IOCTL_BUFFER_SIZE; + passThrough.DataBufferLen = AtaSmart.IOCTL_BUFFER_SIZE; passThrough.MetaDataLen = 0; - passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); + passThrough.ReturnBufferLen = (uint)sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL); - int length = Marshal.SizeOf(); + int length = sizeof(AtaSmart.NVME_PASS_THROUGH_IOCTL); IntPtr buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(passThrough, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + bool validTransfer = PInvoke.DeviceIoControl(handle, PInvoke.IOCTL_SCSI_MINIPORT, (void*)buffer, (uint)length, (void*)buffer, (uint)length, null, null); Marshal.FreeHGlobal(buffer); if (validTransfer) diff --git a/LibreHardwareMonitorLib/Hardware/Storage/NVMeSamsung.cs b/LibreHardwareMonitorLib/Hardware/Storage/NVMeSamsung.cs index 8c42a4f..cb8bcfa 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/NVMeSamsung.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/NVMeSamsung.cs @@ -4,12 +4,14 @@ // All Rights Reserved. using System; -using System.Linq; +using System.IO; using System.Runtime.InteropServices; -using Windows.Win32.Storage.IscsiDisc; -using Windows.Win32.Storage.Nvme; using LibreHardwareMonitor.Interop; using Microsoft.Win32.SafeHandles; +using Windows.Win32; +using Windows.Win32.Storage.FileSystem; +using Windows.Win32.Storage.IscsiDisc; +using Windows.Win32.Storage.Nvme; namespace LibreHardwareMonitor.Hardware.Storage; @@ -30,17 +32,17 @@ internal class NVMeSamsung : INVMeDrive if (hDevice?.IsInvalid != false) return false; - Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS buffers = new(); + AtaSmart.SCSI_PASS_THROUGH buffers = new(); buffers.Spt.Length = (ushort)sizeof(SCSI_PASS_THROUGH); buffers.Spt.PathId = 0; buffers.Spt.TargetId = 0; buffers.Spt.Lun = 0; buffers.Spt.SenseInfoLength = 24; - buffers.Spt.DataTransferLength = Kernel32.IOCTL_BUFFER_SIZE; + buffers.Spt.DataTransferLength = AtaSmart.IOCTL_BUFFER_SIZE; buffers.Spt.TimeOutValue = 2; - buffers.Spt.DataBufferOffset = new UIntPtr((ulong)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf))); - buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); + buffers.Spt.DataBufferOffset = new UIntPtr((ulong)Marshal.OffsetOf(nameof(AtaSmart.SCSI_PASS_THROUGH.DataBuf))); + buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(AtaSmart.SCSI_PASS_THROUGH), nameof(AtaSmart.SCSI_PASS_THROUGH.SenseBuf)); buffers.Spt.CdbLength = 16; buffers.Spt.Cdb[0] = 0xB5; // SECURITY PROTOCOL IN @@ -48,13 +50,13 @@ internal class NVMeSamsung : INVMeDrive buffers.Spt.Cdb[3] = 5; // Identify buffers.Spt.Cdb[8] = 0; // Transfer Length buffers.Spt.Cdb[9] = 0x40; // Transfer Length - buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_OUT; + buffers.Spt.DataIn = (byte)PInvoke.SCSI_IOCTL_DATA_OUT; buffers.DataBuf[0] = 1; - int length = (int)(Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)).ToInt32() + buffers.Spt.DataTransferLength); + int length = (int)(Marshal.OffsetOf(typeof(AtaSmart.SCSI_PASS_THROUGH), nameof(AtaSmart.SCSI_PASS_THROUGH.DataBuf)).ToInt32() + buffers.Spt.DataTransferLength); IntPtr buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(buffers, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); + bool validTransfer = PInvoke.DeviceIoControl(hDevice, PInvoke.IOCTL_SCSI_PASS_THROUGH, (void*)buffer, (uint)length, (void*)buffer, (uint)length, null, null); Marshal.FreeHGlobal(buffer); bool result = false; @@ -62,16 +64,16 @@ internal class NVMeSamsung : INVMeDrive if (validTransfer) { //read data from samsung SSD - buffers = new Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS(); + buffers = new AtaSmart.SCSI_PASS_THROUGH(); buffers.Spt.Length = (ushort)sizeof(SCSI_PASS_THROUGH); buffers.Spt.PathId = 0; buffers.Spt.TargetId = 0; buffers.Spt.Lun = 0; buffers.Spt.SenseInfoLength = 24; - buffers.Spt.DataTransferLength = Kernel32.IOCTL_BUFFER_SIZE; + buffers.Spt.DataTransferLength = AtaSmart.IOCTL_BUFFER_SIZE; buffers.Spt.TimeOutValue = 2; - buffers.Spt.DataBufferOffset = new UIntPtr((ulong)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf))); - buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); + buffers.Spt.DataBufferOffset = new UIntPtr((ulong)Marshal.OffsetOf(nameof(AtaSmart.SCSI_PASS_THROUGH.DataBuf))); + buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(nameof(AtaSmart.SCSI_PASS_THROUGH.SenseBuf)); buffers.Spt.CdbLength = 16; buffers.Spt.Cdb[0] = 0xA2; // SECURITY PROTOCOL IN @@ -79,18 +81,18 @@ internal class NVMeSamsung : INVMeDrive buffers.Spt.Cdb[3] = 5; // Identify buffers.Spt.Cdb[8] = 1; // Transfer Length (high) buffers.Spt.Cdb[9] = 0; // Transfer Length (low) - buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_IN; + buffers.Spt.DataIn = (byte)PInvoke.SCSI_IOCTL_DATA_IN; buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(buffers, buffer, false); - validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); + validTransfer = PInvoke.DeviceIoControl(hDevice, PInvoke.IOCTL_SCSI_PASS_THROUGH, (void*)buffer, (uint)length, (void*)buffer, (uint)length, null, null); - buffers = Marshal.PtrToStructure(buffer); + buffers = Marshal.PtrToStructure(buffer); - if (validTransfer && !IsAllZero(buffers.DataBuf, Kernel32.IOCTL_BUFFER_SIZE)) + if (validTransfer && !IsAllZero(buffers.DataBuf, AtaSmart.IOCTL_BUFFER_SIZE)) { - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); + IntPtr offset = Marshal.OffsetOf(nameof(AtaSmart.SCSI_PASS_THROUGH.DataBuf)); IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); data = Marshal.PtrToStructure(newPtr); result = true; @@ -109,65 +111,65 @@ internal class NVMeSamsung : INVMeDrive return false; bool result = false; - Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS buffers = new Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS(); + AtaSmart.SCSI_PASS_THROUGH buffers = new(); buffers.Spt.Length = (ushort)sizeof(SCSI_PASS_THROUGH); buffers.Spt.PathId = 0; buffers.Spt.TargetId = 0; buffers.Spt.Lun = 0; buffers.Spt.SenseInfoLength = 24; - buffers.Spt.DataTransferLength = Kernel32.IOCTL_BUFFER_SIZE; + buffers.Spt.DataTransferLength = AtaSmart.IOCTL_BUFFER_SIZE; buffers.Spt.TimeOutValue = 2; - buffers.Spt.DataBufferOffset = new UIntPtr((ulong)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf))); - buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); + buffers.Spt.DataBufferOffset = new UIntPtr((ulong)Marshal.OffsetOf(nameof(AtaSmart.SCSI_PASS_THROUGH.DataBuf))); + buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(nameof(AtaSmart.SCSI_PASS_THROUGH.SenseBuf)); buffers.Spt.CdbLength = 16; buffers.Spt.Cdb[0] = 0xB5; // SECURITY PROTOCOL IN buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol buffers.Spt.Cdb[3] = 6; // Log Data buffers.Spt.Cdb[8] = 0; // Transfer Length buffers.Spt.Cdb[9] = 0x40; // Transfer Length - buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_OUT; + buffers.Spt.DataIn = (byte)PInvoke.SCSI_IOCTL_DATA_OUT; buffers.DataBuf[0] = 2; buffers.DataBuf[4] = 0xff; buffers.DataBuf[5] = 0xff; buffers.DataBuf[6] = 0xff; buffers.DataBuf[7] = 0xff; - int length = Marshal.SizeOf(); + int length = Marshal.SizeOf(); IntPtr buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(buffers, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); + bool validTransfer = PInvoke.DeviceIoControl(hDevice, PInvoke.IOCTL_SCSI_PASS_THROUGH, (void*)buffer, (uint)length, (void*)buffer, (uint)length, null, null); Marshal.FreeHGlobal(buffer); if (validTransfer) { //read data from samsung SSD - buffers = new Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS(); + buffers = new AtaSmart.SCSI_PASS_THROUGH(); buffers.Spt.Length = (ushort)sizeof(SCSI_PASS_THROUGH); buffers.Spt.PathId = 0; buffers.Spt.TargetId = 0; buffers.Spt.Lun = 0; buffers.Spt.SenseInfoLength = 24; - buffers.Spt.DataTransferLength = Kernel32.IOCTL_BUFFER_SIZE; + buffers.Spt.DataTransferLength = AtaSmart.IOCTL_BUFFER_SIZE; buffers.Spt.TimeOutValue = 2; - buffers.Spt.DataBufferOffset = new UIntPtr((ulong)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf))); - buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); + buffers.Spt.DataBufferOffset = new UIntPtr((ulong)Marshal.OffsetOf(nameof(AtaSmart.SCSI_PASS_THROUGH.DataBuf))); + buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(nameof(AtaSmart.SCSI_PASS_THROUGH.SenseBuf)); buffers.Spt.CdbLength = 16; buffers.Spt.Cdb[0] = 0xA2; // SECURITY PROTOCOL IN buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol buffers.Spt.Cdb[3] = 6; // Log Data buffers.Spt.Cdb[8] = 2; // Transfer Length (high) buffers.Spt.Cdb[9] = 0; // Transfer Length (low) - buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_IN; + buffers.Spt.DataIn = (byte)PInvoke.SCSI_IOCTL_DATA_IN; - length = Marshal.SizeOf(); + length = Marshal.SizeOf(); buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(buffers, buffer, false); - validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); + validTransfer = PInvoke.DeviceIoControl(hDevice, PInvoke.IOCTL_SCSI_PASS_THROUGH, (void*)buffer, (uint)length, (void*)buffer, (uint)length, null, null); if (validTransfer) { - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); + IntPtr offset = Marshal.OffsetOf(nameof(AtaSmart.SCSI_PASS_THROUGH.DataBuf)); IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); data = Marshal.PtrToStructure(newPtr); Marshal.FreeHGlobal(buffer); @@ -184,67 +186,73 @@ internal class NVMeSamsung : INVMeDrive public static unsafe SafeHandle IdentifyDevice(StorageInfo storageInfo) { - SafeFileHandle handle = Kernel32.OpenDevice(storageInfo.DeviceId); + SafeFileHandle handle = PInvoke.CreateFile(storageInfo.DeviceId, + (uint)FileAccess.ReadWrite, + FILE_SHARE_MODE.FILE_SHARE_READ | FILE_SHARE_MODE.FILE_SHARE_WRITE, + null, + FILE_CREATION_DISPOSITION.OPEN_EXISTING, + FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, + null); if (handle?.IsInvalid != false) return null; - Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS buffers = new(); + AtaSmart.SCSI_PASS_THROUGH buffers = new(); buffers.Spt.Length = (ushort)sizeof(SCSI_PASS_THROUGH); buffers.Spt.PathId = 0; buffers.Spt.TargetId = 0; buffers.Spt.Lun = 0; buffers.Spt.SenseInfoLength = 24; - buffers.Spt.DataTransferLength = Kernel32.IOCTL_BUFFER_SIZE; + buffers.Spt.DataTransferLength = AtaSmart.IOCTL_BUFFER_SIZE; buffers.Spt.TimeOutValue = 2; - buffers.Spt.DataBufferOffset = new UIntPtr((ulong)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf))); - buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); + buffers.Spt.DataBufferOffset = new UIntPtr((ulong)Marshal.OffsetOf(nameof(AtaSmart.SCSI_PASS_THROUGH.DataBuf))); + buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(AtaSmart.SCSI_PASS_THROUGH), nameof(AtaSmart.SCSI_PASS_THROUGH.SenseBuf)); buffers.Spt.CdbLength = 16; buffers.Spt.Cdb[0] = 0xB5; // SECURITY PROTOCOL IN buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol buffers.Spt.Cdb[3] = 5; // Identify buffers.Spt.Cdb[8] = 0; // Transfer Length buffers.Spt.Cdb[9] = 0x40; - buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_OUT; + buffers.Spt.DataIn = (byte)PInvoke.SCSI_IOCTL_DATA_OUT; buffers.DataBuf[0] = 1; - int length = Marshal.SizeOf(); + int length = Marshal.SizeOf(); IntPtr buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(buffers, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); + bool validTransfer = PInvoke.DeviceIoControl(handle, PInvoke.IOCTL_SCSI_PASS_THROUGH, (void*)buffer, (uint)length, (void*)buffer, (uint)length, null, null); Marshal.FreeHGlobal(buffer); if (validTransfer) { //read data from samsung SSD - buffers = new Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS(); + buffers = new AtaSmart.SCSI_PASS_THROUGH(); buffers.Spt.Length = (ushort)sizeof(SCSI_PASS_THROUGH); buffers.Spt.PathId = 0; buffers.Spt.TargetId = 0; buffers.Spt.Lun = 0; buffers.Spt.SenseInfoLength = 24; - buffers.Spt.DataTransferLength = Kernel32.IOCTL_BUFFER_SIZE; + buffers.Spt.DataTransferLength = AtaSmart.IOCTL_BUFFER_SIZE; buffers.Spt.TimeOutValue = 2; - buffers.Spt.DataBufferOffset = new UIntPtr((ulong)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf))); - buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); + buffers.Spt.DataBufferOffset = new UIntPtr((ulong)Marshal.OffsetOf(nameof(AtaSmart.SCSI_PASS_THROUGH.DataBuf))); + buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(AtaSmart.SCSI_PASS_THROUGH), nameof(AtaSmart.SCSI_PASS_THROUGH.SenseBuf)); buffers.Spt.CdbLength = 16; buffers.Spt.Cdb[0] = 0xA2; // SECURITY PROTOCOL IN buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol buffers.Spt.Cdb[3] = 5; // Identify buffers.Spt.Cdb[8] = 2; // Transfer Length buffers.Spt.Cdb[9] = 0; - buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_IN; + buffers.Spt.DataIn = (byte)PInvoke.SCSI_IOCTL_DATA_IN; - length = Marshal.SizeOf(); + length = Marshal.SizeOf(); buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(buffers, buffer, false); - validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); + validTransfer = PInvoke.DeviceIoControl(handle, PInvoke.IOCTL_SCSI_PASS_THROUGH, (void*)buffer, (uint)length, (void*)buffer, (uint)length, null, null); if (validTransfer) { - Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS result = Marshal.PtrToStructure(buffer); + AtaSmart.SCSI_PASS_THROUGH result = Marshal.PtrToStructure(buffer); - if (IsAllZero(result.DataBuf, Kernel32.IOCTL_BUFFER_SIZE)) + if (IsAllZero(result.DataBuf, AtaSmart.IOCTL_BUFFER_SIZE)) { handle.Close(); handle = null; diff --git a/LibreHardwareMonitorLib/Hardware/Storage/NVMeWindows.cs b/LibreHardwareMonitorLib/Hardware/Storage/NVMeWindows.cs index 5e87e96..eb18e48 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/NVMeWindows.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/NVMeWindows.cs @@ -4,11 +4,14 @@ // All Rights Reserved. using System; +using System.IO; using System.Runtime.InteropServices; -using Windows.Win32.Storage.Nvme; -using Windows.Win32.System.Ioctl; using LibreHardwareMonitor.Interop; using Microsoft.Win32.SafeHandles; +using Windows.Win32; +using Windows.Win32.Storage.FileSystem; +using Windows.Win32.Storage.Nvme; +using Windows.Win32.System.Ioctl; namespace LibreHardwareMonitor.Hardware.Storage; @@ -30,7 +33,7 @@ internal class NVMeWindows : INVMeDrive int cb = sizeof(STORAGE_PROPERTY_QUERY) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) + sizeof(NVME_IDENTIFY_CONTROLLER_DATA); IntPtr ptr = Marshal.AllocHGlobal(cb); - Kernel32.RtlZeroMemory(ptr, cb); + Marshal.Copy(new byte[cb], 0, ptr, cb); // Zero memory. STORAGE_PROPERTY_QUERY* query = (STORAGE_PROPERTY_QUERY*)ptr; query->PropertyId = STORAGE_PROPERTY_ID.StorageAdapterProtocolSpecificProperty; @@ -39,11 +42,11 @@ internal class NVMeWindows : INVMeDrive STORAGE_PROTOCOL_SPECIFIC_DATA* protocolData = (STORAGE_PROTOCOL_SPECIFIC_DATA*)(&query->AdditionalParameters); protocolData->ProtocolType = STORAGE_PROTOCOL_TYPE.ProtocolTypeNvme; protocolData->DataType = (uint)STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeIdentify; - protocolData->ProtocolDataRequestValue = (uint)Kernel32.STORAGE_PROTOCOL_NVME_PROTOCOL_DATA_REQUEST_VALUE.NVMeIdentifyCnsController; + protocolData->ProtocolDataRequestValue = 1; protocolData->ProtocolDataOffset = (uint)sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA); protocolData->ProtocolDataLength = (uint)sizeof(NVME_IDENTIFY_CONTROLLER_DATA); - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_STORAGE_QUERY_PROPERTY, ptr, cb, ptr, cb, out _, IntPtr.Zero); + bool validTransfer = PInvoke.DeviceIoControl(hDevice, PInvoke.IOCTL_STORAGE_QUERY_PROPERTY, (void*)ptr, (uint)cb, (void*)ptr, (uint)cb, null, null); if (validTransfer) { var dataDescriptor = (STORAGE_PROTOCOL_DATA_DESCRIPTOR*)ptr; @@ -70,7 +73,7 @@ internal class NVMeWindows : INVMeDrive int cb = sizeof(STORAGE_PROPERTY_QUERY) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) + sizeof(NVME_HEALTH_INFO_LOG); IntPtr ptr = Marshal.AllocHGlobal(cb); - Kernel32.RtlZeroMemory(ptr, cb); + Marshal.Copy(new byte[cb], 0, ptr, cb); // Zero memory. STORAGE_PROPERTY_QUERY* query = (STORAGE_PROPERTY_QUERY*)ptr; query->PropertyId = STORAGE_PROPERTY_ID.StorageAdapterProtocolSpecificProperty; @@ -83,7 +86,7 @@ internal class NVMeWindows : INVMeDrive protocolData->ProtocolDataOffset = (uint)sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA); protocolData->ProtocolDataLength = (uint)sizeof(NVME_HEALTH_INFO_LOG); - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_STORAGE_QUERY_PROPERTY, ptr, cb, ptr, cb, out _, IntPtr.Zero); + bool validTransfer = PInvoke.DeviceIoControl(hDevice, PInvoke.IOCTL_STORAGE_QUERY_PROPERTY, (void*)ptr, (uint)cb, (void*)ptr, (uint)cb, null, null); if (validTransfer) { var dataDescriptor = (STORAGE_PROTOCOL_DATA_DESCRIPTOR*)ptr; @@ -103,7 +106,13 @@ internal class NVMeWindows : INVMeDrive public static SafeHandle IdentifyDevice(StorageInfo storageInfo) { - SafeFileHandle handle = Kernel32.OpenDevice(storageInfo.DeviceId); + SafeFileHandle handle = PInvoke.CreateFile(storageInfo.DeviceId, + (uint)FileAccess.ReadWrite, + FILE_SHARE_MODE.FILE_SHARE_READ | FILE_SHARE_MODE.FILE_SHARE_WRITE, + null, + FILE_CREATION_DISPOSITION.OPEN_EXISTING, + FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, + null); if (handle?.IsInvalid != false) return null; diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SmartAttribute.cs b/LibreHardwareMonitorLib/Hardware/Storage/SmartAttribute.cs index d55df41..fb5ef7c 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SmartAttribute.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SmartAttribute.cs @@ -4,7 +4,9 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. +using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using LibreHardwareMonitor.Interop; namespace LibreHardwareMonitor.Hardware.Storage; @@ -93,10 +95,12 @@ public class SmartAttribute public SensorType? SensorType { get; } - internal float ConvertValue(Kernel32.SMART_ATTRIBUTE value, IReadOnlyList parameters) + internal unsafe float ConvertValue(AtaSmart.SMART_ATTRIBUTE value, IReadOnlyList parameters) { if (_rawValueConversion == null) return value.CurrentValue; - return _rawValueConversion(value.RawValue, value.CurrentValue, parameters); + + Span rawValue = new(value.RawValue, 6); + return _rawValueConversion(rawValue.ToArray(), value.CurrentValue, parameters); } -} \ No newline at end of file +} diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdMicron.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdMicron.cs index 5db2477..4ae6c2e 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdMicron.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdMicron.cs @@ -4,6 +4,7 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. +using System; using System.Collections.Generic; using LibreHardwareMonitor.Interop; @@ -82,24 +83,26 @@ internal class SsdMicron : AtaStorage } /// - protected override void UpdateAdditionalSensors(Kernel32.SMART_ATTRIBUTE[] values) + protected override unsafe void UpdateAdditionalSensors(AtaSmart.SMART_ATTRIBUTE[] values) { float? hostProgramPagesCount = null; float? ftlProgramPagesCount = null; - foreach (Kernel32.SMART_ATTRIBUTE value in values) + foreach (AtaSmart.SMART_ATTRIBUTE value in values) { + byte[] rawValue = new Span(value.RawValue, 6).ToArray(); + if (value.Id == 0xF7) - hostProgramPagesCount = RawToInt(value.RawValue, value.CurrentValue, null); + hostProgramPagesCount = RawToInt(rawValue, value.CurrentValue, null); if (value.Id == 0xF8) - ftlProgramPagesCount = RawToInt(value.RawValue, value.CurrentValue, null); + ftlProgramPagesCount = RawToInt(rawValue, value.CurrentValue, null); if (value.Id == 0xC2) { - _temperature.Value = value.RawValue[0] + _temperature.Parameters[0].Value; + _temperature.Value = rawValue[0] + _temperature.Parameters[0].Value; - if (value.RawValue[0] != 0) + if (rawValue[0] != 0) ActivateSensor(_temperature); } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdSandforce.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdSandforce.cs index 5e16353..cd15703 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdSandforce.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdSandforce.cs @@ -4,6 +4,7 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. +using System; using System.Collections.Generic; using LibreHardwareMonitor.Interop; @@ -50,17 +51,19 @@ internal class SsdSandforce : AtaStorage _writeAmplification = new Sensor("Write Amplification", 1, SensorType.Factor, this, settings); } - protected override void UpdateAdditionalSensors(Kernel32.SMART_ATTRIBUTE[] values) + protected override unsafe void UpdateAdditionalSensors(AtaSmart.SMART_ATTRIBUTE[] values) { float? controllerWritesToNand = null; float? hostWritesToController = null; - foreach (Kernel32.SMART_ATTRIBUTE value in values) + foreach (AtaSmart.SMART_ATTRIBUTE value in values) { + byte[] rawValue = new Span(value.RawValue, 6).ToArray(); + if (value.Id == 0xE9) - controllerWritesToNand = RawToInt(value.RawValue, value.CurrentValue, null); + controllerWritesToNand = RawToInt(rawValue, value.CurrentValue, null); if (value.Id == 0xEA) - hostWritesToController = RawToInt(value.RawValue, value.CurrentValue, null); + hostWritesToController = RawToInt(rawValue, value.CurrentValue, null); } if (controllerWritesToNand.HasValue && hostWritesToController.HasValue) diff --git a/LibreHardwareMonitorLib/Hardware/Storage/WindowsSmart.cs b/LibreHardwareMonitorLib/Hardware/Storage/WindowsSmart.cs index edb4822..b369ca7 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/WindowsSmart.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/WindowsSmart.cs @@ -5,12 +5,13 @@ // All Rights Reserved. using System; -using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; -using Windows.Win32; -using Windows.Win32.System.Ioctl; +using System.Text; using LibreHardwareMonitor.Interop; +using Windows.Win32; +using Windows.Win32.Storage.FileSystem; +using Windows.Win32.System.Ioctl; namespace LibreHardwareMonitor.Hardware.Storage; @@ -22,7 +23,7 @@ internal class WindowsSmart : ISmart public WindowsSmart(int driveNumber) { _driveNumber = driveNumber; - _handle = Kernel32.CreateFile(@"\\.\PhysicalDrive" + driveNumber, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); + _handle = PInvoke.CreateFile(@"\\.\PhysicalDrive" + driveNumber, (uint)FileAccess.ReadWrite, FILE_SHARE_MODE.FILE_SHARE_READ | FILE_SHARE_MODE.FILE_SHARE_WRITE, null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, null); } public bool IsValid => !_handle.IsInvalid && !_handle.IsClosed; @@ -48,10 +49,10 @@ internal class WindowsSmart : ISmart bDriveNumber = (byte)_driveNumber, irDriveRegs = { - bFeaturesReg = (byte)Kernel32.SMART_FEATURES.ENABLE_SMART, - bCylLowReg = Kernel32.SMART_LBA_MID, - bCylHighReg = Kernel32.SMART_LBA_HI, - bCommandReg = (byte)Kernel32.ATA_COMMAND.ATA_SMART + bFeaturesReg = 0xD8, + bCylLowReg = AtaSmart.SMART_LBA_MID, + bCylHighReg = AtaSmart.SMART_LBA_HI, + bCommandReg = (byte) PInvoke.SMART_CMD } }; @@ -67,7 +68,7 @@ internal class WindowsSmart : ISmart null); } - public Kernel32.SMART_ATTRIBUTE[] ReadSmartData() + public unsafe AtaSmart.SMART_ATTRIBUTE[] ReadSmartData() { if (_handle.IsClosed) throw new ObjectDisposedException(nameof(WindowsSmart)); @@ -77,26 +78,42 @@ internal class WindowsSmart : ISmart bDriveNumber = (byte)_driveNumber, irDriveRegs = { - bFeaturesReg = (byte)Kernel32.SMART_FEATURES.SMART_READ_DATA, - bCylLowReg = Kernel32.SMART_LBA_MID, - bCylHighReg = Kernel32.SMART_LBA_HI, - bCommandReg = (byte)Kernel32.ATA_COMMAND.ATA_SMART + bFeaturesReg = 0xD0, + bCylLowReg = AtaSmart.SMART_LBA_MID, + bCylHighReg = AtaSmart.SMART_LBA_HI, + bCommandReg = (byte) PInvoke.SMART_CMD } }; - bool isValid = Kernel32.DeviceIoControl(_handle, - Kernel32.DFP.DFP_RECEIVE_DRIVE_DATA, - ref parameter, - Marshal.SizeOf(parameter), - out Kernel32.ATTRIBUTECMDOUTPARAMS result, - Marshal.SizeOf(), - out _, - IntPtr.Zero); + int cb = sizeof(SENDCMDOUTPARAMS) + 2 + 512; // 2 bytes padding + 512 bytes buffer. + IntPtr buffer = Marshal.AllocHGlobal(cb); - return isValid ? result.Attributes : []; + bool isValid = PInvoke.DeviceIoControl(_handle, + PInvoke.SMART_RCV_DRIVE_DATA, + ¶meter, + (uint)sizeof(SENDCMDINPARAMS), + (void*)buffer, + (uint)cb, + null, + null); + + if (isValid) + { + AtaSmart.SMART_ATTRIBUTE[] attributes = new AtaSmart.SMART_ATTRIBUTE[512 / sizeof(AtaSmart.SMART_ATTRIBUTE)]; + AtaSmart.SMART_ATTRIBUTE* pAttributes = (AtaSmart.SMART_ATTRIBUTE*)((byte*)buffer + (int)Marshal.OffsetOf(nameof(SENDCMDOUTPARAMS.bBuffer)) + 2); + + for (int i = 0; i < attributes.Length; i++) + attributes[i] = pAttributes[i]; + + Marshal.FreeHGlobal(buffer); + return attributes; + } + + Marshal.FreeHGlobal(buffer); + return null; } - public Kernel32.SMART_THRESHOLD[] ReadSmartThresholds() + public unsafe AtaSmart.SMART_THRESHOLD[] ReadSmartThresholds() { if (_handle.IsClosed) throw new ObjectDisposedException(nameof(WindowsSmart)); @@ -106,105 +123,95 @@ internal class WindowsSmart : ISmart bDriveNumber = (byte)_driveNumber, irDriveRegs = { - bFeaturesReg = (byte)Kernel32.SMART_FEATURES.READ_THRESHOLDS, - bCylLowReg = Kernel32.SMART_LBA_MID, - bCylHighReg = Kernel32.SMART_LBA_HI, - bCommandReg = (byte)Kernel32.ATA_COMMAND.ATA_SMART + bFeaturesReg = 0xD1, + bCylLowReg = AtaSmart.SMART_LBA_MID, + bCylHighReg = AtaSmart.SMART_LBA_HI, + bCommandReg = (byte) PInvoke.SMART_CMD } }; - bool isValid = Kernel32.DeviceIoControl(_handle, - Kernel32.DFP.DFP_RECEIVE_DRIVE_DATA, - ref parameter, - Marshal.SizeOf(parameter), - out Kernel32.THRESHOLDCMDOUTPARAMS result, - Marshal.SizeOf(), - out _, - IntPtr.Zero); + int cb = sizeof(SENDCMDOUTPARAMS) + 2 + 512; // 2 bytes padding + 512 bytes buffer. + IntPtr buffer = Marshal.AllocHGlobal(cb); + bool isValid = PInvoke.DeviceIoControl(_handle, + PInvoke.SMART_RCV_DRIVE_DATA, + ¶meter, + (uint)sizeof(SENDCMDINPARAMS), + (void*)buffer, + (uint)cb, + null, + null); - return isValid ? result.Thresholds : []; + if (isValid) + { + AtaSmart.SMART_THRESHOLD[] thresholds = new AtaSmart.SMART_THRESHOLD[512 / sizeof(AtaSmart.SMART_THRESHOLD)]; + AtaSmart.SMART_THRESHOLD* pThresholds = (AtaSmart.SMART_THRESHOLD*) ((byte*)buffer + (int)Marshal.OffsetOf(nameof(SENDCMDOUTPARAMS.bBuffer)) + 2); + + for (int i = 0; i < thresholds.Length; i++) + thresholds[i] = pThresholds[i]; + + Marshal.FreeHGlobal(buffer); + return thresholds; + } + + Marshal.FreeHGlobal(buffer); + return null; } - public bool ReadNameAndFirmwareRevision(out string name, out string firmwareRevision) + public unsafe bool ReadNameAndFirmwareRevision(out string name, out string firmwareRevision) { if (_handle.IsClosed) throw new ObjectDisposedException(nameof(WindowsSmart)); - var parameter = new SENDCMDINPARAMS { bDriveNumber = (byte)_driveNumber, irDriveRegs = { bCommandReg = (byte)Kernel32.ATA_COMMAND.ATA_IDENTIFY_DEVICE } }; + var parameter = new SENDCMDINPARAMS + { + bDriveNumber = (byte)_driveNumber, + irDriveRegs = + { + bCommandReg = 0xEC + } + }; - bool valid = Kernel32.DeviceIoControl(_handle, - Kernel32.DFP.DFP_RECEIVE_DRIVE_DATA, - ref parameter, - Marshal.SizeOf(parameter), - out Kernel32.IDENTIFYCMDOUTPARAMS result, - Marshal.SizeOf(), - out _, - IntPtr.Zero); + int cb = sizeof(SENDCMDOUTPARAMS) + sizeof(AtaSmart.IDENTIFY_DEVICE_DATA); + IntPtr buffer = Marshal.AllocHGlobal(cb); + + bool valid = PInvoke.DeviceIoControl(_handle, + PInvoke.SMART_RCV_DRIVE_DATA, + ¶meter, + (uint)sizeof(SENDCMDINPARAMS), + (void*)buffer, + (uint)cb, + null, + null); if (!valid) { + Marshal.FreeHGlobal(buffer); name = null; firmwareRevision = null; return false; } - name = GetString(result.Identify.ModelNumber); - firmwareRevision = GetString(result.Identify.FirmwareRevision); + AtaSmart.IDENTIFY_DEVICE_DATA identity = *(AtaSmart.IDENTIFY_DEVICE_DATA*)((byte*)buffer + (int)Marshal.OffsetOf(nameof(SENDCMDOUTPARAMS.bBuffer))); + + byte* p = identity.ModelNumber; + for (int i = 0; i < 40; i += 2) + { + (p[i], p[i + 1]) = (p[i + 1], p[i]); + } + + p = identity.FirmwareRevision; + for (int i = 0; i < 8; i += 2) + { + (p[i], p[i + 1]) = (p[i + 1], p[i]); + } + + name = Encoding.ASCII.GetString(identity.ModelNumber, 40).Trim(); + firmwareRevision = Encoding.ASCII.GetString(identity.FirmwareRevision, 8); + + Marshal.FreeHGlobal(buffer); return true; } - /// - /// Reads Smart health status of the drive - /// - /// True, if drive is healthy; False, if unhealthy; Null, if it cannot be read - public bool? ReadSmartHealth() - { - if (_handle.IsClosed) - throw new ObjectDisposedException(nameof(WindowsSmart)); - - var parameter = new SENDCMDINPARAMS - { - bDriveNumber = (byte)_driveNumber, - irDriveRegs = - { - bFeaturesReg = (byte)Kernel32.SMART_FEATURES.RETURN_SMART_STATUS, - bCylLowReg = Kernel32.SMART_LBA_MID, - bCylHighReg = Kernel32.SMART_LBA_HI, - bCommandReg = (byte)Kernel32.ATA_COMMAND.ATA_SMART - } - }; - - bool isValid = Kernel32.DeviceIoControl(_handle, - Kernel32.DFP.DFP_SEND_DRIVE_COMMAND, - ref parameter, - Marshal.SizeOf(parameter), - out Kernel32.STATUSCMDOUTPARAMS result, - Marshal.SizeOf(), - out _, - IntPtr.Zero); - - if (!isValid) - { - return null; - } - - // reference: https://github.com/smartmontools/smartmontools/blob/master/smartmontools/atacmds.cpp - if (Kernel32.SMART_LBA_HI == result.irDriveRegs.bCylHighReg && Kernel32.SMART_LBA_MID == result.irDriveRegs.bCylLowReg) - { - // high and mid registers are unchanged, which means that the drive is healthy - return true; - } - - if (Kernel32.SMART_LBA_HI_EXCEEDED == result.irDriveRegs.bCylHighReg && Kernel32.SMART_LBA_MID_EXCEEDED == result.irDriveRegs.bCylLowReg) - { - // high and mid registers are exceeded, which means that the drive is unhealthy - return false; - } - - // response is not clear - return null; - } - protected void Dispose(bool disposing) { if (disposing && !_handle.IsClosed) @@ -212,16 +219,4 @@ internal class WindowsSmart : ISmart _handle.Close(); } } - - private static string GetString(IReadOnlyList bytes) - { - char[] chars = new char[bytes.Count]; - for (int i = 0; i < bytes.Count; i += 2) - { - chars[i] = (char)bytes[i + 1]; - chars[i + 1] = (char)bytes[i]; - } - - return new string(chars).Trim(' ', '\0'); - } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/WindowsStorage.cs b/LibreHardwareMonitorLib/Hardware/Storage/WindowsStorage.cs index c109a48..a70bff7 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/WindowsStorage.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/WindowsStorage.cs @@ -5,11 +5,12 @@ using System; using System.Collections.Generic; +using System.IO; using System.Management; using System.Runtime.InteropServices; using Windows.Win32; +using Windows.Win32.Storage.FileSystem; using Windows.Win32.System.Ioctl; -using LibreHardwareMonitor.Interop; using Microsoft.Win32.SafeHandles; namespace LibreHardwareMonitor.Hardware.Storage; @@ -18,7 +19,13 @@ internal static class WindowsStorage { public static unsafe Storage.StorageInfo GetStorageInfo(string deviceId, uint driveIndex) { - using SafeFileHandle handle = Kernel32.OpenDevice(deviceId); + using SafeFileHandle handle = PInvoke.CreateFile(deviceId, + (uint)FileAccess.ReadWrite, + FILE_SHARE_MODE.FILE_SHARE_READ | FILE_SHARE_MODE.FILE_SHARE_WRITE, + null, + FILE_CREATION_DISPOSITION.OPEN_EXISTING, + FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, + null); if (handle?.IsInvalid != false) return null; diff --git a/LibreHardwareMonitorLib/Interop/AtaSmart.cs b/LibreHardwareMonitorLib/Interop/AtaSmart.cs new file mode 100644 index 0000000..8b4d7d1 --- /dev/null +++ b/LibreHardwareMonitorLib/Interop/AtaSmart.cs @@ -0,0 +1,98 @@ +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// Copyright (C) LibreHardwareMonitor and Contributors. +// All Rights Reserved. + +using Windows.Win32.Storage.IscsiDisc; + +// ReSharper disable InconsistentNaming + +namespace LibreHardwareMonitor.Interop; + +public class AtaSmart +{ + internal const int IOCTL_BUFFER_SIZE = 4096; + internal const int SCSI_IOCTL_SENSE_SIZE = 24; + internal const int NVME_IOCTL_CMD_DW_SIZE = 16; + internal const int NVME_IOCTL_COMPLETE_DW_SIZE = 4; + internal const int NVME_IOCTL_VENDOR_SPECIFIC_DW_SIZE = 6; + + internal const int NVME_DATA_OUT = 1; + internal const int NVME_DATA_IN = 2; + + internal const uint NVME_PASS_THROUGH_SRB_IO_CODE = 0xe0002000; + + internal const byte SMART_LBA_HI = 0xC2; + internal const byte SMART_LBA_MID = 0x4F; + + public unsafe struct SMART_ATTRIBUTE + { + public byte Id; + public short Flags; + public byte CurrentValue; + public byte WorstValue; + public fixed byte RawValue[6]; + public byte Reserved; + } + + public unsafe struct SMART_THRESHOLD + { + public byte Id; + public byte Threshold; + public fixed byte Reserved[10]; + } + + internal unsafe struct IDENTIFY_DEVICE_DATA + { + public ushort GeneralConfiguration; + public ushort NumberOfCylinders; + public ushort Reserved1; + public ushort NumberOfHeads; + public ushort UnformattedBytesPerTrack; + public ushort UnformattedBytesPerSector; + public ushort SectorsPerTrack; + public fixed ushort VendorUnique[3]; + public fixed byte SerialNumber[20]; + public ushort BufferType; + public ushort BufferSectorSize; + public ushort NumberOfEccBytes; + public fixed byte FirmwareRevision[8]; + public fixed byte ModelNumber[40]; + public byte MaximumBlockTransfer; + public byte VendorUnique2; + public ushort DoubleWordIo; + public ushort Capabilities; + public ushort Reserved2; + public byte VendorUnique3; + public byte PioCycleTimingMode; + public byte VendorUnique4; + public byte DmaCycleTimingMode; + public ushort TranslationFieldsValid; + public ushort NumberOfCurrentCylinders; + public ushort NumberOfCurrentHeads; + public ushort CurrentSectorsPerTrack; + public uint CurrentSectorCapacity; + public fixed ushort Reserved3[197]; + } + + internal unsafe struct NVME_PASS_THROUGH_IOCTL + { + public SRB_IO_CONTROL SrbIoCtrl; + public fixed uint VendorSpecific[NVME_IOCTL_VENDOR_SPECIFIC_DW_SIZE]; + public fixed uint NVMeCmd[NVME_IOCTL_CMD_DW_SIZE]; + public fixed uint CplEntry[NVME_IOCTL_COMPLETE_DW_SIZE]; + public uint Direction; + public uint QueueId; + public uint DataBufferLen; + public uint MetaDataLen; + public uint ReturnBufferLen; + public fixed byte DataBuffer[IOCTL_BUFFER_SIZE]; + } + + internal unsafe struct SCSI_PASS_THROUGH + { + public Windows.Win32.Storage.IscsiDisc.SCSI_PASS_THROUGH Spt; + public fixed byte SenseBuf[SCSI_IOCTL_SENSE_SIZE]; + public fixed byte DataBuf[IOCTL_BUFFER_SIZE]; + } +} diff --git a/LibreHardwareMonitorLib/Interop/Kernel32.cs b/LibreHardwareMonitorLib/Interop/Kernel32.cs deleted file mode 100644 index 194449f..0000000 --- a/LibreHardwareMonitorLib/Interop/Kernel32.cs +++ /dev/null @@ -1,408 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. -// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -// Copyright (C) LibreHardwareMonitor and Contributors. -// All Rights Reserved. - -using System; -using System.IO; -using System.Runtime.InteropServices; -using Windows.Win32.Storage.IscsiDisc; -using Windows.Win32.System.Ioctl; -using Microsoft.Win32.SafeHandles; - -// ReSharper disable InconsistentNaming - -namespace LibreHardwareMonitor.Interop; - -public class Kernel32 -{ - public const int ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420); - public const int ERROR_SERVICE_EXISTS = unchecked((int)0x80070431); - - public const int IOCTL_BUFFER_SIZE = 4096; - public const int NVME_IOCTL_CMD_DW_SIZE = 16; - public const int NVME_IOCTL_COMPLETE_DW_SIZE = 4; - public const int NVME_IOCTL_VENDOR_SPECIFIC_DW_SIZE = 6; - public const int SCSI_IOCTL_SENSE_SIZE = 24; - - internal const uint BATTERY_UNKNOWN_CAPACITY = 0xFFFFFFFF; - internal const int BATTERY_UNKNOWN_RATE = unchecked((int)0x80000000); - internal const uint BATTERY_UNKNOWN_TIME = 0xFFFFFFFF; - internal const uint BATTERY_UNKNOWN_VOLTAGE = 0xFFFFFFFF; - - internal const uint LPTR = 0x0000 | 0x0040; - - internal const int MAX_DRIVE_ATTRIBUTES = 512; - internal const uint NVME_PASS_THROUGH_SRB_IO_CODE = 0xe0002000; - internal const byte SMART_LBA_HI = 0xC2; - internal const byte SMART_LBA_HI_EXCEEDED = 0x2C; - internal const byte SMART_LBA_MID = 0x4F; - internal const byte SMART_LBA_MID_EXCEEDED = 0xF4; - - private const string DllName = "kernel32.dll"; - - internal static SafeFileHandle OpenDevice(string devicePath) - { - SafeFileHandle hDevice = CreateFile(devicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); - if (hDevice.IsInvalid || hDevice.IsClosed) - hDevice = null; - - return hDevice; - } - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern SafeFileHandle CreateFile - ( - [MarshalAs(UnmanagedType.LPTStr)] string lpFileName, - [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess, - [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode, - IntPtr lpSecurityAttributes, - [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition, - [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes, - IntPtr hTemplateFile); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeHandle hDevice, - DFP dwIoControlCode, - ref SENDCMDINPARAMS lpInBuffer, - int nInBufferSize, - out ATTRIBUTECMDOUTPARAMS lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeHandle hDevice, - DFP dwIoControlCode, - ref SENDCMDINPARAMS lpInBuffer, - int nInBufferSize, - out THRESHOLDCMDOUTPARAMS lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeHandle hDevice, - DFP dwIoControlCode, - ref SENDCMDINPARAMS lpInBuffer, - int nInBufferSize, - out IDENTIFYCMDOUTPARAMS lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeHandle hDevice, - DFP dwIoControlCode, - ref SENDCMDINPARAMS lpInBuffer, - int nInBufferSize, - out STATUSCMDOUTPARAMS lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeHandle hDevice, - IOCTL dwIoControlCode, - IntPtr lpInBuffer, - int nInBufferSize, - IntPtr lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeFileHandle hDevice, - uint dwIoControlCode, - [In] byte[] lpInBuffer, - uint nInBufferSize, - [Out] byte[] lpOutBuffer, - uint nOutBufferSize, - ref uint lpBytesReturned, - [In] [Optional] IntPtr lpOverlapped); - - [DllImport(DllName, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern void RtlZeroMemory(IntPtr Destination, int Length); - - [DllImport(DllName, SetLastError = false)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern void RtlCopyMemory(IntPtr Destination, IntPtr Source, uint Length); - - internal enum DFP : uint - { - DFP_GET_VERSION = 0x00074080, - DFP_SEND_DRIVE_COMMAND = 0x0007c084, - DFP_RECEIVE_DRIVE_DATA = 0x0007c088 - } - - internal enum IOCTL : uint - { - IOCTL_SCSI_PASS_THROUGH = 0x04d004, - IOCTL_SCSI_MINIPORT = 0x04d008, - IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x04d014, - IOCTL_SCSI_GET_ADDRESS = 0x41018, - IOCTL_DISK_PERFORMANCE = 0x70020, - IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400, - IOCTL_BATTERY_QUERY_TAG = 0x294040, - IOCTL_BATTERY_QUERY_INFORMATION = 0x294044, - IOCTL_BATTERY_QUERY_STATUS = 0x29404C - } - - [Flags] - internal enum NVME_DIRECTION : uint - { - NVME_FROM_HOST_TO_DEV = 1, - NVME_FROM_DEV_TO_HOST = 2, - NVME_BI_DIRECTION = NVME_FROM_DEV_TO_HOST | NVME_FROM_HOST_TO_DEV - } - - internal enum ATA_COMMAND : byte - { - /// - /// SMART data requested. - /// - ATA_SMART = 0xB0, - - /// - /// Identify data is requested. - /// - ATA_IDENTIFY_DEVICE = 0xEC - } - - internal enum SCSI_IOCTL_DATA - { - SCSI_IOCTL_DATA_OUT = 0, - SCSI_IOCTL_DATA_IN = 1, - SCSI_IOCTL_DATA_UNSPECIFIED = 2 - } - - internal enum SMART_FEATURES : byte - { - /// - /// Read SMART data. - /// - SMART_READ_DATA = 0xD0, - - /// - /// Read SMART thresholds. - /// obsolete - /// - READ_THRESHOLDS = 0xD1, - - /// - /// Autosave SMART data. - /// - ENABLE_DISABLE_AUTOSAVE = 0xD2, - - /// - /// Save SMART attributes. - /// - SAVE_ATTRIBUTE_VALUES = 0xD3, - - /// - /// Set SMART to offline immediately. - /// - EXECUTE_OFFLINE_DIAGS = 0xD4, - - /// - /// Read SMART log. - /// - SMART_READ_LOG = 0xD5, - - /// - /// Write SMART log. - /// - SMART_WRITE_LOG = 0xD6, - - /// - /// Write SMART thresholds. - /// obsolete - /// - WRITE_THRESHOLDS = 0xD7, - - /// - /// Enable SMART. - /// - ENABLE_SMART = 0xD8, - - /// - /// Disable SMART. - /// - DISABLE_SMART = 0xD9, - - /// - /// Get SMART status. - /// - RETURN_SMART_STATUS = 0xDA, - - /// - /// Set SMART to offline automatically. - /// - ENABLE_DISABLE_AUTO_OFFLINE = 0xDB /* obsolete */ - } - - internal enum STORAGE_PROTOCOL_NVME_PROTOCOL_DATA_REQUEST_VALUE - { - NVMeIdentifyCnsSpecificNamespace = 0, - NVMeIdentifyCnsController = 1, - NVMeIdentifyCnsActiveNamespaces = 2 - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct SMART_ATTRIBUTE - { - public byte Id; - public short Flags; - public byte CurrentValue; - public byte WorstValue; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public byte[] RawValue; - - public byte Reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct SMART_THRESHOLD - { - public byte Id; - public byte Threshold; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public byte[] Reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct ATTRIBUTECMDOUTPARAMS - { - public uint cBufferSize; - public DRIVERSTATUS DriverStatus; - public byte Version; - public byte Reserved; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)] - public SMART_ATTRIBUTE[] Attributes; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct THRESHOLDCMDOUTPARAMS - { - public uint cBufferSize; - public DRIVERSTATUS DriverStatus; - public byte Version; - public byte Reserved; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)] - public SMART_THRESHOLD[] Thresholds; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct STATUSCMDOUTPARAMS - { - public uint cBufferSize; - public DRIVERSTATUS DriverStatus; - public IDEREGS irDriveRegs; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct IDENTIFY_DEVICE_DATA - { - public ushort GeneralConfiguration; - public ushort NumberOfCylinders; - public ushort Reserved1; - public ushort NumberOfHeads; - public ushort UnformattedBytesPerTrack; - public ushort UnformattedBytesPerSector; - public ushort SectorsPerTrack; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public ushort[] VendorUnique; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] - public byte[] SerialNumber; - - public ushort BufferType; - public ushort BufferSectorSize; - public ushort NumberOfEccBytes; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] FirmwareRevision; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] - public byte[] ModelNumber; - - public byte MaximumBlockTransfer; - public byte VendorUnique2; - public ushort DoubleWordIo; - public ushort Capabilities; - public ushort Reserved2; - public byte VendorUnique3; - public byte PioCycleTimingMode; - public byte VendorUnique4; - public byte DmaCycleTimingMode; - public ushort TranslationFieldsValid; - public ushort NumberOfCurrentCylinders; - public ushort NumberOfCurrentHeads; - public ushort CurrentSectorsPerTrack; - public uint CurrentSectorCapacity; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 197)] - public ushort[] Reserved3; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct IDENTIFYCMDOUTPARAMS - { - public uint cBufferSize; - public DRIVERSTATUS DriverStatus; - public IDENTIFY_DEVICE_DATA Identify; - } - - internal unsafe struct NVME_PASS_THROUGH_IOCTL - { - public SRB_IO_CONTROL SrbIoCtrl; - public fixed uint VendorSpecific[NVME_IOCTL_VENDOR_SPECIFIC_DW_SIZE]; - public fixed uint NVMeCmd[NVME_IOCTL_CMD_DW_SIZE]; - public fixed uint CplEntry[NVME_IOCTL_COMPLETE_DW_SIZE]; - public NVME_DIRECTION Direction; - public uint QueueId; - public uint DataBufferLen; - public uint MetaDataLen; - public uint ReturnBufferLen; - public fixed byte DataBuffer[IOCTL_BUFFER_SIZE]; - } - - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct SCSI_PASS_THROUGH_WITH_BUFFERS - { - public SCSI_PASS_THROUGH Spt; - public fixed byte SenseBuf[SCSI_IOCTL_SENSE_SIZE]; - public fixed byte DataBuf[IOCTL_BUFFER_SIZE]; - } -} diff --git a/LibreHardwareMonitorLib/NativeMethods.txt b/LibreHardwareMonitorLib/NativeMethods.txt index f414461..5ab08d8 100644 --- a/LibreHardwareMonitorLib/NativeMethods.txt +++ b/LibreHardwareMonitorLib/NativeMethods.txt @@ -55,6 +55,7 @@ BATTERY_SYSTEM_BATTERY BATTERY_STATUS BATTERY_WAIT_STATUS SMART_SEND_DRIVE_COMMAND +SMART_RCV_DRIVE_DATA CreateFile VirtualFree VirtualAlloc @@ -63,3 +64,6 @@ IOCTL_* LoadLibrary FreeLibrary GetProcAddress +SCSI_IOCTL_* +SMART_CMD +BATTERY_UNKNOWN_* diff --git a/LibreHardwareMonitorLib/PawnIo/PawnIo.cs b/LibreHardwareMonitorLib/PawnIo/PawnIo.cs index d993baa..22a0188 100644 --- a/LibreHardwareMonitorLib/PawnIo/PawnIo.cs +++ b/LibreHardwareMonitorLib/PawnIo/PawnIo.cs @@ -4,6 +4,7 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Text; using Windows.Win32.Foundation; +using Windows.Win32.Storage.FileSystem; using LibreHardwareMonitor.Interop; using Microsoft.Win32; using Microsoft.Win32.SafeHandles; @@ -42,28 +43,38 @@ public class PawnIo /// public static Version Version { get; } + /// + /// Gets a value indicating whether the underlying handle is currently valid and open. + /// public bool IsLoaded => _handle is { IsInvalid: false, IsClosed: false }; - internal static PawnIo LoadModuleFromResource(Assembly assembly, string resourceName) + internal static unsafe PawnIo LoadModuleFromResource(Assembly assembly, string resourceName) { - SafeFileHandle handle = Kernel32.CreateFile(@"\\.\PawnIO", FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); + SafeFileHandle handle = PInvoke.CreateFile(@"\\.\PawnIO", + (uint)FileAccess.ReadWrite, + FILE_SHARE_MODE.FILE_SHARE_READ | FILE_SHARE_MODE.FILE_SHARE_WRITE, + null, + FILE_CREATION_DISPOSITION.OPEN_EXISTING, + FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, + null); if (handle.IsInvalid) return new PawnIo(null); - uint read = 0; - - using var stream = assembly.GetManifestResourceStream(resourceName); + using Stream stream = assembly.GetManifestResourceStream(resourceName); using MemoryStream memory = new(); stream.CopyTo(memory); byte[] bin = memory.ToArray(); - if (Kernel32.DeviceIoControl(handle, (uint)ControlCode.LoadBinary, bin, (uint)bin.Length, null, 0u, ref read, IntPtr.Zero)) - return new PawnIo(handle); + fixed (byte* pIn = bin) + { + if (PInvoke.DeviceIoControl(handle, (uint)ControlCode.LoadBinary, pIn, (uint)bin.Length, null, 0u, null, null)) + return new PawnIo(handle); + } return new PawnIo(null); } @@ -74,28 +85,32 @@ public class PawnIo _handle.Close(); } - public long[] Execute(string name, long[] input, int outLength) + public unsafe long[] Execute(string name, long[] input, int outLength) { if (IsLoaded) { byte[] output = new byte[outLength * sizeof(long)]; - byte[] inp = new byte[(input.Length * sizeof(long)) + FN_NAME_LENGTH]; - Buffer.BlockCopy(Encoding.ASCII.GetBytes(name), 0, inp, 0, Math.Min(FN_NAME_LENGTH - 1, name.Length)); - Buffer.BlockCopy(input, 0, inp, FN_NAME_LENGTH, input.Length * sizeof(long)); + byte[] totalInput = new byte[(input.Length * sizeof(long)) + FN_NAME_LENGTH]; + Buffer.BlockCopy(Encoding.ASCII.GetBytes(name), 0, totalInput, 0, Math.Min(FN_NAME_LENGTH - 1, name.Length)); + Buffer.BlockCopy(input, 0, totalInput, FN_NAME_LENGTH, input.Length * sizeof(long)); uint read = 0; - if (Kernel32.DeviceIoControl(_handle, (uint)ControlCode.Execute, inp, (uint)inp.Length, output, (uint)output.Length, ref read)) + + fixed (byte* pIn = totalInput, pOut = output) { - long[] outp = new long[read / sizeof(long)]; - Buffer.BlockCopy(output, 0, outp, 0, (int)read); - return outp; + if (PInvoke.DeviceIoControl(_handle, (uint)ControlCode.Execute, pIn, (uint)totalInput.Length, pOut, (uint)output.Length, &read, null)) + { + long[] outp = new long[read / sizeof(long)]; + Buffer.BlockCopy(output, 0, outp, 0, (int)read); + return outp; + } } } return new long[outLength]; } - public int ExecuteHr(string name, long[] inBuffer, uint inSize, long[] outBuffer, uint outSize, out uint returnSize) + public unsafe int ExecuteHr(string name, long[] inBuffer, uint inSize, long[] outBuffer, uint outSize, out uint returnSize) { if (inBuffer.Length < inSize) throw new ArgumentOutOfRangeException(nameof(inSize)); @@ -112,15 +127,18 @@ public class PawnIo uint read = 0; byte[] output = new byte[outSize * sizeof(long)]; - byte[] inp = new byte[(inSize * sizeof(long)) + FN_NAME_LENGTH]; - Buffer.BlockCopy(Encoding.ASCII.GetBytes(name), 0, inp, 0, Math.Min(FN_NAME_LENGTH - 1, name.Length)); - Buffer.BlockCopy(inBuffer, 0, inp, FN_NAME_LENGTH, inBuffer.Length * sizeof(long)); + byte[] totalInput = new byte[(inSize * sizeof(long)) + FN_NAME_LENGTH]; + Buffer.BlockCopy(Encoding.ASCII.GetBytes(name), 0, totalInput, 0, Math.Min(FN_NAME_LENGTH - 1, name.Length)); + Buffer.BlockCopy(inBuffer, 0, totalInput, FN_NAME_LENGTH, inBuffer.Length * sizeof(long)); - if (Kernel32.DeviceIoControl(_handle, (uint)ControlCode.Execute, inp, (uint)inp.Length, output, (uint)output.Length, ref read)) + fixed (byte* pIn = totalInput, pOut = output) { - Buffer.BlockCopy(output, 0, outBuffer, 0, Math.Min((int)read, outBuffer.Length * sizeof(long))); - returnSize = read / sizeof(long); - return 0; + if (PInvoke.DeviceIoControl(_handle, (uint)ControlCode.Execute, pIn, (uint)totalInput.Length, pOut, (uint)output.Length, &read, null)) + { + Buffer.BlockCopy(output, 0, outBuffer, 0, Math.Min((int)read, outBuffer.Length * sizeof(long))); + returnSize = read / sizeof(long); + return 0; + } } returnSize = 0;