Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get console output in C++ with a Windows program?

If I have a native C++ windows program (i.e. the entry point is WinMain) how do I view output from console functions like std::cout?

like image 652
Obediah Stane Avatar asked Oct 10 '08 15:10

Obediah Stane


People also ask

Does C++ have a console?

A modern console consists of the keyboard and a window on a computer screen. cin (console in), cout (console out), and cerr (console error) are stream objects that become part of every C++ program. The console objects channel streams of bytes to and from running programs.


2 Answers

Check out Adding Console I/O to a Win32 GUI App. This may help you do what you want.

If you don't have, or can't modify the code, try the suggestions found here to redirect console output to a file.


Edit: bit of thread necromancy here. I first answered this 9ish years ago, in the early days of SO, before the (good) policy of non-link-only answers came into effect. I'll repost the code from the original article in the hope to atone for my past sins.

guicon.cpp -- A console redirection function

#include <windows.h> #include <stdio.h> #include <fcntl.h> #include <io.h> #include <iostream> #include <fstream> #ifndef _USE_OLD_IOSTREAMS using namespace std; #endif // maximum mumber of lines the output console should have static const WORD MAX_CONSOLE_LINES = 500; #ifdef _DEBUG void RedirectIOToConsole() {     int hConHandle;     long lStdHandle;     CONSOLE_SCREEN_BUFFER_INFO coninfo;     FILE *fp;      // allocate a console for this app     AllocConsole();      // set the screen buffer to be big enough to let us scroll text     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);     coninfo.dwSize.Y = MAX_CONSOLE_LINES;     SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);      // redirect unbuffered STDOUT to the console     lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);     hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);     fp = _fdopen( hConHandle, "w" );     *stdout = *fp;     setvbuf( stdout, NULL, _IONBF, 0 );      // redirect unbuffered STDIN to the console     lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);     hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);     fp = _fdopen( hConHandle, "r" );     *stdin = *fp;     setvbuf( stdin, NULL, _IONBF, 0 );      // redirect unbuffered STDERR to the console     lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);     hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);     fp = _fdopen( hConHandle, "w" );     *stderr = *fp;     setvbuf( stderr, NULL, _IONBF, 0 );      // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog     // point to console as well     ios::sync_with_stdio(); }  #endif //End of File 

guicon.h -- Interface to console redirection function

#ifndef __GUICON_H__ #define __GUICON_H__ #ifdef _DEBUG  void RedirectIOToConsole();  #endif #endif  // End of File 

test.cpp -- Demonstrating console redirection

#include <windows.h> #include <iostream> #include <fstream> #include <conio.h> #include <stdio.h> #ifndef _USE_OLD_OSTREAMS using namespace std; #endif #include "guicon.h"   #include <crtdbg.h>  int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {     #ifdef _DEBUG     RedirectIOToConsole();     #endif     int iVar;      // test stdio     fprintf(stdout, "Test output to stdout\n");     fprintf(stderr, "Test output to stderr\n");     fprintf(stdout, "Enter an integer to test stdin: ");     scanf("%d", &iVar);     printf("You entered %d\n", iVar);      //test iostreams     cout << "Test output to cout" << endl;     cerr << "Test output to cerr" << endl;     clog << "Test output to clog" << endl;     cout << "Enter an integer to test cin: ";     cin >> iVar;     cout << "You entered " << iVar << endl;     #ifndef _USE_OLD_IOSTREAMS      // test wide iostreams     wcout << L"Test output to wcout" << endl;     wcerr << L"Test output to wcerr" << endl;     wclog << L"Test output to wclog" << endl;     wcout << L"Enter an integer to test wcin: ";     wcin >> iVar;     wcout << L"You entered " << iVar << endl;     #endif      // test CrtDbg output     _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );     _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );     _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );     _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR);     _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );     _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR);     _RPT0(_CRT_WARN, "This is testing _CRT_WARN output\n");     _RPT0(_CRT_ERROR, "This is testing _CRT_ERROR output\n");     _ASSERT( 0 && "testing _ASSERT" );     _ASSERTE( 0 && "testing _ASSERTE" );     Sleep(2000);     return 0; }  //End of File 
like image 76
luke Avatar answered Sep 21 '22 06:09

luke


The problem some of the other answers is that they unnecessarily create new FILE instances which are then leaked and can cause debug assertions in the CRT cleanup code.

freopen_s is all that is really needed:

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

You'll probably want to do a little error checking and cleanup as well. Below is the complete solution that I currently use.

Redirecting Console Standard IO:

bool RedirectConsoleIO() {     bool result = true;     FILE* fp;      // Redirect STDIN if the console has an input handle     if (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)         if (freopen_s(&fp, "CONIN$", "r", stdin) != 0)             result = false;         else             setvbuf(stdin, NULL, _IONBF, 0);      // Redirect STDOUT if the console has an output handle     if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE)         if (freopen_s(&fp, "CONOUT$", "w", stdout) != 0)             result = false;         else             setvbuf(stdout, NULL, _IONBF, 0);      // Redirect STDERR if the console has an error handle     if (GetStdHandle(STD_ERROR_HANDLE) != INVALID_HANDLE_VALUE)         if (freopen_s(&fp, "CONOUT$", "w", stderr) != 0)             result = false;         else             setvbuf(stderr, NULL, _IONBF, 0);      // Make C++ standard streams point to console as well.     ios::sync_with_stdio(true);      // Clear the error state for each of the C++ standard streams.     std::wcout.clear();     std::cout.clear();     std::wcerr.clear();     std::cerr.clear();     std::wcin.clear();     std::cin.clear();      return result; } 

Releasing a Console:

bool ReleaseConsole() {     bool result = true;     FILE* fp;      // Just to be safe, redirect standard IO to NUL before releasing.      // Redirect STDIN to NUL     if (freopen_s(&fp, "NUL:", "r", stdin) != 0)         result = false;     else         setvbuf(stdin, NULL, _IONBF, 0);      // Redirect STDOUT to NUL     if (freopen_s(&fp, "NUL:", "w", stdout) != 0)         result = false;     else         setvbuf(stdout, NULL, _IONBF, 0);      // Redirect STDERR to NUL     if (freopen_s(&fp, "NUL:", "w", stderr) != 0)         result = false;     else         setvbuf(stderr, NULL, _IONBF, 0);      // Detach from console     if (!FreeConsole())         result = false;      return result; } 

Resizing Console Buffer:

void AdjustConsoleBuffer(int16_t minLength) {     // Set the screen buffer to be big enough to scroll some text     CONSOLE_SCREEN_BUFFER_INFO conInfo;     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &conInfo);     if (conInfo.dwSize.Y < minLength)         conInfo.dwSize.Y = minLength;     SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), conInfo.dwSize); } 

Allocating a New Console:

bool CreateNewConsole(int16_t minLength) {     bool result = false;      // Release any current console and redirect IO to NUL     ReleaseConsole();      // Attempt to create new console     if (AllocConsole())     {         AdjustConsoleBuffer(minLength);         result = RedirectConsoleIO();     }      return result; } 

Attaching to Parent's Console:

bool AttachParentConsole(int16_t minLength) {     bool result = false;      // Release any current console and redirect IO to NUL     ReleaseConsole();      // Attempt to attach to parent process's console     if (AttachConsole(ATTACH_PARENT_PROCESS))     {         AdjustConsoleBuffer(minLength);         result = RedirectConsoleIO();     }      return result; } 

Calling from WinMain:

Link with /SUBSYSTEM:Windows

int APIENTRY WinMain(     HINSTANCE /*hInstance*/,     HINSTANCE /*hPrevInstance*/,     LPTSTR    /*lpCmdLine*/,     int       /*cmdShow*/) {     if (CreateNewConsole(1024))     {         int i;          // test stdio         fprintf(stdout, "Test output to stdout\n");         fprintf(stderr, "Test output to stderr\n");         fprintf(stdout, "Enter an integer to test stdin: ");         scanf("%d", &i);         printf("You entered %d\n", i);          // test iostreams         std::cout << "Test output to std::cout" << std::endl;         std::cerr << "Test output to std::cerr" << std::endl;         std::clog << "Test output to std::clog" << std::endl;         std::cout << "Enter an integer to test std::cin: ";         std::cin >> i;         std::cout << "You entered " << i << std::endl;          std::cout << endl << "Press any key to continue..." << endl;         _getch();          ReleaseConsole();     }      return 0; }; 
like image 44
Chris Olsen Avatar answered Sep 22 '22 06:09

Chris Olsen