From ed939dcf6c0025b20a18d672c5e2e2f4454ca820 Mon Sep 17 00:00:00 2001 From: Antoine Larine Date: Thu, 25 Jan 2024 11:13:16 +0300 Subject: [PATCH] Add DeviceIoControl and NT status codes --- src/WinAPI/NativeMethods/ErrorCodes.cs | 12 +++- src/WinAPI/NativeMethods/Kernel32.cs | 92 +++++++++++++++++++++----- src/WinAPI/NativeMethods/NtStatus.cs | 33 +++++++++ src/WinAPI/NativeMethods/SetupAPI.cs | 59 ++++++++++++----- 4 files changed, 161 insertions(+), 35 deletions(-) create mode 100644 src/WinAPI/NativeMethods/NtStatus.cs diff --git a/src/WinAPI/NativeMethods/ErrorCodes.cs b/src/WinAPI/NativeMethods/ErrorCodes.cs index 83457b6..9598c75 100644 --- a/src/WinAPI/NativeMethods/ErrorCodes.cs +++ b/src/WinAPI/NativeMethods/ErrorCodes.cs @@ -1,5 +1,3 @@ -using System.Reflection.Emit; - namespace Larin.WinAPI.NativeMethods; /// @@ -133,6 +131,16 @@ public static class ErrorCodes /// public const int ERROR_ALREADY_EXISTS = 183; + /// + /// More data is available. + /// + public const int ERROR_MORE_DATA = 234; + + /// + /// The wait operation timed out. + /// + public const int WAIT_TIMEOUT = 258; + /// /// No more data is available. /// diff --git a/src/WinAPI/NativeMethods/Kernel32.cs b/src/WinAPI/NativeMethods/Kernel32.cs index 0847531..3ee132f 100644 --- a/src/WinAPI/NativeMethods/Kernel32.cs +++ b/src/WinAPI/NativeMethods/Kernel32.cs @@ -1,20 +1,10 @@ // Copyright © Anton Larin, 2024. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Microsoft.VisualBasic; -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Net.NetworkInformation; -using System.Reflection.Metadata; -using System.Reflection.PortableExecutable; using System.Runtime.InteropServices; -using System.Runtime.Intrinsics.X86; using System.Runtime.Versioning; using static Larin.WinAPI.NativeMethods.ErrorCodes; -using static System.Collections.Specialized.BitVector32; -using static System.Net.WebRequestMethods; +using static Larin.WinAPI.NativeMethods.NtStatus; namespace Larin.WinAPI.NativeMethods; @@ -22,7 +12,7 @@ namespace Larin.WinAPI.NativeMethods; /// P/Invoke items for the Kernel32.dll Windows API library /// [SupportedOSPlatform("WINDOWS")] -public static class Kernel32 +public static unsafe class Kernel32 { /// /// Kernel32 library file name @@ -34,6 +24,47 @@ public static class Kernel32 /// public const nint INVALID_HANDLE_VALUE = -1; + /// + /// Contains information used in asynchronous (or overlapped) input and output (I/O). + /// + /// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped + [StructLayout(LayoutKind.Sequential)] + public struct OVERLAPPED + { + /// + /// The status code for the I/O request. When the request is issued, the system sets this member to to indicate that the operation has not yet started. + /// When the request is completed, the system sets this member to the status code for the completed request. + /// + public nuint Internal; + + /// + /// The number of bytes transferred for the I/O request. The system sets this member if the request is completed without errors. + /// + public nuint InternalHigh; + + + /// + /// The low-order portion of the file position at which to start the I/O request, as specified by the user. + /// This member is nonzero only when performing I/O requests on a seeking device that supports the concept of an offset(also referred to as a file pointer mechanism), such as a file. + /// Otherwise, this member must be zero. + /// + public uint Offset; + + /// + /// The high-order portion of the file position at which to start the I/O request, as specified by the user. + /// This member is nonzero only when performing I/O requests on a seeking device that supports the concept of an offset(also referred to as a file pointer mechanism), such as a file. + /// Otherwise, this member must be zero. + /// + public uint OffsetHigh; + + /// + /// A handle to the event that will be set to a signaled state by the system when the operation has completed. + /// The user must initialize this member either to zero or a valid event handle using the function before passing this structure to any overlapped functions. + /// This event can then be used to synchronize simultaneous I/O requests for a device. + /// + public nint hEvent; + } + /// /// Creates or opens a file or I/O device. /// @@ -55,7 +86,7 @@ public static extern nint CreateFile( [In] string lpFileName, [In] uint dwDesiredAccess, [In] uint dwShareMode, - [In, Optional] nint lpSecurityAttributes, + [In, Optional] void* lpSecurityAttributes, [In] uint dwCreationDisposition, [In] uint dwFlagsAndAttributes, [In, Optional] nint hTemplateFile @@ -430,7 +461,6 @@ public static extern nint CreateFile( /// public const uint SECURITY_EFFECTIVE_ONLY = 0x00080000; - /// /// Closes an open object handle. /// @@ -442,6 +472,38 @@ public static extern nint CloseHandle( [In] nint hObject ); + /// + /// Sends a control code directly to a specified device driver, causing the corresponding device to perform the corresponding operation. + /// + /// A handle to the device on which the operation is to be performed. The device is typically a volume, directory, file, or stream. + /// To retrieve a device handle, use the function. + /// The control code for the operation. This value identifies the specific operation to be performed and the type of device on which to perform it. + /// A pointer to the input buffer that contains the data required to perform the operation. The format of this data depends on the value of the dwIoControlCode parameter. + /// This parameter can be NULL if dwIoControlCode specifies an operation that does not require input data. + /// The size of the input buffer, in bytes. + /// A pointer to the output buffer that is to receive the data returned by the operation. The format of this data depends on the value of the dwIoControlCode parameter. + /// This parameter can be NULL if dwIoControlCode specifies an operation that does not return data. + /// The size of the output buffer, in bytes. + /// A pointer to a variable that receives the size of the data stored in the output buffer, in bytes. + /// A pointer to an structure. If hDevice was opened without specifying , lpOverlapped is ignored. + /// If hDevice was opened with the flag, the operation is performed as an overlapped(asynchronous) operation. + /// In this case, lpOverlapped must point to a valid structure that contains a handle to an event object. Otherwise, the function fails in unpredictable ways. + /// For overlapped operations, returns immediately, and the event object is signaled when the operation has been completed. + /// Otherwise, the function does not return until the operation has been completed or an error occurs. + /// + /// https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-deviceiocontrol + [DllImport(Kernel32Lib, CharSet = CharSet.Unicode, SetLastError = true)] + public static extern bool DeviceIoControl( + [In] nint hDevice, + [In] uint dwIoControlCode, + [In, Optional] void* lpInBuffer, + [In] uint nInBufferSize, + [Out, Optional] void* lpOutBuffer, + [In] uint nOutBufferSize, + [Out, Optional] uint* lpBytesReturned, + [In, Out, Optional] OVERLAPPED* lpOverlapped + ); + /// /// Frees the specified local memory object and invalidates its handle. /// @@ -450,6 +512,6 @@ [In] nint hObject /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localfree [DllImport(Kernel32Lib, CharSet = CharSet.Unicode, SetLastError = true)] public static extern nint LocalFree( - [In] nint hMem + [In] void* hMem ); } diff --git a/src/WinAPI/NativeMethods/NtStatus.cs b/src/WinAPI/NativeMethods/NtStatus.cs new file mode 100644 index 0000000..446bb1a --- /dev/null +++ b/src/WinAPI/NativeMethods/NtStatus.cs @@ -0,0 +1,33 @@ +namespace Larin.WinAPI.NativeMethods; + +/// +/// Windows System Error codes +/// +/// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55 +public static class NtStatus +{ + /// + /// The operation completed successfully. + /// + public const uint STATUS_WAIT_0 = 0x00000000; + + /// + /// The caller attempted to wait for a mutex that has been abandoned. + /// + public const uint STATUS_ABANDONED_WAIT_0 = 0x00000080; + + /// + /// The delay completed because the thread was alerted. + /// + public const uint STATUS_ALERTED = 0x00000101; + + /// + /// The given Timeout interval expired. + /// + public const uint STATUS_TIMEOUT = 0x00000102; + + /// + /// The operation that was requested is pending completion. + /// + public const uint STATUS_PENDING = 0x00000103; +} diff --git a/src/WinAPI/NativeMethods/SetupAPI.cs b/src/WinAPI/NativeMethods/SetupAPI.cs index 619179b..b322b55 100644 --- a/src/WinAPI/NativeMethods/SetupAPI.cs +++ b/src/WinAPI/NativeMethods/SetupAPI.cs @@ -1,13 +1,9 @@ // Copyright © Anton Larin, 2024. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Microsoft.VisualBasic; using System; using System.Runtime.InteropServices; using System.Runtime.Versioning; -using System.Security.Principal; -using static Larin.WinAPI.NativeMethods.Crypt32; -using static Larin.WinAPI.NativeMethods.SetupAPI; namespace Larin.WinAPI.NativeMethods; @@ -36,8 +32,8 @@ public static unsafe class SetupAPI /// https://learn.microsoft.com/en-us/windows/win32/api/setupapi/nf-setupapi-setupdigetclassdevsw [DllImport(SetupApiLib, CharSet = CharSet.Unicode, SetLastError = true)] public static extern nint SetupDiGetClassDevs( - [In] nint ClassGuid, - [In] nint Enumerator, + [In] Guid* ClassGuid, + [In] void* Enumerator, [In] nint hwndParent, [In] uint Flags ); @@ -89,7 +85,7 @@ [In] uint Flags /// Enumerates the device interfaces that are contained in a device information set. /// /// A pointer to a device information set that contains the device interfaces for which to return information. This handle is typically returned by . - /// A pointer to a structure that specifies a device information element in DeviceInfoSet. This parameter is optional and can be NULL. + /// A pointer to a structure that specifies a device information element in DeviceInfoSet. This parameter is optional and can be NULL. /// If this parameter is specified, constrains the enumeration to the interfaces that are supported by the specified device. /// If this parameter is NULL, repeated calls to return information about the interfaces that are associated with all the device information elements in DeviceInfoSet. /// This pointer is typically returned by . @@ -100,13 +96,14 @@ [In] uint Flags /// A pointer to a caller-allocated buffer that contains, on successful return, a completed structure that identifies an interface that meets the search parameters. /// The caller must set DeviceInterfaceData.cbSize to sizeof(SP_DEVICE_INTERFACE_DATA) before calling this function. /// Returns TRUE if the function completed without error. If the function completed with an error, FALSE is returned and the error code for the failure can be retrieved by calling GetLastError. + /// https://learn.microsoft.com/en-us/windows/win32/api/setupapi/nf-setupapi-setupdienumdeviceinterfaces [DllImport(SetupApiLib, CharSet = CharSet.Unicode, SetLastError = true)] public static extern bool SetupDiEnumDeviceInterfaces( [In] nint hDeviceInfoSet, - [In] nint DeviceInfoData, - [In] nint InterfaceClassGuid, + [In, Optional] SP_DEVINFO_DATA* pDeviceInfoData, + [In] Guid* InterfaceClassGuid, [In] uint MemberIndex, - [Out] nint DeviceInterfaceData + [Out] SP_DEVICE_INTERFACE_DATA* DeviceInterfaceData ); /// @@ -202,27 +199,53 @@ public SP_DEVICE_INTERFACE_DATA() /// Returns details about a device interface. /// /// A pointer to the device information set that contains the interface for which to retrieve details. This handle is typically returned by . - /// A pointer to an structure that specifies the interface in DeviceInfoSet for which to retrieve details. + /// A pointer to an structure that specifies the interface in DeviceInfoSet for which to retrieve details. /// A pointer of this type is typically returned by . - /// A pointer to an structure to receive information about the specified interface. This parameter is optional and can be NULL. + /// A pointer to an structure to receive information about the specified interface. This parameter is optional and can be NULL. /// This parameter must be NULL if DeviceInterfaceDetailSize is zero. If this parameter is specified, the caller must set DeviceInterfaceDetailData.cbSize to sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) before calling this function. /// The cbSize member always contains the size of the fixed part of the data structure, not a size reflecting the variable-length string at the end. /// The size of the DeviceInterfaceDetailData buffer. The buffer must be at least (offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath) + sizeof(TCHAR)) bytes, to contain the fixed part of the structure and a single NULL to terminate an empty MULTI_SZ string. /// This parameter must be zero if DeviceInterfaceDetailData is NULL. - /// A pointer to a variable of type DWORD that receives the required size of the DeviceInterfaceDetailData buffer. This size includes the size of the fixed part of the structure plus the number of bytes required for the variable-length device path string. This parameter is optional and can be NULL. - /// A pointer to a buffer that receives information about the device that supports the requested interface. The caller must set DeviceInfoData.cbSize to sizeof(SP_DEVINFO_DATA). This parameter is optional and can be NULL. + /// A pointer to a variable of type DWORD that receives the required size of the DeviceInterfaceDetailData buffer. This size includes the size of the fixed part of the structure plus the number of bytes required for the variable-length device path string. This parameter is optional and can be NULL. + /// A pointer to a buffer that receives information about the device that supports the requested interface. The caller must set DeviceInfoData.cbSize to sizeof(SP_DEVINFO_DATA). This parameter is optional and can be NULL. /// Returns TRUE if the function completed without error. If the function completed with an error, FALSE is returned and the error code for the failure can be retrieved by calling GetLastError. /// https://learn.microsoft.com/en-us/windows/win32/api/setupapi/nf-setupapi-setupdigetdeviceinterfacedetailw [DllImport(SetupApiLib, CharSet = CharSet.Unicode, SetLastError = true)] public static extern bool SetupDiGetDeviceInterfaceDetail( [In] nint hDeviceInfoSet, - [In] nint DeviceInterfaceData, - [Out, Optional] nint DeviceInterfaceDetailData, + [In] SP_DEVICE_INTERFACE_DATA* pDeviceInterfaceData, + [Out, Optional] void* pDeviceInterfaceDetailData, [In] uint DeviceInterfaceDetailDataSize, - [Out, Optional] nint RequiredSize, - [Out, Optional] nint DeviceInfoData + [Out, Optional] uint* pRequiredSize, + [Out, Optional] void* pDeviceInfoData ); + /// + /// Contains the path for a device interface. + /// + /// https://learn.microsoft.com/en-us/windows/win32/api/setupapi/ns-setupapi-sp_device_interface_detail_data_w + [StructLayout(LayoutKind.Sequential)] + public struct SP_DEVICE_INTERFACE_DETAIL_DATA_W + { + /// + /// The size, in bytes, of the structure. + /// + public uint cbSize; + + /// + /// A NULL-terminated string that contains the device interface path. This path can be passed to Win32 functions such as CreateFile. + /// + public char DevicePath; + + /// + /// Initializes a new instance of the structure + /// + public SP_DEVICE_INTERFACE_DETAIL_DATA_W() + { + cbSize = (uint)Marshal.SizeOf(this); + } + } + /// /// Deletes a device information set and frees all associated memory. ///