Search code examples
c++winapiconsolecout

C++ Win32 GUI App, Console prompt overwrites previous logged text after program exit


Operating System is Windows 10.

The application is linked with /SUBSYSTEM:WINDOWS with a console Attached/Allocated and the Input/Output streams redirected like so:

void InitConsole()
{
    if (AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole()) {
        SetConsoleOutputCP(CP_UTF8);

        FILE* dummy;
        freopen_s(&dummy, "CONIN$", "r", stdin);
        freopen_s(&dummy, "CONOUT$", "w", stdout);
        freopen_s(&dummy, "CONOUT$", "w", stderr);

        DWORD consoleMode;
        GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &consoleMode);
        consoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
        SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), consoleMode);

        std::ios::sync_with_stdio(true);

        std::wcout.clear();
        std::cout.clear();
        std::wcerr.clear();
        std::cerr.clear();
        std::wcin.clear();
        std::cin.clear();
    }
}

This works, the text is displayed with colors and such, however after the program exits, the console prompt overwrites the logged text instead of continuing from where it ended:

GIF of the Prompt overwriting the logged text

This happens on the Windows Terminal, PowerShell and Command Prompt, as well as the VSCode integrated terminal.

The text is logged using the fmtlib. However std::cout and printf() behave equally as wrong.

Is there any way to correct this behavior to the more familiar one of the console prompt continuing from where the logged text ended whilst using /SUBSYSTEM:WINDOWS? Like so:

Image of the expected behavior

The expected behavior was achieved by using /SUBSYSTEM:CONSOLE without calling the InitConsole() function.

Minimum reproducible example: (Link with /SUBSYSTEM:WINDOWS)

#define UNICODE
#define _UNICODE
#include <iostream>
#include <windows.h>

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    if (AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole()) {
        SetConsoleOutputCP(CP_UTF8);

        FILE* dummy;
        freopen_s(&dummy, "CONIN$", "r", stdin);
        freopen_s(&dummy, "CONOUT$", "w", stdout);
        freopen_s(&dummy, "CONOUT$", "w", stderr);

        DWORD consoleMode;
        GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &consoleMode);
        consoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
        SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), consoleMode);

        std::ios::sync_with_stdio(true);

        std::wcout.clear();
        std::cout.clear();
        std::wcerr.clear();
        std::cerr.clear();
        std::wcin.clear();
        std::cin.clear();
    }

    std::cout << "Test Text 1\n";
    std::cout << "Test Text 2\n";
    std::cout << "Test Text 3\n";

    FreeConsole();

    return 0;
}


Solution

  • When compiled as a Windows program, it starts asynchronously - in the background so to speak - and the command prompt comes immediately. It doesn't wait for the program to finish.

    I recommend compiling it as a console program if you don't want the command prompt to appear until after the program has finished.