mirror of https://github.com/dahall/Vanara.git
275 lines
10 KiB
C#
275 lines
10 KiB
C#
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
|
|
/// <summary>Constants for StorageDeviceManagementStatus</summary>
|
|
[PInvokeData("winioctl.h")]
|
|
public enum STORAGE_DISK_HEALTH_STATUS
|
|
{
|
|
DiskHealthUnknown = 0,
|
|
DiskHealthUnhealthy,
|
|
DiskHealthWarning,
|
|
DiskHealthHealthy,
|
|
DiskHealthMax,
|
|
}
|
|
|
|
/// <summary>Operational States</summary>
|
|
[PInvokeData("winioctl.h")]
|
|
public enum STORAGE_DISK_OPERATIONAL_STATUS
|
|
{
|
|
DiskOpStatusNone = 0,
|
|
DiskOpStatusUnknown,
|
|
DiskOpStatusOk,
|
|
DiskOpStatusPredictingFailure,
|
|
DiskOpStatusInService,
|
|
DiskOpStatusHardwareError,
|
|
DiskOpStatusNotUsable,
|
|
DiskOpStatusTransientError,
|
|
DiskOpStatusMissing,
|
|
}
|
|
|
|
/// <summary>Operational Reasons</summary>
|
|
[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
|
|
|
|
/// <summary>
|
|
/// The NULL-terminated Unicode string of the adapter serial number for the StorageAdapterSerialNumberProperty as defined in STORAGE_PROPERTY_ID.
|
|
/// </summary>
|
|
// 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
|
|
{
|
|
/// <summary>The version of this structure. The Size serves as the version.</summary>
|
|
public uint Version;
|
|
|
|
/// <summary>The size of this structure.</summary>
|
|
public uint Size;
|
|
|
|
/// <summary>The serial number.</summary>
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = STORAGE_ADAPTER_SERIAL_NUMBER_V1_MAX_LENGTH)]
|
|
public string SerialNumber;
|
|
}
|
|
|
|
/// <summary>The STORAGE_DEVICE_LAYOUT_SIGNATURE structure defines a device layout structure.</summary>
|
|
[PInvokeData("storduid.h", MSDNShortId = "NS:storduid._STORAGE_DEVICE_LAYOUT_SIGNATURE")]
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct STORAGE_DEVICE_LAYOUT_SIGNATURE
|
|
{
|
|
/// <summary>The version of the DUID.</summary>
|
|
public uint Version;
|
|
|
|
/// <summary>The size, in bytes, of this STORAGE_DEVICE_LAYOUT_SIGNATURE structure.</summary>
|
|
public uint Size;
|
|
|
|
/// <summary>
|
|
/// 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).
|
|
/// </summary>
|
|
public bool Mbr;
|
|
|
|
/// <summary>The device specific info.</summary>
|
|
public DEVICESPECIFIC DeviceSpecific;
|
|
|
|
/// <summary>The device specific info.</summary>
|
|
[StructLayout(LayoutKind.Explicit)]
|
|
public struct DEVICESPECIFIC
|
|
{
|
|
/// <summary>The signature value, which uniquely identifies the disk.</summary>
|
|
[FieldOffset(0)]
|
|
public uint MbrSignature;
|
|
|
|
/// <summary>The GUID that uniquely identifies the disk.</summary>
|
|
[FieldOffset(0)]
|
|
public Guid GptDiskId;
|
|
}
|
|
}
|
|
|
|
/// <summary>Structure for STORAGE_PROPERTY_ID.StorageDeviceManagementStatus</summary>
|
|
[PInvokeData("winioctl.h")]
|
|
[VanaraMarshaler(typeof(SafeAnysizeStructMarshaler<STORAGE_DEVICE_MANAGEMENT_STATUS>), nameof(NumberOfAdditionalReasons))]
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct STORAGE_DEVICE_MANAGEMENT_STATUS
|
|
{
|
|
/// <summary>Sizeof() of this structure serves as the version.</summary>
|
|
public uint Version;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public uint Size;
|
|
|
|
/// <summary>Health status.</summary>
|
|
public STORAGE_DISK_HEALTH_STATUS Health;
|
|
|
|
/// <summary>The number of operational status returned.</summary>
|
|
public uint NumberOfOperationalStatus;
|
|
|
|
/// <summary>The number of additional reasons returned.</summary>
|
|
public uint NumberOfAdditionalReasons;
|
|
|
|
/// <summary>
|
|
/// Operational statuses. The primary operational status is the first element in the array. There are NumberOfOperationalStatus valid
|
|
/// elements in the array.
|
|
/// </summary>
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = STORAGE_DEVICE_MAX_OPERATIONAL_STATUS)]
|
|
public STORAGE_DISK_OPERATIONAL_STATUS[] OperationalStatus;
|
|
|
|
/// <summary>Additional reasons. There are NumberOfAdditionalReasons valid elements in the array.</summary>
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
|
|
public STORAGE_OPERATIONAL_REASON[] AdditionalReasons;
|
|
}
|
|
|
|
/// <summary>The STORAGE_DEVICE_UNIQUE_IDENTIFIER structure defines a device unique identifier (DUID).</summary>
|
|
// 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
|
|
{
|
|
/// <summary>The version of the DUID.</summary>
|
|
public uint Version;
|
|
|
|
/// <summary>
|
|
/// The offset, in bytes, from the beginning of the header to the device ID descriptor ( <see cref="STORAGE_DEVICE_ID_DESCRIPTOR"/>).
|
|
/// The device ID descriptor contains the IDs that are extracted from page 0x83 of the device's vital product data (VPD).
|
|
/// </summary>
|
|
public STORAGE_DEVICE_ID_DESCRIPTOR StorageDeviceId;
|
|
|
|
/// <summary>
|
|
/// The offset, in bytes, from the beginning of the header to the device descriptor ( <see cref="STORAGE_DEVICE_DESCRIPTOR"/>). The
|
|
/// device descriptor contains IDs that are extracted from non-VPD inquiry data.
|
|
/// </summary>
|
|
public STORAGE_DEVICE_DESCRIPTOR_MGD StorageDevice;
|
|
|
|
/// <summary>The offset, in bytes, to the drive layout signature ( <see cref="STORAGE_DEVICE_LAYOUT_SIGNATURE"/>).</summary>
|
|
public STORAGE_DEVICE_LAYOUT_SIGNATURE DriveLayoutSignature;
|
|
}
|
|
|
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
/// <summary>Additional reasons.</summary>
|
|
[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;
|
|
|
|
/// <summary>This is the format if Reason == DiskOpReasonScsiSenseCode.</summary>
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct ScsiSenseKeyStruct
|
|
{
|
|
public byte SenseKey;
|
|
public byte ASC;
|
|
public byte ASCQ;
|
|
public byte Reserved;
|
|
}
|
|
|
|
/// <summary>This is the format if Reason == DiskOpReasonNVDIMM_N.</summary>
|
|
[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
|
|
{
|
|
/// <summary>This is the format if Reason == DiskOpReasonScsiSenseCode.</summary>
|
|
[FieldOffset(0)]
|
|
public ScsiSenseKeyStruct ScsiSenseKey;
|
|
|
|
/// <summary>This is the format if Reason == DiskOpReasonNVDIMM_N.</summary>
|
|
[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<STORAGE_DEVICE_ID_DESCRIPTOR>(allocatedBytes, (int)sdd.StorageDeviceIdOffset),
|
|
StorageDevice = sdd.StorageDeviceOffset == 0 ? default : pNativeData.ToStructure<STORAGE_DEVICE_DESCRIPTOR_MGD>(allocatedBytes, (int)sdd.StorageDeviceOffset),
|
|
DriveLayoutSignature = sdd.DriveLayoutSignatureOffset == 0 ? default : pNativeData.ToStructure<STORAGE_DEVICE_LAYOUT_SIGNATURE>(allocatedBytes, (int)sdd.DriveLayoutSignatureOffset),
|
|
};
|
|
}
|
|
}
|
|
} |