如何使用Win32调用在C#中关闭/打开控制台?

以下程序在“Console.ReadKey()”上引发错误。

禁用后如何重新启用控制台?

using System; using System.Threading; using System.Runtime.InteropServices; namespace ConsoleApplication { class Program { static void Main(string[] args) { ThreadPool.QueueUserWorkItem((o) => { Thread.Sleep(1000); IntPtr stdin = GetStdHandle(StdHandle.Stdin); CloseHandle(stdin); }); Console.ReadLine(); Console.Write("ReadLine() successfully aborted by background thread.\n"); Console.Write("[any key to exit]"); Console.ReadKey(); // Throws an exception "Cannot read keys when either application does not have a console or when console input has been redirected from a file. Try Console.Read." } // 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); } } 

专家额外

如果你想知道,我需要能够在C#中杀死运行ReadLine()的后台线程。 这似乎是唯一的方法(thread.Abort不起作用,因为ReadLine()在操作系统的内部深处运行,在非托管代码中)。 在StackOverflow上有很多关于这个主题的讨论,没有人真正发现(或发布)一个令人满意的中止Console.ReadLine()的方法。 我认为这段代码是正确的 – 只要我们可以在禁用它后重新启用它。

不知道它是否有帮助,但是当我需要能够在win form应用程序中写入控制台时,我已经使用过这个类:

 public class ConsoleHelper { ///  /// Allocates a new console for current process. ///  [DllImport("kernel32.dll")] public static extern Boolean AllocConsole(); ///  /// Frees the console. ///  [DllImport("kernel32.dll")] public static extern Boolean FreeConsole(); } 

调用AllocConsole创建一个控制台,然后您可以写入(并从中读取)它。 然后在完成后调用FreeConsole。

使用PostMessage将[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 to verify this works in a background process.\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(); } } 

这个答案也解决了这样一个事实,即在ReadLine()上调用.Abort将无法工作,因为代码在Windows内核深处的非托管代码中运行。

这个答案优于任何仅在当前进程具有焦点时才有效的答案,例如SendKeys和Input Simulator 。

这个答案优于关闭当前控制台句柄的方法,因为关闭当前控制台句柄的行为导致将来调用ReadLine()引发错误。