Cancelling Console.Read

 
 
  • Gérald Barré

Console.ReadLine and other read methods block the current thread until the user enters input. Sometimes you need to cancel the read operation when a condition is met, such as after a timeout or in response to an event.

Windows provides a function to cancel an I/O request: CancelIoEx. To use it, you need the handle of the I/O stream. In this case, it is the console input stream handle, which you can obtain with GetStdHandle using the STD_INPUT_HANDLE constant. Combining these two functions makes it straightforward to cancel a pending read. Once canceled, Console.Read throws an exception that you need to handle. Depending on the read method used, catch either InvalidOperationException or OperationCanceledException.

The following code starts a 10-second timer and calls Console.Read. If the user does not enter anything in time, the timer cancels the I/O request:

C#
class Program
{
    const int STD_INPUT_HANDLE = -10;

    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern IntPtr GetStdHandle(int nStdHandle);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool CancelIoEx(IntPtr handle, IntPtr lpOverlapped);

    static void Main(string[] args)
    {
        // Start the timeout
        var read = false;
        Task.Delay(10000).ContinueWith(_ =>
        {
            if (!read)
            {
                // Timeout => cancel the console read
                var handle = GetStdHandle(STD_INPUT_HANDLE);
                CancelIoEx(handle, IntPtr.Zero);
            }
        });

        try
        {
            // Start reading from the console
            Console.WriteLine("Do you want to continue [Y/n] (10 seconds remaining):");
            var key = Console.ReadKey();
            read = true;
            Console.WriteLine("Key read");
        }
        // Handle the exception when the operation is canceled
        catch (InvalidOperationException)
        {
            Console.WriteLine("Operation canceled");
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("Operation canceled");
        }
    }
}

Documentation:

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?