Listing 3: ConStream.cpp — implementation of the ConStream class

//
// ConStream.cpp: implementation of the ConStream class.
//
// Mark Nelson, October 17, 1998
//
//
// 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 <cio> and <cfcnt> for these
// two includes. stdafx.h is here because the code is being used
// in an MFC application
// 

#include "stdafx.h"
#include <io.h>
#include <fcntl.h>

#include "ConStream.h"

//
// The ConStream 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
// ConStream so that it will direct its output to the given file.
//

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

//
// The ConStream 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 ConStream 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.
//
ConStream::~ConStream()
{
    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 ConStream::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<wchar_t>( m_fConsole );
#else
        m_FileBuf = new basic_filebuf<char>( m_fConsole );
#endif
        init( m_FileBuf );
        setf(ios::unitbuf);
    }
};

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