Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Console created through AllocConsole does not receive colored output #1731

Closed
bstordrup opened this issue Jan 5, 2024 · 3 comments · Fixed by #1732
Closed

[BUG] Console created through AllocConsole does not receive colored output #1731

bstordrup opened this issue Jan 5, 2024 · 3 comments · Fixed by #1732

Comments

@bstordrup
Copy link
Contributor

bstordrup commented Jan 5, 2024

Describe the bug
I use benchmark.dll inside a non-console application because I want to benchmark different implementations of ways to solve the same problem. And it is not possible to extract the code into a separate project, as the benchmarked code calls several other functions.

Therefore, I rolled my own BenchmarkMain method that does the same as BENCHMARK_MAIN macro, but also creates a console with AllocConsole, creates std::ostream instances for STD_OUTPUT_HANDLE and STD_ERROR_HANDLE, creates a ConsoleReporter instance and calls RunSpecificBenchmarks with this displayReporter.

The console did receive output, but it reported that Color printing was only supported on Windows - which makes no sense as the console being written to is on Windows.

Along the way, the std::cout.rdbuf() is saved, and replaced with the the same .rdbuf() that is used for the std::ostream out instance.

System

  • OS: Windows 11 23H2 (build 22631.2861)
  • Compiler and version: Visual C++ 2022 (Visual Studio 2022 17.8.3), cl.exe version 19.38.33133 for x64

To reproduce
Inside a non-console application, add the following function:

int BenchmarkMain (int argc, char **argv)
{
    char arg0_default[] = "benchmark";
    char* args_default = arg0_default;
    if (!argv) {
      argc = 1;
      argv = &args_default;
    }

    if (!argv)
    {
        argc = 2;
        argv = (char **) args_default;
    }

    ::benchmark::Initialize (&argc, argv);
    if (::benchmark::ReportUnrecognizedArguments (argc, argv))
    {
        return 1;
    }

    // Create console reporter
    AllocConsole ();
    HANDLE stdOutHandle = GetStdHandle (STD_OUTPUT_HANDLE);
    HANDLE stdErrHandle = GetStdHandle (STD_ERROR_HANDLE);


    // Get file descriptors
    int fdOut = _open_osfhandle ((intptr_t) stdOutHandle, _O_TEXT);
    int fdErr = _open_osfhandle ((intptr_t) stdErrHandle, _O_TEXT);

    // Get FILE*
    FILE *fpOut = _fdopen (fdOut, "w");
    FILE *fpErr = _fdopen (fdErr, "w");

    // Create ofstream
    std::ofstream outStream (fpOut);
    std::ofstream errStream (fpErr);

    // Create ostream
    std::ostream out (outStream.rdbuf ());
    std::ostream err (errStream.rdbuf ());

    auto savedBuf = std::cout.rdbuf ();
    std::cout.rdbuf (outStream.rdbuf ());

    auto displayReporter = std::make_unique<::benchmark::ConsoleReporter> ();
    displayReporter->SetOutputStream (&out);
    displayReporter->SetErrorStream (&err);

    ::benchmark::RunSpecifiedBenchmarks (displayReporter.get());

    // Restore std::cout.rdbuf() - otherwise an exception is thrown at exit.
    std::cout.rdbuf (savedBuf);

    return 0;
}

Make sure that the function is being called when the application starts - I control this with a command line parameter.

Note that the output written to the console is without any color formatting.

Expected behavior
Output from benchmarking should get color-enabled output in the created console window

Additional context
The application, where I call the benchmark library, is a MFC Windows application created with use of an external library (CodeJock).

@dmah42
Copy link
Member

dmah42 commented Jan 5, 2024

can you point to where the bug in the library is that is causing the issue, as opposed to an issue with how you're redirecting the various streaming buffers?

@bstordrup bstordrup changed the title [BUG] Console created through AllocConsole does not receive output [BUG] Console created through AllocConsole does not receive colored output Jan 5, 2024
@bstordrup
Copy link
Contributor Author

Updated the issue to more precisely describe the problem.

There are two places in code that contributes to this error:

  1. In console_reporter.cc, there is a check on the output stream where std::cout is directly compared to GetOutputStream(), and if different, the "Color printing is only supported..." is reported.
  2. The ColorPrintf (std::ostream& out, LogColor color, const char* fmt, va_list args) method operates directly on stdout for flushing the stream and uses vprintf to make the actual output.

I have a branch in my local fork with changes in these two places that makes color printing work in a Console window created with AllocConsole.

@dmah42
Copy link
Member

dmah42 commented Jan 5, 2024

ah great, thank you for the clarification! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants