mirror of https://github.com/dahall/Vanara.git
Finished work on #403
parent
91490dcd1b
commit
71b857bf7e
|
@ -612,15 +612,18 @@ namespace Vanara.PInvoke
|
|||
/// <param name="outVal">
|
||||
/// The data returned by the operation. The format of this data depends on the value of the dwIoControlCode parameter.
|
||||
/// </param>
|
||||
/// <param name="outSz">
|
||||
/// The amount of memory to allocate for <paramref name="outVal"/> retrieval. If this value is <c>0</c>, then initialize the default structure.
|
||||
/// </param>
|
||||
/// <returns><c>true</c> if successful.</returns>
|
||||
[PInvokeData("Winbase.h", MSDNShortId = "aa363216")]
|
||||
public static bool DeviceIoControl<TIn, TOut>(HFILE hDev, uint ioControlCode, TIn inVal, out TOut outVal) where TIn : struct where TOut : struct
|
||||
public static bool DeviceIoControl<TIn, TOut>(HFILE hDev, uint ioControlCode, TIn inVal, out TOut outVal, SizeT outSz = default) where TIn : struct where TOut : struct
|
||||
{
|
||||
using SafeHGlobalHandle ptrIn = SafeHGlobalHandle.CreateFromStructure(inVal), ptrOut = SafeHGlobalHandle.CreateFromStructure<TOut>();
|
||||
using SafeHGlobalHandle ptrIn = SafeHGlobalHandle.CreateFromStructure(inVal), ptrOut = outSz == 0 ? SafeHGlobalHandle.CreateFromStructure<TOut>() : new(outSz);
|
||||
var ret = DeviceIoControl(hDev, ioControlCode, ptrIn, ptrIn.Size, ptrOut, ptrOut.Size, out var bRet, IntPtr.Zero);
|
||||
if (!ret && Win32Error.GetLastError() == Win32Error.ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
ptrOut.Size = bRet;
|
||||
ptrOut.Size = bRet == 0 ? ptrOut.Size * 16 : bRet;
|
||||
ret = DeviceIoControl(hDev, ioControlCode, ptrIn, ptrIn.Size, ptrOut, ptrOut.Size, out bRet, IntPtr.Zero);
|
||||
}
|
||||
outVal = ret ? ptrOut.ToStructure<TOut>() : default;
|
||||
|
@ -642,11 +645,14 @@ namespace Vanara.PInvoke
|
|||
/// <param name="outVal">
|
||||
/// The data returned by the operation. The format of this data depends on the value of the dwIoControlCode parameter.
|
||||
/// </param>
|
||||
/// <param name="outSz">
|
||||
/// The amount of memory to allocate for <paramref name="outVal"/> retrieval. If this value is <c>0</c>, then initialize the default structure.
|
||||
/// </param>
|
||||
/// <returns><c>true</c> if successful.</returns>
|
||||
[PInvokeData("Winbase.h", MSDNShortId = "aa363216")]
|
||||
public static bool DeviceIoControl<TOut>(HFILE hDev, uint ioControlCode, out TOut outVal) where TOut : struct
|
||||
public static bool DeviceIoControl<TOut>(HFILE hDev, uint ioControlCode, out TOut outVal, SizeT outSz = default) where TOut : struct
|
||||
{
|
||||
using var ptrOut = SafeHGlobalHandle.CreateFromStructure<TOut>();
|
||||
using var ptrOut = outSz == 0 ? SafeHGlobalHandle.CreateFromStructure<TOut>() : new(outSz);
|
||||
var ret = DeviceIoControl(hDev, ioControlCode, IntPtr.Zero, 0, ptrOut, ptrOut.Size, out var bRet, IntPtr.Zero);
|
||||
var err = Win32Error.GetLastError();
|
||||
if (!ret && err == Win32Error.ERROR_INSUFFICIENT_BUFFER)
|
||||
|
|
|
@ -2120,7 +2120,7 @@ namespace Vanara.PInvoke
|
|||
public enum STORAGE_PROPERTY_ID
|
||||
{
|
||||
/// <summary>Indicates that the caller is querying for the device descriptor, STORAGE_DEVICE_DESCRIPTOR.</summary>
|
||||
[CorrespondingType(typeof(STORAGE_DEVICE_DESCRIPTOR))]
|
||||
[CorrespondingType(typeof(STORAGE_DEVICE_DESCRIPTOR_MGD))]
|
||||
StorageDeviceProperty = 0,
|
||||
|
||||
/// <summary>Indicates that the caller is querying for the adapter descriptor, STORAGE_ADAPTER_DESCRIPTOR.</summary>
|
||||
|
@ -2139,7 +2139,7 @@ namespace Vanara.PInvoke
|
|||
/// the STORAGE_DEVICE_UNIQUE_IDENTIFIER structure (see the storduid.h header in the DDK). Windows Server 2003 and Windows XP:
|
||||
/// This value is not supported before Windows Vista and Windows Server 2008.
|
||||
/// </summary>
|
||||
[CorrespondingType(typeof(STORAGE_DEVICE_UNIQUE_IDENTIFIER))]
|
||||
[CorrespondingType(typeof(STORAGE_DEVICE_UNIQUE_IDENTIFIER_MGD))]
|
||||
StorageDeviceUniqueIdProperty,
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Vanara.Extensions;
|
||||
using Vanara.InteropServices;
|
||||
|
||||
namespace Vanara.PInvoke;
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
public static partial class Kernel32
|
||||
{
|
||||
private const int STORAGE_ADAPTER_SERIAL_NUMBER_V1_MAX_LENGTH = 128;
|
||||
|
@ -84,6 +85,40 @@ public static partial class Kernel32
|
|||
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))]
|
||||
|
@ -125,29 +160,27 @@ public static partial class Kernel32
|
|||
// _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")]
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct 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 size, in bytes, of the identifier header and the identifiers (IDs) that follow the header.</summary>
|
||||
public uint Size;
|
||||
/// <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 ID descriptor (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).
|
||||
/// 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 uint StorageDeviceIdOffset;
|
||||
public STORAGE_DEVICE_DESCRIPTOR_MGD StorageDevice;
|
||||
|
||||
/// <summary>
|
||||
/// The offset, in bytes, from the beginning of the header to the device descriptor (STORAGE_DEVICE_DESCRIPTOR). The device
|
||||
/// descriptor contains IDs that are extracted from non-VPD inquiry data.
|
||||
/// </summary>
|
||||
public uint StorageDeviceOffset;
|
||||
|
||||
/// <summary>The offset, in bytes, to the drive layout signature (STORAGE_DEVICE_LAYOUT_SIGNATURE).</summary>
|
||||
public uint DriveLayoutSignatureOffset;
|
||||
/// <summary>The offset, in bytes, to the drive layout signature ( <see cref="STORAGE_DEVICE_LAYOUT_SIGNATURE"/>).</summary>
|
||||
public STORAGE_DEVICE_LAYOUT_SIGNATURE DriveLayoutSignature;
|
||||
}
|
||||
|
||||
/// <summary>Additional reasons.</summary>
|
||||
|
@ -201,4 +234,38 @@ public static partial class Kernel32
|
|||
public uint AsUlong;
|
||||
}
|
||||
}
|
||||
|
||||
[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),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,43 +1,111 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Vanara.InteropServices;
|
||||
using static Vanara.PInvoke.AdvApi32;
|
||||
using System.IO;
|
||||
using Vanara.PInvoke;
|
||||
using Vanara.PInvoke.Tests;
|
||||
using static Vanara.PInvoke.Kernel32;
|
||||
using FileAccess = Vanara.PInvoke.Kernel32.FileAccess;
|
||||
|
||||
namespace Vanara.PInvoke.Tests
|
||||
namespace Kernel32;
|
||||
|
||||
[TestFixture]
|
||||
public class IoApiSetTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class IoApiSetTests
|
||||
private const string vol = @"\\.\PhysicalDrive0";
|
||||
|
||||
[Test]
|
||||
public void DeviceIoControlNoInOutTest()
|
||||
{
|
||||
[Test]
|
||||
public void DeviceIoControlNoInOutTest()
|
||||
{
|
||||
using var hFile = CreateFile(@"\\.\C:", FileAccess.GENERIC_READ, System.IO.FileShare.Read,
|
||||
default, System.IO.FileMode.Open, 0);
|
||||
Assert.That(hFile, ResultIs.ValidHandle);
|
||||
Assert.True(DeviceIoControl(hFile, IOControlCode.FSCTL_IS_VOLUME_MOUNTED));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeviceIoControlOutAndInTest()
|
||||
{
|
||||
using var hFile = CreateFile(TestCaseSources.WordDoc, FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE,
|
||||
System.IO.FileShare.None, default, System.IO.FileMode.Open, 0);
|
||||
Assert.That(hFile, ResultIs.ValidHandle);
|
||||
|
||||
Assert.That(DeviceIoControl(hFile, IOControlCode.FSCTL_GET_COMPRESSION, out COMPRESSION_FORMAT compr), ResultIs.Successful);
|
||||
Assert.That(DeviceIoControl(hFile, IOControlCode.FSCTL_SET_COMPRESSION, compr == COMPRESSION_FORMAT.COMPRESSION_FORMAT_NONE ? COMPRESSION_FORMAT.COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT.COMPRESSION_FORMAT_NONE), ResultIs.Successful);
|
||||
Assert.That(DeviceIoControl(hFile, IOControlCode.FSCTL_GET_COMPRESSION, out COMPRESSION_FORMAT newcompr), ResultIs.Successful);
|
||||
Assert.That(compr, Is.Not.EqualTo(newcompr));
|
||||
Assert.That(DeviceIoControl(hFile, IOControlCode.FSCTL_SET_COMPRESSION, compr), ResultIs.Successful);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StructSizeTest()
|
||||
{
|
||||
TestHelper.GetNestedStructSizes(typeof(Kernel32)).WriteValues();
|
||||
}
|
||||
using SafeHFILE hFile = CreateFile(vol, FileAccess.GENERIC_READ, FileShare.Read,
|
||||
default, FileMode.Open, 0);
|
||||
Assert.That(hFile, ResultIs.ValidHandle);
|
||||
Assert.False(DeviceIoControl(hFile, IOControlCode.FSCTL_IS_VOLUME_MOUNTED));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeviceIoControlOutAndInTest()
|
||||
{
|
||||
using SafeHFILE hFile = CreateFile(TestCaseSources.WordDoc, FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE,
|
||||
FileShare.None, default, FileMode.Open, 0);
|
||||
Assert.That(hFile, ResultIs.ValidHandle);
|
||||
|
||||
Assert.That(DeviceIoControl(hFile, IOControlCode.FSCTL_GET_COMPRESSION, out COMPRESSION_FORMAT compr), ResultIs.Successful);
|
||||
Assert.That(DeviceIoControl(hFile, IOControlCode.FSCTL_SET_COMPRESSION, compr == COMPRESSION_FORMAT.COMPRESSION_FORMAT_NONE ? COMPRESSION_FORMAT.COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT.COMPRESSION_FORMAT_NONE), ResultIs.Successful);
|
||||
Assert.That(DeviceIoControl(hFile, IOControlCode.FSCTL_GET_COMPRESSION, out COMPRESSION_FORMAT newcompr), ResultIs.Successful);
|
||||
Assert.That(compr, Is.Not.EqualTo(newcompr));
|
||||
Assert.That(DeviceIoControl(hFile, IOControlCode.FSCTL_SET_COMPRESSION, compr), ResultIs.Successful);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StorageAdapterSerialNumberPropertyTest()
|
||||
{
|
||||
TestContext.WriteLine(vol + ":");
|
||||
using SafeHFILE hdisk = CreateFile(vol.TrimEnd('\\'), 0, FileShare.ReadWrite, null, FileMode.Open, 0);
|
||||
Assert.IsFalse(hdisk.IsInvalid);
|
||||
|
||||
STORAGE_PROPERTY_QUERY query = new(STORAGE_PROPERTY_ID.StorageAdapterSerialNumberProperty);
|
||||
Assert.That(DeviceIoControl(hdisk, IOControlCode.IOCTL_STORAGE_QUERY_PROPERTY, query, out STORAGE_ADAPTER_SERIAL_NUMBER outVar),
|
||||
ResultIs.Successful);
|
||||
outVar.WriteValues();
|
||||
|
||||
TestContext.WriteLine(new string('=', 20));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StorageDeviceManagementStatusTest()
|
||||
{
|
||||
TestContext.WriteLine(vol + ":");
|
||||
using SafeHFILE hdisk = CreateFile(vol.TrimEnd('\\'), 0, FileShare.ReadWrite, null, FileMode.Open, 0);
|
||||
Assert.IsFalse(hdisk.IsInvalid);
|
||||
|
||||
STORAGE_PROPERTY_QUERY query = new(STORAGE_PROPERTY_ID.StorageDeviceManagementStatus);
|
||||
Assert.That(DeviceIoControl(hdisk, IOControlCode.IOCTL_STORAGE_QUERY_PROPERTY, query, out STORAGE_DEVICE_MANAGEMENT_STATUS outVar),
|
||||
ResultIs.Successful);
|
||||
Assert.IsTrue(outVar.Health.HasFlag(STORAGE_DISK_HEALTH_STATUS.DiskHealthHealthy));
|
||||
Assert.That(outVar.NumberOfOperationalStatus, Is.GreaterThan(0));
|
||||
for (int i = 0; i < outVar.NumberOfOperationalStatus; i++)
|
||||
Assert.IsTrue(outVar.OperationalStatus[i].HasFlag(STORAGE_DISK_OPERATIONAL_STATUS.DiskOpStatusOk));
|
||||
outVar.WriteValues();
|
||||
|
||||
TestContext.WriteLine(new string('=', 20));
|
||||
}
|
||||
|
||||
// Courtesy of @elf2k00
|
||||
[Test]
|
||||
public void StorageDevicePropertyTest()
|
||||
{
|
||||
TestContext.WriteLine(vol + ":");
|
||||
using SafeHFILE hdisk = CreateFile(vol.TrimEnd('\\'), 0, FileShare.ReadWrite, null, FileMode.Open, 0);
|
||||
Assert.IsFalse(hdisk.IsInvalid);
|
||||
|
||||
STORAGE_PROPERTY_QUERY query = new(STORAGE_PROPERTY_ID.StorageDeviceProperty);
|
||||
Assert.That(DeviceIoControl(hdisk, IOControlCode.IOCTL_STORAGE_QUERY_PROPERTY, query, out STORAGE_DESCRIPTOR_HEADER sdh),
|
||||
ResultIs.Successful);
|
||||
Assert.That(DeviceIoControl(hdisk, IOControlCode.IOCTL_STORAGE_QUERY_PROPERTY, query, out STORAGE_DEVICE_DESCRIPTOR_MGD outVar, sdh.Size),
|
||||
ResultIs.Successful);
|
||||
Assert.IsTrue(Enum.IsDefined(typeof(STORAGE_BUS_TYPE), outVar.BusType));
|
||||
outVar.WriteValues();
|
||||
|
||||
TestContext.WriteLine(new string('=', 20));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StorageDeviceUniqueIdPropertyTest()
|
||||
{
|
||||
TestContext.WriteLine(vol + ":");
|
||||
using SafeHFILE hdisk = CreateFile(vol.TrimEnd('\\'), 0, FileShare.ReadWrite, null, FileMode.Open, 0);
|
||||
Assert.IsFalse(hdisk.IsInvalid);
|
||||
|
||||
STORAGE_PROPERTY_QUERY query = new(STORAGE_PROPERTY_ID.StorageDeviceUniqueIdProperty);
|
||||
Assert.That(DeviceIoControl(hdisk, IOControlCode.IOCTL_STORAGE_QUERY_PROPERTY, query, out STORAGE_DESCRIPTOR_HEADER sdh),
|
||||
ResultIs.Successful);
|
||||
Assert.That(DeviceIoControl(hdisk, IOControlCode.IOCTL_STORAGE_QUERY_PROPERTY, query, out STORAGE_DEVICE_UNIQUE_IDENTIFIER_MGD outVar, sdh.Size),
|
||||
ResultIs.Successful);
|
||||
outVar.WriteValues();
|
||||
|
||||
TestContext.WriteLine(new string('=', 20));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StructSizeTest() => typeof(Vanara.PInvoke.Kernel32).GetNestedStructSizes().WriteValues();
|
||||
}
|
Loading…
Reference in New Issue