Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I prevent my program from closing when a open console window is closed?

I am trying to open the console from my main program (Win32). I found some code, and it works, but I don't understand it. The problem I'm happening is that when I click X on the console, it closes the program as well.

Roughly I have this:

int APIENTRY WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) {

  // create the main program window, classes registered, etc...
  hwnd = CreateWindowEx(0, csClassName, "theNewTimer", WS_POPUP | WS_CLIPCHILDREN, 300, 0, WINDOW_WIDTH, WINDOW_HEIGHT, HWND_DESKTOP, NULL, hThisInstance, NULL);
  ShowWindow (hwnd, nFunsterStil);

  // and now the console
  AllocConsole();
  HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
  int hCrt = _open_osfhandle((long) handle_out, _O_TEXT);
  FILE* hf_out = _fdopen(hCrt, "w");
  setvbuf(hf_out, NULL, _IONBF, 1);
  *stdout = *hf_out;

  HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);
  hCrt = _open_osfhandle((long) handle_in, _O_TEXT);
  FILE* hf_in = _fdopen(hCrt, "r");
  setvbuf(hf_in, NULL, _IONBF, 128);
  *stdin = *hf_in;


// and then the message loop concluding

I googled some of it, but had no idea of what I was reading.

like image 962
Evan Carslake Avatar asked Nov 27 '13 02:11

Evan Carslake


2 Answers

One thing you can do is disable the close button on the console window:

HWND hwnd = ::GetConsoleWindow();
if (hwnd != NULL)
{
   HMENU hMenu = ::GetSystemMenu(hwnd, FALSE);
   if (hMenu != NULL) DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
}
like image 167
Jonathan Potter Avatar answered Nov 09 '22 07:11

Jonathan Potter


I do not think this is possible. From the MSDN documentation for a HandlerRoutine, there's this sentence.

The CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals give the process an opportunity to clean up before termination.

I read this as saying that CTRL_CLOSE_EVENT is advisory, and that the process is going to exit regardless. My guess is that when the system sends CTRL_CLOSE_EVENT, it starts a timer. The process is allowed to keep running for a little bit of time, but eventually, the OS will just kill the process unilaterally.

Here's the handler that I registered

BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType) {
   switch (dwCtrlType) {
       case CTRL_C_EVENT:
       case CTRL_CLOSE_EVENT:
           return TRUE; // breakpoint set here

       default:
           return FALSE;
   }
}

Here's how I registered the handler, after my call to AllocConsole:

BOOL result = SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE /* Add */);
assert(result);

I set a breakpoint on the line marked //breakpoint set here. Then, I ran the process under the Visual Studio debugger. When the console window was focused, I pressed Ctrl+C. My breakpoint got hit, and I was able to step through my handler and back into KernelBase.dll!CtrlRoutine and so on. The process kept running when I let the process resume normal execution.

However, when I closed the console window, my handler did get called, but I was unable to trace its execution very far. I was able to single step execution a few times, but then the process simply exited. Visual Studio reported "The program '[10644] Win32Project.exe' has exited with code -1073741510 (0xc000013a)."

0xc000013a is STATUS_CONTROL_C_EXIT:

c:\Tools\ERR>Err.exe 0xc000013a
# for hex 0xc000013a / decimal -1073741510 :
  STATUS_CONTROL_C_EXIT                                         ntstatus.h
# {Application Exit by CTRL+C}
# The application terminated as a result of a CTRL+C.
# 1 matches found for "0xc000013a"
like image 39
chwarr Avatar answered Nov 09 '22 07:11

chwarr