Contango
Contango

Reputation: 80192

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

The following program throws an error on "Console.ReadKey()".

How do I re-enable the console after disabling it?

    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);
        }
    }

Extra for Experts

If you're wondering, I need to be able to kill a background thread running ReadLine(), within C#. This appears to be the only way (thread.Abort won't work because ReadLine() runs deep within the bowels of the operating system, in unmanaged code). There is a lot of talk on this topic on StackOverflow, nobody has really discovered (or posted) a satisfactory method of aborting Console.ReadLine() yet. I think this code is on the right track - if only we can re-enable the console after disabling it.

Upvotes: 5

Views: 3247

Answers (2)

Contango
Contango

Reputation: 80192

Use PostMessage to send [enter] into the current process:

    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();
        }
    }

This answer also works around the fact that calling .Abort on ReadLine() won't work, as the code is running in unmanaged code deep within the Windows kernel.

This answer is superior to any answers that only work if the current process has the focus, such as SendKeys and Input Simulator.

This answer is superior to the method of closing the current console handle, as the act of closing the current console handle results in future calls to ReadLine() throwing an error.

Upvotes: 6

Matt Burland
Matt Burland

Reputation: 45135

Don't know if it helps, but when I've needed to be able to write to the console in a win form app, I've used this class:

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();
}

Call AllocConsole to create a console and then you can write to (and read from) it. Then call FreeConsole when you're done.

Upvotes: 0

Related Questions