Finished work on #403

pull/411/head
David Hall 2023-06-08 19:05:16 -06:00
parent 91490dcd1b
commit 71b857bf7e
5 changed files with 7054 additions and 6860 deletions

View File

@ -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)

View File

@ -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>

View File

@ -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

View File

@ -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();
}