/// <summary> /// Helper method to construct an asyncResult object and use it to /// call NativeControl(). Called by BeginAsyncControl(). /// </summary> private static DeviceAsyncResult <T> AsyncControl <T>( SafeFileHandle device, int controlCode, T outBuffer, AsyncCallback asyncCallback, object state ) { SafePinnedObject outDeviceBuffer = null; if (outBuffer != null) { outDeviceBuffer = new SafePinnedObject(outBuffer); } // Create the async result object DeviceAsyncResult <T> asyncResult = new DeviceAsyncResult <T>(outDeviceBuffer, asyncCallback, state ); unsafe { uint bytesReturned = 0; NativeAsyncControl(device, controlCode, outDeviceBuffer, ref bytesReturned, asyncResult.GetNativeOverlapped() ); } return(asyncResult); }
/// <summary> /// Helper method that actually sends the given IOCTL to the driver by /// calling the native DeviceIOControl() function. Called by AsyncControl(). /// </summary> private static unsafe void NativeAsyncControl( SafeFileHandle device, int controlCode, SafePinnedObject outBuffer, ref uint bytesReturned, NativeOverlapped *nativeOverlapped ) { bool succeeded = Kernel32Import.DeviceIoControl(device, controlCode, null, 0, outBuffer, outBuffer.Size, ref bytesReturned, nativeOverlapped ); // If DeviceIoControl returns TRUE, the operation completed // synchronously if (succeeded) { throw new InvalidOperationException($"Async call to DeviceIoControl completed synchronously."); } // DeviceIoControl is operating asynchronously; test the returned // error code to see if it is pending or not Int32 error = Marshal.GetLastWin32Error(); const Int32 cErrorIOPending = 997; // system-defined code for pending I/O if (error == cErrorIOPending) { return; } // Throw an exception if DeviceIoControl fails altogether throw new InvalidOperationException($"Control failed with error {error}"); }