Win32 Console Applications
[主要内容是翻译自一篇国外的文章,我一边看,一边挑重点翻译了让自己好看,就有了本文]记得刚学C++的发现怎么做出来的程序都是黑乎乎的,难看死了。后来知道了MFC这个GUI库,才知道漂亮的程序是这么写出来的,当然SDK也可以写。后来一次浏览网站发现了《Win32 Console Applications》,才知道控制台也可以进行界面编程。控制台应用程序,它看起来象是 DOS 应用程序,但它却是WIN32的程序,拥有独立的4GB虚拟内存空间。
屏幕 I/O 的许多基本动作只能在控制台模式下才能正常工作。也就是说,在控制台的C程序中,你必须包含 STDIO.H 和(或)CONIO.H 文件才能使用 printf,gets,getchar,getch 等函数。这些函数让你可以控制在屏幕上输出数据。而C++程序则使用iostream.h,因为cin和cout。他们是不能同时存在。这里我使用C++做示范,IDE是VC++6.0。
//-----------------------------修改标题------------------------
默认的,控制台程序是用程序所在的完整路径做为窗口标题。如果我们想改变标题可以使用API函数
SetConsoleTitle,但是注意要包含头文件windows.h。还要注意的是这只适合与VC++控制台程序。
C程序在它的编译器TC里有单独的方法。
#include <windows.h>
#include <iostream.h>
int main()
{
SetConsoleTitle("Hello!");
cout << "Hello World!" << endl;
return 0;
}
//-----------------------------出错机智------------------------
正如通常一样,所有的API函数都会返回调用成功或者失败的状态. 上面的例子中我并没有检查返回值.
为了更加专业, 当你调用API函数的时候应该检查它的返回值. 即使你不能修复这个错误, 调试的时候去
发现调用不成功的原因依然是有用的,最好能知道为什么. 下面这个程序示范了如何处理返回值, (注意
常规API exit() 包含在process.h中).你应翻阅编译器的帮助文件或者 MSDN来理解返回值表示的意义。
#include <windows.h>
#include <process.h>
#include <iostream.h>
int main()
{
int Status;
Status = SetConsoleTitle("Hello!");
if (Status == 0)
{
Status = GetLastError();
cout << "SetConsoleTitle() failed! Reason : " << Status << endl;
exit(Status);
}
cout << "Hello World!" << endl;
return 0;
}
//-----------------------------标准句柄------------------------
所有的控制台有3种"标准句柄",并且许多控制台处理函数需要HANDLE作为参数来处理I/O。
一个句柄就是一个32位整数. 它是窗口用来对同型事物进行区别的. 考虑一下控制台,它有一个标题栏
,最小化、最大化、关闭按纽,一个或多个滚动条. 那就是,当你想到这些是多么复杂的一件事。 Windows 隐藏所有复杂的东西, 当然你也可以自己处理这些东西,但是我的建议是如果不需要处理,你
最好别动. Windows会为你照顾好一切,你所需要做的就是使用句柄处理你感兴趣的东西. 一旦你深入到
windows程序,你就会发现需要事情需要handle的支持。如果你现在不明白,也不必要担心,句柄非常容易获得也非常容易处理。
为了得到句柄,你需要声明HANDLE类型的变量并调用GetStdHandle()函数来初始化它.
函数GetStdHandle(),其声明如下
HANDLE GetStdHandle(
DWORD nStdHandle
);
GetStdHandle()返回标准的输入、输出或错误的设备的句柄,也就是获得输入、输出/错误的屏幕
缓冲区的句柄. 其参数nStdHandle的值为下面几种类型的一种:
值 含义
STD_INPUT_HANDLE 标准输入的句柄
STD_OUTPUT_HANDLE 标准输出的句柄
STD_ERROR_HANDLE 标准错误的句柄
下面这个程序演示了如何获得句柄。
#include <windows.h>
int main()
{
HANDLE hIn;
HANDLE hOut;
HANDLE hError;
hIn = GetStdHandle(STD_INPUT_HANDLE);
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
hError = GetStdHandle(STD_ERROR_HANDLE);
return 0;
}
这里有两个常规函数 ReadConsole() 和WriteConsole() 会使用到句柄。
//-----------------------------改变输出光标位置------------------------
现在我们已经可以得到句柄, 是时候我们该做些什么了,那么就让我们来改变光标输出位置. 其中我们
需要使用到结构体COORD.这是简单的结构体包含一个x和y坐标对.它的定义如下:
typedef struct _COORD {
SHORT X;
SHORT Y;
} COORD;
屏幕左上角为原点(0,0)。往右X为正,往下Y为正。
为了移动光标,你只要简单的使用COORD指定你想光标移动到的坐标值并且调API 函数SetConsoleCursorPosition()。下面是简单的示范。
#include <windows.h>
#include <iostream.h>
int main()
{
HANDLE hOut;
int i;
COORD Position;
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
for(i=0; i<10; i+=2)
{
Position.X = i;
Position.Y = i;
SetConsoleCursorPosition(hOut,
Position);
cout << "*" << flush;
}
return 0;
}
正如你所理解的,每步循环移动光标两格下两格右。如果想还原,只要把坐标设为(0,0).
//-----------------------------自定义位置输出------------------------
下面要介绍的是函数FillConsoleOutputCharacter().这个函数允许你自定义位置填充字符串.
函数原型如下:
BOOL FillConsoleOutputCharacter(
HANDLE hConsoleOutput,//标准输出句柄
TCHAR cCharacter, //要输出的字符
DWORD nLength, //输出字符的次数
COORD dwWriteCoord, //开始输出坐标
LPDWORD lpNumberOfCharsWritten //存放所写的字节数,并作为函数的返回值
);
如果你写的字符个数超过一行,输出会转到下一行继续进行。如果你试图写的字符数超出了缓冲区
范围,什么事也不会发生,也不会有额外的调用来处理这些多出的字符。这样,如果你用 80x25 格式的
代码写程序就很安全。如果你要计算用来刷新整个屏幕字符的确切数目,可以使用
GetConsoleScreenBufferInfo 函数。
下面这个例子使用FillConsoleOutputCharacter()来从(4,4)开始输出一行15个"X"字符。
#include <windows.h>
#include <iostream.h>
int main()
{
HANDLE hOut;
COORD Position;
DWORD Written;
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
Position.X = 4;
Position.Y = 4;
FillConsoleOutputCharacter(hOut,
'X',
15,
Position,
&Written);
return 0;
}
//-----------------------------自定义位置输入------------------------
下面介绍的这个函数可以屏幕缓冲区的指定位置读入一个和多个字符。参数基本同上一个介绍的函数。
BOOL ReadConsoleOutputCharacter(
HANDLE hConsoleOutput,
LPTSTR lpCharacter,
DWORD nLength,
COORD dwReadCoord,
LPDWORD lpNumberOfCharsRead
);
这个程序使用了函数两次, 第一次从(0,0)处读入一个字符,第二次从(4,0)读入五个字符. 如果要读入
的字符长度大于现有行的字符个数,那么继续从下一行读入字符补足。当然正如前面也说过的,如果要
读入字符个数大于了缓冲区,读到缓冲区最后一个字符就会返回。实际读入的字符个数将在最后一个参
数返回。
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
HANDLE hOut;
char Letter;
char Letters[5];
COORD Where;
DWORD NumRead;
int i;
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
cout << "A line of little consequence." << endl;
Where.X = 0;
Where.Y = 0;
ReadConsoleOutputCharacter(hOut,
&Letter,
1,
Where,
&NumRead);
cout << "Letter at (0,0) is " << Letter << endl;
Where.X = 4;
ReadConsoleOutputCharacter(hOut,
Letters,
5,
Where,
&NumRead);
cout << "5 letters starting from (4,0) ";
for (i=0; i<5; i++)
{
cout << Letters;
}
cout << endl;
return 0;
}
//-----------------------------光标的显示与隐藏------------------------
也许你想隐藏或者改变控制台里的光标. 另一个API SetConsoleCursorInfo()可以实现这个功能, . 该函数有两个参数,一个标准的输出句柄,还有一个CONSOLE_CURSOR_INFO结构体的指针.
结构体的定义如下:
typedef struct _CONSOLE_CURSOR_INFO {
DWORD dwSize;
BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
第一个值是取值范围为1-100的整数, 它描述了光标填充一个字符单元的百分比.
另一个值是个boolean类型,他描述了光标是否可见. true-可见,false-不可见
#include <windows.h>
int main()
{
HANDLE hOut;
CONSOLE_CURSOR_INFO ConCurInf;
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTitle("Size 50");
ConCurInf.dwSize = 50;//示范使用的是50
ConCurInf.bVisible = TRUE;
SetConsoleCursorInfo(hOut,
&ConCurInf);
return 0;
}
#include <windows.h>
int main()
{
HANDLE hOut;
CONSOLE_CURSOR_INFO ConCurInf;
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTitle("No Cursor");
ConCurInf.dwSize = 10;
ConCurInf.bVisible = FALSE;
SetConsoleCursorInfo(hOut,
&ConCurInf);
return 0;
}
//-----------------------------文字的颜色与背景------------------------
函数SetConsoleTextAttribute()的作用是在console程序设置输入或输出文本的文本颜色和背景颜
色.只有在此函数设置后才能显示彩色的文本.其函数原型为:
BOOL SetConsoleTextAttribute(
HANDLE hConsoleOutput, // console 屏幕缓冲区的句柄
WORD wAttributes // 文本及背景的颜色
);
如果函数设置文本及背景颜色成功,则返回非零;如失败返回零.其参数含义如下:
hConsoleOutput-------------console 屏幕缓冲区的句柄.
WORD wAttributes-----------文本及背景的颜色.
其文本与背景颜色可以是
FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED, FOREGROUND_INTENSITY,
BACKGROUND_BLUE, BACKGROUND_GREEN, BACKGROUND_RED, and BACKGROUND_INTENSITY.
#include<windows.h>
#include<iostream>
using namespace std;
void SetColor(unsigned short ForeColor=0,unsigned short BackGroundColor=0)
{
HANDLE hCon=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hCon,ForeColor|BackGroundColor);
}
int main()
{
int FC,BC;
for(BC=0;BC<=1;BC++)
{
for(FC=0;FC<=255;FC++)
{
SetColor(FC,BC);
std::cout<<FC<<','<<BC<<'/t';
SetColor(7,0);
if(FC%16==15)std::cout<<endl;
}
}
return 0;
}
完了