30

What I want to have happen is that the console window just goes away, or better yet that it is hidden, but I want my application to keep running. Is that possible? I want to be able to use Console.WriteLine and have the console serve as an output window. I want to be able to hide and show it, and I don't want the whole app to die just because the console was closed.

EDIT

Code:

internal class SomeClass {

    [DllImport("kernel32")]
    private static extern bool AllocConsole();

    private static void Main() {
        AllocConsole();
        while(true) continue;
    }
}

EDIT 2

I tried the accepted solution here [ Capture console exit C# ], per the suggestion in the comments on this question. The example code is bugged in that the DLLImport needs to be "kernel32.dll" or "kernel32", not "Kernel32". After making that change, I'm getting a message to my handler for CTRL_CLOSE_EVENT when I click the X on the console window. However, calling FreeConsole and/or returning true doesn't prevent the application from terminating.

Community
  • 1
  • 1
Kelsie
  • 1,000
  • 1
  • 9
  • 21
  • I think this is a variant of http://stackoverflow.com/questions/474679/capture-console-exit-c-sharp with the addition that you want to call FreeConsole in your handling of that event. – Jon Hanna Aug 14 '12 at 19:52
  • @DanielHilgarth The whole point is to have a console app that runs without showing a console to the user who is running the app. It can literally be **any** code that runs within the program. – Servy Aug 14 '12 at 19:53
  • 1
    I agree with Daniel, we need to see the critical lines of code that reproduce this issue. The way I understand the question, this shouldn't be happening. A call to [`FreeConsole`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms683150.aspx) should *not* end the entire application/process. You should be able to call `FreeConsole` and then later call `AllocConsole` or `AttachConsole`. – Cody Gray - on strike Aug 14 '12 at 19:53
  • @JonHanna Rather than catching the console exit and not crashing, why not just hide the shell from the user, which is what he is asking for? – Servy Aug 14 '12 at 19:53
  • @Servy Or that too. In either case, they need to catch that event so that a user closing the console window doesn't take down the app. (Of course, it could be they're already trying that - in which case I agree with Daniel saying we need more info on the actual code). – Jon Hanna Aug 14 '12 at 19:55
  • @Servy: I think you misunderstood the question. The OP is showing the console actively via `AllocConsole`. That's nothing you do in an ordinary console application. – Daniel Hilgarth Aug 14 '12 at 19:55
  • 1
    Well, after edit 2 I at least know one thing: That I do not know the answer! I'm also slightly alarmed since while I've never had to do this, I always thought I could free in response to that event if I had too, so I really hope there's an answer. – Jon Hanna Aug 14 '12 at 20:36
  • @JonHanna: If there isn't an answer, I wonder if there are any third party libraries that offer a console subsystem that isn't based on the Windows console subsystem? – Kelsie Aug 14 '12 at 20:40
  • Is there a reason you want to use a windows console, instead of simply creating a window with a textbox? – CodesInChaos Aug 14 '12 at 20:45
  • 1
    It's a fair amount of effort to make the options windows for configuring fonts and colors, etc, and then hooking all that up to work with the textbox. The windows console subsystem is already there. If I can't find a premade solution, I'm sure that's what I'll end up doing, but it does seem a bit silly to have to do that. – Kelsie Aug 14 '12 at 20:55

4 Answers4

30

Ah, yes, this is one of the caveats of using the Windows console subsystem. When the user closes the console window (regardless of how the console was allocated), all of the processes that are attached to the console are terminated. That behavior makes obvious sense for console applications (i.e., those that specifically target the console subsystem, as opposed to standard Windows applications), but it can be a major pain in cases like yours.

The only workaround that I know of is to use the SetConsoleCtrlHandler function, which allows you to register a handler function for Ctrl+C and Ctrl+Break signals, as well as system events like the user closing the console window, the user logging off, or the system shutting down. The documentation says that if you're only interested in ignoring these events, you can pass null for the first argument. For example:

[DllImport("kernel32")]
static extern bool SetConsoleCtrlHandler(HandlerRoutine HandlerRoutine, bool Add);

delegate bool HandlerRoutine(uint dwControlType);

static void Main()
{
    AllocConsole();
    SetConsoleCtrlHandler(null, true);
    while (true) continue;
}

That works perfectly for Ctrl+C and Ctrl+Break signals (which would have otherwise caused your application to terminate as well), but it doesn't work for the one you're asking about, which is the CTRL_CLOSE_EVENT, generated by the system when the user closes the console window.

Honestly, I don't know how to prevent that. Even the sample in the SDK doesn't actually allow you to ignore the CTRL_CLOSE_EVENT. I tried it in a little test app, and it beeps when you close the window and prints the message, but the process still gets terminated.

Perhaps more worryingly, the documentation makes me think it is not possible to prevent this:

The system generates CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals when the user closes the console, logs off, or shuts down the system so that the process has an opportunity to clean up before termination. Console functions, or any C run-time functions that call console functions, may not work reliably during processing of any of the three signals mentioned previously. The reason is that some or all of the internal console cleanup routines may have been called before executing the process signal handler.

It's that last sentence that catches my eye. If the console subsystem starts cleaning up after itself immediately in response to the user attempting to close the window, it may not be possible to halt it after the fact.

(At least now you understand the problem. Maybe someone else can come along with a solution!)

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • 1
    There seems to be a way, though. For example, Far Manager can still prompt for saving when I'm in the editor when I close-click the console window. Its code is open-source, so someone who knows C++ better than me might be able to glean how they do it. – Joey Jul 09 '13 at 18:36
  • 1
    "Honestly, I don't know how to prevent that." Can you cheat and call FreeConsole in the callback itself, such that the console is no longer associated with that process, and when the callback returns, there is no process to kill? – Dwayne Robinson Nov 02 '14 at 10:16
25

Unfortunately there's nothing you can do to really alter this behaviour.

Console windows are "special" in that they're hosted by another process and do not allow sub-classing. This limits your ability to modify their behaviour.

From what I know, your two options are:

1. Disable the close button altogether. You can do this with the following code fragment:

HWND hwnd = ::GetConsoleWindow();
if (hwnd != NULL)
{
   HMENU hMenu = ::GetSystemMenu(hwnd, FALSE);
   if (hMenu != NULL) DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
}

2. Stop using consoles altogether, and implement your own text output solution.

Option #2 is the more complicated option but would provide you the greatest control. I found an article on CodeProject that implements a console-like application using a rich edit control to display the text (rich edit controls have the ability to stream text like the console, so they are well suited to this sort of application).

Xearinox
  • 3,224
  • 2
  • 24
  • 38
Jonathan Potter
  • 36,172
  • 4
  • 64
  • 79
  • Unfortunately your solution (#1) does not handle the case of using Alt+F4, and apparently there is no way to subclass the window to suppress WM_SYSKEYDOWN/WM_SYSKEYUP to work around this. – Mike Weir Apr 14 '21 at 05:54
11

On closing the console window obtained using AllocConsole or AttachConsole, the associated process will exit. There is no escape from that.

Prior to Windows Vista, closing the console window would present a confirmation dialogue to the user asking him whether the process should be terminated or not but Windows Vista and later do not provide any such dialogue and the process gets terminated.

One possible solution to work around this is avoiding AttachConsole altogether and achieving the desired functionality through other means.

For instance in the case described by OP, console window was needed to output some text on Console using Console static class.

This can be achieved very easily using inter-process communication. For example a console application can be developed to act as an echo server

namespace EchoServer
{
    public class PipeServer
    {
        public static void Main()
        {
            var pipeServer = new NamedPipeServerStream(@"Com.MyDomain.EchoServer.PipeServer", PipeDirection.In);
            pipeServer.WaitForConnection();

            StreamReader reader = new StreamReader(pipeServer);

            try
            {
                int i = 0;
                while (i >= 0)
                {
                    i = reader.Read();
                    if (i >= 0)
                    {
                        Console.Write(Convert.ToChar(i));
                    }
                }
            }
            catch (IOException)
            {
                //error handling code here
            }
            finally
            {
                pipeServer.Close();
            }
        }
    }
} 

and then instead of allocating/attaching a console to the current application, the echo server can be started from within the application and Console's output stream can be redirected to write to the pipe server.

class Program
{
    private static NamedPipeClientStream _pipeClient;

    static void Main(string[] args)
    {
        //Current application is a Win32 application without any console window
        var processStartInfo = new ProcessStartInfo("echoserver.exe");

        Process serverProcess = new Process {StartInfo = processStartInfo};
        serverProcess.Start();

        _pipeClient = new NamedPipeClientStream(".", @"Com.MyDomain.EchoServer.PipeServer", PipeDirection.Out, PipeOptions.None);
        _pipeClient.Connect();
        StreamWriter writer = new StreamWriter(_pipeClient) {AutoFlush = true};
        Console.SetOut(writer);

        Console.WriteLine("Testing");

        //Do rest of the work. 
        //Also detect that the server has terminated (serverProcess.HasExited) and then close the _pipeClient
        //Also remember to terminate the server process when current process exits, serverProcess.Kill();
        while (true)
            continue;
    }
}

This is just one of the possible solutions. In essence the work around is to allot the console window to its own process so that it can terminate without affecting the parent process.

Amit Mittal
  • 2,646
  • 16
  • 24
  • This seems like a viable solution. I'll give this the bounty unless the OP says another answer more directly helps her problem. – Jon Hanna Aug 22 '12 at 18:54
  • 1
    I ended up making a custom Form that runs a message loop on it's own thread. It has a RichTextBox and whatnot. Seems to work pretty well. – Kelsie Aug 22 '12 at 23:51
  • @Kelsie That is like avoiding the Console altogether, a deviation from original problem statement :) – Amit Mittal Aug 23 '12 at 07:51
  • Yep, it is. I just wanted to post it as a possible solution to the problem that did solve the issue. Thanks for your suggestion. – Kelsie Aug 23 '12 at 08:10
-2

You can do this by disabling keyboard mouse input by external program called Keyfreez.

you can use it multiple times in your program where no user input required. And if any user input require u can add a process Takskkill /f /IM .

https://www.sordum.org/7921/bluelife-keyfreeze-v1-4-block-keyboard-and-mouse/

Hope this helps all of you

  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/31106229) – acarlstein Feb 23 '22 at 15:14
  • This doesn’t answer the question in the slightest. The question is about how to write software to behave in a particular way. I’m not going to release software to someone that requires them to run an external agent to get it to behave well. – Kelsie Mar 01 '22 at 13:48