using System; using System.IO; using System.Runtime.InteropServices; using System.Threading; using Vanara.Extensions; using Vanara.InteropServices; namespace Vanara.PInvoke { public static partial class Kernel32 { /// /// Starts the asynchronous operation of sending a control code directly to a specified device driver, causing the corresponding /// device to perform the corresponding operation. /// /// The type of the . /// The type of the . /// /// 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 CreateFile function. For more information, see Remarks. /// /// /// 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. /// /// /// 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. /// /// An AsyncCallback delegate that references the method to invoke when the operation is complete. /// An IAsyncResult instance that references the asynchronous request. [PInvokeData("Winbase.h", MSDNShortId = "aa363216")] public static IAsyncResult BeginDeviceIoControl(HFILE hDevice, uint dwIoControlCode, TIn? inVal, TOut? outVal, AsyncCallback userCallback) where TIn : struct where TOut : struct { var buffer = Pack(inVal, outVal); return BeginDeviceIoControl(hDevice, dwIoControlCode, buffer, userCallback, null); } /// /// Starts the asynchronous operation of sending 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 CreateFile function. For more information, see Remarks. /// /// /// 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. /// /// The input buffer required to perform the operation. Can be null if unnecessary. /// The output buffer that is to receive the data returned by the operation. Can be null if unnecessary. /// An AsyncCallback delegate that references the method to invoke when the operation is complete. /// An IAsyncResult instance that references the asynchronous request. [PInvokeData("Winbase.h", MSDNShortId = "aa363216")] public static IAsyncResult BeginDeviceIoControl(HFILE hDevice, uint dwIoControlCode, byte[] inputBuffer, byte[] outputBuffer, AsyncCallback userCallback) { var buffer = Pack(inputBuffer, outputBuffer); return BeginDeviceIoControl(hDevice, dwIoControlCode, buffer, userCallback, null); } /// /// /// Cancels all pending input and output (I/O) operations that are issued by the calling thread for the specified file. The function /// does not cancel I/O operations that other threads issue for a file handle. /// /// To cancel I/O operations from another thread, use the CancelIoEx function. /// /// /// A handle to the file. /// The function cancels all pending I/O operations for this file handle. /// /// /// /// If the function succeeds, the return value is nonzero. The cancel operation for all pending I/O operations issued by the calling /// thread for the specified file handle was successfully requested. The thread can use the GetOverlappedResult function to /// determine when the I/O operations themselves have been completed. /// /// If the function fails, the return value is zero (0). To get extended error information, call the GetLastError function. /// // BOOL WINAPI CancelIo( _In_ HANDLE hFile);// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363791(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("IoAPI.h", MSDNShortId = "aa363791")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CancelIo([In] HFILE hFile); /// /// Marks any outstanding I/O operations for the specified file handle. The function only cancels I/O operations in the current /// process, regardless of which thread created the I/O operation. /// /// A handle to the file. /// /// A pointer to an OVERLAPPED data structure that contains the data used for asynchronous I/O. /// If this parameter is NULL, all I/O requests for the hFile parameter are canceled. /// /// If this parameter is not NULL, only those specific I/O requests that were issued for the file with the specified /// lpOverlapped overlapped structure are marked as canceled, meaning that you can cancel one or more requests, while the /// CancelIo function cancels all outstanding requests on a file handle. /// /// /// /// /// If the function succeeds, the return value is nonzero. The cancel operation for all pending I/O operations issued by the calling /// process for the specified file handle was successfully requested. The application must not free or reuse the OVERLAPPED /// structure associated with the canceled I/O operations until they have completed. The thread can use the /// GetOverlappedResult function to determine when the I/O operations themselves have been completed. /// /// If the function fails, the return value is 0 (zero). To get extended error information, call the GetLastError function. /// If this function cannot find a request to cancel, the return value is 0 (zero), and GetLastError returns ERROR_NOT_FOUND. /// // BOOL WINAPI CancelIoEx( _In_ HANDLE hFile, _In_opt_ LPOVERLAPPED lpOverlapped);// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363792(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("IoAPI.h", MSDNShortId = "aa363792")] [return: MarshalAs(UnmanagedType.Bool)] public static extern unsafe bool CancelIoEx([In] HFILE hFile, [In] NativeOverlapped* lpOverlapped); /// Marks pending synchronous I/O operations that are issued by the specified thread as canceled. /// A handle to the thread. /// /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is 0 (zero). To get extended error information, call the GetLastError function. /// If this function cannot find a request to cancel, the return value is 0 (zero), and GetLastError returns ERROR_NOT_FOUND. /// // BOOL WINAPI CancelSynchronousIo( _In_ HANDLE hThread); https://msdn.microsoft.com/en-us/library/windows/desktop/aa363794(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("IoAPI.h", MSDNShortId = "aa363794")] [return: MarshalAs(UnmanagedType.Bool)] public static extern unsafe bool CancelSynchronousIo([In] HTHREAD hThread); /// /// /// Creates an input/output (I/O) completion port and associates it with a specified file handle, or creates an I/O completion port /// that is not yet associated with a file handle, allowing association at a later time. /// /// /// Associating an instance of an opened file handle with an I/O completion port allows a process to receive notification of the /// completion of asynchronous I/O operations involving that file handle. /// /// /// /// An open file handle or INVALID_HANDLE_VALUE. /// The handle must be to an object that supports overlapped I/O. /// /// If a handle is provided, it has to have been opened for overlapped I/O completion. For example, you must specify the /// FILE_FLAG_OVERLAPPED flag when using the CreateFile function to obtain the handle. /// /// /// If INVALID_HANDLE_VALUE is specified, the function creates an I/O completion port without associating it with a file /// handle. In this case, the ExistingCompletionPort parameter must be NULL and the CompletionKey parameter is ignored. /// /// /// /// A handle to an existing I/O completion port or NULL. /// /// If this parameter specifies an existing I/O completion port, the function associates it with the handle specified by the /// FileHandle parameter. The function returns the handle of the existing I/O completion port if successful; it does not create a new /// I/O completion port. /// /// /// If this parameter is NULL, the function creates a new I/O completion port and, if the FileHandle parameter is valid, /// associates it with the new I/O completion port. Otherwise no file handle association occurs. The function returns the handle to /// the new I/O completion port if successful. /// /// /// /// The per-handle user-defined completion key that is included in every I/O completion packet for the specified file handle. For /// more information, see the Remarks section. /// /// /// /// The maximum number of threads that the operating system can allow to concurrently process I/O completion packets for the I/O /// completion port. This parameter is ignored if the ExistingCompletionPort parameter is not NULL. /// /// If this parameter is zero, the system allows as many concurrently running threads as there are processors in the system. /// /// /// If the function succeeds, the return value is the handle to an I/O completion port: /// /// /// /// /// /// /// /// /// /// /// /// /// If the function fails, the return value is NULL. To get extended error information, call the GetLastError function. /// /// /// /// /// The I/O system can be instructed to send I/O completion notification packets to I/O completion ports, where they are queued. The /// CreateIoCompletionPort function provides this functionality. /// /// /// An I/O completion port and its handle are associated with the process that created it and is not sharable between processes. /// However, a single handle is sharable between threads in the same process. /// /// CreateIoCompletionPort can be used in three distinct modes: /// /// /// Create only an I/O completion port without associating it with a file handle. /// /// /// Associate an existing I/O completion port with a file handle. /// /// /// Perform both creation and association in a single call. /// /// /// /// To create an I/O completion port without associating it, set the FileHandle parameter to INVALID_HANDLE_VALUE, the /// ExistingCompletionPort parameter to NULL, and the CompletionKey parameter to zero (which is ignored in this case). Set the /// NumberOfConcurrentThreads parameter to the desired concurrency value for the new I/O completion port, or zero for the default /// (the number of processors in the system). /// /// /// The handle passed in the FileHandle parameter can be any handle that supports overlapped I/O. Most commonly, this is a handle /// opened by the CreateFile function using the FILE_FLAG_OVERLAPPED flag (for example, files, mail slots, and pipes). /// Objects created by other functions such as socket can also be associated with an I/O completion port. For an example using /// sockets, see AcceptEx. A handle can be associated with only one I/O completion port, and after the association is made, /// the handle remains associated with that I/O completion port until it is closed. /// /// For more information on I/O completion port theory, usage, and associated functions, see I/O Completion Ports. /// /// Multiple file handles can be associated with a single I/O completion port by calling CreateIoCompletionPort multiple times /// with the same I/O completion port handle in the ExistingCompletionPort parameter and a different file handle in the FileHandle /// parameter each time. /// /// /// Use the CompletionKey parameter to help your application track which I/O operations have completed. This value is not used by /// CreateIoCompletionPort for functional control; rather, it is attached to the file handle specified in the FileHandle /// parameter at the time of association with an I/O completion port. This completion key should be unique for each file handle, and /// it accompanies the file handle throughout the internal completion queuing process. It is returned in the /// GetQueuedCompletionStatus function call when a completion packet arrives. The CompletionKey parameter is also used by the /// PostQueuedCompletionStatus function to queue your own special-purpose completion packets. /// /// /// After an instance of an open handle is associated with an I/O completion port, it cannot be used in the ReadFileEx or /// WriteFileEx function because these functions have their own asynchronous I/O mechanisms. /// /// /// It is best not to share a file handle associated with an I/O completion port by using either handle inheritance or a call to the /// DuplicateHandle function. Operations performed with such duplicate handles generate completion notifications. Careful /// consideration is advised. /// /// /// The I/O completion port handle and every file handle associated with that particular I/O completion port are known as references /// to the I/O completion port. The I/O completion port is released when there are no more references to it. Therefore, all of these /// handles must be properly closed to release the I/O completion port and its associated system resources. After these conditions /// are satisfied, close the I/O completion port handle by calling the CloseHandle function. /// /// In Windows 8 and Windows Server 2012, this function is supported by the following technologies. /// /// /// Technology /// Supported /// /// /// Server Message Block (SMB) 3.0 protocol /// Yes /// /// /// SMB 3.0 Transparent Failover (TFO) /// Yes /// /// /// SMB 3.0 with Scale-out File Shares (SO) /// Yes /// /// /// Cluster Shared Volume File System (CsvFS) /// Yes /// /// /// Resilient File System (ReFS) /// Yes /// /// /// // https://docs.microsoft.com/en-us/windows/desktop/FileIO/createiocompletionport // HANDLE WINAPI CreateIoCompletionPort( _In_ HANDLE FileHandle, _In_opt_ HANDLE ExistingCompletionPort, _In_ ULONG_PTR CompletionKey, _In_ DWORD NumberOfConcurrentThreads ); [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("IoAPI.h", MSDNShortId = "40cb47fc-7b15-47f6-bee2-2611d4686053")] public static extern HANDLE CreateIoCompletionPort([In] HANDLE FileHandle, [In, Optional] HANDLE ExistingCompletionPort, UIntPtr CompletionKey, uint NumberOfConcurrentThreads); /// This macro is used to create a unique system I/O control code (IOCTL). /// /// Defines the type of device for the given IOCTL. This parameter can be no bigger then a WORD value. The values used by Microsoft /// are in the range 0-32767 and the values 32768-65535 are reserved for use by OEMs and IHVs. /// /// /// Defines an action within the device category. That function codes 0-2047 are reserved for Microsoft, and 2048-4095 are reserved /// for OEMs and IHVs. The function code can be no larger then 4095. /// /// /// Defines the method codes for how buffers are passed for I/O and file system controls. The following list shows the possible /// values for this parameter: /// /// /// METHOD_BUFFERED /// /// /// METHOD_IN_DIRECT /// /// /// METHOD_OUT_DIRECT /// /// /// METHOD_NEITHER /// /// /// /// This field is ignored under Windows CE and you should always use the METHOD_BUFFERED value unless compatibility with the desktop /// is required using a different Method value. /// /// /// /// Defines the access check value for any access. The following table shows the possible flags for this parameter. The /// FILE_ACCESS_ANY is generally the correct value. /// /// /// Flag /// Description /// /// /// FILE_ANY_ACCESS /// Request all access. /// /// /// FILE_READ_ACCESS /// Request read access. Can be used with FILE_WRITE_ACCESS. /// /// /// FILE_WRITE_ACCESS /// Request write access. Can be used with FILE_READ_ACCESS. /// /// /// /// The resulting I/O control code. /// function public static uint CTL_CODE(ushort deviceType, ushort function, byte method, byte access) { if (function > 0xfff) throw new ArgumentOutOfRangeException(nameof(function)); return (uint)((deviceType << 0x10) | (access << 14) | (function << 2) | method); } /// This macro is used to create a unique system I/O control code (IOCTL). /// /// Defines the type of device for the given IOCTL. This parameter can be no bigger then a WORD value. The values used by Microsoft /// are in the range 0-32767 and the values 32768-65535 are reserved for use by OEMs and IHVs. /// /// /// Defines an action within the device category. That function codes 0-2047 are reserved for Microsoft, and 2048-4095 are reserved /// for OEMs and IHVs. The function code can be no larger then 4095. /// /// /// Defines the method codes for how buffers are passed for I/O and file system controls. /// /// This field is ignored under Windows CE and you should always use the METHOD_BUFFERED value unless compatibility with the desktop /// is required using a different Method value. /// /// /// Defines the access check value for any access. /// The resulting I/O control code. public static uint CTL_CODE(DEVICE_TYPE deviceType, ushort function, IOMethod method, IOAccess access) => CTL_CODE((ushort)deviceType, function, (byte)method, (byte)access); /// /// 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 CreateFile function. For more information, see Remarks. /// /// /// 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. /// /// If the output buffer is too small to receive any data, the call fails, GetLastError returns ERROR_INSUFFICIENT_BUFFER, and /// lpBytesReturned is zero. /// /// /// If the output buffer is too small to hold all of the data but can hold some entries, some drivers will return as much data as /// fits. In this case, the call fails, GetLastError returns ERROR_MORE_DATA, and lpBytesReturned indicates the amount of data /// received. Your application should call DeviceIoControl again with the same operation, specifying a new starting point. /// /// /// If lpOverlapped is NULL, lpBytesReturned cannot be NULL. Even when an operation returns no output data and lpOutBuffer is NULL, /// DeviceIoControl makes use of lpBytesReturned. After such an operation, the value of lpBytesReturned is meaningless. /// /// /// If lpOverlapped is not NULL, lpBytesReturned can be NULL. If this parameter is not NULL and the operation returns data, /// lpBytesReturned is meaningless until the overlapped operation has completed. To retrieve the number of bytes returned, call /// GetOverlappedResult. If hDevice is associated with an I/O completion port, you can retrieve the number of bytes returned by /// calling GetQueuedCompletionStatus. /// /// /// /// A pointer to an OVERLAPPED structure. /// If hDevice was opened without specifying FILE_FLAG_OVERLAPPED, lpOverlapped is ignored. /// /// If hDevice was opened with the FILE_FLAG_OVERLAPPED flag, the operation is performed as an overlapped (asynchronous) operation. /// In this case, lpOverlapped must point to a valid OVERLAPPED structure that contains a handle to an event object. Otherwise, the /// function fails in unpredictable ways. /// /// /// For overlapped operations, DeviceIoControl 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. /// /// /// /// If the operation completes successfully, the return value is nonzero. /// If the operation fails or is pending, the return value is zero. To get extended error information, call GetLastError. /// /// /// /// To retrieve a handle to the device, you must call the CreateFile function with either the name of a device or the name of the /// driver associated with a device. To specify a device name, use the following format: /// /// \\.\DeviceName /// /// DeviceIoControl can accept a handle to a specific device. For example, to open a handle to the logical drive /// A: with CreateFile, specify \\.\a:. Alternatively, you can use the names \\.\PhysicalDrive0, \\.\PhysicalDrive1, and so on, to /// open handles to the physical drives on a system. /// /// /// You should specify the FILE_SHARE_READ and FILE_SHARE_WRITE access flags when calling CreateFile to open a handle to a device /// driver. However, when you open a communications resource, such as a serial port, you must specify exclusive access. Use the other /// CreateFile parameters as follows when opening a device handle: /// /// /// /// The fdwCreate parameter must specify OPEN_EXISTING. /// /// /// The hTemplateFile parameter must be NULL. /// /// /// /// The fdwAttrsAndFlags parameter can specify FILE_FLAG_OVERLAPPED to indicate that the returned handle can be used in overlapped /// (asynchronous) I/O operations. /// /// /// /// [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] [PInvokeData("Winbase.h", MSDNShortId = "aa363216")] public static extern bool DeviceIoControl(HFILE hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped); /// /// 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 CreateFile function. For more information, see Remarks. /// /// /// 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. /// /// If the output buffer is too small to receive any data, the call fails, GetLastError returns ERROR_INSUFFICIENT_BUFFER, and /// lpBytesReturned is zero. /// /// /// If the output buffer is too small to hold all of the data but can hold some entries, some drivers will return as much data as /// fits. In this case, the call fails, GetLastError returns ERROR_MORE_DATA, and lpBytesReturned indicates the amount of data /// received. Your application should call DeviceIoControl again with the same operation, specifying a new starting point. /// /// /// If lpOverlapped is NULL, lpBytesReturned cannot be NULL. Even when an operation returns no output data and lpOutBuffer is NULL, /// DeviceIoControl makes use of lpBytesReturned. After such an operation, the value of lpBytesReturned is meaningless. /// /// /// If lpOverlapped is not NULL, lpBytesReturned can be NULL. If this parameter is not NULL and the operation returns data, /// lpBytesReturned is meaningless until the overlapped operation has completed. To retrieve the number of bytes returned, call /// GetOverlappedResult. If hDevice is associated with an I/O completion port, you can retrieve the number of bytes returned by /// calling GetQueuedCompletionStatus. /// /// /// /// A pointer to an OVERLAPPED structure. /// If hDevice was opened without specifying FILE_FLAG_OVERLAPPED, lpOverlapped is ignored. /// /// If hDevice was opened with the FILE_FLAG_OVERLAPPED flag, the operation is performed as an overlapped (asynchronous) operation. /// In this case, lpOverlapped must point to a valid OVERLAPPED structure that contains a handle to an event object. Otherwise, the /// function fails in unpredictable ways. /// /// /// For overlapped operations, DeviceIoControl 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. /// /// /// /// If the operation completes successfully, the return value is nonzero. /// If the operation fails or is pending, the return value is zero. To get extended error information, call GetLastError. /// /// /// /// To retrieve a handle to the device, you must call the CreateFile function with either the name of a device or the name of the /// driver associated with a device. To specify a device name, use the following format: /// /// \\.\DeviceName /// /// DeviceIoControl can accept a handle to a specific device. For example, to open a handle to the logical drive /// A: with CreateFile, specify \\.\a:. Alternatively, you can use the names \\.\PhysicalDrive0, \\.\PhysicalDrive1, and so on, to /// open handles to the physical drives on a system. /// /// /// You should specify the FILE_SHARE_READ and FILE_SHARE_WRITE access flags when calling CreateFile to open a handle to a device /// driver. However, when you open a communications resource, such as a serial port, you must specify exclusive access. Use the other /// CreateFile parameters as follows when opening a device handle: /// /// /// /// The fdwCreate parameter must specify OPEN_EXISTING. /// /// /// The hTemplateFile parameter must be NULL. /// /// /// /// The fdwAttrsAndFlags parameter can specify FILE_FLAG_OVERLAPPED to indicate that the returned handle can be used in overlapped /// (asynchronous) I/O operations. /// /// /// /// [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] [PInvokeData("Winbase.h", MSDNShortId = "aa363216")] public static extern unsafe bool DeviceIoControl(HFILE hDevice, uint dwIoControlCode, byte* lpInBuffer, uint nInBufferSize, byte* lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, NativeOverlapped* lpOverlapped); /// /// Sends a control code directly to a specified device driver, causing the corresponding device to perform the corresponding operation. /// /// The type of the . /// The type of the . /// /// 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 CreateFile function. For more information, see Remarks. /// /// /// 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. /// /// /// The data required to perform the operation. The format of this data depends on the value of the dwIoControlCode parameter. /// /// /// The data returned by the operation. The format of this data depends on the value of the dwIoControlCode parameter. /// /// true if successful. [PInvokeData("Winbase.h", MSDNShortId = "aa363216")] public static bool DeviceIoControl(HFILE hDev, uint ioControlCode, TIn inVal, out TOut outVal) where TIn : struct where TOut : struct { using (SafeHGlobalHandle ptrIn = SafeHGlobalHandle.CreateFromStructure(inVal), ptrOut = SafeHGlobalHandle.CreateFromStructure()) { var ret = DeviceIoControl(hDev, ioControlCode, (IntPtr)ptrIn, (uint)ptrIn.Size, (IntPtr)ptrOut, (uint)ptrOut.Size, out var bRet, IntPtr.Zero); outVal = ptrOut.ToStructure(); return ret; } } /// /// Sends a control code directly to a specified device driver, causing the corresponding device to perform the corresponding operation. /// /// The type of the . /// /// 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 CreateFile function. For more information, see Remarks. /// /// /// 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. /// /// /// The data returned by the operation. The format of this data depends on the value of the dwIoControlCode parameter. /// /// true if successful. [PInvokeData("Winbase.h", MSDNShortId = "aa363216")] public static bool DeviceIoControl(HFILE hDev, uint ioControlCode, out TOut outVal) where TOut : struct { using (var ptrOut = SafeHGlobalHandle.CreateFromStructure()) { var ret = DeviceIoControl(hDev, ioControlCode, IntPtr.Zero, 0, (IntPtr)ptrOut, (uint)ptrOut.Size, out var bRet, IntPtr.Zero); outVal = ptrOut.ToStructure(); return ret; } } /// /// Sends a control code directly to a specified device driver, causing the corresponding device to perform the corresponding operation. /// /// The type of the . /// /// 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 CreateFile function. For more information, see Remarks. /// /// /// 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. /// /// /// The data required to perform the operation. The format of this data depends on the value of the dwIoControlCode parameter. /// /// true if successful. [PInvokeData("Winbase.h", MSDNShortId = "aa363216")] public static bool DeviceIoControl(HFILE hDev, uint ioControlCode, TIn inVal) where TIn : struct { using (var ptrIn = SafeHGlobalHandle.CreateFromStructure(inVal)) { return DeviceIoControl(hDev, ioControlCode, (IntPtr)ptrIn, (uint)ptrIn.Size, IntPtr.Zero, 0, out var bRet, IntPtr.Zero); } } /// Ends the asynchronous call to BeginDeviceIoControl<TIn, TOut>(HFILE, uint, TIn?, TOut?, AsyncCallback). /// The type of the input value. /// The type of the output value. /// The asynchronous result returned from BeginDeviceIoControl>TIn, TOut<(HFILE, uint, TIn?, TOut?, AsyncCallback). /// The output value, if exists; null otherwise. [PInvokeData("Winbase.h", MSDNShortId = "aa363216")] public static TOut? EndDeviceIoControl(IAsyncResult asyncResult) where TIn : struct where TOut : struct { var ret = OverlappedAsync.EndOverlappedFunction(asyncResult); return Unpack(ret as byte[]).Item2; } /// Ends the asynchronous call to BeginDeviceIoControl<TIn, TOut>(HFILE, uint, TIn?, TOut?, AsyncCallback). /// /// The asynchronous result returned from BeginDeviceIoControl<TIn, TOut>(HFILE, uint, TIn?, TOut?, AsyncCallback). /// /// The output buffer, if exists; null otherwise. [PInvokeData("Winbase.h", MSDNShortId = "aa363216")] public static byte[] EndDeviceIoControl(IAsyncResult asyncResult) { var ret = OverlappedAsync.EndOverlappedFunction(asyncResult); return Unpack(ret as byte[]).Item2; } /// /// Retrieves the results of an overlapped operation on the specified file, named pipe, or communications device. To specify a /// timeout interval or wait on an alertable thread, use GetOverlappedResultEx. /// /// /// A handle to the file, named pipe, or communications device. This is the same handle that was specified when the overlapped /// operation was started by a call to the ReadFile, WriteFile, ConnectNamedPipe, TransactNamedPipe, /// DeviceIoControl, or WaitCommEvent function. /// /// /// A pointer to an OVERLAPPED structure that was specified when the overlapped operation was started. /// /// /// A pointer to a variable that receives the number of bytes that were actually transferred by a read or write operation. For a /// TransactNamedPipe operation, this is the number of bytes that were read from the pipe. For a DeviceIoControl /// operation, this is the number of bytes of output data returned by the device driver. For a ConnectNamedPipe or /// WaitCommEvent operation, this value is undefined. /// /// /// If this parameter is TRUE, and the Internal member of the lpOverlapped structure is STATUS_PENDING, the /// function does not return until the operation has been completed. If this parameter is FALSE and the operation is still /// pending, the function returns FALSE and the GetLastError function returns ERROR_IO_INCOMPLETE. /// /// /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// // BOOL WINAPI GetOverlappedResult( _In_ HANDLE hFile, _In_ LPOVERLAPPED lpOverlapped, _Out_ LPDWORD lpNumberOfBytesTransferred, _In_ // BOOL bWait); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683209(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("WinBase.h", MSDNShortId = "ms683209")] [return: MarshalAs(UnmanagedType.Bool)] public static extern unsafe bool GetOverlappedResult([In] HFILE hFile, [In] NativeOverlapped* lpOverlapped, out uint lpNumberOfBytesTransferred, [MarshalAs(UnmanagedType.Bool)] bool bWait); /// /// Retrieves the results of an overlapped operation on the specified file, named pipe, or communications device within the specified /// time-out interval. The calling thread can perform an alertable wait. /// /// /// A handle to the file, named pipe, or communications device. This is the same handle that was specified when the overlapped /// operation was started by a call to the ReadFile, WriteFile, ConnectNamedPipe, TransactNamedPipe, /// DeviceIoControl, or WaitCommEvent function. /// /// /// A pointer to an OVERLAPPED structure that was specified when the overlapped operation was started. /// /// /// A pointer to a variable that receives the number of bytes that were actually transferred by a read or write operation. For a /// TransactNamedPipe operation, this is the number of bytes that were read from the pipe. For a DeviceIoControl /// operation, this is the number of bytes of output data returned by the device driver. For a ConnectNamedPipe or /// WaitCommEvent operation, this value is undefined. /// /// /// The time-out interval, in milliseconds. /// /// If dwMilliseconds is zero and the operation is still in progress, the function returns immediately and the GetLastError /// function returns ERROR_IO_INCOMPLETE. /// /// /// If dwMilliseconds is nonzero and the operation is still in progress, the function waits until the object is signaled, an I/O /// completion routine or APC is queued, or the interval elapses before returning. Use GetLastError to get extended error information. /// /// /// If dwMilliseconds is INFINITE, the function returns only when the object is signaled or an I/O completion routine or APC /// is queued. /// /// /// /// /// If this parameter is TRUE and the calling thread is in the waiting state, the function returns when the system queues an /// I/O completion routine or APC. The calling thread then runs the routine or function. Otherwise, the function does not return, and /// the completion routine or APC function is not executed. /// /// /// A completion routine is queued when the ReadFileEx or WriteFileEx function in which it was specified has completed. /// The function returns and the completion routine is called only if bAlertable is TRUE, and the calling thread is the thread /// that initiated the read or write operation. An APC is queued when you call QueueUserAPC. /// /// /// /// If the function succeeds, the return value is nonzero. /// /// If the function fails, the return value is zero. To get extended error information, call GetLastError. Common error codes /// include the following: /// /// // WINBASEAPI BOOL WINAPI GetOverlappedResultEx( _In_ HANDLE hFile, _In_ LPOVERLAPPED lpOverlapped, _Out_ LPDWORD // lpNumberOfBytesTransferred, _In_ DWORD dwMilliseconds, _In_ BOOL bAlertable); https://msdn.microsoft.com/en-us/library/windows/desktop/hh448542(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("Ioapiset.h", MSDNShortId = "hh448542")] [return: MarshalAs(UnmanagedType.Bool)] public static extern unsafe bool GetOverlappedResultEx([In] HFILE hFile, [In] NativeOverlapped* lpOverlapped, out uint lpNumberOfBytesTransferred, uint dwMilliseconds, [MarshalAs(UnmanagedType.Bool)] bool bAlertable); /// /// /// Attempts to dequeue an I/O completion packet from the specified I/O completion port. If there is no completion packet queued, the /// function waits for a pending I/O operation associated with the completion port to complete. /// /// To dequeue multiple I/O completion packets at once, use the GetQueuedCompletionStatusEx function. /// /// /// A handle to the completion port. To create a completion port, use the CreateIoCompletionPort function. /// /// /// A pointer to a variable that receives the number of bytes transferred during an I/O operation that has completed. /// /// /// A pointer to a variable that receives the completion key value associated with the file handle whose I/O operation has completed. /// A completion key is a per-file key that is specified in a call to CreateIoCompletionPort. /// /// /// /// A pointer to a variable that receives the address of the OVERLAPPED structure that was specified when the completed I/O /// operation was started. /// /// /// Even if you have passed the function a file handle associated with a completion port and a valid OVERLAPPED structure, an /// application can prevent completion port notification. This is done by specifying a valid event handle for the hEvent /// member of the OVERLAPPED structure, and setting its low-order bit. A valid event handle whose low-order bit is set keeps /// I/O completion from being queued to the completion port. /// /// /// /// /// The number of milliseconds that the caller is willing to wait for a completion packet to appear at the completion port. If a /// completion packet does not appear within the specified time, the function times out, returns FALSE, and sets *lpOverlapped /// to NULL. /// /// /// If dwMilliseconds is INFINITE, the function will never time out. If dwMilliseconds is zero and there is no I/O operation /// to dequeue, the function will time out immediately. /// /// /// /// Returns nonzero ( TRUE) if successful or zero ( FALSE) otherwise. /// To get extended error information, call GetLastError. /// For more information, see the Remarks section. /// // BOOL WINAPI GetQueuedCompletionStatus( _In_ HANDLE CompletionPort, _Out_ LPDWORD lpNumberOfBytes, _Out_ PULONG_PTR // lpCompletionKey, _Out_ LPOVERLAPPED // *lpOverlapped, _In_ DWORD dwMilliseconds); https://msdn.microsoft.com/en-us/library/windows/desktop/aa364986(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("WinBase.h", MSDNShortId = "aa364986")] [return: MarshalAs(UnmanagedType.Bool)] public static extern unsafe bool GetQueuedCompletionStatus([In] HANDLE CompletionPort, out uint lpNumberOfBytes, out UIntPtr lpCompletionKey, NativeOverlapped** lpOverlapped, uint dwMilliseconds); /// /// /// Attempts to dequeue an I/O completion packet from the specified I/O completion port. If there is no completion packet queued, the /// function waits for a pending I/O operation associated with the completion port to complete. /// /// To dequeue multiple I/O completion packets at once, use the GetQueuedCompletionStatusEx function. /// /// /// A handle to the completion port. To create a completion port, use the CreateIoCompletionPort function. /// /// /// A pointer to a variable that receives the number of bytes transferred during an I/O operation that has completed. /// /// /// A pointer to a variable that receives the completion key value associated with the file handle whose I/O operation has completed. /// A completion key is a per-file key that is specified in a call to CreateIoCompletionPort. /// /// /// /// A pointer to a variable that receives the address of the OVERLAPPED structure that was specified when the completed I/O /// operation was started. /// /// /// Even if you have passed the function a file handle associated with a completion port and a valid OVERLAPPED structure, an /// application can prevent completion port notification. This is done by specifying a valid event handle for the hEvent /// member of the OVERLAPPED structure, and setting its low-order bit. A valid event handle whose low-order bit is set keeps /// I/O completion from being queued to the completion port. /// /// /// /// /// The number of milliseconds that the caller is willing to wait for a completion packet to appear at the completion port. If a /// completion packet does not appear within the specified time, the function times out, returns FALSE, and sets *lpOverlapped /// to NULL. /// /// /// If dwMilliseconds is INFINITE, the function will never time out. If dwMilliseconds is zero and there is no I/O operation /// to dequeue, the function will time out immediately. /// /// /// /// Returns nonzero ( TRUE) if successful or zero ( FALSE) otherwise. /// To get extended error information, call GetLastError. /// For more information, see the Remarks section. /// // BOOL WINAPI GetQueuedCompletionStatus( _In_ HANDLE CompletionPort, _Out_ LPDWORD lpNumberOfBytes, _Out_ PULONG_PTR // lpCompletionKey, _Out_ LPOVERLAPPED // *lpOverlapped, _In_ DWORD dwMilliseconds); https://msdn.microsoft.com/en-us/library/windows/desktop/aa364986(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("WinBase.h", MSDNShortId = "aa364986")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetQueuedCompletionStatus([In] HANDLE CompletionPort, out uint lpNumberOfBytes, out UIntPtr lpCompletionKey, out IntPtr lpOverlapped, uint dwMilliseconds); /// /// /// Retrieves multiple completion port entries simultaneously. It waits for pending I/O operations that are associated with the /// specified completion port to complete. /// /// To dequeue I/O completion packets one at a time, use the GetQueuedCompletionStatus function. /// /// /// A handle to the completion port. To create a completion port, use the CreateIoCompletionPort function. /// /// /// On input, points to a pre-allocated array of OVERLAPPED_ENTRY structures. /// /// On output, receives an array of OVERLAPPED_ENTRY structures that hold the entries. The number of array elements is /// provided by ulNumEntriesRemoved. /// /// /// The number of bytes transferred during each I/O, the completion key that indicates on which file each I/O occurred, and the /// overlapped structure address used in each original I/O are all returned in the lpCompletionPortEntries array. /// /// /// The maximum number of entries to remove. /// A pointer to a variable that receives the number of entries actually removed. /// /// /// The number of milliseconds that the caller is willing to wait for a completion packet to appear at the completion port. If a /// completion packet does not appear within the specified time, the function times out and returns FALSE. /// /// /// If dwMilliseconds is INFINITE (0xFFFFFFFF), the function will never time out. If dwMilliseconds is zero and there is no /// I/O operation to dequeue, the function will time out immediately. /// /// /// /// If this parameter is FALSE, the function does not return until the time-out period has elapsed or an entry is retrieved. /// /// If the parameter is TRUE and there are no available entries, the function performs an alertable wait. The thread returns /// when the system queues an I/O completion routine or APC to the thread and the thread executes the function. /// /// /// A completion routine is queued when the ReadFileEx or WriteFileEx function in which it was specified has completed, /// and the calling thread is the thread that initiated the operation. An APC is queued when you call QueueUserAPC. /// /// // BOOL WINAPI GetQueuedCompletionStatusEx( _In_ HANDLE CompletionPort, _Out_ LPOVERLAPPED_ENTRY lpCompletionPortEntries, _In_ ULONG // ulCount, _Out_ PULONG ulNumEntriesRemoved, _In_ DWORD dwMilliseconds, _In_ BOOL fAlertable); https://msdn.microsoft.com/en-us/library/windows/desktop/aa364988(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("IoAPI.h", MSDNShortId = "aa364988")] public static extern void GetQueuedCompletionStatusEx(HANDLE CompletionPort, OVERLAPPED_ENTRY[] lpCompletionPortEntries, uint ulCount, out uint ulNumEntriesRemoved, uint dwMilliseconds, [MarshalAs(UnmanagedType.Bool)] bool fAlertable); /// Posts an I/O completion packet to an I/O completion port. /// A handle to an I/O completion port to which the I/O completion packet is to be posted. /// /// The value to be returned through the lpNumberOfBytesTransferred parameter of the GetQueuedCompletionStatus function. /// /// /// The value to be returned through the lpCompletionKey parameter of the GetQueuedCompletionStatus function. /// /// /// The value to be returned through the lpOverlapped parameter of the GetQueuedCompletionStatus function. /// /// /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero. To get extended error information, call GetLastError . /// // BOOL WINAPI PostQueuedCompletionStatus( _In_ HANDLE CompletionPort, _In_ DWORD dwNumberOfBytesTransferred, _In_ ULONG_PTR // dwCompletionKey, _In_opt_ LPOVERLAPPED lpOverlapped); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365458(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("IoAPI.h", MSDNShortId = "aa365458")] [return: MarshalAs(UnmanagedType.Bool)] public static extern unsafe bool PostQueuedCompletionStatus([In] HANDLE CompletionPort, uint dwNumberOfBytesTransferred, UIntPtr dwCompletionKey, NativeOverlapped* lpOverlapped); /// Posts an I/O completion packet to an I/O completion port. /// A handle to an I/O completion port to which the I/O completion packet is to be posted. /// /// The value to be returned through the lpNumberOfBytesTransferred parameter of the GetQueuedCompletionStatus function. /// /// /// The value to be returned through the lpCompletionKey parameter of the GetQueuedCompletionStatus function. /// /// /// The value to be returned through the lpOverlapped parameter of the GetQueuedCompletionStatus function. /// /// /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero. To get extended error information, call GetLastError . /// // BOOL WINAPI PostQueuedCompletionStatus( _In_ HANDLE CompletionPort, _In_ DWORD dwNumberOfBytesTransferred, _In_ ULONG_PTR // dwCompletionKey, _In_opt_ LPOVERLAPPED lpOverlapped); https://msdn.microsoft.com/en-us/library/windows/desktop/aa365458(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("IoAPI.h", MSDNShortId = "aa365458")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool PostQueuedCompletionStatus([In] HANDLE CompletionPort, uint dwNumberOfBytesTransferred, [Optional] UIntPtr dwCompletionKey, [Optional] IntPtr lpOverlapped); private static unsafe IAsyncResult BeginDeviceIoControl(HFILE hDevice, uint dwIoControlCode, byte[] buffer, AsyncCallback userCallback, object userState) where TIn : struct where TOut : struct => BeginDeviceIoControl(hDevice, dwIoControlCode, buffer, userCallback, userState); private static unsafe IAsyncResult BeginDeviceIoControl(HFILE hDevice, uint dwIoControlCode, byte[] buffer, AsyncCallback userCallback, object userState) { var ar = OverlappedAsync.SetupOverlappedFunction(hDevice, userCallback, buffer); var intSz = Marshal.SizeOf(typeof(int)); var inSz = BitConverter.ToInt32(buffer, 0); var outSz = BitConverter.ToInt32(buffer, intSz); fixed (byte* pIn = &buffer[intSz * 2], pOut = &buffer[outSz == 0 ? 0 : intSz * 2 + inSz]) { var ret = DeviceIoControl(hDevice, dwIoControlCode, pIn, (uint)inSz, pOut, (uint)outSz, out var bRet, ar.Overlapped); return OverlappedAsync.EvaluateOverlappedFunction(ar, ret); } } private static T MemRead(byte[] buffer, ref int startIndex) where T : struct { using (var pin = new PinnedObject(buffer, startIndex)) { startIndex += Marshal.SizeOf(typeof(T)); return ((IntPtr)pin).ToStructure(); } } private static int MemWrite(byte[] buffer, T value, int startIndex = 0) where T : struct { var sz = Marshal.SizeOf(typeof(T)); using (var pin = new PinnedObject(value)) Marshal.Copy(pin, buffer, startIndex, sz); return sz; } private static byte[] Pack(TIn? inVal, TOut? outVal) where TIn : struct where TOut : struct { using (var ms = new MemoryStream()) using (var wtr = new BinaryWriter(ms)) { wtr.Write(inVal.HasValue ? Marshal.SizeOf(typeof(TIn)) : 0); wtr.Write(outVal.HasValue ? Marshal.SizeOf(typeof(TOut)) : 0); if (inVal.HasValue) wtr.Write(inVal.Value); if (outVal.HasValue) wtr.Write(outVal.Value); return ms.ToArray(); } } private static byte[] Pack(byte[] inputBuffer, byte[] outputBuffer) { using (var ms = new MemoryStream()) using (var wtr = new BinaryWriter(ms)) { wtr.Write(inputBuffer != null ? inputBuffer.Length : 0); wtr.Write(outputBuffer != null ? outputBuffer.Length : 0); if (inputBuffer != null && inputBuffer.Length > 0) wtr.Write(inputBuffer); if (outputBuffer != null && outputBuffer.Length > 0) wtr.Write(outputBuffer); return ms.ToArray(); } } private static Tuple Unpack(byte[] buffer) where TIn : struct where TOut : struct { using (var ms = new MemoryStream(buffer)) using (var rdr = new BinaryReader(ms)) { var inLen = rdr.ReadInt32(); var outLen = rdr.ReadInt32(); return new Tuple(inLen > 0 ? rdr.Read() : (TIn?)null, outLen > 0 ? rdr.Read() : (TOut?)null); } } private static Tuple Unpack(byte[] buffer) { using (var ms = new MemoryStream(buffer)) using (var rdr = new BinaryReader(ms)) { var inLen = rdr.ReadInt32(); var outLen = rdr.ReadInt32(); return new Tuple(rdr.ReadBytes(inLen), rdr.ReadBytes(outLen)); } } /// Contains the information returned by a call to the GetQueuedCompletionStatusEx function. // https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped_entry typedef struct _OVERLAPPED_ENTRY { // ULONG_PTR lpCompletionKey; LPOVERLAPPED lpOverlapped; ULONG_PTR Internal; DWORD dwNumberOfBytesTransferred; } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY; [PInvokeData("minwinbase.h", MSDNShortId = "3e244e6c-0731-477a-b1d3-2601c29449ca")] [StructLayout(LayoutKind.Sequential)] public struct OVERLAPPED_ENTRY { /// /// Receives the completion key value associated with the file handle whose I/O operation has completed. A completion key is a /// per-file key that is specified in a call to CreateIoCompletionPort. /// public UIntPtr lpCompletionKey; /// Receives the address of the OVERLAPPED structure that was specified when the completed I/O operation was started. public IntPtr lpOverlapped; /// Reserved. public UIntPtr Internal; /// Receives the number of bytes transferred during the I/O operation that has completed. public uint dwNumberOfBytesTransferred; } } }