// // ConStream.cpp: implementation of the ConStream class. // // Mark Nelson, October 17, 1998 // // The ConStream 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 "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")), m_fConsole(nullptr), #ifdef _UNICODE basic_ostream(&m_Nul) #else basic_ostream(&m_Nul) #endif { m_FileBuf = nullptr; 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((INT_PTR)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 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; } };