New Console Window without a crash

for those who are fed up with bad behavior (app crash when closing it) of console window (check copyright before any use) :

This code also avoid some bad compiler errors with filebuf ff(hCrt) line...

When using this smart object you have to replace every call like "cout

1) in stdafx.h you must declare
extern ConsoleStream GlobalConsoleStream

2) Here is a new very clean Winmain.cpp

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"

#ifdef AFX_CORE1_SEG
#pragma code_seg(AFX_CORE1_SEG)
#endif

/////////////////////////////////////////////////////////////////////////////
// Standard WinMain implementation
// Can be replaced as long as 'AfxWinInit' is called first

// GlobalConsoleStream definition :
ConsoleStream GlobalConsoleStream;

int AFXAPI AfxWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{

// Redirection of standard output in a consol
BOOL bIsDisplayingConsole(TRUE);
int hCrt;
if (bIsDisplayingConsole)
{
GlobalConsoleStream.Open();
}

ASSERT(hPrevInstance == NULL);

int nReturnCode = -1;
CWinApp* pApp = AfxGetApp();
// AFX internal initialization
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;

// App global initializations (rare)
ASSERT_VALID(pApp);
if (!pApp->InitApplication())
goto InitFailure;
ASSERT_VALID(pApp);

// Perform specific initializations
if (!pApp->InitInstance())
{
if (pApp->m_pMainWnd != NULL)
{
TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
pApp->m_pMainWnd->DestroyWindow();
}
nReturnCode = pApp->ExitInstance();
goto InitFailure;
}
ASSERT_VALID(pApp);

#ifdef _DEBUG // By Matra
Application:
try
{
nReturnCode = pApp->Run();
}
catch(Standard_Failure)
{
CATCH_STANDARD_FAILURE(MyT("OCC"));
goto Application; // restart application loop
}
#else // _DEBUG // By Matra
nReturnCode = pApp->Run();
#endif // _DEBUG // By Matra

ASSERT_VALID(pApp);

InitFailure:
#ifdef _DEBUG
// Check for missing AfxLockTempMap calls
if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
{
TRACE1("Warning: Temp map lock count non-zero (%ld).\n",
AfxGetModuleThreadState()->m_nTempMapLock);
}

AfxLockTempMaps();
AfxUnlockTempMaps();
#endif

AfxWinTerm();

if (bIsDisplayingConsole)
{
GlobalConsoleStream.Close();
}

return nReturnCode;
}

3) Here is the smart object

ConsoleStream.h

//
// ConsoleStream.h: interface for the ConsoleStream class.
//
// Mark Nelson, October 17, 1998
//
// The ConsoleStream class creates a C++ ostream object that can be
// used in Win32 C++ programs to write to a console window, often
// for debugging purposes. This code is demonstrated in the
// ConStreamDemo MFC program, and is fully explained in the
// accompanying Dr. Dobb's Journal article. For more details,
// see the article online at http://www.dogma.net/markn
//

//
// This header file defines the entire interface to the ConsoleStream class.
// ConsoleStream is a class that works like a standard iostream, and writes
// to a console window when created in a Win32 application. You can only
// have a single console window open at a time, so only a single ConsoleStream
// class is ordinarily created in an application. ConsoleStream is compatible with
// Windows 9x and Windows NT. It uses Unicode text if the _UNICODE macro
// is defined. It must be linked with source code found in ConsoleStream.cpp
//
#if !defined( _CONSTREAM_H )
#define _CONSTREAM_H

//
// Note that ConsoleStream uses the standard C++ libraries that ship with
// Visual C++ 5.0 and later, not the older libraries with the .h suffix.
// The library would require some modifications to work with the older
// libraries.
//
#include
#include

using namespace std;

//
// The ConsoleStream class is derived from what we normally think of as ostream,
// which means you can use standard insertion operators to write to it. Of
// course, this includes insertion operators for user defined classes. At
// all times, a ConsoleStream object is either writing out to to a FILE
// object attached to the NUL device, or a FILE object attached to a console
// created using the Win32 API. Which of the two is in use depends on whether
// or not the ConsoleStream object has had its Open() or Close() method called.
//
class ConsoleStream
#ifdef _UNICODE
: public basic_ostream
#else
: public basic_ostream
#endif
{
public :
ConsoleStream();
virtual ~ConsoleStream();
void Open();
void Close();

#ifdef _UNICODE
basic_filebuf * GetFileBuf() {return m_FileBuf;}
#else
basic_filebuf * GetFileBuf() {return m_FileBuf;}
#endif

protected :
HANDLE m_hConsole;
#ifdef _UNICODE
basic_filebuf *m_FileBuf;
basic_filebuf m_Nul;
#else
basic_filebuf *m_FileBuf;
basic_filebuf m_Nul;
#endif
FILE *m_fNul;
FILE *m_fConsole;
};

#endif // !defined( _CONSTREAM_H )

ConsoleStream.cpp

//
// ConsoleStream.cpp: implementation of the ConsoleStream class.
//
// Mark Nelson, October 17, 1998
//
// The ConsoleStream class creates a C++ ostream object that can be
// used in Win32 C++ programs to write to a console window, often
// for debugging purposes. This code is demonstrated in the
// ConStreamDemo MFC program, and is fully explained in the
// accompanying Dr. Dobb's Journal article. For more details,
// see the article online at http://www.dogma.net/markn
//

//
// Implementation of this class requires that you link in the IO.H
// and FCNTL.H header files from the standard C library. You should
// be able to substitute and for these two includes.
// stdafx.h is here because the code is being used in an MFC application
//

#include "stdafx.h"
#include
#include

#include

//
// The ConsoleStream constructor initializes the object to point to the
// NUL device. It does this by calling two consecutive constructors.
// First, the member variable m_Nul is initialized with a FILE object
// created by opening device "nul", the bit bucket. Second, the base
// class constructor is called with a reference to m_Nul, which is
// an ofstream object. This sets up ConsoleStream so that it will direct
// its output to the given file.
//

ConsoleStream::ConsoleStream() : m_Nul( m_fNul = fopen( "nul", "w" ) ),
#ifdef _UNICODE
basic_ostream( &m_Nul )
#else
basic_ostream( &m_Nul )
#endif
{
m_FileBuf = 0;
m_hConsole = INVALID_HANDLE_VALUE;
}

//
// The ConsoleStream destructor always has to close the m_fNul FILE object
// which was created in the constructor. Even if the Open() method has
// been called and the bit bucket isn't being used, the FILE object is
// still using memory and a system file handle.
//
// If the ConsoleStream object has been opened with a call to member function
// Open(), we have to call the Win32 API function FreeConsole() to close
// the console window. If the console window was open, we also call the
// C fclose() function on the m_fConsole member.
//
ConsoleStream::~ConsoleStream()
{
delete m_FileBuf;
if ( m_hConsole != INVALID_HANDLE_VALUE ) {
FreeConsole();
fclose( m_fConsole );
}
fclose( m_fNul );
}

//
// Opening the stream means doing these things:
// 1) Opening a Win32 console using the Win32 API
// 2) Getting an O/S handle to the console
// 3) Converting the O/S handle to a C stdio file handle
// 4) Converting the C stdio file handler to a C FILE object
// 5) Attaching the C FILE object to a C++ filebuf
// 6) Attaching the filebuf object to this
// 7) Disabling buffering so we see our output in real time.
//
void ConsoleStream::Open()
{
if ( m_hConsole == INVALID_HANDLE_VALUE ) {
AllocConsole();
m_hConsole = GetStdHandle( STD_OUTPUT_HANDLE );
int handle = _open_osfhandle( (long) m_hConsole, _O_TEXT );
m_fConsole = _fdopen( handle, "w" );
#ifdef _UNICODE
m_FileBuf = new basic_filebuf( m_fConsole );
#else
m_FileBuf = new basic_filebuf( m_fConsole );
#endif
init( m_FileBuf );
setf(ios::unitbuf);
}
};

//
// Closing the ConsoleStream is considerably simpler. We just use the
// init() call to attach this to the NUL file stream, then close
// the console descriptors.
//
void ConsoleStream::Close()
{
if ( m_hConsole != INVALID_HANDLE_VALUE ) {
init( &m_Nul );
FreeConsole();
fclose( m_fConsole );
m_hConsole = INVALID_HANDLE_VALUE;
}
};

Philippe CARRET's picture

Correction1 :

1) of course in stdafx.h you must declare

#include
extern ConsoleStream GlobalConsoleStream

Liang Quan's picture

At the end of the "extern ConsoleStream GlobalConsoleStream" should have ";",like this

#include
extern ConsoleStream GlobalConsoleStream;