是否可以通过编程方式停止Console.ReadLine()?
我有一个控制台应用程序:大部分逻辑在不同的线程上运行,在主线程中,我使用Console.ReadLine()接受输入。当分离的线程停止运行时,我想停止从控制台读取。
我如何才能做到这一点?
发布于 2012-02-28 17:56:36
更新:此技术在Windows10上不再可靠。请不要使用。
在Win10中进行了相当多的实现更改,使控制台的行为更像终端。无疑要协助新的Linux子系统。一个(非故意的?)副作用是CloseHandle()在读操作完成之前会死锁,这会终止这种方法。我会把原来的帖子留在原处,只是因为它可能会帮助别人找到替代方案。
UPDATE2:看一下wischi的答案,找到一个像样的替代方案。
这是可能的,您必须通过关闭stdin流来猛地拉动脚垫。这个程序演示了这个想法:
using System;
using System.Threading;
using System.Runtime.InteropServices;
namespace ConsoleApplication2 {
class Program {
static void Main(string[] args) {
ThreadPool.QueueUserWorkItem((o) => {
Thread.Sleep(1000);
IntPtr stdin = GetStdHandle(StdHandle.Stdin);
CloseHandle(stdin);
});
Console.ReadLine();
}
// P/Invoke:
private enum StdHandle { Stdin = -10, Stdout = -11, Stderr = -12 };
[DllImport("kernel32.dll")]
private static extern IntPtr GetStdHandle(StdHandle std);
[DllImport("kernel32.dll")]
private static extern bool CloseHandle(IntPtr hdl);
}
}发布于 2012-03-09 21:02:14
将enter发送到当前运行的控制台应用程序:
class Program
{
[DllImport("User32.Dll", EntryPoint = "PostMessageA")]
private static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
const int VK_RETURN = 0x0D;
const int WM_KEYDOWN = 0x100;
static void Main(string[] args)
{
Console.Write("Switch focus to another window now.\n");
ThreadPool.QueueUserWorkItem((o) =>
{
Thread.Sleep(4000);
var hWnd = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
PostMessage(hWnd, WM_KEYDOWN, VK_RETURN, 0);
});
Console.ReadLine();
Console.Write("ReadLine() successfully aborted by background thread.\n");
Console.Write("[any key to exit]");
Console.ReadKey();
}
}此代码将enter发送到当前控制台进程,中止在windows内核深层的非托管代码中阻塞的任何ReadLine()调用,这允许C#线程自然退出。
我使用了这段代码,而不是涉及关闭控制台的答案,因为关闭控制台意味着ReadLine()和ReadKey()从此在代码中被永久禁用(如果使用它,它将抛出异常)。
这个答案比涉及SendKeys和Windows Input Simulator的所有解决方案都要好,因为即使当前的应用程序没有重点,它也可以工作。
发布于 2019-10-21 00:58:04
免责声明:这只是一个复制粘贴的答案。
感谢Gérald Barré提供了如此出色的解决方案:
https://www.meziantou.net/cancelling-console-read.htm
CancelIoEX文档:
https://docs.microsoft.com/en-us/windows/win32/fileio/cancelioex-func
我在Windows10上对它进行了测试,它工作得很好,而且比其他解决方案(比如重新实现Console.ReadLine、通过PostMessage发送返回或关闭句柄等)要简单得多。
为了防止网站瘫痪,我在这里引用了代码片段:
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");
}
}
}https://stackoverflow.com/questions/9479573
复制相似问题