Evan Teran Evan Teran - 2 months ago 24
C++ Question

Redirecting cout to a console in windows

I have an application which is a relatively old. Through some minor changes, it builds nearly perfectly with Visual C++ 2008. One thing that I've noticed is that my "debug console" isn't quite working right. Basically in the past, I've use

AllocConsole()
to create a console for my debug output to go to. Then I would use
freopen
to redirect
stdout
to it. This worked perfectly with both C and C++ style IO.

Now, it seems that it will only work with C style IO. What is the proper way to redirect things like
cout
to a console allocated with
AllocConsole()
?

Here's the code which used to work:

if(AllocConsole()) {
freopen("CONOUT$", "wt", stdout);
SetConsoleTitle("Debug Console");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
}


EDIT: one thing which occurred to me is that I could make a custom streambuf whose overflow method writes using C style IO and replace
std::cout
's default stream buffer with it. But that seems like a cop-out. Is there a proper way to do this in 2008? Or is this perhaps something that MS overlooked?

EDIT2: OK, so I've made an implementaiton of the idea I spelled out above. Basically it looks like this:

class outbuf : public std::streambuf {
public:
outbuf() {
setp(0, 0);
}

virtual int_type overflow(int_type c = traits_type::eof()) {
return fputc(c, stdout) == EOF ? traits_type::eof() : c;
}
};

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
// create the console
if(AllocConsole()) {
freopen("CONOUT$", "w", stdout);
SetConsoleTitle("Debug Console");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
}

// set std::cout to use my custom streambuf
outbuf ob;
std::streambuf *sb = std::cout.rdbuf(&ob);

// do some work here

// make sure to restore the original so we don't get a crash on close!
std::cout.rdbuf(sb);
return 0;
}


Anyone have a better/cleaner solution than just forcing
std::cout
to be a glorified
fputc
?

Answer

I'm posting a portable solution in answer form so it can be accepted. Basically I replaced cout's streambuf with one that is implemented using c file I/O which does end up being redirected. Thanks to everyone for your input.

class outbuf : public std::streambuf {
public:
    outbuf() {
        setp(0, 0);
    }

    virtual int_type overflow(int_type c = traits_type::eof()) {
        return fputc(c, stdout) == EOF ? traits_type::eof() : c;
    }
};

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
    // create the console
    if(AllocConsole()) {
        freopen("CONOUT$", "w", stdout);
        SetConsoleTitle("Debug Console");
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);  
    }

    // set std::cout to use my custom streambuf
    outbuf ob;
    std::streambuf *sb = std::cout.rdbuf(&ob);

    // do some work here

    // make sure to restore the original so we don't get a crash on close!
    std::cout.rdbuf(sb);
    return 0;
}
Comments