using System; using System.Runtime.InteropServices; using Vanara.Extensions; using Vanara.InteropServices; namespace Vanara.PInvoke; public static partial class Kernel32 { private const int STORAGE_ADAPTER_SERIAL_NUMBER_V1_MAX_LENGTH = 128; private const int STORAGE_DEVICE_MAX_OPERATIONAL_STATUS = 16; #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member /// Constants for StorageDeviceManagementStatus [PInvokeData("winioctl.h")] public enum STORAGE_DISK_HEALTH_STATUS { DiskHealthUnknown = 0, DiskHealthUnhealthy, DiskHealthWarning, DiskHealthHealthy, DiskHealthMax, } /// Operational States [PInvokeData("winioctl.h")] public enum STORAGE_DISK_OPERATIONAL_STATUS { DiskOpStatusNone = 0, DiskOpStatusUnknown, DiskOpStatusOk, DiskOpStatusPredictingFailure, DiskOpStatusInService, DiskOpStatusHardwareError, DiskOpStatusNotUsable, DiskOpStatusTransientError, DiskOpStatusMissing, } /// Operational Reasons [PInvokeData("winioctl.h")] public enum STORAGE_OPERATIONAL_STATUS_REASON { DiskOpReasonUnknown = 0, DiskOpReasonScsiSenseCode, DiskOpReasonMedia, DiskOpReasonIo, DiskOpReasonThresholdExceeded, DiskOpReasonLostData, DiskOpReasonEnergySource, DiskOpReasonConfiguration, DiskOpReasonDeviceController, DiskOpReasonMediaController, DiskOpReasonComponent, DiskOpReasonNVDIMM_N, DiskOpReasonBackgroundOperation, DiskOpReasonInvalidFirmware, DiskOpReasonHealthCheck, DiskOpReasonLostDataPersistence, DiskOpReasonDisabledByPlatform, DiskOpReasonLostWritePersistence, DiskOpReasonDataPersistenceLossImminent, DiskOpReasonWritePersistenceLossImminent, DiskOpReasonMax, } #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// The NULL-terminated Unicode string of the adapter serial number for the StorageAdapterSerialNumberProperty as defined in STORAGE_PROPERTY_ID. /// // https://learn.microsoft.com/en-us/windows/win32/api/winioctl/ns-winioctl-storage_adapter_serial_number typedef struct // _STORAGE_ADAPTER_SERIAL_NUMBER { DWORD Version; DWORD Size; WCHAR SerialNumber[STORAGE_ADAPTER_SERIAL_NUMBER_V1_MAX_LENGTH]; } // STORAGE_ADAPTER_SERIAL_NUMBER, *PSTORAGE_ADAPTER_SERIAL_NUMBER; [PInvokeData("winioctl.h", MSDNShortId = "NS:winioctl._STORAGE_ADAPTER_SERIAL_NUMBER")] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct STORAGE_ADAPTER_SERIAL_NUMBER { /// The version of this structure. The Size serves as the version. public uint Version; /// The size of this structure. public uint Size; /// The serial number. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = STORAGE_ADAPTER_SERIAL_NUMBER_V1_MAX_LENGTH)] public string SerialNumber; } /// The STORAGE_DEVICE_LAYOUT_SIGNATURE structure defines a device layout structure. [PInvokeData("storduid.h", MSDNShortId = "NS:storduid._STORAGE_DEVICE_LAYOUT_SIGNATURE")] [StructLayout(LayoutKind.Sequential)] public struct STORAGE_DEVICE_LAYOUT_SIGNATURE { /// The version of the DUID. public uint Version; /// The size, in bytes, of this STORAGE_DEVICE_LAYOUT_SIGNATURE structure. public uint Size; /// /// A Boolean value that indicates whether the partition table of the disk is formatted with a master boot record (MBR). If TRUE, the /// partition table of the disk is formatted with a master boot record (MBR). If FALSE, the disk has a GUID partition table (GPT). /// public bool Mbr; /// The device specific info. public DEVICESPECIFIC DeviceSpecific; /// The device specific info. [StructLayout(LayoutKind.Explicit)] public struct DEVICESPECIFIC { /// The signature value, which uniquely identifies the disk. [FieldOffset(0)] public uint MbrSignature; /// The GUID that uniquely identifies the disk. [FieldOffset(0)] public Guid GptDiskId; } } /// Structure for STORAGE_PROPERTY_ID.StorageDeviceManagementStatus [PInvokeData("winioctl.h")] [VanaraMarshaler(typeof(SafeAnysizeStructMarshaler), nameof(NumberOfAdditionalReasons))] [StructLayout(LayoutKind.Sequential)] public struct STORAGE_DEVICE_MANAGEMENT_STATUS { /// Sizeof() of this structure serves as the version. public uint Version; /// /// The total size of the structure, including operational status reasons that didn't fit in the caller's array. Callers should use /// this field to learn how big the input buffer should be to contain all the available information. /// public uint Size; /// Health status. public STORAGE_DISK_HEALTH_STATUS Health; /// The number of operational status returned. public uint NumberOfOperationalStatus; /// The number of additional reasons returned. public uint NumberOfAdditionalReasons; /// /// Operational statuses. The primary operational status is the first element in the array. There are NumberOfOperationalStatus valid /// elements in the array. /// [MarshalAs(UnmanagedType.ByValArray, SizeConst = STORAGE_DEVICE_MAX_OPERATIONAL_STATUS)] public STORAGE_DISK_OPERATIONAL_STATUS[] OperationalStatus; /// Additional reasons. There are NumberOfAdditionalReasons valid elements in the array. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public STORAGE_OPERATIONAL_REASON[] AdditionalReasons; } /// The STORAGE_DEVICE_UNIQUE_IDENTIFIER structure defines a device unique identifier (DUID). // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/storduid/ns-storduid-_storage_device_unique_identifier typedef struct // _STORAGE_DEVICE_UNIQUE_IDENTIFIER { ULONG Version; ULONG Size; ULONG StorageDeviceIdOffset; ULONG StorageDeviceOffset; ULONG // DriveLayoutSignatureOffset; } STORAGE_DEVICE_UNIQUE_IDENTIFIER, *PSTORAGE_DEVICE_UNIQUE_IDENTIFIER; [PInvokeData("storduid.h", MSDNShortId = "NS:storduid._STORAGE_DEVICE_UNIQUE_IDENTIFIER")] [VanaraMarshaler(typeof(STORAGE_DEVICE_UNIQUE_IDENTIFIER_Marshaler))] [StructLayout(LayoutKind.Sequential)] public struct STORAGE_DEVICE_UNIQUE_IDENTIFIER_MGD { /// The version of the DUID. public uint Version; /// /// The offset, in bytes, from the beginning of the header to the device ID descriptor ( ). /// The device ID descriptor contains the IDs that are extracted from page 0x83 of the device's vital product data (VPD). /// public STORAGE_DEVICE_ID_DESCRIPTOR StorageDeviceId; /// /// The offset, in bytes, from the beginning of the header to the device descriptor ( ). The /// device descriptor contains IDs that are extracted from non-VPD inquiry data. /// public STORAGE_DEVICE_DESCRIPTOR_MGD StorageDevice; /// The offset, in bytes, to the drive layout signature ( ). public STORAGE_DEVICE_LAYOUT_SIGNATURE DriveLayoutSignature; } #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member /// Additional reasons. [PInvokeData("winioctl.h")] [StructLayout(LayoutKind.Explicit)] public struct STORAGE_OPERATIONAL_REASON { [FieldOffset(0)] public uint Version; [FieldOffset(4)] public uint Size; [FieldOffset(8)] public STORAGE_OPERATIONAL_STATUS_REASON Reason; [FieldOffset(12)] public RawBytesUnion RawBytes; /// This is the format if Reason == DiskOpReasonScsiSenseCode. [StructLayout(LayoutKind.Sequential)] public struct ScsiSenseKeyStruct { public byte SenseKey; public byte ASC; public byte ASCQ; public byte Reserved; } /// This is the format if Reason == DiskOpReasonNVDIMM_N. [StructLayout(LayoutKind.Sequential)] public unsafe struct NVDIMM_NStruct { public byte CriticalHealth; public fixed byte ModuleHealth[2]; public byte ErrorThresholdStatus; } [StructLayout(LayoutKind.Explicit)] public struct RawBytesUnion { /// This is the format if Reason == DiskOpReasonScsiSenseCode. [FieldOffset(0)] public ScsiSenseKeyStruct ScsiSenseKey; /// This is the format if Reason == DiskOpReasonNVDIMM_N. [FieldOffset(0)] public NVDIMM_NStruct NVDIMM_N; [FieldOffset(0)] public uint AsUlong; } } #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member [StructLayout(LayoutKind.Sequential)] private struct STORAGE_DEVICE_UNIQUE_IDENTIFIER { public uint Version; public uint Size; public uint StorageDeviceIdOffset; public uint StorageDeviceOffset; public uint DriveLayoutSignatureOffset; } private class STORAGE_DEVICE_UNIQUE_IDENTIFIER_Marshaler : IVanaraMarshaler { SizeT IVanaraMarshaler.GetNativeSize() => Marshal.SizeOf(typeof(STORAGE_DEVICE_UNIQUE_IDENTIFIER)); SafeAllocatedMemoryHandle IVanaraMarshaler.MarshalManagedToNative(object managedObject) => new SafeCoTaskMemHandle(1024); object IVanaraMarshaler.MarshalNativeToManaged(IntPtr pNativeData, SizeT allocatedBytes) { if (pNativeData == IntPtr.Zero) return null; STORAGE_DEVICE_UNIQUE_IDENTIFIER sdd = (STORAGE_DEVICE_UNIQUE_IDENTIFIER)Marshal.PtrToStructure(pNativeData, typeof(STORAGE_DEVICE_UNIQUE_IDENTIFIER))!; return new STORAGE_DEVICE_UNIQUE_IDENTIFIER_MGD { Version = sdd.Version, StorageDeviceId = sdd.StorageDeviceIdOffset == 0 ? default : pNativeData.ToStructure(allocatedBytes, (int)sdd.StorageDeviceIdOffset), StorageDevice = sdd.StorageDeviceOffset == 0 ? default : pNativeData.ToStructure(allocatedBytes, (int)sdd.StorageDeviceOffset), DriveLayoutSignature = sdd.DriveLayoutSignatureOffset == 0 ? default : pNativeData.ToStructure(allocatedBytes, (int)sdd.DriveLayoutSignatureOffset), }; } } }