9
Here's the code I use to redirect std::cout to a GUI on Windows:
struct STDOUT_BLOCK : SLIST_ENTRY
{
char sz[];
};
class capturebuf : public std::stringbuf
{
protected:
virtual int sync()
{
if (g_threadUI && g_hwndProgressDialog) {
// ensure NUL termination
overflow(0);
// allocate space
STDOUT_BLOCK* pBlock = (STDOUT_BLOCK*)_aligned_malloc(sizeof *pBlock + pptr() - pbase(), MEMORY_ALLOCATION_ALIGNMENT);
// copy buffer into string
strcpy(pBlock->sz, pbase());
// clear buffer
str(std::string());
// queue string
::InterlockedPushEntrySList(g_slistStdout, pBlock);
// kick to log window
::PostMessageA(g_hwndProgressDialog, WM_APP, 0, 0);
}
return __super::sync();
}
};
Then inside main():
capturebuf altout;
std::cout.set_rdbuf(&altout);
Of course, you then need to handle the WM_APP message in your window procedure and pull the strings off the SList. But this handles the cout redirection part.
As jweyrich correctly notes, you need to change the streambuf* back before altout goes out of scope. This code will do so:
struct scoped_cout_streambuf_association
{
std::streambuf* orig;
scoped_cout_streambuf_association( std::streambuf& buf )
: orig(std::cout.rdbuf())
{
std::cout.rdbuf(&buf);
}
~scoped_cout_streambuf_association()
{
std::cout.rdbuf(orig);
}
};
And inside main:
capturebuf altout;
scoped_cout_streambuf_association redirect(altout);