Alex Rivera | Logout

Override c++ streams

Asked 2011-08-24T00:33:50.193
9

In a C++ program, we have 3 streams: stdin, stdout, and stderr. Can I override these in a console application and use them in a application that uses forms?

For example, if in some base class, I have cout<< "...", can I "redirect" to something visual (like a Windows Form)?

Edit
Report

1 Answer

3

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);
answered 2011-08-24T03:10:25.853

Your Answer