繁体   English   中英

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

[英]How to close / open console within C# using Win32 calls?

以下程序在“ 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()的方法。 我认为这段代码是在正确的轨道上-如果只有在禁用它之后我们才能重新启用控制台。

使用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内核深处的非托管代码中运行。

该答案优于仅在当前流程具有焦点的情况下才有效的所有答案,例如SendKeysInput Simulator

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

不知道它是否有帮助,但是当我需要能够在Win Form应用程序中写入控制台时,我使用了此类:

public class ConsoleHelper
{
    /// <summary>
    /// Allocates a new console for current process.
    /// </summary>
    [DllImport("kernel32.dll")]
    public static extern Boolean AllocConsole();

    /// <summary>
    /// Frees the console.
    /// </summary>
    [DllImport("kernel32.dll")]
    public static extern Boolean FreeConsole();
}

调用AllocConsole创建一个控制台,然后可以对其进行写入(读取)。 完成后,致电FreeConsole。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM