title: Cancelling read key with CancelIoEx also interrupts the next read
body: <p>Following <a href="https://stackoverflow.com/questions/9479573/how-to-interrupt-console-readline/9634490">How to interrupt Console.ReadLine</a> to figure out to interrupt a <code>Console.ReadlLine</code> (and <code>Console.ReadKey</code>), I encountered the following behavior (I don't know if it's a bug in Windows, the .NET framework, or whatnot):
  When I use <code>CancelIoEx</code> to cancel a <code>ReadKey</code> (or <code>ReadLine</code>), it cancels the read successfully (i.e., interrupts the call and the thread continues), but it seems the read action is still happening in the console (and will be ignored when done).</p>
  <p>Am I doing something wrong? Is it a bug in Windows/.NET? Should I perform another action to stop the actual read?</p>
  <p>How to reproduce:</p>
  <ol>
  <li>I'm using a console project with .NET Framework 4.7.2 (this would reproduce on .NET5.0 as well).</li>
  <li>I'm running the following code:</li>
  </ol>
  <pre><code>    class Program
      {
          const int STD_INPUT_HANDLE = -10;
          [DllImport(&quot;kernel32.dll&quot;, SetLastError = true)]
          private static extern IntPtr GetStdHandle(int nStdHandle);
          [DllImport(&quot;kernel32.dll&quot;, SetLastError = true)]
          private static extern bool CancelIoEx(IntPtr handle, IntPtr lpOverlapped);
  
          private static void InterruptReadLine()
          {
              var handle = GetStdHandle(STD_INPUT_HANDLE);
              bool success = CancelIoEx(handle, IntPtr.Zero);
          }
  
          private static ConsoleKey? ReadHiddenKey()
          {
              ConsoleKey? result = null;
              try
              {
                  result = Console.ReadKey(true).Key;
              }
              // This is interrupted on Dispose.
              catch (InvalidOperationException) { }
              catch (OperationCanceledException) { }
              return result;
          }
  
          static void Main(string[] args)
          {
              Task task = Task.Delay(2000).ContinueWith(_ =&gt;
              {
                  Console.WriteLine(&quot;Interrupting...&quot;);
                  InterruptReadLine();
              });
  
              Console.WriteLine(&quot;Read key1&quot;);
              var key1 = ReadHiddenKey();
              Console.WriteLine(&quot;Read key2&quot;);
              var key2 = ReadHiddenKey();
              Console.WriteLine($&quot;Keys: {key1}, {key2}&quot;);
          }
      }
  </code></pre>
  <ol start="3">
  <li>Wait 2 seconds, then click a key (the key is ignored) and then another key (which will be written). The output for 'a' then 'b':</li>
  </ol>
  <pre><code>Read key1
  Interrupting...
  Read key2
  Keys: , B
  </code></pre>
  <ol start="4">
  <li>I would expect the first actual read (for <code>key2</code>) would not be ignored (i.e., the output would say <code>Keys: , A</code> and I will not have a chance to click 'b').</li>
  <li>Note that if I change something in the console (change its size, or minimize/maximize) it then behaves as expected: After 2 seconds, it interrupts, I change the size, click <code>a</code> and its done. No need for an extra key input.</li>
  </ol>
  <p>Note that when experimenting with it I encountered the following behavior as well:</p>
  <ol>
  <li>Changing the <code>try</code> in <code>ReadHiddenKey</code> to</li>
  </ol>
  <pre><code>                var str = Console.ReadLine();
                  result = ConsoleKey.Enter;
                  Console.WriteLine(&quot;Read: &quot; + str);
  </code></pre>
  <ol start="2">
  <li>Adding <code>Console.ReadKey();</code> before the second <code>ReadHiddenKey</code>.</li>
  </ol>
  <p>The result for when writing <code>abc</code> then enter and then <code>1234</code> and enter is:</p>
  <pre><code>Read key1
  Interrupting...
  Read key2
  abc
  1234
  Read: 234
  Keys: , Enter
  </code></pre>
  <p>Proving that the behavior is that the first <code>Console.ReadLine()</code> throws an exception, <strong>but continues as usual</strong> (thus the first line I write is &quot;swallowed&quot;).</p>