std::ostream Implementation for Text Output with CWnd-derived Controls | CodeGuru

std::ostream Implementation for Text Output with CWnd-derived Controls

I needed this class for keeping some other parts of a larger application portable. These other classes just require ostream & parameters for doing message and error text output (adapted lex and yacc generated classes actually). The basic ideas for the implementation came from a sample implementation for a X-Motif widget ostream by Dietmar Kuehl, […]

Written By
CodeGuru Staff
CodeGuru Staff
Nov 3, 2000
2 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

I needed this class for keeping some other parts of a larger application
portable. These other classes just require ostream & parameters for
doing message and error text output (adapted lex and yacc generated classes
actually).

The basic ideas for the implementation came from a sample implementation
for a X-Motif widget ostream by
Dietmar Kuehl,
see this URL to read more about it, and compare what i have been changing:


I added extra handling for special characters

n

and

a

:




  • ‘n’ needs to have a ‘r’ prefixed for proper output of a CR-LF sequence
    (linebreak) in a CWnd

  • ‘a’ is commonly defined as alert character, i have implemented this as
    an ‘optical bell’ (flashing of top window title)

The implementation is intended for use with a STATIC or EDIT control window
class and actually uses the CWnd::GetWindowText() and CWnd::SetWindowText()
methods for doing the text rendering. To get a CDC * with CWnd::GetWindowDC()
and to draw directly in the windows’ client area would be more efficient
and flexible (concerning text colouring and formatting). But if you use
an EDIT control in conjunction with winostream you’ll have advantage of
all the standard control features as ‘copy & paste’ for instance.

There’s another article to be found on CodeGuru, mentioning to send
a WM_SETSEL message to append text to the actual window text (thus you
can omit the CWnd::GetWindowText() calls). But this can be realized with
EDIT control window classes only; my solution will be slower but more general.

Implementation of special stream manipulators in the same style as ‘std::endl(ostream
&)’ will reqire to reimplement std::ostream overloadings of the operator<<()
method to return a winostream & actually. Otherwise the manipulator
function will receive an ostream & when a standard operator<<()
overloading is seen at the left side.

The methods overloaded and declared with winstrbuf should represent
a sufficient abstraction for implementing an ostream/streambuf pair. Overload
or rewrite the methods winstrbuf::TranslateWinChar(), winstrbuf::put_buffer()
and winstrbuf::put_char() to adapt character rendering to your needs.

//////////////////////////////////////////////////////////////////////
// winostream.h: interface of class winostream
// author: g. makulik
// purpose: implementing std::ostream for text output on
// a MFC-CWnd. This is primarily intended to use
// with CStatic/CEdit controls.
//
//////////////////////////////////////////////////////////////////////
// … some includes etc.
class winostream : public ostream
{
public:
 winostream ( CWnd * pWnd_
 , int nBufSize_ = 0
 );
 virtual ~winostream ();
 // It’s not essential to reimplement all the operator<< overloads
 // of ostream. But this will be useful if you like to implement
 // special manipulator methods and their global pendants in the
 // same style as ‘endl’.
 winostream & operator<< ( winostream & (*fmanip)(winostream &)
 );
 winostream & operator<< ( ostream & (*fmanip)(ostream &)
 )
 { fmanip(*this); return *this; };
 winostream & operator<< ( ios & (*fmanip)(ios &)
 )
 { fmanip(static_cast<ios>(*this)); return *this; };
 winostream & operator<< ( ios_base & (*fmanip)(ios_base &)
 )
 { fmanip(static_cast<ios_base>(*this)); return *this; };
 winostream & operator<< ( bool x_
 )
 { ostream::operator <<(x_); return *this; };
 winostream & operator<< ( short x_
 )
 { ostream::operator <<(x_); return *this; };
 // … put more << operator overloadings here, see ostream for
 // their signature
 // declare special winostream manipulators here
 //====================================================================
protected:
 virtual CWnd * getwnd ()
 { return m_pWinstrbuf->getwnd(); };
private:
 winstrbuf * m_pWinstrbuf;
};
//////////////////////////////////////////////////////////////////////
// winstrbuf.h: interface of class winstrbuf.
// author: g. makulik
// purpose: see winostream.h
//////////////////////////////////////////////////////////////////////
// … some includes etc.
class winstrbuf : public streambuf
{
public:
 winstrbuf ( CWnd * pWnd_
 , int nBufSize_ = 0
 );
 virtual ~winstrbuf ();
 CWnd * getwnd ()
 { return m_pWnd; };
protected:
 virtual int overflow ( int c_
 );
 virtual int sync ();
 virtual CString TranslateWinChar( int c_
 );
 virtual CString TranslateWinChar( CString const & cs_
 );
 virtual void PutAlertChar ();
private:
 CWnd * m_pWnd;
 int m_nBufSize;
 // helper class for representing installed
 // WIN32 timer ressources
 struct CFlashTimer {
 CFlashTimer ( UINT nId_
 , CWnd * pWnd_
 , UINT nTimes_
 )
 : m_nId(nId_)
 , m_pWnd(pWnd_)
 // Assure to have an odd value for m_nTimes, to
 // get the same window state as before, when the
 // flashing is over
 , m_nTimes((nTimes_%2)?nTimes_+1:nTimes_)
 , m_nCount(0)
 {};
 UINT m_nId;
 CWnd * m_pWnd;
 UINT m_nTimes;
 UINT m_nCount;
 BOOL m_bNextFlash;
 static void CALLBACK EXPORT
 TimerProc ( HWND hWnd_
 , UINT nMsg_
 , UINT nId_
 , DWORD dwTime_
 );
 };
 friend struct CFlashTimer;
 CFlashTimer * InstallTimer ( CWnd * pWnd_
 , DWORD dwFreq_
 , UINT nTimes_
 );
 static CFlashTimer * GetTimer ( UINT nId_
 );
 static BOOL KillTimer ( UINT nId_
 );
 static UINT sm_nextTimerId;
 static map<UINT,CFlashTimer*> sm_mapFlshTimers;
 void put_buffer ();
 void put_char ( int c_
 );
};
//////////////////////////////////////////////////////////////////////
// winstrbuf.cpp: implementation of class winstrbuf.
// author: g. makulik
//
//////////////////////////////////////////////////////////////////////
// … some includes etc.
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
winstrbuf::winstrbuf ( CWnd * pWnd_
 , int nBufSize_
 )
 : streambuf()
 , m_pWnd(pWnd_)
 , m_nBufSize(nBufSize_)
{
 ASSERT_VALID(pWnd_);
 if (m_nBufSize)
 {
 // if the requested buffer size is greater than 0,
 // allocate the buffer memory and tell streambuf
 // where it is allocated
 char * ptr = new char[m_nBufSize];
 setp(ptr, ptr + m_nBufSize);
 }
 else
 setp(0, 0);
 setg(0, 0, 0);
}
winstrbuf::~winstrbuf ()
{
 sync();
 if (m_nBufSize)
 {
 // free any buffer memory which was
 // allocated on construction
 delete [] pbase();
 }
}
// overflow is called when the buffer is full
int winstrbuf::overflow ( int c_
 )
{
 // render textoutput and clear the buffer
 put_buffer();
 // check for end of file character
 if (c_ != EOF)
 if (pbase() == epptr())
 // if there’s no space left in the buffer
 // send the character directly to the device
 put_char(c_);
 else
 // otherwise append it to the buffer
 sputc(c_);
 return 0;
}
// called to syncronize contents of buffer and device
int winstrbuf::sync ()
{
 put_buffer();
 return 0;
}
// called to render a single character on the device
void winstrbuf::put_char( int c_
 )
{
 // extract actual window text
 ASSERT_VALID(m_pWnd);
 CString csBuf;
 m_pWnd->GetWindowText(csBuf);
 // append character to extracted text
 csBuf += TranslateWinChar(c_);
 // write back text to the window (render)
 m_pWnd->SetWindowText(csBuf);
}
// called to render the actual content of the buffer on the device
void winstrbuf::put_buffer()
{
 if (pbase() != pptr())
 {
 int nBufLength = (pptr() – pbase());
 // extract actual window text
 ASSERT_VALID(m_pWnd);
 CString csBuf;
 m_pWnd->GetWindowText(csBuf);
 // append buffer to extracted text
 CString csHelp(pbase(),nBufLength);
 csBuf += TranslateWinChar(csHelp);
 // write back text to the window (render)
 m_pWnd->SetWindowText(csBuf);
 setp(pbase(), epptr());
 }
}
// used to implement rendering of special characters
// on the specific device (CWnd* actually)
CString winstrbuf::TranslateWinChar ( int c_
 )
{
 CString csRes;
 csRes = “”;
 switch((char)c_)
 {
 // prefix ‘LF’ with ‘CR’
 case ‘n’:
 csRes += ‘r’;
 break;
 // implement alert character as ‘optical bell’. Just override if
 // you want to do anything other.
 case ‘a’:
 PutAlertChar();
 return csRes;
 break;
 }
 csRes += (char)c_;
 return csRes;
}
// respects rendering of special characters
// on the specific device for a sequence of
// characters
CString winstrbuf::TranslateWinChar ( CString const & cs_
 )
{
 CString csRes;
 csRes = “”;
 for(int i = 0;
 i < cs_.GetLength();
 i++)
 {
 csRes += TranslateWinChar(cs_[i]);
 }
 return csRes;
}
// The following functions implement an ‘optical bell’ for
// a MFC standard window
void winstrbuf::PutAlertChar()
{
 ASSERT(m_pWnd);
 // flashing is always done with the top level parent window
 // (the one with the title bar usually)
 CWnd * pFlashWin = m_pWnd->GetTopLevelParent();
 // Install a timer activated every 100 ms and
 // killed after 5th activation
 InstallTimer(pFlashWin,100,5);
}
// the static timer callback function, it is called when the
// timer is activated. Note since this is a static method, a
// pseudo-this pointer is externalized in a static map of
// this class. It can be uniquely identified with the associated
// timer’s ID. Any access to the static map will be thread critical;
// use critical sections for map access, to make this class thread
// safe.
void CALLBACK EXPORT
 winstrbuf::CFlashTimer::TimerProc ( HWND hWnd_
 , UINT nMsg_
 , UINT nId_
 , DWORD dwTime_
 )
{
 CFlashTimer * pThis;
 // Thread critical
 //———————————————————
 // get pseudo-this pointer
 if((pThis = winstrbuf::GetTimer(nId_)) != NULL)
 {
 // Thread critical end
 //———————————————————
 // increment call counter first
 if(++pThis->m_nCount <= pThis->m_nTimes)
 {
 // change flash state of the window to former state
 pThis->m_bNextFlash = ::FlashWindow(hWnd_,pThis->m_bNextFlash);
 }
 else
 {
 // kill the timer if the specified number
 // of activations was done
 winstrbuf::KillTimer(nId_);
 }
 }
}
// initialize static members
UINT winstrbuf::sm_nextTimerId = 0;
map<UINT,CFlashTimer*> winstrbuf::sm_mapFlshTimers;
// this method installs a timer. The this-pointer of a CFlashTimer
// is stored in the global timer map
winstrbuf::CFlashTimer *
 winstrbuf::InstallTimer ( CWnd * pWnd_
 , DWORD dwFreq_
 , UINT nTimes_
 )
{
 CFlashTimer * pRes = NULL;
 // Thread critical from here to return
 //———————————————————
 if(pWnd_->SetTimer(++sm_nextTimerId,dwFreq_,CFlashTimer::TimerProc)
 != sm_nextTimerId)
 {
 return NULL;
 }
 pRes = new CFlashTimer(sm_nextTimerId,pWnd_,nTimes_);
 sm_mapFlshTimers[sm_nextTimerId] = pRes;
 return pRes;
}
// finds a specific CFlashTimer-pointer identified by
// an associated timer ID
winstrbuf::CFlashTimer * winstrbuf::GetTimer ( UINT nId_
 )
{
 CFlashTimer * pRes = NULL;
 // Thread critical from here to return
 //———————————————————
 if(sm_mapFlshTimers.find(nId_) != sm_mapFlshTimers.end())
 {
 pRes = sm_mapFlshTimers[nId_];
 }
 return pRes;
}
// releases the WIN32 timer resource and removes the associated
// CFlashTimer object from the global timer map
BOOL winstrbuf::KillTimer ( UINT nId_
 )
{
 BOOL bRes = FALSE;
 // Thread critical from here to return
 //———————————————————
 CFlashTimer * pFlashTimer = GetTimer(nId_);
 if(pFlashTimer)
 {
 bRes = pFlashTimer->m_pWnd->KillTimer(pFlashTimer->m_nId);
 delete pFlashTimer;
 sm_mapFlshTimers.erase(nId_);
 }
 return bRes;
}

Downloads


Download demo project – 24 Kb
Download source – 4 Kb
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.