Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
61 views
in Technique[技术] by (71.8m points)

c# - Cancelling read key with CancelIoEx also interrupts the next read

Following How to interrupt Console.ReadLine to figure out to interrupt a Console.ReadlLine (and Console.ReadKey), I encountered the following behavior (I don't know if it's a bug in Windows, the .NET framework, or whatnot): When I use CancelIoEx to cancel a ReadKey (or ReadLine), 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).

Am I doing something wrong? Is it a bug in Windows/.NET? Should I perform another action to stop the actual read?

How to reproduce:

  1. I'm using a console project with .NET Framework 4.7.2 (this would reproduce on .NET5.0 as well).
  2. I'm running the following code:
    class Program
    {
        const int STD_INPUT_HANDLE = -10;
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern IntPtr GetStdHandle(int nStdHandle);
        [DllImport("kernel32.dll", 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(_ =>
            {
                Console.WriteLine("Interrupting...");
                InterruptReadLine();
            });

            Console.WriteLine("Read key1");
            var key1 = ReadHiddenKey();
            Console.WriteLine("Read key2");
            var key2 = ReadHiddenKey();
            Console.WriteLine($"Keys: {key1}, {key2}");
        }
    }
  1. 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':
Read key1
Interrupting...
Read key2
Keys: , B
  1. I would expect the first actual read (for key2) would not be ignored (i.e., the output would say Keys: , A and I will not have a chance to click 'b').
  2. 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 a and its done. No need for an extra key input.

Note that when experimenting with it I encountered the following behavior as well:

  1. Changing the try in ReadHiddenKey to
                var str = Console.ReadLine();
                result = ConsoleKey.Enter;
                Console.WriteLine("Read: " + str);
  1. Adding Console.ReadKey(); before the second ReadHiddenKey.

The result for when writing abc then enter and then 1234 and enter is:

Read key1
Interrupting...
Read key2
abc
1234
Read: 234
Keys: , Enter

Proving that the behavior is that the first Console.ReadLine() throws an exception, but continues as usual (thus the first line I write is "swallowed").

question from:https://stackoverflow.com/questions/65848877/cancelling-read-key-with-cancelioex-also-interrupts-the-next-read

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...