Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Output to console from a Win32 GUI application on Windows 10

Tags:

c++

winapi

I tried this code to output to the console:

#include <Windows.h>

#include <stdio.h>
#include <io.h>
#include <fcntl.h>

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    AllocConsole();

    HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
    int hCrt = _open_osfhandle((long) handle_out, _O_TEXT);
    FILE* hf_out = _fdopen(hCrt, "w");
    setvbuf(hf_out, NULL, _IONBF, 1);
    *stdout = *hf_out;

    HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);
    hCrt = _open_osfhandle((long) handle_in, _O_TEXT);
    FILE* hf_in = _fdopen(hCrt, "r");
    setvbuf(hf_in, NULL, _IONBF, 128);
    *stdin = *hf_in;

    printf("Hello!");
}

the console opens but nothing is outputted to it. What's wrong with that code?

I tried all these suggestions:

https://justcheckingonall.wordpress.com/2008/08/29/console-window-win32-app/

http://dslweb.nwnexus.com/~ast/dload/guicon.htm

How do I print to the debug output window in a Win32 app?

but I couldn't get any output to the console created with AllocConsole() on Windows 10 in WinMain. Note: I actually didn't create any real Window. Was something changed in Window 10 that prevents the above solutions from working or is there something that I might be missing (compiler flags or something)?

What do you think?

like image 325
Zingam Avatar asked Aug 24 '15 15:08

Zingam


3 Answers

Based on the accepted answer from ProXicT link with a few modifications. The following code works for std::cout. The other methods won't work on 64bit with Visual Studio 2015:

#include <iostream>
#include <cstdio>
#include <fstream>

#include <Windows.h>


// For debugging
#include <io.h>
#include <fcntl.h>


#define UNUSED(x) (void)(x)       // Unused param (C compatible - not applicable to expressions)

class outbuf : public std::streambuf {
public:
    outbuf() {
        setp(0, 0);
    }

    virtual int_type overflow(int_type c = traits_type::eof()) {
        return fputc(c, stdout) == EOF ? traits_type::eof() : c;
    }
};

int CALLBACK
WinMain (HINSTANCE hInstance,
         HINSTANCE /*hPrevInst*/, // Unused param (C++ only)
         LPSTR lpCmdLine,
         int (nShowCmd))
{
    UNUSED(hInstance);
//    UNUSED(hPrevInst);
    UNUSED(lpCmdLine);
    UNUSED(nShowCmd); // This param is used


    // create the console
    if (AllocConsole()) {
        FILE* pCout;
        freopen_s(&pCout, "CONOUT$", "w", stdout);
        SetConsoleTitle(L"Debug Console");
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
    }

    // set std::cout to use my custom streambuf
    outbuf ob;
    std::streambuf *sb = std::cout.rdbuf(&ob);

    // do some work here
    printf("Hello!\n");

    std::cout << "nShowCmd = " << nShowCmd << std::endl;
    std::cout << "Now making my first Windows window!" << std::endl;


    // make sure to restore the original so we don't get a crash on close!
    std::cout.rdbuf(sb);

    MessageBoxW (NULL,
                 L"Hello World!",
                 L"hello",
                 MB_OK | MB_ICONINFORMATION);

    return 0;
}

EDIT:

The same stuff as above but with colors for completeness:

#include <iostream>
#include <cstdio>
#include <fstream>

#include <Windows.h>


// For debugging
#include <io.h>
#include <fcntl.h>


#define UNUSED(x) (void)(x)       // Unused param (C compatible - not applicable to expressions)

class outbuf : public std::streambuf {
public:
    outbuf() {
        setp(0, 0);
    }

    virtual int_type overflow(int_type c = traits_type::eof()) {
        return fputc(c, stdout) == EOF ? traits_type::eof() : c;
    }
};

int CALLBACK
WinMain (HINSTANCE hInstance,
         HINSTANCE /*hPrevInst*/, // Unused param (C++ only)
         LPSTR lpCmdLine,
         int (nShowCmd))
{
    UNUSED(hInstance);
//    UNUSED(hPrevInst);
    UNUSED(lpCmdLine);
    UNUSED(nShowCmd); // This param is used


    // create the console
    if (AllocConsole()) {
        FILE* pCout;
        freopen_s(&pCout, "CONOUT$", "w", stdout);
        SetConsoleTitle(L"Debug Console");

    }

    // set std::cout to use my custom streambuf
    outbuf ob;
    std::streambuf *sb = std::cout.rdbuf(&ob);

    // do some work here

    printf("Hello!\n");

    HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
    WORD defaultConsoleTextAttributes;
    GetConsoleScreenBufferInfo(stdHandle, &consoleInfo);
    defaultConsoleTextAttributes = consoleInfo.wAttributes;
    WORD currentConsoleTextAttributes = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
    SetConsoleTextAttribute(stdHandle, currentConsoleTextAttributes);
    std::cout << "nShowCmd = " << nShowCmd << std::endl;
    currentConsoleTextAttributes = FOREGROUND_GREEN;
    SetConsoleTextAttribute(stdHandle, currentConsoleTextAttributes);
    std::cout << "Now making my first Windows window!" << std::endl;
    currentConsoleTextAttributes = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
    SetConsoleTextAttribute(stdHandle, currentConsoleTextAttributes);
    std::cout << "Now making my first Windows window!" << std::endl;
    currentConsoleTextAttributes = FOREGROUND_BLUE;
    SetConsoleTextAttribute(stdHandle, currentConsoleTextAttributes);
    std::cout << "Now making my first Windows window!" << std::endl;
    currentConsoleTextAttributes = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
    SetConsoleTextAttribute(stdHandle, currentConsoleTextAttributes);
    std::cout << "Now making my first Windows window!" << std::endl;
    currentConsoleTextAttributes = FOREGROUND_RED;
    SetConsoleTextAttribute(stdHandle, currentConsoleTextAttributes);
    std::cout << "Now making my first Windows window!" << std::endl;
    currentConsoleTextAttributes = FOREGROUND_RED | FOREGROUND_INTENSITY;
    SetConsoleTextAttribute(stdHandle, currentConsoleTextAttributes);
    std::cout << "Now making my first Windows window!" << std::endl;
    currentConsoleTextAttributes = FOREGROUND_GREEN | FOREGROUND_BLUE;
    SetConsoleTextAttribute(stdHandle, currentConsoleTextAttributes);
    std::cout << "Now making my first Windows window!" << std::endl;
    currentConsoleTextAttributes = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
    SetConsoleTextAttribute(stdHandle, currentConsoleTextAttributes);
    std::cout << "Now making my first Windows window!" << std::endl;
    currentConsoleTextAttributes = FOREGROUND_GREEN | FOREGROUND_RED;
    SetConsoleTextAttribute(stdHandle, currentConsoleTextAttributes);
    std::cout << "Now making my first Windows window!" << std::endl;
    currentConsoleTextAttributes = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
    SetConsoleTextAttribute(stdHandle, currentConsoleTextAttributes);
    std::cout << "Now making my first Windows window!" << std::endl;
    currentConsoleTextAttributes = FOREGROUND_BLUE | FOREGROUND_RED;
    SetConsoleTextAttribute(stdHandle, currentConsoleTextAttributes);
    std::cout << "Now making my first Windows window!" << std::endl;
    currentConsoleTextAttributes = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
    SetConsoleTextAttribute(stdHandle, currentConsoleTextAttributes);
    std::cout << "Now making my first Windows window!" << std::endl;



    // make sure to restore the original so we don't get a crash on close!
    std::cout.rdbuf(sb);

    Sleep(5000);
    ShowWindow(GetConsoleWindow(), SW_HIDE);
    FreeConsole();

    MessageBoxW (NULL,
                 L"Hello World!",
                 L"hello",
                 MB_OK | MB_ICONINFORMATION);

    return 0;
}

All that remains now is to make it into a complete logging class.

like image 96
Zingam Avatar answered Nov 03 '22 12:11

Zingam


Try this code.

AllocConsole();
HANDLE stdHandle;
int hConsole;
FILE* fp;
stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
hConsole = _open_osfhandle( (long)stdHandle, _O_TEXT);
fp = _fdopen(hConsole, "w");

freopen_s( &fp, "CONOUT$", "w", stdout);

printf("Hello console on\n");
std::cout << "Windows 10" << std::endl;
like image 7
Atori Avatar answered Nov 03 '22 12:11

Atori


If you're using g++, and you want your application to always have both a console and a GUI, then you can supply linker flags of both -mconsole and -mwindows to achieve this.

See this answer for more detail.

like image 2
M.M Avatar answered Nov 03 '22 14:11

M.M