1. 程式人生 > >控制檯程式設計相關API 及相關程式設計

控制檯程式設計相關API 及相關程式設計

1. 編寫控制檯程式,獲得標準輸入輸出的視窗控制代碼

HANDLE GetStdHandle

(

        DWORD nStdHandle

 );

 GetStdHandle()返回標準的輸入、輸出或錯誤的裝置的控制代碼,也就是獲得輸入、輸出 /錯誤的螢幕緩衝區的控制代碼。

        其引數nStdHandle的值為下面幾種型別的一種:

        STD_INPUT_HANDLE 標準輸入的控制代碼

        STD_OUTPUT_HANDLE 標準輸出的控制代碼

        STD_ERROR_HANDLE 標準錯誤的控制代碼

2

2. SetConsoleTextAttribute是設定控制檯字型顏色和背景色。

BOOL SetConsoleTextAttribute(

  HANDLE hConsoleOutput,  // 使用GetStdHandle取得的控制代碼

  WORD wAttributes        // 設定文字、背景色

);

wAttributes可以取下面的值

FOREGROUND_BLUE              Text color contains blue.

FOREGROUND_GREEN             Text color contains green.

FOREGROUND_RED               Text color contains red.

FOREGROUND_INTENSITY         Text color is intensified.

BACKGROUND_BLUE              Background color contains blue.

BACKGROUND_GREEN             Background color contains green.

BACKGROUND_RED               Background color contains red.

BACKGROUND_INTENSITY         Background color is intensified.

COMMON_LVB_LEADING_BYTE     Leading byte.

COMMON_LVB_TRAILING_BYTE     Trailing byte.

COMMON_LVB_GRID_HORIZONTAL     Top horizontal.

COMMON_LVB_GRID_LVERTICAL     Left vertical.  

COMMON_LVB_GRID_RVERTICAL     Right vertical.

COMMON_LVB_REVERSE_VIDEO     Reverse foreground and background attributes.

COMMON_LVB_UNDERSCORE         Underscore.

3. CONSOLE_CURSOR_INFO用於存放控制游標資訊

typedef struct _CONSOLE_CURSOR_INFO {

  DWORD  dwSize;

  BOOL   bVisible;

} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;

dwSize:游標大小,1-100的值

bVisible:游標是否可見

4. SetConsoleCursorInfo設定游標的資訊

BOOL SetConsoleCursorInfo(

  HANDLE hConsoleOutput,                         // 使用GetStdHandle取得的控制代碼

  CONST CONSOLE_CURSOR_INFO *lpConsoleCursorInfo // 游標資訊

);

5. _CONSOLE_SCREEN_BUFFER_INFO: contains information about a console screen buffer

typedef struct _CONSOLE_SCREEN_BUFFER_INFO {

  COORD      dwSize;                 // Size, in character columns and rows, of the screen buffer.

  COORD      dwCursorPosition;            // 當前游標在螢幕的位置

  WORD       wAttributes;             // 控制檯相當於顯示屏的座標,左上和右下的座標

  SMALL_RECT srWindow;                 // 字元背景屬性,同SetConsoleTextAttribute

  COORD      dwMaximumWindowSize;         // 控制檯視窗的大小

} CONSOLE_SCREEN_BUFFER_INFO ;

6. GetConsoleScreenBufferInfo取得控制檯螢幕資訊

BOOL GetConsoleScreenBufferInfo(

  HANDLE hConsoleOutput,                                // GetStdHandle取得的控制代碼

  PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo // screen buffer information

);

7. SetConsoleCursorPosition設定游標位置

BOOL SetConsoleCursorPosition(

  HANDLE hConsoleOutput,  // handle to screen buffer

  COORD dwCursorPosition  // new cursor coordinates

);

8. WriteConsoleOutput直接寫輸入緩衝區。可以寫入鍵盤、滑鼠等任何Console能夠接收的事件(Event)都可以寫進去。鍵盤操作如果是一些可顯示字元可以直接寫 ASCII字元,否則的話可能要用鍵盤掃描碼(scan code)了

BOOL WriteConsoleOutput(

  HANDLE hConsoleOutput,      // handle to screen buffer

  CONST CHAR_INFO *lpBuffer,  // data buffer

  COORD dwBufferSize,         // size of data buffer

  COORD dwBufferCoord,        // cell coordinates

  PSMALL_RECT lpWriteRegion   // rectangle to write

);

9. SetConsoleTitle設定控制檯的標題

BOOL SetConsoleTitle(

  LPCTSTR lpConsoleTitle   // new console title

);

文字介面的控制檯應用程式開發是深入學習C++、掌握互動系統的實現方法的最簡單的一種手段。然而,Visual C++的C++專用庫卻沒有TC所支援的文字(字元)螢幕控制函式,為此本系列文章從一般控制步驟控制檯視窗操作文字(字元)控制滾動和移動游標鍵盤和滑鼠等幾個方面討論控制檯視窗介面的程式設計控制方法。

  在眾多C++開發工具中,由於Microsoft本身的獨特優勢,選用Visual C++已越來越被眾多學習者所接受。顯然,現今如果還再把TC作為開發環境的話,不僅沒有必要,而且也不利於向Windows應用程式開發的過渡。然而,Visual C++的C++專用庫卻沒有TC所支援的文字螢幕(控制檯視窗)控制函式(相應的標頭檔案是conio.h)。這必然給C++學習者在文字介面設計和程式設計上帶來諸多不便。要知道,文字介面設計是一種深入學習C++、掌握互動系統的實現方法的最簡單的一種手段,它不像C++的Windows圖形介面應用程式,涉及知識過多。為此,本系列文章來討論在Visual C++ 6.0開發環境中,如何編寫具有美觀清晰的控制檯視窗介面的C++應用程式。

  一、概述

  所謂控制檯應用程式,就是指那些需要與傳統DOS作業系統保持某種程式的相容,同時又不需要為使用者提供完善介面的程式。簡單地講,就是指在
Windows環境下執行的DOS程式(#add 命令列程式 ,而非正DOS程式)。一旦C++控制檯應用程式在Windows 9x/NT/2000作業系統中執行後,就會彈出一個視窗。例如下列過程:

  單擊Visual C++標準工具欄上的“New Text File”按鈕,開啟一個新的文件視窗。 

  選擇File | Save選單或按快捷鍵Ctrl+S或單擊標準工具欄的Save按鈕,彈出“儲存為”檔案對話方塊。將檔名為“Hello.cpp” (注意副檔名.cpp不能省略)。 

  在文件視窗中輸入下列程式碼:

#include "stdio.h"
#include "iostream"
using namespace std;
void main()
{
cout<<"Hello, Console!"<<endl;

}


  單擊小型編譯工具欄中的“Build”按鈕或按F7鍵,系統出現一個對話方塊,詢問是否將此專案的工作資料夾設定原始檔所在的資料夾,單擊[是]按鈕,系統開始編譯。 

  單擊小型編譯工具欄中的“Execute Program”按鈕或按Ctrl+F5鍵,執行剛才的程式。 

  程式執行後,彈出下圖的視窗。


  這就是控制檯視窗,與傳統的DOS螢幕視窗相比最主要的區別有:



  (1) 預設的控制檯視窗有系統選單和標題,它是一個記憶體緩衝區視窗,緩衝區大小取決於Windows作業系統的分配;而DOS螢幕是一種物理視窗,不具有Windows視窗特性,其大小取決於ROM BIOS分配的記憶體空間。

  (2) 控制檯視窗的文字操作是呼叫低層的Win32 APIs,而DOS螢幕的文字操作是通過呼叫BIOS的16(10h)中斷而實現的。

  (3) 預設的控制檯視窗可以接收鍵盤和滑鼠的輸入資訊,裝置驅動由Windows管理,而DOS螢幕視窗接收滑鼠時需要呼叫33h中斷,且滑鼠裝置驅動程式由自己安裝。

  二、控制檯文字視窗的一般控制步驟

  在Visual C++ 6.0中,控制檯視窗介面的一般程式設計控制步驟如下:

  1,呼叫GetStdHandle獲取當前的標準輸入(STDIN)和標準輸出(STDOUT)裝置控制代碼。函式原型為:

   HANDLE GetStdHandle( DWORD nStdHandle );

  其中,nStdHandle可以是STD_INPUT_HANDLE(標準輸入裝置控制代碼)、STD_OUTPUT_HANDLE(標準輸出裝置控制代碼)和STD_ERROR_HANDLE(標準錯誤控制代碼)。需要說明的是,“控制代碼”是Windows最常用的概念。它通常用來標識Windows資源(如選單、圖示、視窗等)和裝置等物件。雖然可以把控制代碼理解為是一個指標變數型別,但它不是物件所在的地址指標,而是作為Windows系統內部表的索引值來使用的。 

  2,呼叫相關文字介面控制的API函式。這些函式可分為三類

一是用於控制檯視窗控制的函式(包括視窗的緩衝區大小、視窗前景字元和背景顏色、視窗標題、大小和位置等);

二是用於控制檯輸入輸出的函式(包括字元屬性操作函式);

其他的函式併為最後一類。 

  3,呼叫CloseHandle()來關閉輸入輸出控制代碼。 

  注意,在程式中還必須包含標頭檔案windows.h。下面看一個程式:

#include "windows.h"
#include "stdio.h"
#include <conio.h>  //console  i/o

void main()
{
 HANDLE hOut;
 // 獲取標準輸出裝置控制代碼
 hOut = GetStdHandle(STD_OUTPUT_HANDLE);
 // 視窗資訊
 CONSOLE_SCREEN_BUFFER_INFO bInfo; 
 // 獲取視窗資訊
 GetConsoleScreenBufferInfo(hOut, &bInfo ); 
 
 printf("\n\nThe soul selects her own society,\n");
 printf("Then shuts the door;\n");
 printf("On her devine majority\n");
 printf("Obtrude no more.\n\n");
 _getch();
 COORD pos = {0, 0}; 
 // 向視窗中填充字元以獲得清屏的效果
 FillConsoleOutputCharacter(hOut, ' ', bInfo.dwSize.X * bInfo.dwSize.Y, pos, NULL);
 // 關閉標準輸出裝置控制代碼
 CloseHandle(hOut); 
}


程式中,COORD和CONSOLE_SCREEN_BUFFER_ INFO是wincon.h定義的控制檯結構體型別,其原型如下:

// 座標結構體
typedef struct _COORD { 
SHORT X; 
SHORT Y; 
} COORD; 

// 控制檯視窗資訊結構體
typedef struct _CONSOLE_SCREEN_BUFFER_INFO { 
COORD dwSize; // 緩衝區大小
COORD dwCursorPosition; // 當前游標位置
WORD wAttributes; // 字元屬性
SMALL_RECT srWindow; // 當前視窗顯示的大小和位置
COORD dwMaximumWindowSize; // 最大的視窗緩衝區大小
} CONSOLE_SCREEN_BUFFER_INFO ;


  還需要說明的是,雖然在C++中,iostream.h定義了cin和cout的標準輸入和輸出流物件。但它們只能實現基本的輸入輸出操作,對於控制檯視窗介面的控制卻無能為力,而且不能與stdio.h和conio.h友好相處,因為iostream.h和它們是C++兩套不同的輸入輸出操作方式,使用時要特別注意。

三、控制檯視窗操作

  用於控制檯視窗操作的API函式如下:

GetConsoleScreenBufferInfo 獲取控制檯視窗資訊
GetConsoleTitle 獲取控制檯視窗標題
ScrollConsoleScreenBuffer 在緩衝區中移動資料塊
SetConsoleScreenBufferSize 更改指定緩衝區大小
SetConsoleTitle 設定控制檯視窗標題
SetConsoleWindowInfo 設定控制檯視窗資訊


  此外,還有視窗字型、顯示模式等控制函式,這裡不再細說。下列舉一個示例,程式如下:

#include "windows.h"
#include "stdio.h"
#include <conio.h>

void main()
{
 // 獲取標準輸出裝置控制代碼
 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); 
 
 // 視窗緩衝區資訊
 CONSOLE_SCREEN_BUFFER_INFO bInfo; 
 // 獲取視窗緩衝區資訊
 GetConsoleScreenBufferInfo(hOut, &bInfo );
 
 char strTitle[255];
 // 獲取視窗標題
 GetConsoleTitle(strTitle, 255); 
 printf("當前視窗標題是:%s\n", strTitle);
 _getch();
 // 獲取視窗標題
 SetConsoleTitle("控制檯視窗操作"); 
 _getch();
 COORD size = {80, 25};
 // 重新設定緩衝區大小
 SetConsoleScreenBufferSize(hOut,size);
 _getch();
 // 重置視窗位置和大小
 SMALL_RECT rc = {0,0, 80-1, 25-1}; 
 SetConsoleWindowInfo(hOut,true ,&rc);
 // 關閉標準輸出裝置控制代碼
 CloseHandle(hOut);
}


  需要說明的是,控制檯視窗的原點座標是(0, 0),而最大的座標是緩衝區大小減1,例如當緩衝區大小為80*25時,其最大的座標是(79, 24)。


  四、文字屬性操作

  與DOS字元相似,控制檯視窗中的字元也有相應的屬性。這些屬性分為:文字的前景色背景色雙位元組字符集(DBCS)屬性三種。事實上,我們最關心是文字顏色,這樣可以構造出美觀的介面。顏色屬性都是一些預定義標識:

FOREGROUND_BLUE 藍色
FOREGROUND_GREEN 綠色
FOREGROUND_RED 紅色
FOREGROUND_INTENSITY 加強
BACKGROUND_BLUE 藍色背景
BACKGROUND_GREEN 綠色背景
BACKGROUND_RED 紅色背景
BACKGROUND_INTENSITY 背景色加強
COMMON_LVB_REVERSE_VIDEO 反色


  與文字屬性相關的主要函式有:

BOOL FillConsoleOutputAttribute( // 填充字元屬性
HANDLE hConsoleOutput, // 控制代碼
WORD wAttribute, // 文字屬性
DWORD nLength, // 個數
COORD dwWriteCoord, // 開始位置
LPDWORD lpNumberOfAttrsWritten // 返回填充的個數
);

BOOL SetConsoleTextAttribute( // 設定WriteConsole等函式的字元屬性
HANDLE hConsoleOutput, // 控制代碼
WORD wAttributes // 文字屬性
);

BOOL WriteConsoleOutputAttribute( // 在指定位置處寫屬性
HANDLE hConsoleOutput, // 控制代碼
CONST WORD *lpAttribute, // 屬性
DWORD nLength, // 個數
COORD dwWriteCoord, // 起始位置
LPDWORD lpNumberOfAttrsWritten // 已寫個數
);


  另外,獲取當前控制檯視窗的文字屬性是通過呼叫函式GetConsoleScreenBufferInfo後,在CONSOLE_SCREEN_ BUFFER_INFO結構成員wAttributes中得到。

  五、文字輸出

  文字輸出函式有:

BOOL FillConsoleOutputCharacter( // 填充指定資料的字元
HANDLE hConsoleOutput, // 控制代碼
TCHAR cCharacter, // 字元
DWORD nLength, // 字元個數
COORD dwWriteCoord, // 起始位置
LPDWORD lpNumberOfCharsWritten // 已寫個數
);

BOOL WriteConsole( // 在當前游標位置處插入指定數量的字元
HANDLE hConsoleOutput, // 控制代碼
CONST VOID *lpBuffer, // 字串
DWORD nNumberOfCharsToWrite, // 字元個數
LPDWORD lpNumberOfCharsWritten, // 已寫個數
LPVOID lpReserved // 保留
);

BOOL WriteConsoleOutput( // 向指定區域寫帶屬性的字元
HANDLE hConsoleOutput, // 控制代碼
CONST CHAR_INFO *lpBuffer, // 字元資料區
COORD dwBufferSize, // 資料區大小
COORD dwBufferCoord, // 起始座標
PSMALL_RECT lpWriteRegion // 要寫的區域
);

BOOL WriteConsoleOutputCharacter( // 在指定位置處插入指定數量的字元
HANDLE hConsoleOutput, // 控制代碼
LPCTSTR lpCharacter, // 字串
DWORD nLength, // 字元個數
COORD dwWriteCoord, // 起始位置
LPDWORD lpNumberOfCharsWritten // 已寫個數
);


  可以看出:WriteConsoleOutput函式功能相當於SetConsoleTextAttribute和WriteConsole的功能。而WriteConsoleOutputCharacter函式相當於SetConsoleCursorPosition(設定游標位置)和WriteConsole的功能。不過在具體使用要注意它們的區別。
 

六、文字操作示例

  下面看一個示例程式

#include "windows.h"
#include "stdio.h"
#include <conio.h>
#include <windows.h> 
HANDLE hOut;
void ShadowWindowLine(char *str); // 在具有陰影效果的視窗中顯示一行字元,視窗為居中顯示
void DrawBox(bool bSingle, SMALL_RECT rc); // 繪製邊框
void main()
{
 hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 獲取標準輸出裝置控制代碼
 SetConsoleOutputCP(437); // 設定內碼表
 ShadowWindowLine("Display a line of words, and center the window with shadow.");
 CloseHandle(hOut); // 關閉標準輸出裝置控制代碼
}

void ShadowWindowLine(char *str)
{
 CONSOLE_SCREEN_BUFFER_INFO bInfo; // 視窗緩衝區資訊
 GetConsoleScreenBufferInfo( hOut, &bInfo ); // 獲取視窗緩衝區資訊
 // 計算顯示視窗大小和位置
 int x1, y1, x2, y2, chNum = strlen(str);
 x1 = (bInfo.dwSize.X - chNum)/2 - 2;
 y1 = bInfo.dwSize.Y/2 - 2;
 x2 = x1 + chNum + 4;
 y2 = y1 + 5;
 WORD att1 = BACKGROUND_INTENSITY; // 陰影屬性
 WORD att0 = FOREGROUND_RED |FOREGROUND_GREEN |FOREGROUND_BLUE |
  FOREGROUND_INTENSITY |
  BACKGROUND_RED | BACKGROUND_BLUE; // 文字屬性
 
 WORD attText = FOREGROUND_RED |FOREGROUND_INTENSITY; // 文字屬性
 // 設定陰影
 COORD posShadow = {x1+1, y1+1}, posText = {x1, y1};
 for (int i=0; i<5; i++){
  FillConsoleOutputAttribute(hOut, att1, chNum + 4, posShadow, NULL); 
  posShadow.Y++;
 }
 // 填充視窗背景
 for (i=0; i<5; i++){
  FillConsoleOutputAttribute(hOut, att0, chNum + 4, posText, NULL); 
  posText.Y++;
 }
 // 寫文字和邊框
 posText.X = x1 + 2;
 posText.Y = y1 + 2;
 WriteConsoleOutputCharacter(hOut, str, strlen(str), posText, NULL);
 SMALL_RECT rc = {x1, y1, x2-1, y2-1};
 DrawBox(true, rc);
 SetConsoleTextAttribute(hOut, bInfo.wAttributes); // 恢復原來的屬性
}

void DrawBox(bool bSingle, SMALL_RECT rc)
{
 char chBox[6];
 if (bSingle) {
  chBox[0] = (char)0xda; // 左上角點
  chBox[1] = (char)0xbf; // 右上角點
  chBox[2] = (char)0xc0; // 左下角點
  chBox[3] = (char)0xd9; // 右下角點
  chBox[4] = (char)0xc4; // 水平
  chBox[5] = (char)0xb3; // 堅直
 } else {
  chBox[0] = (char)0xc9; // 左上角點
  chBox[1] = (char)0xbb; // 右上角點
  chBox[2] = (char)0xc8; // 左下角點
  chBox[3] = (char)0xbc; // 右下角點
  chBox[4] = (char)0xcd; // 水平
  chBox[5] = (char)0xba; // 堅直
 }
 COORD pos = {rc.Left, rc.Top};
 WriteConsoleOutputCharacter(hOut, &chBox[0], 1, pos, NULL);
 
 for (pos.X = rc.Left + 1; pos.X ;)
  WriteConsoleOutputCharacter(hOut, &chBox[4], 1, pos, NULL);
 
 pos.X = rc.Right;
 WriteConsoleOutputCharacter(hOut, &chBox[1], 1, pos, NULL);
 
 for (pos.Y = rc.Top+1; pos.Y;)
 {
  pos.X = rc.Left;
  WriteConsoleOutputCharacter(hOut, &chBox[5], 1, pos, NULL);
  pos.X = rc.Right;
  WriteConsoleOutputCharacter(hOut, &chBox[5], 1, pos, NULL);
 }
 pos.X = rc.Left; pos.Y = rc.Bottom;
 WriteConsoleOutputCharacter(hOut, &chBox[2], 1, pos, NULL);
 
 for (pos.X = rc.Left + 1; pos.X;)
  WriteConsoleOutputCharacter(hOut, &chBox[4], 1, pos, NULL);
 
 pos.X = rc.Right;
 WriteConsoleOutputCharacter(hOut, &chBox[3], 1, pos, NULL);
}


  程式執行結果如下圖所示。(#add 要滾動到下邊,否則看不到)

控制檯視窗程式執行結果 
  需要說明的是,上述程式在不同的字元程式碼頁面(code page)下顯示的結果是不同的。例如,中文Windows作業系統的預設內碼表是簡體中文(936),在該程式碼頁面下值超過128的單字元在Windows NT/XP是顯示不出來的。下表列出了可以使用的內碼表。

內碼表(Code page) 說 明
1258 越南文
1257 波羅的海文
1256 阿拉伯文
1255 希伯來文
1254 土耳其語
1253 希臘文
1252 拉丁文(ANSI)
1251 斯拉夫文
1250 中歐文
950 繁體中文
949 韓文
936 簡體中文
932 日文
874 泰文
850 使用多種語言(MS-DOS拉丁文)
437 MS-DOS美語/英語

七、滾動和移動

  ScrollConsoleScreenBuffer是實現文字區滾動和移動的API函式。它可以將指定的一塊文字區域移動到另一個區域,被移空的那塊區域由指定字元填充。函式的原型如下:

BOOL ScrollConsoleScreenBuffer(
  HANDLE hConsoleOutput, // 控制代碼
  CONST SMALL_RECT* lpScrollRectangle, // 要滾動或移動的區域
  CONST SMALL_RECT* lpClipRectangle, // 裁剪區域
  COORD dwDestinationOrigin, // 新的位置
  CONST CHAR_INFO* lpFill // 填充字元
);


  利用這個API函式還可以實現刪除指定行的操作。下面來舉一個例子,程式如下:

#include 
#include 
#include 
HANDLE hOut;
void DeleteLine(int row); // 刪除一行
void MoveText(int x, int y, SMALL_RECT rc); // 移動文字塊區域
void ClearScreen(void); // 清屏
void main()
{
 hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 獲取標準輸出裝置控制代碼
 WORD att = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY |   
       BACKGROUND_BLUE ;
 // 背景是藍色,文字顏色是黃色
 SetConsoleTextAttribute(hOut, att);
 ClearScreen();
 printf("\n\nThe soul selects her own society,\n");
 printf("Then shuts the door;\n");
 printf("On her devine majority;\n");
 printf("Obtrude no more.\n\n");
 CONSOLE_SCREEN_BUFFER_INFO bInfo;
 GetConsoleScreenBufferInfo( hOut, &bInfo ); 
 COORD endPos = {0, bInfo.dwSize.Y - 1};
 SetConsoleCursorPosition(hOut, endPos); // 設定游標位置
 SMALL_RECT rc = {0, 2, 40, 5};
 _getch();
 MoveText(10, 5, rc);
 _getch();
 DeleteLine(5);
 CloseHandle(hOut); // 關閉標準輸出裝置控制代碼
}

void DeleteLine(int row)
{
 SMALL_RECT rcScroll, rcClip;
 COORD crDest = {0, row - 1};
 CHAR_INFO chFill;
 CONSOLE_SCREEN_BUFFER_INFO bInfo;
 GetConsoleScreenBufferInfo( hOut, &bInfo ); 
 rcScroll.Left = 0;
 rcScroll.Top = row;
 rcScroll.Right = bInfo.dwSize.X - 1;
 rcScroll.Bottom = bInfo.dwSize.Y - 1;
 rcClip = rcScroll;
 chFill.Attributes = bInfo.wAttributes;
 chFill.Char.AsciiChar = ' ';
 ScrollConsoleScreenBuffer(hOut, &rcScroll, &rcClip, crDest, &chFill);
}

void MoveText(int x, int y, SMALL_RECT rc)
{
 COORD crDest = {x, y};
 CHAR_INFO chFill;
 CONSOLE_SCREEN_BUFFER_INFO bInfo;
 GetConsoleScreenBufferInfo( hOut, &bInfo ); 
 chFill.Attributes = bInfo.wAttributes;
 chFill.Char.AsciiChar = ' ';
 ScrollConsoleScreenBuffer(hOut, &rc, NULL, crDest, &chFill);
}

void ClearScreen(void)
{
 CONSOLE_SCREEN_BUFFER_INFO bInfo;
 GetConsoleScreenBufferInfo( hOut, &bInfo ); 
 COORD home = {0, 0};
 WORD att = bInfo.wAttributes;