Wednesday, September 7, 2016

VS Settings: How to output to the console in C++/windows

OUTPUT to the CONSOLE in C++

If you're using Visual Studio you need to modify the project propertyConfiguration Properties ->Linker -> System -> SubSystem.
This should be set to: Console (/SUBSYSTEM:CONSOLE)
Also you should change your WinMain to be this signature:

***
Whether to use subsystem:console or subsystem:windows kind of depends on whether how you want to start your application:
  • If you use subsystem:console, then you get all of the stdout written to the terminal. The trouble is that if you start the application from the Start Menu/Desktop, you (by default) get a console appearing as well as the application window (which can look pretty ugly).
  • If you use subsystem:windows, you won't get stdout/stderr even if you run the application from aDOS window, Cygwin, or other terminal.
If you want the middle way which is to output to the terminal IF the application was started in a terminal, then follow the link that Luke provided in his solution (http://dslweb.nwnexus.com/~ast/dload/guicon.htm)
For reference, I ran into this problem with an application that I want to run in either normal Windows mode or batch mode (that is, as part of a script) depending on command-line switches. The whole differentiation between console and Windows applications is a bit bizarre to Unix folks!

----------------------------

MACROS


If this is for debug output then OutputDebugString is what you want. A useful macro :
#define DBOUT( s )            \
{                             \
   std::ostringstream os_;    \
   os_ << s;                   \
   OutputDebugString( os_.str().c_str() );  \
}
This allows you to say things like:
DBOUT( "The value of x is " << x );
You can extend this using the __LINE__ and __FILE__ macros to give even more information.
For those in Windows and wide character land:
#include <Windows.h>
#include <iostream>
#include <sstream>

 #define DBOUT( s )            \
{                             \
   std::wostringstream os_;    \
   os_ << s;                   \
   OutputDebugStringW( os_.str().c_str() );  \
}
------------------------------

CITED

Adding Console I/O to a Win32 GUI App
Windows Developer Journal, December 1997

One of the common misconceptions surrounding Win32 programming is that you must decide early in the design process whether your application will be a console or GUI application. In reality, console applications can create windows and have a message loop just like a GUI application (see "Adding Graphics to Console Applications" by Michael Covington, Visual Developer, June/July 1997). Alternatively, graphical applications can create and use a console. Although Win32 provides functions for communicating with a console, they are a little clumsy to use and require parameters that are unnecessary for simple text I/O. This article shows how to use standard C/C++ I/O with consoles, and how to work around specific problems in the Visual C++ I/O library.
Win32 Handles versus RTL Handles
The standard C I/O package operates on top of whatever I/O services the local operating system provides. Your C program then manipulates handles of type FILE*, no matter what the actual details of the physical file I/O are. The file I/O package that Win32 provides uses handles of type HANDLE, so Win32 C implementations of the standard I/O functions must internally associate aHANDLE with each FILE*, and eventually call the Win32 API to perform the I/O.
C predefines the meaning of three handles: stdinstdout, and stderr. These names refer to FILE* handles that refer to standard input, output, and error output. Win32 provides a similar concept; it provides a function called GetStdHandle(), and you can pass that function one of three constants (STD_INPUT_HANDLESTD_OUTPUT_HANDLE, or STD_ERROR_HANDLE) to obtain theHANDLE associated with standard input, standard output, or the standard error output. Exactly what these handles refer to depends on how your Win32 program was built and marked. These handles could be redirected to files, or they could be associated with a console window. If you launch a program from a DOS box (which is basically a console window), it may end up using that DOS box as its console window by default (that is, writing to standard output produces output in the DOS box window).
Win32 GUI applications do not, by default, have an associated console window. However, it is possible for your GUI application to explicitly create a console window and then manually associate standard C I/O handles (FILE*) with the appropriate Win32 handles (HANDLE) so that ordinary C runtime functions can operate on the console. To associate a C file handle with a Win32 file handle, the Visual C++ runtime library provides _open_osfhandle(). Given a valid Win32 handle, this function returns an RTL handle that internally operates on the given Win32 handle. This lets you transform the three console handles into compatible C file handles that you can use to redirect stdinstdout, and stderr to the console.
C++ I/O
Once stdinstdout, and stderr are redirected, standard C functions such as printf() and gets() can be used, without change, to communicate with the Win32 console. But what about C++ I/O streams? Since cincoutcerr, and clog are closely tied to C’s stdinstdout, and stderr, you would expect them to behave similarly. This is half right.
C++ I/O streams actually come in two flavors: template and non- template. The older non-template version of I/O streams is slowly being replaced by a newer template style of streams first defined by the Standard Template Library (STL) and which are now being absorbed into the ANSI C++ standard. Visual C++ v5 provides both types and allows you to choose between the two by including different header files. STL I/O streams work as you would expect, automatically using any newly redirected stdio handles. Non-template I/O streams, however, do not work as expected. To discover why, I looked at the source code, conveniently provided on the Visual C++ CD-ROM.
The problem is that the older I/O streams were designed to use UNIX-style "file descriptors," where integers are used instead of handles (0 for stdin, 1 for stdout, and so on). That’s convenient for UNIX implementations, but Win32 C compilers have to provide yet another I/O layer to represent that style of I/O, since Win32 does not provide a compatible set of functions. In any case, when you call _open_osfhandle() to associate a new Win32 handle with (for example) stdout, it has no effect on the other layer of I/O code. Hence, file descriptor 1 will continue using the same underlying Win32 handle as before, and sending output to cout will not produce the desired effect.
Fortunately, the designers of the original I/O stream package foresaw this problem and provided a clean and useful solution. The base class ios provides a static function, sync_with_stdio(), that causes the library to change its underlying file descriptors to reflect any changes in the standard I/O layer. Though this is not strictly necessary for STL I/O streams, it does no harm and lets me write code that works correctly with either the new or old form of I/O streams.
A Redirect Function
guicon.cpp (Listing 1) and guicon.h (Listing 2) provide code for redirecting C and C++ I/O to a Win32 console. RedirectIOToConsole() does all the work, creating a console and increasing the number of lines buffered with calls to AllocConsole() and SetConsoleScreenBufferSize() respectively. Each process is allowed only one console, so calling AllocConsole() multiple times will not produce multiple consoles. Increasing the screen buffer size allows you to scroll back and look at a history of up to MAX_CONSOLE_LINES of text. The code then creates a new FILE* handle forSTD_INPUT_HANDLESTD_OUTPUT_HANDLE, and STD_ERROR_HANDLE, and the existing stdinstdout, and stderr are replaced. setvbuf() is then called to turn off input and output buffering, effectively flushing the data with each read and write. Last, but not least, a call to ios::sync_with_stdio() ensures that cincoutcerr, and clog are associated with the new stdinstdout, and stderr. The code is wrapped in preprocessor conditionals to allow it to be easily compiled out for release applications.
The code in test.cpp (Listing 3) is a sample of using RedirectIOToConsole(). It outputs text using the C stdio and C++ I/O streams and uses a simple integer to test input. Additionally, if you are using STL streams it tests the wide character versions of cincoutcerr, and clog. The rest of the code demonstrates how the Visual C++ C runtime debug functions can be used to output useful debugging information to the console. Since Win32 destroys the console when the application exits, I pause for two seconds before exiting so that you can see the last few pieces of output.
Overall, having a console associated with a Win32 GUI application is a very useful tool. Though similar debug text output can be achieved using Win32’s OutputDebugString() and DBWin32 (see "A DBWin32 Debugger for Windows" by Andrew Tucker, C/C++ Users Journal, October 1996), this console technique is much more portable between the Win32 API flavors (namely Windows 95 and NT) and it provides a method of input as well as output. Another application might be to use the console as a simple debugger that allows you to print out crucial data structures and inspect and change variables without the use of a full-blown interactive debugger. Finally, for those applications whose user interface makes sense as both a console app and a GUI, a command-line switch could allow the user to choose which is appropriate for their situation — something that is not as readily available when using a GUI from a console application.
References
Covington, Michael. "Adding Graphics to Console Applications," Visual Developer, June/July 1997.
Tucker, Andrew. "A DBWin32 Debugger for Windows," C/C++ Users Journal, October 1996.
Andrew Tucker (ast@halcyon.com) is a software engineer in Seatte, WA. His programming interests include compilers, debuggers, and other areas of systems programming.

Listing 1: 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


Listing 2: guicon.h -- Interface to console redirection function
#ifndef __GUICON_H__
#define __GUICON_H__
#ifdef _DEBUG
void RedirectIOToConsole();
#endif
#endif
/* End of File */

Listing 3: 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

No comments:

Post a Comment