一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Adding Console I/O to a Win32 GUI App

 勤奮不止 2013-07-01

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 a HANDLE with each FILE*, and eventually call the Win32 API to perform the I/O.

C predefines the meaning of three handles: stdin, stdout, 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_HANDLE, STD_OUTPUT_HANDLE, or STD_ERROR_HANDLE) to obtain the HANDLE 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 stdin, stdout, and stderr to the console.

C++ I/O

Once stdin, stdout, 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 cin, cout, cerr, and clog are closely tied to C’s stdin, stdout, 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 for STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, and STD_ERROR_HANDLE, and the existing stdin, stdout, 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 cin, cout, cerr, and clog are associated with the new stdin, stdout, 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 cin, cout, cerr, 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);

// FILE *_fdopen(int fd, const char *mode ); 基于文件描述符打開一個(gè)C輸入輸出流 

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

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    暴力性生活在线免费视频| 东京热电东京热一区二区三区| 日韩性生活视频免费在线观看 | 老司机精品视频在线免费| 日韩欧美第一页在线观看| 欧美人禽色视频免费看| 人体偷拍一区二区三区| 免费在线观看激情小视频| 日韩视频在线观看成人| 国产成人精品一区在线观看| 欧美一本在线免费观看| 黄片免费在线观看日韩| 欧美精品中文字幕亚洲| 一区二区三区精品人妻| 欧美成人免费一级特黄| 91欧美亚洲精品在线观看| 熟女免费视频一区二区| 欧美午夜性刺激在线观看| 国产一区二区不卡在线播放| 国产一区二区三区精品免费| 国产性情片一区二区三区 | 亚洲人午夜精品射精日韩| 婷婷亚洲综合五月天麻豆| 亚洲最大福利在线观看| 色偷偷偷拍视频在线观看| 深夜视频在线观看免费你懂| 欧美国产日韩在线综合| 亚洲最大福利在线观看| 亚洲一区精品二人人爽久久| 精品亚洲香蕉久久综合网| 国产成人午夜福利片片| 亚洲一级在线免费观看| 一个人的久久精彩视频| 国产精品尹人香蕉综合网| 欧美一区二区三区播放| 日韩成人中文字幕在线一区| 日本乱论一区二区三区| 精品欧美在线观看国产| 少妇人妻无一区二区三区| 亚洲另类欧美综合日韩精品| 久久精品国产亚洲av麻豆尤物|