Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

SetConsoleCtrlHandler() problem

Status
Not open for further replies.

graetzd

Technical User
Jun 29, 2001
17
US
Hello Forum Gurus:

I am implementing a CONSOLE application vis-a-vis my SDI application. I can get a console to launch correctly and send output to the console.

My Problem:
I would like for the console to exit "gracefully" when the user hits the X-button or choses Close from the menu. I do not want my SDI application to terminate, I simply want the console window to go away.

I have been trying to set a console ctrl handler for the CTRL_CLOSE_EVENT and it does not seem to work as I anticipated:

My Code:

/////////////////////////////////
void CSLOMODoc::LaunchConsole()
/////////////////////////////////
{

//Free any console that may already be attached
FreeConsole();

//Allocate a new console
AllocConsole();

//Use my console Handlers
SetConsoleCtrlHandler(MyConsoleHandler, TRUE);
}

BOOL WINAPI MyConsoleHandler(DWORD dwCtrlType)
{
switch(dwCtrlType)
{
case CTRL_C_EVENT:
return TRUE; //this just disables Ctrl-C
case CTRL_CLOSE_EVENT:
FreeConsole();
return TRUE;
default:
return FALSE;
}
}

I have checked to ensure that MyConsoleHandler() is implemented with no errors. And when I debug and hit the X-button I have verified that I enter the CTRL_CLOSE_EVENT case statement. But I was expecting the FreeConsole() call to simply detach the process (my SDI application) from the console and since that is the only process attached to the console it should simply go away. What happens is that the entire SDI application closes up and goes away!

Any suggestions or help?!?!?

Thank you,
David G.
 
David, just a wild guess, did you try returning FALSE

-pete

 
Pete,

Yes I did - and with no success either!

Thanks.
DG
 
Well i don't know the correct technique but i imagine you could set a flag that was within scope of your main window class and trap the correct message (WM_QUIT or whatever) in the CWnd::preTranslateMessage() function and ignore it, then set the flag to another state so you can actually exit when you want to.

-pete

 
Hi,

In my experience it is impossible catching the 'X' in a console. However, it is possible to disable it.

(assume hConsole is the window handle of the console)

EnableMenuItem ( GetSystemMenu ( hConsole, FALSE),
SC_CLOSE,
MF_BYCOMMAND | MF_GRAYED );

An API is available to get the window handle of the console:
hConsole = GetConsoleWindow ( );

Unfortunately this API is only supported in W2000/XP, not in NT, 9x or ME.

Please post back if you use an unsupported os, i have a function available which lets you get the window handle of the console no matter which os is being used.



Marcel
 
Marcel,

Your reply seems like the easiest to implement.

Your GetConsoleWindow() function does not compile and I cannot find it in my documentation - is that your own function? I would prefer to have a function that is a bit more portable so if you would be willing to post your function that will get the handle of the console no matter which os, that would be great.

Thanks,
David.
 
David,

GetConsoleWindow was introduced in Windows 2000, I think you have a version of Visual C++ which is a few years old. If you're interested, you can find a description here:
Here is the code of my own get console handle function:

Code:
#include <windows.h>
#include <stdio.h>

HWND GetConsoleWindowHandle ( )
//
// This function returns the handle of the console
// It does so by putting temporary a unique text in the console title
// which is found back by the FindWindow API. After this, the original
// console title is restored.
// The Console class is called &quot;ConsoleWindowClass&quot; on NT and it is
// called &quot;tty&quot; on 9x/ME
// This function returns NULL when it fails for some reason.
//

{
  HWND hWnd = NULL;

  char ConsoleClass  [MAX_PATH] = &quot;&quot;;
  char OriginalTitle [MAX_PATH] = &quot;&quot;;
  char TempTitle     [MAX_PATH] = &quot;&quot;;
  char tty9x[]                  = &quot;tty&quot;;
  char ttyNT[]                  = &quot;ConsoleWindowClass&quot;;

// Save the original console title

  if ( !GetConsoleTitle ( OriginalTitle, sizeof ( OriginalTitle )))
     { strcpy ( OriginalTitle, &quot;&quot; ); }

// Create a unique console title

  SYSTEMTIME st;
  GetSystemTime ( &st );
  sprintf ( TempTitle, &quot;___%d-%d-%d_%d:%d:%d:%d___&quot;,
            st.wDay, st.wMonth, st.wYear,
            st.wHour, st.wMinute, st.wSecond, st.wMilliseconds );

// Find out whether it is NT or 9x and use the appropriate class name

  OSVERSIONINFO osv;
  osv.dwOSVersionInfoSize = sizeof ( OSVERSIONINFO );

  if ( GetVersionEx ( &osv ))
     { switch ( osv.dwPlatformId )
          { case VER_PLATFORM_WIN32_NT :
                 strcpy ( ConsoleClass, ttyNT );
                 break;
            case VER_PLATFORM_WIN32_WINDOWS :
                 strcpy ( ConsoleClass, tty9x );
                 break;
            default: break; } }

  if ( strlen ( ConsoleClass ))
     { if ( SetConsoleTitle ( TempTitle ))
          { hWnd = FindWindow ( ConsoleClass, TempTitle );
            SetConsoleTitle ( OriginalTitle ); } }

  return hWnd;  }
you need to include stdio.h, because it uses sprintf. If you change the way an unique console title is created, perhaps you can drop it. Good luck




Marcel
 
Marcel,

Your above post works great with one exception. If I right-click on the top of the console the X gets reactivated and un-grayed. Any suggestions?

I am also going to look into how to gray out the X-Close sub-menu command that is accessible by right-clicking on the console - if you have any suggestions there that would be helpful as well.

Thank you so much for your time and code.

David G.
 
David,

I wasn't aware of this. It seems to be a NT/XP problem, ME goes fine at this point. Also in ME, the close submenu you are mentioning, is disabled by the code.
For the moment I have no solution for NT/XP. When I find a solution I will let you know.

Marcel
 
Marcel,

Thank you. I'll post if I find anything else as well.

I am using Windows2000 and my VC++ compiler is an early version of v.6.0

David G.
 
David,

I've found a solution.
Change : EnableMenuItem ( ... );
to : RemoveMenu ( ... );
with exactly the same parameters).
Works on XP.


Marcel
 
Marcel,

PERFECT! That's exactly what I want.

For those who have interest in this thread: I wanted the console window to gracefully exit (without quitting the SDI program) if the user hit the X-button or select Close from the console window. It appears that catching the &quot;X&quot; or Close command in the console is difficult if not impossible.

Marcel's suggestion to launch the console with the X and Close commands removed from the console is easy to implement. I have a button on my SDI that launches a console with this function:

//////////////////////////////////////////////
void SomeDoc::OnStartConsole()
//////////////////////////////////////////////
{
//Allocate a new console
AllocConsole();

//Disable the ability to close the console window with the X or ctrl-x
HWND hConsole;
hConsole = GetConsoleWindowHandle(); //use Marcel's snippet above for this function
RemoveMenu ( GetSystemMenu ( hConsole, FALSE),SC_CLOSE, MF_BYCOMMAND | MF_GRAYED );
}

And then I have another button that the user must push to remove the console:

///////////////////////////////////////////////
void SomeDoc::OnRemoveConsole()
//////////////////////////////////////////////
{
FreeConsole();
}

Thanks to Marcel and others who replied.

David G.
 
David,

two minor corrections:
1. RemoveMenu does not gray the 'X', so the user might think being able to click it and does not understand why the program doesn't respond to the 'X. Solution: Call EnableMenuItem before RemoveMenu to gray it.
2. I wrote before to call RemoveMenu with the same parameters as EnableMenuItem, but in fact, according to MSDN Library, RemoveMenu does not accept MF_GRAYED (although apparantly it does work).

So the best version up to now must be:
Code:
EnableMenuItem ( GetSystemMenu ( hConsole, FALSE),
                 SC_CLOSE,
                 MF_BYCOMMAND | MF_GRAYED );
RemoveMenu     ( GetSystemMenu ( hConsole, FALSE),
                 SC_CLOSE,
                 MF_BYCOMMAND );

Thank you for helping me to solve one of the bugs in my code ;-)



Marcel
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top