
2.11 控制台编程
DOS的时代已经离我们远去,现在只能去控制台程序中寻找以往的情怀。但,图形界面大行其道的今天,为何还要了解控制台编程?为了在控制台下进行多线程编程,以及在图形界面程序中调用控制台,这样我们可以把调试语句写在控制台窗口中!当然,多线程编程是后面章节的事情了。这里只谈控制台!
以前学C语言的时候,要在控制台窗口中输出信息,最常用的就是使用CRT库函数printf了,现在Visual C++提供了很多控制台函数,也可以用于在控制台窗口中输出信息,这样就不必使用CRT库函数printf了,有人说了,这样代替有什么意义呢?意义很大,这是因为创建线程的函数CreateThread所创建的线程函数中是不能使用CRT库函数的(会造成内存泄漏),所以如果要在CreateThread所创建的线程函数中输出信息到控制台,我们就可以使用控制台函数来替换printf了。
Visual C++提供了很多控制台API函数,如果在控制台程序中使用这些函数,需要包含windows.h。常用的控制台函数有:
(1)GetStdHandle函数
该函数从一个特定的标准设备(标准输入、标准输出或标准错误)中取得一个句柄,也就是获取这些标准设备的缓冲区句柄,以便用户可以进行输入输出。函数声明如下:
HANDLE GetStdHandle( DWORD nStdHandle );
其中参数nStdHandle用来标识标准输入、标准输出或标准错误,取值分别为STD_INPUT_HANDLE(标准输入)、STD_OUTPUT_HANDLE(标准输出)、STD_ERROR_HANDLE(标准错误)。如果函数成功,返回特定设备的句柄;如果函数失败,返回INVALID_HANDLE_VALUE。
比如我们获得当前标准输出设备的句柄:
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
(2)SetConsoleTextAttribute函数
该函数用来设置输出到控制台屏幕(或窗口)的字符属性,比如前景色和背景色。函数声明如下:
BOOL SetConsoleTextAttribute( HANDLE hConsoleOutput, WORD wAttributes);
其中参数hConsoleOutput是控制台屏幕缓冲区的句柄;wAttributes为要设置给字符的属性,比如取值FOREGROUND_BLUE表示字体颜色为蓝色,取值为BACKGROUND_GREEN表示背景颜色为绿色。如果函数成功返回非零,否则返回零。
(3)WriteConsole函数
该函数向控制台屏幕或窗口的缓冲区写入一段字符串,输出位置始于当前光标处。函数声明如下:
BOOL WriteConsole( HANDLE hConsoleOutput, const VOID* lpBuffer, DWORD nNumberOfCharsToWrite, LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved);
其中参数hConsoleOutput是控制台屏幕缓冲区的句柄;lpBuffer指向字符缓冲区;
【例2.48】 向控制台窗口输出有颜色的字符串
(1)新建一个控制台工程。
(2)在Test.cpp中输入代码如下:
#include "stdafx.h" #include <windows.h> void SetConsoleColor(unsigned short ForeColor = FOREGROUND_RED, unsigned short BackGroundColor = 0) { HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE); //获取控制台输出缓冲区的句柄 SetConsoleTextAttribute(hCon, ForeColor | BackGroundColor); //设置前景色和背景色 } int main() { SetConsoleColor(); printf("你好世界\n"); SetConsoleColor(FOREGROUND_BLUE, BACKGROUND_GREEN); printf("同志们好!\n"); return 0; }
(3)保存工程并运行,运行结果如图2-102所示。

图2-102
【例2.49】 使用WriteConsole函数输出字符串
(1)新建一个控制台工程。
(2)在Test.cpp中输入代码如下:
#include "stdafx.h" #include "windows.h" int _tmain(int argc, _TCHAR* argv[]) { HANDLE hStdout; DWORD dwChars; TCHAR msgBuf[] = _T("你好,世界,Hello world! \n"); int len = lstrlen(msgBuf); hStdout = GetStdHandle(STD_OUTPUT_HANDLE); //得到标准输出设备的句柄,为了打印 if (hStdout == INVALID_HANDLE_VALUE) return -1; WriteConsole(hStdout, msgBuf, len, &dwChars, NULL); //在终端窗口输出字符串 }
(3)保存工程并运行,运行结果如图2-103所示。

图2-103
【例2.50】 在对话框程序中显示控制台窗口
(1)新建一个MFC对话框工程。
(2)切换资源视图,打开对话框编辑器,删除上面所有控件,并放一个按钮,为其添加事件处理函数,代码如下:
void CTestDlg::OnBnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 InitConsoleWindow(); printf("你好,世界!\n "); }
其中,InitConsoleWindow是一个自定义的全局函数,代码如下:
void InitConsoleWindow() { int nCrt = 0; FILE* fp; AllocConsole(); nCrt = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT); fp = _fdopen(nCrt, "w"); *stdout = *fp; setvbuf(stdout, NULL, _IONBF, 0); }
在TestDlg.cpp的文件开头添加头文件包含:
#include <io.h> #include <fcntl.h> //for _O_TEXT
(3)保存工程并运行,运行结果如图2-104所示。

图2-104