-1

Since BGI is obsolete, and a lot of its source code seems to be missing from the original website, I've been meaning to design my own color engine that will affect lines individually. So far, the 16 colors that "SetConsoleTextAttribute ()" from windows.h can accept have been doing fine, but I've been meaning to use more colors (by using RGB instead of 0xbf) to upgrade the look of it and color my own ASCII art.

"SetTextColor ()" seems to be the route I want to go. I've set up a testing function to see if it works. Here's the snippet of code with the setup.

HDC hType;    // Handle DC, save some work to reduce repetition
int initColor ()    // Initializes engine
{
    hType = GetDC (GetConsoleWindow ());

    printf ("String     Hexadecimal\n");
    testcolorR (RGB(255, 0, 0));    // Red
    testcolorR (RGB(0, 255, 0));    // Green
    testcolorR (RGB(0, 0, 255));    // Blue

    getch ();    // Pause to see results
    return 0;    // Exit success
}

// Take in RGB
void colortextR (COLORREF rgbcolor)
{
    SetTextColor (hType, rgbcolor);
}

// Test RGB colors
int testcolorR (COLORREF color)
{
    colortextR (color);
    printf ("Hello      %#x\n", color);
    return 0;
}

However, on the command line, the color did not change and remained as the default light-gray, but this is the result.

  1. String Hexadecimal
  2. Hello 0xff
  3. Hello 0xff00
  4. Hello 0xff0000

Which means that the RGB color is being passed, but something else is causing this problem. I suspect the culprit is the GetConsoleWindow () function.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Jamesthe1
  • 107
  • 14
  • 4
    Or maybe the console window doesn't work how you think it does – user253751 Dec 12 '18 at 01:47
  • 2
    `SetTextColor()` is not the way to handle this. You have to use `SetConsoleTextAttribute()`, so you are limited to 16 colors max - HOWEVER - you can set those 16 colors to whatever RGB values you want by using `SetConsoleScreenBufferInfoEx()`. See [this answer](https://stackoverflow.com/a/9509664/65863) to [RGB Specific Console Text Color](https://stackoverflow.com/questions/9509278/) – Remy Lebeau Dec 12 '18 at 02:31
  • So I am unfortunately stuck with no workaround other than modifying 16 colors. I’m all ears to any other solution that may work, still, if there is another way. – Jamesthe1 Dec 12 '18 at 03:08
  • Write your own console (or use a third party one)? – Jonathan Potter Dec 12 '18 at 03:32
  • I think I have tried to do this before but actually end up using the 16 colors only. It seems what you want is not supported by the `cmd` – mr5 Dec 12 '18 at 04:43
  • I’ll look into what GetDC and SetTextColor are returning, now that I think about it. The latter could be giving CLR_INVALID for all I know currently. – Jamesthe1 Dec 12 '18 at 04:51
  • The console itself has nothing to do, at least at the API level, with HDC. – Michael Chourdakis Dec 12 '18 at 08:35

1 Answers1

2

SetTextColor is a GUI function; it will not have the effect you want in a standard Windows console.


If your application will only be run on Windows 10 build 14392 or later, or on (most) non-Windows platforms such as Linux, then you can generally use virtual terminal sequences. Please note that even on supported versions of Windows, VT functionality must be explicitly enabled:

// error handling omitted for brevity; see GetLastError
HANDLE hOut = GetStdHandle( STD_OUTPUT_HANDLE );
if( hOut == INVALID_HANDLE_VALUE ) { return; }

DWORD dwMode = 0;
if( !GetConsoleMode( hOut, &dwMode ) ) { return; }
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if( !SetConsoleMode( hOut, dwMode ) ) { return; }

std::cout << "\x1b[91mRed\n"
          << "\x1b[92mGreen\n"
          << "\x1b[94mBlue\n"
          << "\x1b[38;5;221mArbitrary RGB color\n"
          << "\x1b[0mReset colors\n";

If your application needs to run on older versions of Windows, and the standard 16-color palette is sufficient, then something similar to the following will work (see SetConsoleTextAttribute and console screen buffer text attributes):

// error handling omitted for brevity; see GetLastError
HANDLE hOut = GetStdHandle( STD_OUTPUT_HANDLE );
if( hOut == INVALID_HANDLE_VALUE ) { return; }

// save current buffer information
CONSOLE_SCREEN_BUFFER_INFO sbInfo{ sizeof CONSOLE_SCREEN_BUFFER_INFO };
GetConsoleScreenBufferInfo( hOut, &sbInfo );

SetConsoleTextAttribute( hOut, FOREGROUND_RED | FOREGROUND_INTENSITY );
std::cout << "Red\n";

SetConsoleTextAttribute( hOut, FOREGROUND_GREEN | FOREGROUND_INTENSITY );
std::cout << "Green\n";

SetConsoleTextAttribute( hOut, FOREGROUND_BLUE | FOREGROUND_INTENSITY );
std::cout << "Blue\n";

SetConsoleTextAttribute( hOut, FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN );
std::cout << "Light Gray\n";

SetConsoleTextAttribute( hOut, sbInfo.wAttributes );
std::cout << "Reset colors\n";
  • Thank you. I guess I didn’t see that it was for the GUI in its documentation. – Jamesthe1 Dec 12 '18 at 14:06
  • 1
    @jam: In the [documentation](https://learn.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-settextcolor), there's a breadcrumb navigation bar at the top, reflecting the documentation hierarchy. `SetTextColor` is part of the *Windows GDI*. – IInspectable Dec 12 '18 at 22:19
  • Since the ENABLE_VIRTUAL_TERMINAL_PROCESSING flag didn't exist for me, I read up and found its value to be 0x0004. Just a note for anyone else looking at this answer. – Jamesthe1 Dec 12 '18 at 23:07
  • @Jamesthe1 If `ENABLE_VIRTUAL_TERMINAL_PROCESSING` isn't defined, you're most likely using an older SDK. Apparently the flag was (quietly) added to the console subsystem at some point before or around build 10586, but wasn't added to the SDK headers until the next release: 1607, or build 14393. I can't personally verify that as the headers I currently have access to jump straight from 10.0.10240.0 to 10.0.15063.0. – pandorafalters Dec 13 '18 at 06:37
  • @pandorafalters I'm guessing that I am using an older SDK, since I earned the files from MinGW. – Jamesthe1 Dec 15 '18 at 16:51