7

I tried using system("color 24"); but that didn't change the color in the prompt. So after more Googling I saw SetConsoleTextAttribute and wrote the below code.

This results in both stdout and stderr both getting colored red instead of stdout being green and stderr being red.

How do I solve this? My prompt is also now red but I don't care about that since I know how to fix it.

Should work in Windows 7. At the moment I'm building this from the prompt (using VS 2010 cl) and running it in a regular cmd prompt

#include <windows.h>
#include <stdio.h>
int main(int argc, char **argv)
{
    int i;
    unsigned long totalTime=0;


    HANDLE hConsoleOut; //handle to the console
    hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsoleOut, FOREGROUND_GREEN);

    HANDLE hConsoleErr;
    hConsoleErr = GetStdHandle(STD_ERROR_HANDLE);
    SetConsoleTextAttribute(hConsoleErr, FOREGROUND_RED);

    fprintf(stdout, "%s\n", "out");
    fprintf(stderr, "%s\n", "err");
    return 0;
}
jotik
  • 17,044
  • 13
  • 58
  • 123
  • The [`GetStdHandle`](https://learn.microsoft.com/en-us/windows/console/getstdhandle) documentation is poorly written. Examples: "[i]nitially, this is the active console screen buffer, CONOUT$" and "[h]andles returned by GetStdHandle can be used by applications that need to read from or write to the console". The initial standard handles depend on the parent process. Don't assume that they're console handles, or that they're even set, or that you can even open "CONIN$" and "CONOUT$". – Eryk Sun May 23 '20 at 09:38
  • For example, with the `DETACHED_PROCESS` creation flag, at startup the process won't attach to a console (so opening "CONOUT$" will fail) and won't have standard handles set unless the parent process sets them explicitly. A console application should handle these cases gracefully. – Eryk Sun May 23 '20 at 09:39

3 Answers3

7

According to the MSDN GetStdHandle() documentation, the function will return handles to the same active console screen buffer. So setting attributes using these handles will always change the same buffer. Because of this you have to specify the color right before you right to the output device:

/* ... */

HANDLE hConsoleOut; //handle to the console
HANDLE hConsoleErr;
hConsoleErr = GetStdHandle(STD_ERROR_HANDLE);
hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsoleOut, FOREGROUND_GREEN);
fprintf(stdout, "%s\n", "out");

SetConsoleTextAttribute(hConsoleErr, FOREGROUND_RED);
fprintf(stderr, "%s\n", "err");
return 0;
jotik
  • 17,044
  • 13
  • 58
  • 123
Eiberle
  • 94
  • 2
5

The handle for error and normal console output are the same. Or more like, they point to the same console window. When you change the console color, it applies to all text written after that, so you'd need to change the color directly before the output. If you don't want to do that for every text you output, pack the calls into a seperate function:

#include <windows.h>
#include <stdio.h>
// global vars (better pack it in a class)
// initialize both to normal white color
#define FOREGROUND_WHITE (FOREGORUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN)
int g_console_out_color = FOREGROUND_WHITE;
int g_console_err_color = FOREGROUND_WHITE;
HANDLE g_console_out_handle = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE g_console_err_handle = GetStdHandle(STD_ERROR_HANDLE);

void SetConsoleOutColor(int color){
    g_console_out_color = color;
}

void SetConsoleErrColor(int color){
    g_console_err_color = color;
}

void PrintOut(const char* format, ...){
    SetConsoleTextAttribute(g_console_out_handle, g_console_out_color);
    va_list args;
    va_start(args, str);
    fprintf(stdout, format, args);
    va_end(args);
    // set color back to normal
    SetConsoleTextAttribute(g_console_out_handle, FOREGROUND_WHITE);
}

void PrintErr(const char* format, ...){
    SetConsoleTextAttribute(g_console_err_handle, g_console_err_color);
    va_list args;
    va_start(args, str);
    fprintf(stderr, format, args);
    va_end(args);
    // set color back to normal
    SetConsoleTextAttribute(g_console_err_handle, FOREGROUND_WHITE);
}

int main(void){
    PrintOut("%s\n", "out");
    PrintErr("%s\n", "err");
}
Xeo
  • 129,499
  • 52
  • 291
  • 397
0

Try to set the color before each output. You can do that in a function to avoid code duplication.

frast
  • 2,700
  • 1
  • 25
  • 34