Skip to content

Instantly share code, notes, and snippets.

@kingseva
Created January 27, 2018 15:11
  • Star 8 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save kingseva/a918ec66079a9475f19642ec31276a21 to your computer and use it in GitHub Desktop.
Example redirecting cout/stdout to allocated terminal in GUI programs.
#include "rang.hpp"
#include <windows.h>
#include <cstdlib>
void BindStdHandlesToConsole()
{
//TODO: Add Error checking.
// Redirect the CRT standard input, output, and error handles to the console
freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stderr);
freopen("CONOUT$", "w", stdout);
// Note that there is no CONERR$ file
HANDLE hStdout = CreateFile("CONOUT$", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hStdin = CreateFile("CONIN$", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
SetStdHandle(STD_OUTPUT_HANDLE,hStdout);
SetStdHandle(STD_ERROR_HANDLE,hStdout);
SetStdHandle(STD_INPUT_HANDLE,hStdin);
//Clear the error state for each of the C++ standard stream objects.
std::wclog.clear();
std::clog.clear();
std::wcout.clear();
std::cout.clear();
std::wcerr.clear();
std::cerr.clear();
std::wcin.clear();
std::cin.clear();
}
INT WINAPI WinMain(HINSTANCE,HINSTANCE,PSTR,INT)
{
// I want to create console terminal for GUI application
// Allocate new console for app:
AllocConsole();
// Redirect stderr/stdout/stdin to new console
BindStdHandlesToConsole();
using namespace std;
using namespace rang;
// Because rang use static values it means that all redirections should be done
// before calling rang functions.
// Visual test for background colors
cout << bg::green
<< "This text has green background." << bg::reset << endl
<< bg::red << "This text has red background." << bg::reset << endl
<< bg::black << "This text has black background." << bg::reset << endl
<< bg::yellow << "This text has yellow background." << bg::reset
<< endl
<< bg::blue << "This text has blue background." << bg::reset << endl
<< bg::magenta << "This text has magenta background." << bg::reset
<< endl
<< bg::cyan << "This text has cyan background." << bg::reset << endl
<< bg::gray << fg::black << "This text has gray background."
<< bg::reset << style::reset << endl
<< endl
// Visual test for foreground colors
<< fg::green << "This text has green color." << fg::reset << endl
<< fg::red << "This text has red color." << fg::reset << endl
<< fg::black << bg::gray << "This text has black color." << fg::reset
<< bg::reset << endl
<< fg::yellow << "This text has yellow color." << fg::reset << endl
<< fg::blue << "This text has blue color." << fg::reset << endl
<< fg::magenta << "This text has magenta color." << fg::reset << endl
<< fg::cyan << "This text has cyan color." << fg::reset << endl
<< fg::gray << "This text has gray color." << style::reset << endl
<< endl
// Visual test for bright background colors
<< bgB::green << fg::black << "This text has bright green background."
<< style::reset << endl
<< bgB::red << "This text has bright red background." << style::reset
<< endl
<< bgB::black << "This text has bright black background."
<< style::reset << endl
<< bgB::yellow << fg::black
<< "This text has bright yellow background." << style::reset << endl
<< bgB::blue << "This text has bright blue background." << style::reset
<< endl
<< bgB::magenta << "This text has bright magenta background."
<< style::reset << endl
<< bgB::cyan << "This text has bright cyan background." << style::reset
<< endl
<< bgB::gray << fg::black << "This text has bright gray background."
<< style::reset << style::reset << endl
<< endl
// Visual test for bright foreground colors
<< fgB::green << "This text has bright green color." << endl
<< fgB::red << "This text has bright red color." << endl
<< fgB::black << "This text has bright black color." << endl
<< fgB::yellow << "This text has bright yellow color." << endl
<< fgB::blue << "This text has bright blue color." << endl
<< fgB::magenta << "This text has bright magenta color." << endl
<< fgB::cyan << "This text has bright cyan color." << endl
<< fgB::gray << "This text has bright gray color." << style::reset
<< endl
<< endl
// Visual test for text effects
<< style::bold << "This text is bold." << style::reset << endl
<< style::dim << "This text is dim." << style::reset << endl
<< style::italic << "This text is italic." << style::reset << endl
<< style::underline << "This text is underlined." << style::reset
<< endl
<< style::blink << "This text text has blink effect." << style::reset
<< endl
<< style::rblink << "This text text has rapid blink effect."
<< style::reset << endl
<< style::reversed << "This text is reversed." << style::reset << endl
<< style::conceal << "This text is concealed." << style::reset << endl
<< style::crossed << "This text is crossed."
<< style::reset << endl;
cin.get();
return 0;
}
@kingseva
Copy link
Author

Tested on MinGW 64 GCC 7.2.0 with -mwindows argument.

@ferrellsl
Copy link

Where is rang.hpp?

@viniciusrplima
Copy link

@ovidiubuligan
Copy link

Do you know how to make it also work when starting with output redirection from command line App.exe > out.txt ? . I am also using AttachConsole . Output redirection is blank ...

@kingseva
Copy link
Author

Do you know how to make it also work when starting with output redirection from command line App.exe > out.txt ? . I am also using AttachConsole . Output redirection is blank ...

Hi @ovidiubuligan! My opinion is that if user wants to interact with file instead of created or attached console than we need to check it before creating console like this:

BOOL IsDiskHandle(DWORD nStdHandle)
{
    HANDLE hConsoleHandle = GetStdHandle(nStdHandle);
    DWORD dwFileType = FILE_TYPE_UNKNOWN;
    if(hConsoleHandle != INVALID_HANDLE_VALUE)
        dwFileType = GetFileType(hConsoleHandle);
    return dwFileType == FILE_TYPE_DISK ? TRUE : FALSE;
}

BOOL IsConsoleRedirected()
{
    return (IsDiskHandle(STD_OUTPUT_HANDLE) || IsDiskHandle(STD_ERROR_HANDLE) ||
            IsDiskHandle(STD_INPUT_HANDLE)) ? TRUE : FALSE;
}

...
// Than check that user is not redirecting to the file
if(!IsConsoleRedirected())
{
    AllocConsole();   // or AttachConsole( with pid of process )
    BindStdHandlesToConsole();
}

If you want to use both output to console and file than this is not simple. We need to create our own wrapper that writes both to console and file. Or we can use libraries like boost tee_device.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment