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?
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.
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
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; };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With