控制台基础概念实例

上一篇文章 控制台基础概念 介绍了控制的基本构成,以及一些操作处理。这一部分以实际代码为主,给出控制台使用的几个例子。

以main函数作为入口函数的程序都是控制台程序,最简单的控制台程序就是Hello World的程序。这里不给出了。

GUI程序可以使用以下几种方式使用控制台:

  • 在调用CreateProcess时使用CREATE_NEW_CONSOLE标志。(默认情况下,待启动进程为控制台程序时不推荐使用该参数,因为无法确定用户输入是有哪个控制台处理的)
  • 通过 AttachConsole函数附加到一个已经存在的控制台。
  • 未附加到控制台的程序可通过AllocConsole函数创建控制台。(GUI进程默认不会和控制台关联。若使用DETACHED_PROCESS参数调用CreateProcess启动一个控制台进程,则会创建一个无控制台的控制台进程。)

GUI程序可使用FreeConsole函数来释放控制台。一个控制台程序可以通过GetConsoleProcessList函数获取所有与其关联的进程列表。

控制台程序提供以下函数,用于改变控制台属性:

GetConsoleScreenBufferInfo 获得窗口大小、屏幕缓冲大小和颜色属性
SetConsoleWindowInfo 设置控制台窗口大小
SetConsoleScreenBufferSize 设置控制台屏幕缓冲大小
SetConsoleTextAttribute 设置控制台字符属性
SetConsoleTitle 设置控制台标题
GetConsoleTitle 获取控制台标题

实例a 控制台参数获取及设置

本实例说明如何获取和设置控制台相关参数,例如设置和获取标题栏、设置和获取控制台显示窗口位置等。

代码如下: 

// 显示及设置控制台相关参数
// 1. 设置及获取控制台标题栏
// 2. 获取屏幕输出缓冲的参数
// 3. 设置控制台窗口大小
// 4. 设置控制台屏幕缓冲大小
// 建议使用visual studio 2005以上版本编译,使用unicode编码

#include <windows.h>
#include <iostream>
using std::wcout;
using std::endl;

int _tmain(int argc, _TCHAR* argv[])
{
    std::wcout.imbue(std::locale("chs"));

    // 获取和设置控制台标题栏
    DWORD title_need_size = 1024; // 64k
    TCHAR * console_title = new TCHAR[title_need_size+1];
    memset(console_title, 0, (title_need_size+1)*sizeof(TCHAR));
    DWORD title_size = GetConsoleTitle(console_title, title_need_size);
    if (0 == title_size)
    {
        wcout << "调用GetConsoleTitle异常,错误码"<< GetLastError() << endl;
        delete [] console_title;
        return 0;
    }
    wcout << _T("控制台标题栏") << console_title << endl;
    SetConsoleTitle(_T("ShowConsoleInfo"));
    wcout << endl << endl;

    HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    if (INVALID_HANDLE_VALUE == stdOutHandle)
    {
        wcout << "调用GetStdHandle失败,错误码" << GetLastError() << endl;
        return 0;
    }

    // 获取屏幕缓冲信息
    CONSOLE_SCREEN_BUFFER_INFO console_screen_buff_info;
    memset(&console_screen_buff_info, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFO));
    if (GetConsoleScreenBufferInfo(stdOutHandle, &console_screen_buff_info))
    {
        wcout << _T("屏幕缓冲大小:列数x行数") << console_screen_buff_info.dwSize.X
            << _T("x") << console_screen_buff_info.dwSize.Y << endl;
        wcout << _T("控制台光标位置(x,y):(") << console_screen_buff_info.dwCursorPosition.X
            << _T(",") << console_screen_buff_info.dwCursorPosition.Y << _T(")") << endl;
        wcout << _T("屏幕缓冲字符属性: ") << std::hex << console_screen_buff_info.wAttributes << endl;
        wcout << _T("屏幕缓冲显示窗口位置left:") << console_screen_buff_info.srWindow.Left 
            << _T(" Right:") << console_screen_buff_info.srWindow.Right 
            << _T(" Top:") << console_screen_buff_info.srWindow.Top
            << _T(" Bottom:") << console_screen_buff_info.srWindow.Bottom <<endl;
        wcout << _T("最大显示窗口大小:") << console_screen_buff_info.dwMaximumWindowSize.X
            << _T("x") << console_screen_buff_info.dwMaximumWindowSize.Y << endl;
    }

    // 下面设置需要将控制台屏幕缓冲窗口下移三行,用于移除关于设置控制台标题提示
    SMALL_RECT sRect;
    sRect.Left = 0;
    sRect.Right = 0;
    sRect.Top = 3;
    sRect.Bottom = 3;
    if (!SetConsoleWindowInfo(stdOutHandle, FALSE, &sRect))
    {
        wcout << "调用SetConsoleWindowInfo失败,错误码" << GetLastError() << endl;
        return 0;
    }
    // 以上代码是控制台滚屏的一种实现方式,可考虑扩展下
    // msdn上的例子
    // http://msdn.microsoft.com/en-us/library/windows/desktop/ms685118(v=vs.85).aspx

    // 可使用SetConsoleScreenBufferSize来设置屏幕缓冲大小

    return 0;
}
View Code

实例b GUI程序创建控制台及销毁

可以使用本实例的方法,在GUI程序中使用控制台调试跟踪相关问题。

最终运行效果如下图,GUI程序界面+后台的Console界面

代码如下:

// GUI程序创建控制台示例代码,1_bGuiAllocConsole
// GUI程序可以使用AttachConsole函数与某个已经存在的控制台关联,需要预先知道该进程pid
// 本demo展示了如何使用Alloc创建控制台,主要代码位于WM_CREATE、WM_DESTORY消息处理中
// 编译建议使用visual studio 2010 类型win32,使用unicode编码

#include <iostream>

// 全局变量:
HINSTANCE hInst;                                // 当前实例
TCHAR szTitle[] = _T("win32Test");// 标题栏文本
TCHAR szWindowClass[]= _T("WIN32TEST");// 主窗口类名

// 此代码模块中包含的函数的前向声明:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
    std::wcout.imbue(std::locale("chs"));

    MyRegisterClass(hInstance);

    // 执行应用程序初始化:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    MSG msg;
    // 主消息循环:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}



//
//  函数: MyRegisterClass()
//
//  目的: 注册窗口类。
//
//  注释:
//
//    仅当希望
//    此代码与添加到 Windows 95 中的“RegisterClassEx”
//    函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要,
//    这样应用程序就可以获得关联的
//    “格式正确的”小图标。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style            = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra        = 0;
    wcex.cbWndExtra        = 0;
    wcex.hInstance        = hInstance;
    wcex.hIcon            = NULL;
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground    = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName    = NULL;
    wcex.lpszClassName    = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassEx(&wcex);
}

//
//   函数: InitInstance(HINSTANCE, int)
//
//   目的: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // 将实例句柄存储在全局变量中

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的: 处理主窗口的消息。
//
//  WM_COMMAND    - 处理应用程序菜单
//  WM_PAINT    - 绘制主窗口
//  WM_DESTROY    - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    static RECT rcText = {10,10,300,100};

    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // TODO: 在此添加任意绘图代码...
        DrawText(hdc, _T("这是一个Win32测试程序!"), -1, &rcText, DT_CENTER);
        EndPaint(hWnd, &ps);
        break;
    case WM_CREATE:
        if (!AllocConsole())
        {
            MessageBox(hWnd, _T("创建控制台失败"), _T("初始化错误"), MB_OK);
        }
        SetConsoleTitle(_T("win32AllocConsoleTest"));
        // 这里重定向标准输出到控制台上
        // 如果不做重定向就需要使用WriteConsole或者_cprintf函数
        freopen( "CONOUT$", "w+t", stdout );// 申请写
        //freopen( "CONIN$", "r+t", stdin ); // 申请读

        std::wcout << _T("创建控制台并成功初始化") << std::endl;
        break;
    case WM_DESTROY:
        FreeConsole();
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
View Code

  实例c 控制台字符属性详细用法介绍

 函数SetConsoleTextAttribute可设置控制台显示的字符属性。支持一下设置:

AttributeMeaning
FOREGROUND_BLUE 前景色,包含蓝色
FOREGROUND_GREEN 前景色,包含绿色
FOREGROUND_RED 前景色,包含红色
FOREGROUND_INTENSITY 前景色,加亮
BACKGROUND_BLUE 背景色,包含蓝色
BACKGROUND_GREEN 背景色,包含绿色
BACKGROUND_RED 背景色,包含红色
BACKGROUND_INTENSITY 背景色,加亮
COMMON_LVB_LEADING_BYTE 多字节码的Leading byte.
COMMON_LVB_TRAILING_BYTE 多字节码的Trailing byte.
COMMON_LVB_GRID_HORIZONTAL 顶部水平网格(上划线)
COMMON_LVB_GRID_LVERTICAL 左竖直网格
COMMON_LVB_GRID_RVERTICAL 右竖直网格
COMMON_LVB_REVERSE_VIDEO 前景色背景色反转
COMMON_LVB_UNDERSCORE 下划线

示例代码如下: 

// 控制台字体属性设置示例 ChangeTextAttrDemo
// 设置前景色、背景色、unicode下划线、删除线等
// 建议使用vs2005以上版本编译,unicode编码

#include <windows.h>
#include <iostream>
using std::wcout;
using std::endl;

int _tmain(int argc, _TCHAR* argv[])
{
    // 输出中文
    std::wcout.imbue(std::locale("chs"));

    // 设置控制台标题栏
    SetConsoleTitle(_T("ChangeTextAttrDemo"));

    HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    if (INVALID_HANDLE_VALUE == stdOutHandle)
    {
        wcout << L"调用GetStdHandle失败,错误码" << GetLastError() << endl;
        return 0;
    }

    // 默认背景色黑色,前景色白色
    wcout << _T("默认背景色,ABCabc123*&@!") << endl << endl;

    // 红色前景色,绿色背景色
    SetConsoleTextAttribute(stdOutHandle, FOREGROUND_RED|BACKGROUND_GREEN);
    wcout << _T("设置红色前景色,绿色背景色") << endl;
    wcout << _T("测试字符串,ABCabc123*&@!") << endl << endl;

    // 前景色加亮对比
    SetConsoleTextAttribute(stdOutHandle, 
        FOREGROUND_RED|BACKGROUND_GREEN|FOREGROUND_INTENSITY);
    wcout << _T("设置红色前景色,绿色背景色,前景色加亮对比") << endl;
    wcout << _T("测试字符串,ABCabc123*&@!") << endl << endl;

    // 设置为默认字体属性+上划线
    SetConsoleTextAttribute(stdOutHandle, 
        FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN|COMMON_LVB_GRID_HORIZONTAL);
    wcout << _T("设置为默认字体属性+顶部水平网格") << endl;
    wcout << _T("测试字符串,ABCabc123*&@!") << endl << endl;

    // 设置为蓝色前景+下划线
    SetConsoleTextAttribute(stdOutHandle, 
        FOREGROUND_BLUE|COMMON_LVB_UNDERSCORE);
    wcout << _T("设置为蓝色前景+下划线") << endl;
    wcout << _T("测试字符串,ABCabc123*&@!") << endl << endl;

    // 设置为绿色前景+左划线
    SetConsoleTextAttribute(stdOutHandle, 
        FOREGROUND_GREEN|COMMON_LVB_GRID_LVERTICAL);
    wcout << _T("设置为绿色前景+左竖网格") << endl;
    wcout << _T("  测试字符串,ABCabc123*&@!") << endl << endl;

    // 设置为绿色背景+右划线
    SetConsoleTextAttribute(stdOutHandle, 
        BACKGROUND_GREEN|COMMON_LVB_GRID_RVERTICAL);
    wcout << _T("设置为绿色背景+右竖网格") << endl;
    wcout << _T("  测试字符串,ABCabc123*&@!") << endl << endl;

    SetConsoleTextAttribute(stdOutHandle, 
        FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN);
    return 0;
}
View Code

如果需要彩色的控制台,建议关注下代码中的各种效果。上述宏可组合使用,支持8种前景色和背景色,输出效果如下图:

 

实例d 控制台光标位置、样式及位置

本实例介绍控制台下光标的样式获取及设置,光标位置的设置等。

代码如下。(具体效果需要自己编译代码查看) 

// 控制台光标样式获取、设置,CursorAttrDemo
// 1. 光标属性获取及设置
// 2. 光标位置获取及设置
// 建议使用vs2005以上版本编译,unicode编码

#include <windows.h>
#include <iostream>
using std::wcout;
using std::endl;

int _tmain(int argc, _TCHAR* argv[])
{
    // 输出中文
    std::wcout.imbue(std::locale("chs"));

    // 设置控制台标题栏
    SetConsoleTitle(_T("CursorAttrDemo"));

    HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    if (INVALID_HANDLE_VALUE == stdOutHandle)
    {
        wcout << L"调用GetStdHandle失败,错误码" << GetLastError() << endl;
        return 0;
    }

    CONSOLE_CURSOR_INFO cursor_info;
    memset(&cursor_info, 0, sizeof(cursor_info));
    if (GetConsoleCursorInfo(stdOutHandle, &cursor_info))
    {
        wcout << _T("光标可见:") << (cursor_info.bVisible ? _T("") : _T("")) << endl;
        wcout << _T("光标占位比例 :") << cursor_info.dwSize << _T("%") << endl;

        cursor_info.bVisible = TRUE;
        cursor_info.dwSize = 100;
        SetConsoleCursorInfo(stdOutHandle, &cursor_info);
        wcout << _T("设置100%光标占比") << endl;
        int x;
        std::cin >> x;

        cursor_info.dwSize = 50;
        SetConsoleCursorInfo(stdOutHandle, &cursor_info);
        wcout << _T("设置50%光标占比") << endl;
    }

    // 获取光标位置使用GetConsoleScreenBufferInfo函数
    // 直接输出定位到第二行
    COORD cursor_pos = {0, 8};
    SetConsoleCursorPosition(stdOutHandle, cursor_pos);
    
    return 0;
}
View Code

注:本文涉及所有代码可使用Git直接下载:https://git.oschina.net/Tocy/SampleCode.git。实际代码位于Console目录下,以1_开头的cpp文件。

 

本文作者:Tocy

版权所有,请勿用于商业用途,转载请注明原文地址。本人保留所有权利。

posted @ 2014-11-24 22:19  Tocy  阅读(1865)  评论(0编辑  收藏  举报