diff --git a/DeviceIOControlLib/DeviceIOControlLib.csproj b/DeviceIOControlLib/DeviceIOControlLib.csproj index 48e3b3f..ffbb04e 100644 --- a/DeviceIOControlLib/DeviceIOControlLib.csproj +++ b/DeviceIOControlLib/DeviceIOControlLib.csproj @@ -1,19 +1,10 @@  - netstandard1.3;netstandard2.0 + net8.0-windows;net9.0-windows;net10.0-windows Library to interact with Windows' DeviceIoControl method Win32 DeviceIoControl + True - - - - - - - - - - diff --git a/DeviceIOControlLib/Objects/Disk/DRIVE_LAYOUT_INFORMATION_EX_INTERNAL.cs b/DeviceIOControlLib/Objects/Disk/DRIVE_LAYOUT_INFORMATION_EX_INTERNAL.cs index 8c538d5..38ecb9f 100644 --- a/DeviceIOControlLib/Objects/Disk/DRIVE_LAYOUT_INFORMATION_EX_INTERNAL.cs +++ b/DeviceIOControlLib/Objects/Disk/DRIVE_LAYOUT_INFORMATION_EX_INTERNAL.cs @@ -1,3 +1,4 @@ +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using DeviceIOControlLib.Objects.Enums; @@ -10,7 +11,5 @@ internal struct DRIVE_LAYOUT_INFORMATION_EX_INTERNAL public PartitionStyle PartitionStyle; public int PartitionCount; public DRIVE_LAYOUT_INFORMATION_UNION DriveLayoutInformaiton; - [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 128)] - public PARTITION_INFORMATION_EX[] PartitionEntry; } } \ No newline at end of file diff --git a/DeviceIOControlLib/Objects/Disk/DRIVE_LAYOUT_INFORMATION_INTERNAL.cs b/DeviceIOControlLib/Objects/Disk/DRIVE_LAYOUT_INFORMATION_INTERNAL.cs index 07b4027..fc60465 100644 --- a/DeviceIOControlLib/Objects/Disk/DRIVE_LAYOUT_INFORMATION_INTERNAL.cs +++ b/DeviceIOControlLib/Objects/Disk/DRIVE_LAYOUT_INFORMATION_INTERNAL.cs @@ -7,7 +7,5 @@ internal struct DRIVE_LAYOUT_INFORMATION_INTERNAL { public int PartitionCount; public uint Signature; - [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 128)] - public PARTITION_INFORMATION[] PartitionEntry; } } \ No newline at end of file diff --git a/DeviceIOControlLib/Objects/Disk/GETVERSIONINPARAMS.cs b/DeviceIOControlLib/Objects/Disk/GETVERSIONINPARAMS.cs index adbb9ee..0664aeb 100644 --- a/DeviceIOControlLib/Objects/Disk/GETVERSIONINPARAMS.cs +++ b/DeviceIOControlLib/Objects/Disk/GETVERSIONINPARAMS.cs @@ -3,14 +3,13 @@ namespace DeviceIOControlLib.Objects.Disk { [StructLayout(LayoutKind.Sequential)] - public struct GETVERSIONINPARAMS + public unsafe struct GETVERSIONINPARAMS { public byte bVersion; public byte bRevision; public byte bReserved; public byte bIDEDeviceMap; public ulong fCapabilities; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public ulong[] dwReserved; + public fixed ulong dwReserved[4]; } } \ No newline at end of file diff --git a/DeviceIOControlLib/Objects/Disk/PARTITION_INFORMATION_GPT.cs b/DeviceIOControlLib/Objects/Disk/PARTITION_INFORMATION_GPT.cs index 6ac7373..69a5a4f 100644 --- a/DeviceIOControlLib/Objects/Disk/PARTITION_INFORMATION_GPT.cs +++ b/DeviceIOControlLib/Objects/Disk/PARTITION_INFORMATION_GPT.cs @@ -5,7 +5,7 @@ namespace DeviceIOControlLib.Objects.Disk { [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] - public struct PARTITION_INFORMATION_GPT + public unsafe struct PARTITION_INFORMATION_GPT { [FieldOffset(0)] public Guid PartitionType; @@ -15,7 +15,6 @@ public struct PARTITION_INFORMATION_GPT [MarshalAs(UnmanagedType.U8)] public EFIPartitionAttributes Attributes; [FieldOffset(40)] - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 36)] - public string Name; + public fixed char Name[36]; } } \ No newline at end of file diff --git a/DeviceIOControlLib/Objects/Storage/STORAGE_DEVICE_DESCRIPTOR.cs b/DeviceIOControlLib/Objects/Storage/STORAGE_DEVICE_DESCRIPTOR.cs index 2dbc5bd..4912bf8 100644 --- a/DeviceIOControlLib/Objects/Storage/STORAGE_DEVICE_DESCRIPTOR.cs +++ b/DeviceIOControlLib/Objects/Storage/STORAGE_DEVICE_DESCRIPTOR.cs @@ -3,7 +3,7 @@ namespace DeviceIOControlLib.Objects.Storage { [StructLayout(LayoutKind.Sequential)] - public struct STORAGE_DEVICE_DESCRIPTOR + public unsafe struct STORAGE_DEVICE_DESCRIPTOR { public uint Version; public uint Size; @@ -20,6 +20,6 @@ public struct STORAGE_DEVICE_DESCRIPTOR public STORAGE_BUS_TYPE BusType; public uint RawPropertiesLength; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x16)] - public byte[] RawDeviceProperties; + public fixed byte RawDeviceProperties[0x16]; } } \ No newline at end of file diff --git a/DeviceIOControlLib/Objects/Storage/STORAGE_DEVICE_DESCRIPTOR_PARSED.cs b/DeviceIOControlLib/Objects/Storage/STORAGE_DEVICE_DESCRIPTOR_PARSED.cs index 4112135..e05ca1d 100644 --- a/DeviceIOControlLib/Objects/Storage/STORAGE_DEVICE_DESCRIPTOR_PARSED.cs +++ b/DeviceIOControlLib/Objects/Storage/STORAGE_DEVICE_DESCRIPTOR_PARSED.cs @@ -3,7 +3,7 @@ namespace DeviceIOControlLib.Objects.Storage { [StructLayout(LayoutKind.Sequential)] - public struct STORAGE_DEVICE_DESCRIPTOR_PARSED + public unsafe struct STORAGE_DEVICE_DESCRIPTOR_PARSED { public uint Version; public uint Size; @@ -20,7 +20,7 @@ public struct STORAGE_DEVICE_DESCRIPTOR_PARSED public STORAGE_BUS_TYPE BusType; public uint RawPropertiesLength; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x16)] - public byte[] RawDeviceProperties; + public fixed byte RawDeviceProperties[0x16]; public string SerialNumber; public string VendorId; public string ProductId; diff --git a/DeviceIOControlLib/Objects/Storage/STORAGE_PROPERTY_QUERY.cs b/DeviceIOControlLib/Objects/Storage/STORAGE_PROPERTY_QUERY.cs index 4a45790..3051222 100644 --- a/DeviceIOControlLib/Objects/Storage/STORAGE_PROPERTY_QUERY.cs +++ b/DeviceIOControlLib/Objects/Storage/STORAGE_PROPERTY_QUERY.cs @@ -3,10 +3,10 @@ namespace DeviceIOControlLib.Objects.Storage { [StructLayout(LayoutKind.Sequential)] - public struct STORAGE_PROPERTY_QUERY + public unsafe struct STORAGE_PROPERTY_QUERY { public STORAGE_PROPERTY_ID PropertyId; public STORAGE_QUERY_TYPE QueryType; - public byte[] AdditionalParameters; + public byte* AdditionalParameters; } } \ No newline at end of file diff --git a/DeviceIOControlLib/Objects/Usn/USN_RECORD_V2.cs b/DeviceIOControlLib/Objects/Usn/USN_RECORD_V2.cs index 448b356..cba221b 100644 --- a/DeviceIOControlLib/Objects/Usn/USN_RECORD_V2.cs +++ b/DeviceIOControlLib/Objects/Usn/USN_RECORD_V2.cs @@ -4,7 +4,7 @@ namespace DeviceIOControlLib.Objects.Usn { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public struct USN_RECORD_V2 : IUSN_RECORD + public unsafe struct USN_RECORD_V2 : IUSN_RECORD { private uint _recordLength; private ushort _majorVersion; @@ -19,8 +19,7 @@ public struct USN_RECORD_V2 : IUSN_RECORD private FileAttributes _fileAttributes; private ushort _fileNameLength; private ushort _fileNameOffset; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)] - private string _fileName; + private fixed char _fileName[1]; public uint RecordLength { @@ -89,8 +88,20 @@ public ushort FileNameOffset } public string FileName { - get { return _fileName; } - set { _fileName = value; } + get + { + fixed(char* fileNamePtr = _fileName) + { + return new string(fileNamePtr, 0, 1); + } + } + set + { + fixed(char * fileNamePtr = _fileName) + { + fileNamePtr[0] = value[0]; + } + } } } } \ No newline at end of file diff --git a/DeviceIOControlLib/Objects/Usn/USN_RECORD_V3.cs b/DeviceIOControlLib/Objects/Usn/USN_RECORD_V3.cs index 3937f09..ca12dc8 100644 --- a/DeviceIOControlLib/Objects/Usn/USN_RECORD_V3.cs +++ b/DeviceIOControlLib/Objects/Usn/USN_RECORD_V3.cs @@ -1,18 +1,17 @@ +using System; using System.Runtime.InteropServices; using DeviceIOControlLib.Objects.Enums; namespace DeviceIOControlLib.Objects.Usn { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public struct USN_RECORD_V3 : IUSN_RECORD + public unsafe struct USN_RECORD_V3 : IUSN_RECORD { internal uint _recordLength; internal ushort _majorVersion; internal ushort _minorVersion; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] _fileReferenceNumber; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] _parentFileReferenceNumber; + public fixed byte _fileReferenceNumber[16]; + public fixed byte _parentFileReferenceNumber[16]; public long _usn; public ulong _timeStamp; public UsnJournalReasonMask _reason; @@ -21,8 +20,7 @@ public struct USN_RECORD_V3 : IUSN_RECORD public FileAttributes _fileAttributes; public ushort _fileNameLength; public ushort _fileNameOffset; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)] - public string _fileName; + public fixed char _fileName[1]; public uint RecordLength { @@ -41,13 +39,48 @@ public ushort MinorVersion } public byte[] FileReferenceNumber { - get { return _fileReferenceNumber; } - set { _fileReferenceNumber = value; } + get + { + byte[] fileReferenceNumber = new byte[16]; + fixed (byte* fileReferenceNumberDst = fileReferenceNumber) + fixed (byte* fileReferenceNumberSrc = _fileReferenceNumber) + { + Buffer.MemoryCopy(fileReferenceNumberSrc, fileReferenceNumberDst, 16, 16); + } + + return fileReferenceNumber; + } + set + { + fixed (byte* fileReferenceNumberDst = _fileReferenceNumber) + fixed (byte* fileReferenceNumberSrc = value) + { + Buffer.MemoryCopy(fileReferenceNumberSrc, fileReferenceNumberDst, 16, 16); + } + } } + public byte[] ParentFileReferenceNumber { - get { return _parentFileReferenceNumber; } - set { _parentFileReferenceNumber = value; } + get + { + byte[] parentFileReferenceNumber = new byte[16]; + fixed (byte* parentFileReferenceNumberDst = parentFileReferenceNumber) + fixed (byte* parentFileReferenceNumberSrc = _parentFileReferenceNumber) + { + Buffer.MemoryCopy(parentFileReferenceNumberSrc, parentFileReferenceNumberDst, 16, 16); + } + + return parentFileReferenceNumber; + } + set + { + fixed (byte* parentFileReferenceNumberDst = _parentFileReferenceNumber) + fixed (byte* parentFileReferenceNumberSrc = value) + { + Buffer.MemoryCopy(parentFileReferenceNumberSrc, parentFileReferenceNumberDst, 16, 16); + } + } } public USN Usn { @@ -91,8 +124,20 @@ public ushort FileNameOffset } public string FileName { - get { return _fileName; } - set { _fileName = value; } + get + { + fixed (char* fileNamePtr = _fileName) + { + return new string(fileNamePtr, 0, 1); + } + } + set + { + fixed (char* fileNamePtr = _fileName) + { + fileNamePtr[0] = value[0]; + } + } } } } \ No newline at end of file diff --git a/DeviceIOControlLib/Utilities/MarshalHelper.cs b/DeviceIOControlLib/Utilities/MarshalHelper.cs index d9a21d1..ea8f191 100644 --- a/DeviceIOControlLib/Utilities/MarshalHelper.cs +++ b/DeviceIOControlLib/Utilities/MarshalHelper.cs @@ -5,22 +5,14 @@ namespace DeviceIOControlLib.Utilities { internal static class MarshalHelper { - public static T ToStructure(this IntPtr ptr) + public static unsafe T ToStructure(this IntPtr ptr) where T : unmanaged { -#if NETCORE - return Marshal.PtrToStructure(ptr); -#else - return (T)Marshal.PtrToStructure(ptr, typeof(T)); -#endif + return *(T*)ptr.ToPointer(); } - public static uint SizeOf() + public static unsafe uint SizeOf() where T : unmanaged { -#if NETCORE - return (uint)Marshal.SizeOf(); -#else - return (uint)Marshal.SizeOf(typeof(T)); -#endif + return (uint)sizeof(T); } } } \ No newline at end of file diff --git a/DeviceIOControlLib/Utilities/Utils.cs b/DeviceIOControlLib/Utilities/Utils.cs index 301f03c..bbd72d0 100644 --- a/DeviceIOControlLib/Utilities/Utils.cs +++ b/DeviceIOControlLib/Utilities/Utils.cs @@ -12,7 +12,7 @@ public static string GetWin32ErrorMessage(int errorCode) return new Win32Exception(errorCode).Message; } - public static T ByteArrayToStruct(byte[] data, int index) where T : struct + public static T ByteArrayToStruct(byte[] data, int index) where T : unmanaged { using (UnmanagedMemory mem = new UnmanagedMemory(data.Length - index)) { diff --git a/DeviceIOControlLib/Wrapper/DeviceIoControlHelper.cs b/DeviceIOControlLib/Wrapper/DeviceIoControlHelper.cs index 993158f..683d556 100644 --- a/DeviceIOControlLib/Wrapper/DeviceIoControlHelper.cs +++ b/DeviceIOControlLib/Wrapper/DeviceIoControlHelper.cs @@ -7,29 +7,16 @@ namespace DeviceIOControlLib.Wrapper { - public static class DeviceIoControlHelper + public static partial class DeviceIoControlHelper { - [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - private static extern bool DeviceIoControl( - SafeFileHandle hDevice, - IOControlCode IoControlCode, - [MarshalAs(UnmanagedType.AsAny)] - [In] object InBuffer, - uint nInBufferSize, - [MarshalAs(UnmanagedType.AsAny)] - [Out] object OutBuffer, - uint nOutBufferSize, - ref uint pBytesReturned, - [In] IntPtr Overlapped - ); - - [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - private static extern bool DeviceIoControl( + [LibraryImport("Kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static partial bool DeviceIoControl( SafeFileHandle hDevice, IOControlCode ioControlCode, - byte[] inBuffer, + IntPtr inBuffer, uint nInBufferSize, - byte[] outBuffer, + IntPtr outBuffer, uint nOutBufferSize, ref uint pBytesReturned, IntPtr overlapped @@ -43,18 +30,22 @@ public static bool InvokeIoControl(SafeFileHandle handle, IOControlCode controlC { uint returnedBytes = 0; - return DeviceIoControl(handle, controlCode, null, 0, null, 0, ref returnedBytes, IntPtr.Zero); + return DeviceIoControl(handle, controlCode, IntPtr.Zero, 0, IntPtr.Zero, 0, ref returnedBytes, IntPtr.Zero); } /// /// Invoke DeviceIOControl with no input, and retrieve the output in the form of a byte array. /// - public static byte[] InvokeIoControl(SafeFileHandle handle, IOControlCode controlCode, uint outputLength) + public unsafe static byte[] InvokeIoControl(SafeFileHandle handle, IOControlCode controlCode, uint outputLength) { + bool success; uint returnedBytes = 0; byte[] output = new byte[outputLength]; - bool success = DeviceIoControl(handle, controlCode, null, 0, output, outputLength, ref returnedBytes, IntPtr.Zero); + fixed (byte* outputPtr = output) + { + success = DeviceIoControl(handle, controlCode, IntPtr.Zero, 0, new IntPtr(outputPtr), outputLength, ref returnedBytes, IntPtr.Zero); + } if (!success) { @@ -68,12 +59,16 @@ public static byte[] InvokeIoControl(SafeFileHandle handle, IOControlCode contro /// /// Invoke DeviceIOControl with no input, and retrieve the output in the form of a byte array. Lets the caller handle the errorcode (if any). /// - public static byte[] InvokeIoControl(SafeFileHandle handle, IOControlCode controlCode, uint outputLength, out int errorCode) + public unsafe static byte[] InvokeIoControl(SafeFileHandle handle, IOControlCode controlCode, uint outputLength, out int errorCode) { + bool success; uint returnedBytes = 0; byte[] output = new byte[outputLength]; - bool success = DeviceIoControl(handle, controlCode, null, 0, output, outputLength, ref returnedBytes, IntPtr.Zero); + fixed (byte* outputPtr = output) + { + success = DeviceIoControl(handle, controlCode, IntPtr.Zero, 0, new IntPtr(outputPtr), outputLength, ref returnedBytes, IntPtr.Zero); + } errorCode = 0; @@ -86,13 +81,14 @@ public static byte[] InvokeIoControl(SafeFileHandle handle, IOControlCode contro /// /// Invoke DeviceIOControl with no input, and retrieve the output in the form of an object of type T. /// - public static T InvokeIoControl(SafeFileHandle handle, IOControlCode controlCode) + public unsafe static T InvokeIoControl(SafeFileHandle handle, IOControlCode controlCode) + where T : unmanaged { uint returnedBytes = 0; - object output = default(T); + T output = default; uint outputSize = MarshalHelper.SizeOf(); - bool success = DeviceIoControl(handle, controlCode, null, 0, output, outputSize, ref returnedBytes, IntPtr.Zero); + bool success = DeviceIoControl(handle, controlCode, IntPtr.Zero, 0, new IntPtr(&output), outputSize, ref returnedBytes, IntPtr.Zero); if (!success) { @@ -100,21 +96,23 @@ public static T InvokeIoControl(SafeFileHandle handle, IOControlCode controlC throw new Win32Exception(lastError, "Couldn't invoke DeviceIoControl for " + controlCode + ". LastError: " + Utils.GetWin32ErrorMessage(lastError)); } - return (T)output; + return output; } /// /// Invoke DeviceIOControl with input of type V, and retrieve the output in the form of an object of type T. /// - public static T InvokeIoControl(SafeFileHandle handle, IOControlCode controlCode, V input) + public unsafe static T InvokeIoControl(SafeFileHandle handle, IOControlCode controlCode, V input) + where T : unmanaged + where V : unmanaged { uint returnedBytes = 0; - object output = default(T); + T output = default; uint outputSize = MarshalHelper.SizeOf(); uint inputSize = MarshalHelper.SizeOf(); - bool success = DeviceIoControl(handle, controlCode, input, inputSize, output, outputSize, ref returnedBytes, IntPtr.Zero); + bool success = DeviceIoControl(handle, controlCode, new IntPtr(&input), inputSize, new IntPtr(&output), outputSize, ref returnedBytes, IntPtr.Zero); if (!success) { @@ -122,18 +120,19 @@ public static T InvokeIoControl(SafeFileHandle handle, IOControlCode contr throw new Win32Exception(lastError, "Couldn't invoke DeviceIoControl for " + controlCode + ". LastError: " + Utils.GetWin32ErrorMessage(lastError)); } - return (T)output; + return output; } /// /// Invoke DeviceIOControl with input of type V, and retrieves no output. /// - public static void InvokeIoControl(SafeFileHandle handle, IOControlCode controlCode, V input) + public unsafe static void InvokeIoControl(SafeFileHandle handle, IOControlCode controlCode, V input) + where V : unmanaged { uint returnedBytes = 0; uint inputSize = MarshalHelper.SizeOf(); - bool success = DeviceIoControl(handle, controlCode, input, inputSize, null, 0, ref returnedBytes, IntPtr.Zero); + bool success = DeviceIoControl(handle, controlCode, new IntPtr(&input), inputSize, IntPtr.Zero, 0, ref returnedBytes, IntPtr.Zero); if (!success) { @@ -145,15 +144,20 @@ public static void InvokeIoControl(SafeFileHandle handle, IOControlCode contr /// /// Calls InvokeIoControl with the specified input, returning a byte array. It allows the caller to handle errors. /// - public static byte[] InvokeIoControl(SafeFileHandle handle, IOControlCode controlCode, uint outputLength, V input, out int errorCode) + public unsafe static byte[] InvokeIoControl(SafeFileHandle handle, IOControlCode controlCode, uint outputLength, V input, out int errorCode) + where V : unmanaged { + bool success; uint returnedBytes = 0; uint inputSize = MarshalHelper.SizeOf(); errorCode = 0; - byte[] output = new byte[outputLength]; - bool success = DeviceIoControl(handle, controlCode, input, inputSize, output, outputLength, ref returnedBytes, IntPtr.Zero); + byte[] output = new byte[outputLength]; + fixed (byte* outputPtr = output) + { + success = DeviceIoControl(handle, controlCode, new IntPtr(&input), inputSize, new IntPtr(outputPtr), outputLength, ref returnedBytes, IntPtr.Zero); + } if (!success) { @@ -166,16 +170,21 @@ public static byte[] InvokeIoControl(SafeFileHandle handle, IOControlCode con /// /// Repeatedly invokes InvokeIoControl, as long as it gets return code 234 ("More data available") from the method. /// - public static byte[] InvokeIoControlUnknownSize(SafeFileHandle handle, IOControlCode controlCode, uint increment = 128) + public unsafe static byte[] InvokeIoControlUnknownSize(SafeFileHandle handle, IOControlCode controlCode, uint increment = 128) { uint returnedBytes = 0; uint outputLength = increment; + byte[] output = new byte[outputLength]; + do { - byte[] output = new byte[outputLength]; - bool success = DeviceIoControl(handle, controlCode, null, 0, output, outputLength, ref returnedBytes, IntPtr.Zero); + bool success; + fixed(byte* outputPtr = output) + { + success = DeviceIoControl(handle, controlCode, IntPtr.Zero, 0, new IntPtr(outputPtr), outputLength, ref returnedBytes, IntPtr.Zero); + } if (!success) { @@ -205,7 +214,8 @@ public static byte[] InvokeIoControlUnknownSize(SafeFileHandle handle, IOControl /// /// Repeatedly invokes InvokeIoControl with the specified input, as long as it gets return code 234 ("More data available") from the method. /// - public static byte[] InvokeIoControlUnknownSize(SafeFileHandle handle, IOControlCode controlCode, V input, uint increment = 128, uint inputSizeOverride = 0) + public unsafe static byte[] InvokeIoControlUnknownSize(SafeFileHandle handle, IOControlCode controlCode, V input, uint increment = 128, uint inputSizeOverride = 0) + where V : unmanaged { uint returnedBytes = 0; @@ -221,10 +231,15 @@ public static byte[] InvokeIoControlUnknownSize(SafeFileHandle handle, IOCont inputSize = MarshalHelper.SizeOf(); } + byte[] output = new byte[outputLength]; + do { - byte[] output = new byte[outputLength]; - bool success = DeviceIoControl(handle, controlCode, input, inputSize, output, outputLength, ref returnedBytes, IntPtr.Zero); + bool success; + fixed(byte* outputPtr = output) + { + success = DeviceIoControl(handle, controlCode, new IntPtr(&input), inputSize, new IntPtr(outputPtr), outputLength, ref returnedBytes, IntPtr.Zero); + } if (!success) { @@ -251,5 +266,50 @@ public static byte[] InvokeIoControlUnknownSize(SafeFileHandle handle, IOCont } while (true); } + /// + /// Repeatedly invokes InvokeIoControl with the specified input, as long as it gets return code 234 ("More data available") from the method. + /// + public unsafe static byte[] InvokeIoControlUnknownSize(SafeFileHandle handle, IOControlCode controlCode, byte[] input, uint increment = 128) + { + uint returnedBytes = 0; + + uint inputSize = (uint)input.Length; + uint outputLength = increment; + + byte[] output = new byte[outputLength]; + + do + { + bool success; + fixed (byte* inputPtr = input) + fixed (byte* outputPtr = output) + { + success = DeviceIoControl(handle, controlCode, new IntPtr(inputPtr), inputSize, new IntPtr(outputPtr), outputLength, ref returnedBytes, IntPtr.Zero); + } + + if (!success) + { + int lastError = Marshal.GetLastWin32Error(); + + if (lastError == 234) + { + // More data + outputLength += increment; + continue; + } + + throw new Win32Exception(lastError, "Couldn't invoke DeviceIoControl for " + controlCode + ". LastError: " + Utils.GetWin32ErrorMessage(lastError)); + } + + // Return the result + if (output.Length == returnedBytes) + return output; + + byte[] res = new byte[returnedBytes]; + Array.Copy(output, res, (int)returnedBytes); + + return res; + } while (true); + } } } \ No newline at end of file diff --git a/DeviceIOControlLib/Wrapper/DiskDeviceWrapper.cs b/DeviceIOControlLib/Wrapper/DiskDeviceWrapper.cs index 496f253..cbf6055 100644 --- a/DeviceIOControlLib/Wrapper/DiskDeviceWrapper.cs +++ b/DeviceIOControlLib/Wrapper/DiskDeviceWrapper.cs @@ -57,9 +57,16 @@ public PARTITION_INFORMATION_EX DiskGetPartitionInfoEx() //DiskSetPartitionInfoEx /// - public DRIVE_LAYOUT_INFORMATION DiskGetDriveLayout() + public unsafe DRIVE_LAYOUT_INFORMATION DiskGetDriveLayout() { - DRIVE_LAYOUT_INFORMATION_INTERNAL data = DeviceIoControlHelper.InvokeIoControl(Handle, IOControlCode.DiskGetDriveLayout); + byte[] outputBytes = DeviceIoControlHelper.InvokeIoControl(Handle, IOControlCode.DiskGetDriveLayoutEx, + (uint)sizeof(DRIVE_LAYOUT_INFORMATION_INTERNAL) + 128 * (uint)sizeof(PARTITION_INFORMATION)); + + DRIVE_LAYOUT_INFORMATION_INTERNAL data; + fixed (byte* outputPtr = outputBytes) + { + data = MarshalHelper.ToStructure(new IntPtr(outputPtr)); + } DRIVE_LAYOUT_INFORMATION res = new DRIVE_LAYOUT_INFORMATION(); @@ -67,16 +74,28 @@ public DRIVE_LAYOUT_INFORMATION DiskGetDriveLayout() res.Signature = data.Signature; res.PartitionEntry = new PARTITION_INFORMATION[res.PartitionCount]; - for (int i = 0; i < res.PartitionCount; i++) - res.PartitionEntry[i] = data.PartitionEntry[i]; + fixed (byte* outputPtr = outputBytes) + { + PARTITION_INFORMATION* partitionPtr = (PARTITION_INFORMATION*) + (outputPtr + sizeof(DRIVE_LAYOUT_INFORMATION_INTERNAL)); + for (int i = 0; i < res.PartitionCount; i++) + res.PartitionEntry[i] = *partitionPtr++; + } return res; } /// - public DRIVE_LAYOUT_INFORMATION_EX DiskGetDriveLayoutEx() + public unsafe DRIVE_LAYOUT_INFORMATION_EX DiskGetDriveLayoutEx() { - DRIVE_LAYOUT_INFORMATION_EX_INTERNAL data = DeviceIoControlHelper.InvokeIoControl(Handle, IOControlCode.DiskGetDriveLayoutEx); + byte[] outputBytes = DeviceIoControlHelper.InvokeIoControl(Handle, IOControlCode.DiskGetDriveLayoutEx, + (uint)sizeof(DRIVE_LAYOUT_INFORMATION_EX_INTERNAL) + 128 * (uint)sizeof(PARTITION_INFORMATION_EX)); + + DRIVE_LAYOUT_INFORMATION_EX_INTERNAL data; + fixed (byte* outputPtr = outputBytes) + { + data = MarshalHelper.ToStructure(new IntPtr(outputPtr)); + } DRIVE_LAYOUT_INFORMATION_EX res = new DRIVE_LAYOUT_INFORMATION_EX(); @@ -85,8 +104,13 @@ public DRIVE_LAYOUT_INFORMATION_EX DiskGetDriveLayoutEx() res.DriveLayoutInformaiton = data.DriveLayoutInformaiton; res.PartitionEntry = new PARTITION_INFORMATION_EX[res.PartitionCount]; - for (int i = 0; i < res.PartitionCount; i++) - res.PartitionEntry[i] = data.PartitionEntry[i]; + fixed(byte* outputPtr = outputBytes) + { + PARTITION_INFORMATION_EX* partitionPtr = (PARTITION_INFORMATION_EX*) + (outputPtr + sizeof(DRIVE_LAYOUT_INFORMATION_EX_INTERNAL)); + for (int i = 0; i < res.PartitionCount; i++) + res.PartitionEntry[i] = *partitionPtr++; + } return res; } diff --git a/DeviceIOControlLib/Wrapper/MountManagerWrapper.cs b/DeviceIOControlLib/Wrapper/MountManagerWrapper.cs index 2f217f1..819b514 100644 --- a/DeviceIOControlLib/Wrapper/MountManagerWrapper.cs +++ b/DeviceIOControlLib/Wrapper/MountManagerWrapper.cs @@ -69,7 +69,7 @@ public List QueryDosVolumePaths(string deviceName) Encoding.Unicode.GetBytes(deviceName, 0, deviceName.Length, tmp, 2); - byte[] data = DeviceIoControlHelper.InvokeIoControlUnknownSize(Handle, IOControlCode.MountmgrQueryDosVolumePaths, tmp, 64, (uint)tmp.Length); + byte[] data = DeviceIoControlHelper.InvokeIoControlUnknownSize(Handle, IOControlCode.MountmgrQueryDosVolumePaths, tmp, 64); return new List(Utils.ReadUnicodeStringArray(data, sizeof(uint))); } diff --git a/DeviceIOControlLib/Wrapper/StorageDeviceWrapper.cs b/DeviceIOControlLib/Wrapper/StorageDeviceWrapper.cs index 2b2e83b..5634ffe 100644 --- a/DeviceIOControlLib/Wrapper/StorageDeviceWrapper.cs +++ b/DeviceIOControlLib/Wrapper/StorageDeviceWrapper.cs @@ -2,6 +2,8 @@ using DeviceIOControlLib.Objects.Storage; using DeviceIOControlLib.Utilities; using Microsoft.Win32.SafeHandles; +using System; +using System.Runtime.InteropServices; namespace DeviceIOControlLib.Wrapper { @@ -17,7 +19,7 @@ public StorageDeviceWrapper(SafeFileHandle handle, bool ownsHandle = false) //StorageCheckVerify2 //StorageMediaRemoval - public STORAGE_DEVICE_DESCRIPTOR_PARSED StorageGetDeviceProperty() + public unsafe STORAGE_DEVICE_DESCRIPTOR_PARSED StorageGetDeviceProperty() { STORAGE_PROPERTY_QUERY query = new STORAGE_PROPERTY_QUERY(); query.QueryType = STORAGE_QUERY_TYPE.PropertyStandardQuery; @@ -40,7 +42,7 @@ public STORAGE_DEVICE_DESCRIPTOR_PARSED StorageGetDeviceProperty() returnValue.SerialNumberOffset = descriptor.SerialNumberOffset; returnValue.BusType = descriptor.BusType; returnValue.RawPropertiesLength = descriptor.RawPropertiesLength; - returnValue.RawDeviceProperties = descriptor.RawDeviceProperties; + Buffer.MemoryCopy(descriptor.RawDeviceProperties, returnValue.RawDeviceProperties, 0x16, 0x16); if (descriptor.SerialNumberOffset > 0) returnValue.SerialNumber = Utils.ReadNullTerminatedAsciiString(res, (int)descriptor.SerialNumberOffset);